Golang implemented sidechain for Bytom
Revision | eed308370dd59342dd354707cf5bd213c9febc3b (tree) |
---|---|
Time | 2019-06-18 10:44:33 |
Author | Chengcheng Zhang <943420582@qq.c...> |
Commiter | Chengcheng Zhang |
fix conflicts
@@ -1,7 +1,6 @@ | ||
1 | 1 | package database |
2 | 2 | |
3 | 3 | import ( |
4 | - "fmt" | |
5 | 4 | "strconv" |
6 | 5 | |
7 | 6 | "github.com/golang/groupcache/singleflight" |
@@ -13,17 +12,17 @@ import ( | ||
13 | 12 | ) |
14 | 13 | |
15 | 14 | const ( |
16 | - maxCachedBlockHeaders = 1000 | |
17 | - maxCachedBlockTransactions = 1000 | |
18 | - maxCachedVoteResults = 144 // int(60 * 60 * 24 * 1000 / consensus.BlockTimeInterval / consensus.RoundVoteBlockNums) | |
15 | + maxCachedBlockHeaders = 4096 | |
16 | + maxCachedBlockTransactions = 1024 | |
17 | + maxCachedVoteResults = 128 | |
19 | 18 | ) |
20 | 19 | |
21 | 20 | type fillBlockHeaderFn func(hash *bc.Hash, height uint64) (*types.BlockHeader, error) |
22 | 21 | type fillBlockTransactionsFn func(hash *bc.Hash) ([]*types.Tx, error) |
23 | 22 | type fillVoteResultFn func(seq uint64) (*state.VoteResult, error) |
24 | 23 | |
25 | -func newBlockCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillVoteResult fillVoteResultFn) blockCache { | |
26 | - return blockCache{ | |
24 | +func newCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTransactionsFn, fillVoteResult fillVoteResultFn) cache { | |
25 | + return cache{ | |
27 | 26 | lruBlockHeaders: common.NewCache(maxCachedBlockHeaders), |
28 | 27 | lruBlockTxs: common.NewCache(maxCachedBlockTransactions), |
29 | 28 | lruVoteResults: common.NewCache(maxCachedVoteResults), |
@@ -34,7 +33,7 @@ func newBlockCache(fillBlockHeader fillBlockHeaderFn, fillBlockTxs fillBlockTran | ||
34 | 33 | } |
35 | 34 | } |
36 | 35 | |
37 | -type blockCache struct { | |
36 | +type cache struct { | |
38 | 37 | lruBlockHeaders *common.Cache |
39 | 38 | lruBlockTxs *common.Cache |
40 | 39 | lruVoteResults *common.Cache |
@@ -43,28 +42,22 @@ type blockCache struct { | ||
43 | 42 | fillBlockTransactionFn func(hash *bc.Hash) ([]*types.Tx, error) |
44 | 43 | fillVoteResultFn func(seq uint64) (*state.VoteResult, error) |
45 | 44 | |
46 | - singleBlockHeader singleflight.Group | |
47 | - singleBlockTxs singleflight.Group | |
48 | - singleVoteResult singleflight.Group | |
45 | + sf singleflight.Group | |
49 | 46 | } |
50 | 47 | |
51 | -func (c *blockCache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) { | |
52 | - if bH, ok := c.getBlockHeader(hash); ok { | |
53 | - return bH, nil | |
48 | +func (c *cache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) { | |
49 | + if data, ok := c.lruBlockHeaders.Get(*hash); ok { | |
50 | + return data.(*types.BlockHeader), nil | |
54 | 51 | } |
55 | 52 | |
56 | - blockHeader, err := c.singleBlockHeader.Do(hash.String(), func() (interface{}, error) { | |
57 | - bH, err := c.fillBlockHeaderFn(hash, height) | |
53 | + blockHeader, err := c.sf.Do("BlockHeader:"+hash.String(), func() (interface{}, error) { | |
54 | + blockHeader, err := c.fillBlockHeaderFn(hash, height) | |
58 | 55 | if err != nil { |
59 | 56 | return nil, err |
60 | 57 | } |
61 | 58 | |
62 | - if bH == nil { | |
63 | - return nil, fmt.Errorf("There are no blockHeader with given hash %s", hash.String()) | |
64 | - } | |
65 | - | |
66 | - c.addBlockHeader(bH) | |
67 | - return bH, nil | |
59 | + c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader) | |
60 | + return blockHeader, nil | |
68 | 61 | }) |
69 | 62 | if err != nil { |
70 | 63 | return nil, err |
@@ -72,87 +65,51 @@ func (c *blockCache) lookupBlockHeader(hash *bc.Hash, height uint64) (*types.Blo | ||
72 | 65 | return blockHeader.(*types.BlockHeader), nil |
73 | 66 | } |
74 | 67 | |
75 | -func (c *blockCache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) { | |
76 | - if bTxs, ok := c.getBlockTransactions(hash); ok { | |
77 | - return bTxs, nil | |
68 | +func (c *cache) lookupBlockTxs(hash *bc.Hash) ([]*types.Tx, error) { | |
69 | + if data, ok := c.lruBlockTxs.Get(*hash); ok { | |
70 | + return data.([]*types.Tx), nil | |
78 | 71 | } |
79 | 72 | |
80 | - blockTransactions, err := c.singleBlockTxs.Do(hash.String(), func() (interface{}, error) { | |
81 | - bTxs, err := c.fillBlockTransactionFn(hash) | |
73 | + blockTxs, err := c.sf.Do("BlockTxs:"+hash.String(), func() (interface{}, error) { | |
74 | + blockTxs, err := c.fillBlockTransactionFn(hash) | |
82 | 75 | if err != nil { |
83 | 76 | return nil, err |
84 | 77 | } |
85 | 78 | |
86 | - if bTxs == nil { | |
87 | - return nil, fmt.Errorf("There are no block transactions with given hash %s", hash.String()) | |
88 | - } | |
89 | - | |
90 | - c.addBlockTxs(*hash, bTxs) | |
91 | - return bTxs, nil | |
79 | + c.lruBlockTxs.Add(hash, blockTxs) | |
80 | + return blockTxs, nil | |
92 | 81 | }) |
93 | 82 | if err != nil { |
94 | 83 | return nil, err |
95 | 84 | } |
96 | - return blockTransactions.([]*types.Tx), nil | |
85 | + return blockTxs.([]*types.Tx), nil | |
97 | 86 | } |
98 | 87 | |
99 | -func (c *blockCache) lookupVoteResult(seq uint64) (*state.VoteResult, error) { | |
100 | - if vr, ok := c.getVoteResult(seq); ok { | |
101 | - return vr, nil | |
88 | +func (c *cache) lookupVoteResult(seq uint64) (*state.VoteResult, error) { | |
89 | + if data, ok := c.lruVoteResults.Get(seq); ok { | |
90 | + return data.(*state.VoteResult).Fork(), nil | |
102 | 91 | } |
103 | 92 | |
104 | 93 | seqStr := strconv.FormatUint(seq, 10) |
105 | - voteResult, err := c.singleVoteResult.Do(seqStr, func() (interface{}, error) { | |
106 | - v, err := c.fillVoteResultFn(seq) | |
94 | + voteResult, err := c.sf.Do("VoteResult:"+seqStr, func() (interface{}, error) { | |
95 | + voteResult, err := c.fillVoteResultFn(seq) | |
107 | 96 | if err != nil { |
108 | 97 | return nil, err |
109 | 98 | } |
110 | 99 | |
111 | - if v == nil { | |
112 | - return nil, fmt.Errorf("There are no vote result with given seq %s", seqStr) | |
113 | - } | |
114 | - | |
115 | - c.addVoteResult(v) | |
116 | - return v, nil | |
100 | + c.lruVoteResults.Add(voteResult.Seq, voteResult) | |
101 | + return voteResult, nil | |
117 | 102 | }) |
118 | 103 | if err != nil { |
119 | 104 | return nil, err |
120 | 105 | } |
121 | - return voteResult.(*state.VoteResult), nil | |
122 | -} | |
123 | - | |
124 | -func (c *blockCache) getBlockHeader(hash *bc.Hash) (*types.BlockHeader, bool) { | |
125 | - blockHeader, ok := c.lruBlockHeaders.Get(*hash) | |
126 | - if blockHeader == nil { | |
127 | - return nil, ok | |
128 | - } | |
129 | - return blockHeader.(*types.BlockHeader), ok | |
130 | -} | |
131 | - | |
132 | -func (c *blockCache) getBlockTransactions(hash *bc.Hash) ([]*types.Tx, bool) { | |
133 | - txs, ok := c.lruBlockTxs.Get(*hash) | |
134 | - if txs == nil { | |
135 | - return nil, ok | |
136 | - } | |
137 | - return txs.([]*types.Tx), ok | |
138 | -} | |
139 | - | |
140 | -func (c *blockCache) getVoteResult(seq uint64) (*state.VoteResult, bool) { | |
141 | - voteResult, ok := c.lruVoteResults.Get(seq) | |
142 | - if voteResult == nil { | |
143 | - return nil, ok | |
144 | - } | |
145 | - return voteResult.(*state.VoteResult), ok | |
146 | -} | |
147 | - | |
148 | -func (c *blockCache) addBlockHeader(blockHeader *types.BlockHeader) { | |
149 | - c.lruBlockHeaders.Add(blockHeader.Hash(), blockHeader) | |
106 | + return voteResult.(*state.VoteResult).Fork(), nil | |
150 | 107 | } |
151 | 108 | |
152 | -func (c *blockCache) addBlockTxs(hash bc.Hash, txs []*types.Tx) { | |
153 | - c.lruBlockTxs.Add(hash, txs) | |
109 | +func (c *cache) removeBlockHeader(blockHeader *types.BlockHeader) { | |
110 | + c.lruBlockHeaders.Remove(blockHeader.Hash()) | |
154 | 111 | } |
155 | 112 | |
156 | -func (c *blockCache) addVoteResult(voteResult *state.VoteResult) { | |
157 | - c.lruVoteResults.Add(voteResult.Seq, voteResult) | |
113 | +func (c *cache) removeVoteResult(voteResult *state.VoteResult) { | |
114 | + c.lruVoteResults.Remove(voteResult.Seq) | |
158 | 115 | } |
@@ -44,7 +44,7 @@ func TestBlockCache(t *testing.T) { | ||
44 | 44 | return voteResults[seq], nil |
45 | 45 | } |
46 | 46 | |
47 | - cache := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn) | |
47 | + cache := newCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn) | |
48 | 48 | |
49 | 49 | for i := 0; i < maxCachedBlockHeaders+10; i++ { |
50 | 50 | block := newBlock(uint64(i)) |
@@ -55,7 +55,7 @@ func TestBlockCache(t *testing.T) { | ||
55 | 55 | for i := 0; i < 10; i++ { |
56 | 56 | block := newBlock(uint64(i)) |
57 | 57 | hash := block.Hash() |
58 | - if b, _ := cache.getBlockHeader(&hash); b != nil { | |
58 | + if _, ok := cache.lruBlockHeaders.Get(hash); ok { | |
59 | 59 | t.Fatalf("find old block") |
60 | 60 | } |
61 | 61 | } |
@@ -63,7 +63,7 @@ func TestBlockCache(t *testing.T) { | ||
63 | 63 | for i := 10; i < maxCachedBlockHeaders+10; i++ { |
64 | 64 | block := newBlock(uint64(i)) |
65 | 65 | hash := block.Hash() |
66 | - if b, _ := cache.getBlockHeader(&hash); b == nil { | |
66 | + if _, ok := cache.lruBlockHeaders.Get(hash); !ok { | |
67 | 67 | t.Fatalf("can't find new block") |
68 | 68 | } |
69 | 69 | } |
@@ -75,14 +75,14 @@ func TestBlockCache(t *testing.T) { | ||
75 | 75 | |
76 | 76 | for i := 0; i < 10; i++ { |
77 | 77 | voteResult := newVoteResult(uint64(i)) |
78 | - if v, _ := cache.getVoteResult(voteResult.Seq); v != nil { | |
78 | + if _, ok := cache.lruVoteResults.Get(voteResult.Seq); ok { | |
79 | 79 | t.Fatalf("find old vote result") |
80 | 80 | } |
81 | 81 | } |
82 | 82 | |
83 | 83 | for i := 10; i < maxCachedVoteResults+10; i++ { |
84 | 84 | voteResult := newVoteResult(uint64(i)) |
85 | - if v, _ := cache.getVoteResult(voteResult.Seq); v == nil { | |
85 | + if _, ok := cache.lruVoteResults.Get(voteResult.Seq); !ok { | |
86 | 86 | t.Fatalf("can't find new vote result") |
87 | 87 | } |
88 | 88 | } |
@@ -3,11 +3,11 @@ package database | ||
3 | 3 | import ( |
4 | 4 | "encoding/binary" |
5 | 5 | "encoding/json" |
6 | + "fmt" | |
6 | 7 | "time" |
7 | 8 | |
8 | 9 | "github.com/golang/protobuf/proto" |
9 | 10 | log "github.com/sirupsen/logrus" |
10 | - "github.com/tendermint/tmlibs/common" | |
11 | 11 | |
12 | 12 | dbm "github.com/vapor/database/leveldb" |
13 | 13 | "github.com/vapor/database/storage" |
@@ -33,9 +33,10 @@ func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState { | ||
33 | 33 | if bytes == nil { |
34 | 34 | return nil |
35 | 35 | } |
36 | + | |
36 | 37 | bsj := &protocol.BlockStoreState{} |
37 | 38 | if err := json.Unmarshal(bytes, bsj); err != nil { |
38 | - common.PanicCrisis(common.Fmt("Could not unmarshal bytes: %X", bytes)) | |
39 | + log.WithField("err", err).Panic("fail on unmarshal BlockStoreStateJSON") | |
39 | 40 | } |
40 | 41 | return bsj |
41 | 42 | } |
@@ -45,7 +46,7 @@ func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState { | ||
45 | 46 | // methods for querying current data. |
46 | 47 | type Store struct { |
47 | 48 | db dbm.DB |
48 | - cache blockCache | |
49 | + cache cache | |
49 | 50 | } |
50 | 51 | |
51 | 52 | func calcBlockHeaderKey(height uint64, hash *bc.Hash) []byte { |
@@ -71,26 +72,26 @@ func calcVoteResultKey(seq uint64) []byte { | ||
71 | 72 | |
72 | 73 | // GetBlockHeader return the block header by given hash and height |
73 | 74 | func GetBlockHeader(db dbm.DB, hash *bc.Hash, height uint64) (*types.BlockHeader, error) { |
74 | - block := &types.Block{} | |
75 | 75 | binaryBlockHeader := db.Get(calcBlockHeaderKey(height, hash)) |
76 | 76 | if binaryBlockHeader == nil { |
77 | - return nil, nil | |
77 | + return nil, fmt.Errorf("There are no blockHeader with given hash %s", hash.String()) | |
78 | 78 | } |
79 | + | |
80 | + block := &types.Block{} | |
79 | 81 | if err := block.UnmarshalText(binaryBlockHeader); err != nil { |
80 | 82 | return nil, err |
81 | 83 | } |
82 | - | |
83 | 84 | return &block.BlockHeader, nil |
84 | 85 | } |
85 | 86 | |
86 | 87 | // GetBlockTransactions return the block transactions by given hash |
87 | 88 | func GetBlockTransactions(db dbm.DB, hash *bc.Hash) ([]*types.Tx, error) { |
88 | - block := &types.Block{} | |
89 | 89 | binaryBlockTxs := db.Get(calcBlockTransactionsKey(hash)) |
90 | 90 | if binaryBlockTxs == nil { |
91 | - return nil, errors.New("The transactions in the block is empty") | |
91 | + return nil, fmt.Errorf("There are no block transactions with given hash %s", hash.String()) | |
92 | 92 | } |
93 | 93 | |
94 | + block := &types.Block{} | |
94 | 95 | if err := block.UnmarshalText(binaryBlockTxs); err != nil { |
95 | 96 | return nil, err |
96 | 97 | } |
@@ -122,22 +123,17 @@ func NewStore(db dbm.DB) *Store { | ||
122 | 123 | fillVoteResultFn := func(seq uint64) (*state.VoteResult, error) { |
123 | 124 | return GetVoteResult(db, seq) |
124 | 125 | } |
125 | - bc := newBlockCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn) | |
126 | + bc := newCache(fillBlockHeaderFn, fillBlockTxsFn, fillVoteResultFn) | |
126 | 127 | return &Store{ |
127 | 128 | db: db, |
128 | 129 | cache: bc, |
129 | 130 | } |
130 | 131 | } |
131 | 132 | |
132 | -// GetUtxo will search the utxo in db | |
133 | -func (s *Store) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) { | |
134 | - return getUtxo(s.db, hash) | |
135 | -} | |
136 | - | |
137 | 133 | // BlockExist check if the block is stored in disk |
138 | 134 | func (s *Store) BlockExist(hash *bc.Hash, height uint64) bool { |
139 | - blockHeader, err := s.cache.lookupBlockHeader(hash, height) | |
140 | - return err == nil && blockHeader != nil | |
135 | + _, err := s.cache.lookupBlockHeader(hash, height) | |
136 | + return err == nil | |
141 | 137 | } |
142 | 138 | |
143 | 139 | // GetBlock return the block by given hash |
@@ -160,20 +156,17 @@ func (s *Store) GetBlock(hash *bc.Hash, height uint64) (*types.Block, error) { | ||
160 | 156 | |
161 | 157 | // GetBlockHeader return the BlockHeader by given hash |
162 | 158 | func (s *Store) GetBlockHeader(hash *bc.Hash, height uint64) (*types.BlockHeader, error) { |
163 | - blockHeader, err := s.cache.lookupBlockHeader(hash, height) | |
164 | - if err != nil { | |
165 | - return nil, err | |
166 | - } | |
167 | - return blockHeader, nil | |
159 | + return s.cache.lookupBlockHeader(hash, height) | |
168 | 160 | } |
169 | 161 | |
170 | 162 | // GetBlockTransactions return the Block transactions by given hash |
171 | 163 | func (s *Store) GetBlockTransactions(hash *bc.Hash) ([]*types.Tx, error) { |
172 | - txs, err := s.cache.lookupBlockTxs(hash) | |
173 | - if err != nil { | |
174 | - return nil, err | |
175 | - } | |
176 | - return txs, nil | |
164 | + return s.cache.lookupBlockTxs(hash) | |
165 | +} | |
166 | + | |
167 | +// GetStoreStatus return the BlockStoreStateJSON | |
168 | +func (s *Store) GetStoreStatus() *protocol.BlockStoreState { | |
169 | + return loadBlockStoreStateJSON(s.db) | |
177 | 170 | } |
178 | 171 | |
179 | 172 | // GetTransactionsUtxo will return all the utxo that related to the input txs |
@@ -195,9 +188,9 @@ func (s *Store) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, erro | ||
195 | 188 | return ts, nil |
196 | 189 | } |
197 | 190 | |
198 | -// GetStoreStatus return the BlockStoreStateJSON | |
199 | -func (s *Store) GetStoreStatus() *protocol.BlockStoreState { | |
200 | - return loadBlockStoreStateJSON(s.db) | |
191 | +// GetUtxo will search the utxo in db | |
192 | +func (s *Store) GetUtxo(hash *bc.Hash) (*storage.UtxoEntry, error) { | |
193 | + return getUtxo(s.db, hash) | |
201 | 194 | } |
202 | 195 | |
203 | 196 | // GetVoteResult retrive the voting result in specified vote sequence |
@@ -251,7 +244,6 @@ func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error | ||
251 | 244 | // SaveBlock persists a new block in the protocol. |
252 | 245 | func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error { |
253 | 246 | startTime := time.Now() |
254 | - | |
255 | 247 | binaryBlockHeader, err := block.MarshalTextForBlockHeader() |
256 | 248 | if err != nil { |
257 | 249 | return errors.Wrap(err, "Marshal block header") |
@@ -285,8 +277,6 @@ func (s *Store) SaveBlock(block *types.Block, ts *bc.TransactionStatus) error { | ||
285 | 277 | |
286 | 278 | // SaveBlockHeader persists a new block header in the protocol. |
287 | 279 | func (s *Store) SaveBlockHeader(blockHeader *types.BlockHeader) error { |
288 | - startTime := time.Now() | |
289 | - | |
290 | 280 | binaryBlockHeader, err := blockHeader.MarshalText() |
291 | 281 | if err != nil { |
292 | 282 | return errors.Wrap(err, "Marshal block header") |
@@ -294,18 +284,7 @@ func (s *Store) SaveBlockHeader(blockHeader *types.BlockHeader) error { | ||
294 | 284 | |
295 | 285 | blockHash := blockHeader.Hash() |
296 | 286 | s.db.Set(calcBlockHeaderKey(blockHeader.Height, &blockHash), binaryBlockHeader) |
297 | - | |
298 | - // updata blockheader cache | |
299 | - if _, ok := s.cache.getBlockHeader(&blockHash); ok { | |
300 | - s.cache.addBlockHeader(blockHeader) | |
301 | - } | |
302 | - | |
303 | - log.WithFields(log.Fields{ | |
304 | - "module": logModule, | |
305 | - "height": blockHeader.Height, | |
306 | - "hash": blockHash.String(), | |
307 | - "duration": time.Since(startTime), | |
308 | - }).Info("blockHeader saved on disk") | |
287 | + s.cache.removeBlockHeader(blockHeader) | |
309 | 288 | return nil |
310 | 289 | } |
311 | 290 |
@@ -323,9 +302,7 @@ func (s *Store) SaveChainStatus(node, irreversibleNode *state.BlockNode, view *s | ||
323 | 302 | } |
324 | 303 | |
325 | 304 | batch.Set(calcVoteResultKey(vote.Seq), bytes) |
326 | - if _, ok := s.cache.getVoteResult(vote.Seq); ok { | |
327 | - s.cache.addVoteResult(vote) | |
328 | - } | |
305 | + s.cache.removeVoteResult(vote) | |
329 | 306 | } |
330 | 307 | |
331 | 308 | bytes, err := json.Marshal(protocol.BlockStoreState{ |
@@ -213,7 +213,6 @@ func txInToUtxos(tx *types.Tx, statusFail bool) []*account.UTXO { | ||
213 | 213 | Vote: resOut.Vote, |
214 | 214 | } |
215 | 215 | default: |
216 | - log.WithFields(log.Fields{"module": logModule, "err": errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", inpID.Bytes(), e)}).Error("txInToUtxos fail on get resOut") | |
217 | 216 | continue |
218 | 217 | } |
219 | 218 | utxos = append(utxos, utxo) |