diff options
author | Bojie Wu <bojie@dexon.org> | 2018-10-09 13:28:45 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@byzantine-lab.io> | 2019-06-12 17:27:17 +0800 |
commit | 3f320c9048198d14bc44413861efcbc5665324b1 (patch) | |
tree | d0ae47cd428ba4fa21546efcd1ac4ab50933d600 /core | |
parent | e0c84599b660438d34972ceb494d36f83c26d430 (diff) | |
download | go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.tar go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.tar.gz go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.tar.bz2 go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.tar.lz go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.tar.xz go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.tar.zst go-tangerine-3f320c9048198d14bc44413861efcbc5665324b1.zip |
app: add cache mechanism to increase performance
Diffstat (limited to 'core')
-rw-r--r-- | core/blockchain.go | 178 | ||||
-rw-r--r-- | core/types/block.go | 35 | ||||
-rw-r--r-- | core/types/gen_header_json.go | 75 |
3 files changed, 136 insertions, 152 deletions
diff --git a/core/blockchain.go b/core/blockchain.go index 80d4b2f08..429b3a4cc 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -30,7 +30,7 @@ import ( coreCommon "github.com/dexon-foundation/dexon-consensus-core/common" coreTypes "github.com/dexon-foundation/dexon-consensus-core/core/types" - lru "github.com/hashicorp/golang-lru" + "github.com/hashicorp/golang-lru" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" @@ -142,9 +142,11 @@ type BlockChain struct { badBlocks *lru.Cache // Bad block cache shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. - confirmedBlockMu sync.Mutex - confirmedBlocks map[coreCommon.Hash]*coreTypes.Block - chainConfirmedBlocks map[uint32][]*coreTypes.Block + confirmedBlocks map[coreCommon.Hash]*blockInfo + addressNonce map[common.Address]uint64 + addressCost map[common.Address]*big.Int + addressCounter map[common.Address]uint64 + chainLastHeight map[uint32]uint64 pendingBlocks map[uint64]struct { block *types.Block @@ -171,28 +173,30 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par badBlocks, _ := lru.New(badBlockLimit) bc := &BlockChain{ - chainConfig: chainConfig, - cacheConfig: cacheConfig, - db: db, - triegc: prque.New(nil), - stateCache: state.NewDatabase(db), - stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit), - quit: make(chan struct{}), - shouldPreserve: shouldPreserve, - bodyCache: bodyCache, - bodyRLPCache: bodyRLPCache, - receiptsCache: receiptsCache, - blockCache: blockCache, - futureBlocks: futureBlocks, - engine: engine, - vmConfig: vmConfig, - badBlocks: badBlocks, - confirmedBlocks: make(map[coreCommon.Hash]*coreTypes.Block), - chainConfirmedBlocks: make(map[uint32][]*coreTypes.Block), + chainConfig: chainConfig, + cacheConfig: cacheConfig, + db: db, + triegc: prque.New(nil), + stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit), + quit: make(chan struct{}), + shouldPreserve: shouldPreserve, + bodyCache: bodyCache, + bodyRLPCache: bodyRLPCache, + receiptsCache: receiptsCache, + blockCache: blockCache, + futureBlocks: futureBlocks, + engine: engine, + vmConfig: vmConfig, + badBlocks: badBlocks, + confirmedBlocks: make(map[coreCommon.Hash]*blockInfo), pendingBlocks: make(map[uint64]struct { block *types.Block receipts types.Receipts }), + addressNonce: make(map[common.Address]uint64), + addressCost: make(map[common.Address]*big.Int), + addressCounter: make(map[common.Address]uint64), + chainLastHeight: make(map[uint32]uint64), } bc.SetValidator(NewDexonBlockValidator(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) @@ -236,105 +240,79 @@ func (bc *BlockChain) GetVMConfig() *vm.Config { return &bc.vmConfig } -func (bc *BlockChain) AddConfirmedBlock(block *coreTypes.Block) { - bc.confirmedBlockMu.Lock() - defer bc.confirmedBlockMu.Unlock() - - bc.confirmedBlocks[block.Hash] = block - chainBlocks := bc.chainConfirmedBlocks[block.Position.ChainID] - bc.chainConfirmedBlocks[block.Position.ChainID] = append(chainBlocks, block) +type blockInfo struct { + addresses map[common.Address]interface{} + block *coreTypes.Block } -func (bc *BlockChain) RemoveConfirmedBlock(hash coreCommon.Hash) { - bc.confirmedBlockMu.Lock() - defer bc.confirmedBlockMu.Unlock() - - block := bc.confirmedBlocks[hash] - delete(bc.confirmedBlocks, block.Hash) - - chainBlocks := bc.chainConfirmedBlocks[block.Position.ChainID] - bc.chainConfirmedBlocks[block.Position.ChainID] = chainBlocks[1:] - if len(bc.chainConfirmedBlocks[block.Position.ChainID]) == 0 { - delete(bc.chainConfirmedBlocks, block.Position.ChainID) +func (bc *BlockChain) AddConfirmedBlock(block *coreTypes.Block) error { + var transactions types.Transactions + err := rlp.Decode(bytes.NewReader(block.Payload), &transactions) + if err != nil { + return err } -} - -func (bc *BlockChain) GetConfirmedBlockByHash(hash coreCommon.Hash) *coreTypes.Block { - bc.confirmedBlockMu.Lock() - defer bc.confirmedBlockMu.Unlock() - - return bc.confirmedBlocks[hash] -} - -func (bc *BlockChain) GetConfirmedTxsByAddress(chainID uint32, address common.Address) (types.Transactions, error) { - bc.confirmedBlockMu.Lock() - defer bc.confirmedBlockMu.Unlock() - var addressTxs types.Transactions - for _, block := range bc.chainConfirmedBlocks[chainID] { - var transactions types.Transactions - err := rlp.Decode(bytes.NewReader(block.Payload), &transactions) + addressMap := map[common.Address]interface{}{} + for _, tx := range transactions { + msg, err := tx.AsMessage(types.MakeSigner(bc.Config(), new(big.Int))) if err != nil { - return nil, err + return err } + addressMap[msg.From()] = nil - for _, tx := range transactions { - msg, err := tx.AsMessage(types.MakeSigner(bc.chainConfig, new(big.Int))) - if err != nil { - return nil, err - } + // get latest nonce in block + bc.addressNonce[msg.From()] = msg.Nonce() - if msg.From() == address { - addressTxs = append(addressTxs, tx) - } + // calculate max cost in confirmed blocks + if bc.addressCost[msg.From()] == nil { + bc.addressCost[msg.From()] = tx.Cost() + } else { + bc.addressCost[msg.From()] = new(big.Int).Add(bc.addressCost[msg.From()], tx.Cost()) } } - return addressTxs, nil -} -func (bc *BlockChain) GetLastNonceFromConfirmedBlocks(chainID uint32, address common.Address) (uint64, bool, error) { - chainBlocks, exist := bc.chainConfirmedBlocks[chainID] - if !exist { - return 0, true, nil + for addr := range addressMap { + bc.addressCounter[addr]++ } - for i := len(chainBlocks) - 1; i >= 0; i-- { - var transactions types.Transactions - err := rlp.Decode(bytes.NewReader(chainBlocks[i].Payload), &transactions) - if err != nil { - return 0, true, err - } - - for _, tx := range transactions { - msg, err := tx.AsMessage(types.MakeSigner(bc.chainConfig, new(big.Int))) - if err != nil { - return 0, true, err - } + bc.confirmedBlocks[block.Hash] = &blockInfo{ + addresses: addressMap, + block: block, + } + bc.chainLastHeight[block.Position.ChainID] = block.Position.Height + return nil +} - if msg.From() == address { - return msg.Nonce(), false, nil - } +func (bc *BlockChain) RemoveConfirmedBlock(hash coreCommon.Hash) { + blockInfo := bc.confirmedBlocks[hash] + for addr := range blockInfo.addresses { + bc.addressCounter[addr]-- + if bc.addressCounter[addr] == 0 { + delete(bc.addressCounter, addr) + delete(bc.addressCost, addr) + delete(bc.addressNonce, addr) } } - return 0, true, nil + delete(bc.confirmedBlocks, hash) } -func (bc *BlockChain) GetChainLastConfirmedHeight(chainID uint32) (uint64, bool) { - bc.confirmedBlockMu.Lock() - defer bc.confirmedBlockMu.Unlock() +func (bc *BlockChain) GetConfirmedBlockByHash(hash coreCommon.Hash) *coreTypes.Block { + return bc.confirmedBlocks[hash].block +} - chainBlocks := bc.chainConfirmedBlocks[chainID] - size := len(chainBlocks) - if size == 0 { - return 0, true - } +func (bc *BlockChain) GetLastNonceInConfirmedBlocks(address common.Address) (uint64, bool) { + nonce, exist := bc.addressNonce[address] + return nonce, exist +} - return chainBlocks[size-1].Position.Height, false +func (bc *BlockChain) GetCostInConfirmedBlocks(address common.Address) (*big.Int, bool) { + cost, exist := bc.addressCost[address] + return cost, exist } -func (bc *BlockChain) GetConfirmedBlocksByChainID(chainID uint32) []*coreTypes.Block { - return bc.chainConfirmedBlocks[chainID] +func (bc *BlockChain) GetChainLastConfirmedHeight(chainID uint32) uint64 { + return bc.chainLastHeight[chainID] } // loadLastState loads the last known chain state from the database. This method @@ -1615,11 +1593,10 @@ func (bc *BlockChain) processPendingBlock(block *types.Block, witness *coreTypes proctime := time.Since(bstart) // commit state to refresh stateCache - root, err := pendingState.Commit(true) + _, err = pendingState.Commit(true) if err != nil { return 0, nil, nil, fmt.Errorf("pendingState commit error: %v", err) } - log.Info("Commit pending root", "hash", root) // add into pending blocks bc.pendingBlocks[block.NumberU64()] = struct { @@ -1641,7 +1618,6 @@ func (bc *BlockChain) processPendingBlock(block *types.Block, witness *coreTypes } // Write the block to the chain and get the status. - log.Debug("Insert pending block", "height", pendingHeight) status, err := bc.WriteBlockWithState(pendingIns.block, pendingIns.receipts, s) if err != nil { return 0, events, coalescedLogs, fmt.Errorf("WriteBlockWithState error: %v", err) diff --git a/core/types/block.go b/core/types/block.go index 9e42a776a..07fc55358 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -75,25 +75,26 @@ type WitnessData struct { // Header represents a block header in the Ethereum blockchain. type Header struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner" gencodec:"required"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *big.Int `json:"difficulty" gencodec:"required"` - Number *big.Int `json:"number" gencodec:"required"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - GasUsed uint64 `json:"gasUsed" gencodec:"required"` - Time uint64 `json:"timestamp" gencodec:"required"` - Extra []byte `json:"extraData" gencodec:"required"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner" gencodec:"required"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *big.Int `json:"difficulty" gencodec:"required"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash"` Nonce BlockNonce `json:"nonce"` - Randomness []byte `json:"randomness" gencodec:"required"` - Position coreTypes.Position `json:"position" gencodec:"required"` - Round uint64 `json:"round" gencodec:"required"` - DexconMeta []byte `json:"dexconMeta" gencodec:"required"` + Randomness []byte `json:"randomness" gencodec:"required"` + Position coreTypes.Position `json:"position" gencodec:"required"` + Round uint64 `json:"round" gencodec:"required"` + DexconMeta []byte `json:"dexconMeta" gencodec:"required"` + BlockReward *big.Int `json:"blockReward" gencodec:"required"` } // field type overrides for gencodec diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index 31796bf5b..b49d48f14 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -17,25 +17,26 @@ var _ = (*headerMarshaling)(nil) // MarshalJSON marshals as JSON. func (h Header) MarshalJSON() ([]byte, error) { type Header struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase common.Address `json:"miner" gencodec:"required"` - Root common.Hash `json:"stateRoot" gencodec:"required"` - TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra hexutil.Bytes `json:"extraData" gencodec:"required"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner" gencodec:"required"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra hexutil.Bytes `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash"` Nonce BlockNonce `json:"nonce"` - Randomness hexutil.Bytes `json:"randomness" gencodec:"required"` - Position types.Position `json:"position" gencodec:"required"` - Round hexutil.Uint64 `json:"round" gencodec:"required"` - DexconMeta hexutil.Bytes `json:"dexconMeta" gencodec:"required"` + Randomness hexutil.Bytes `json:"randomness" gencodec:"required"` + Position types.Position `json:"position" gencodec:"required"` + Round hexutil.Uint64 `json:"round" gencodec:"required"` + DexconMeta hexutil.Bytes `json:"dexconMeta" gencodec:"required"` + BlockReward *big.Int `json:"blockReward" gencodec:"required"` Hash common.Hash `json:"hash"` } var enc Header @@ -58,6 +59,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.Position = h.Position enc.Round = hexutil.Uint64(h.Round) enc.DexconMeta = h.DexconMeta + enc.BlockReward = h.BlockReward enc.Hash = h.Hash() return json.Marshal(&enc) } @@ -65,25 +67,26 @@ func (h Header) MarshalJSON() ([]byte, error) { // UnmarshalJSON unmarshals from JSON. func (h *Header) UnmarshalJSON(input []byte) error { type Header struct { - ParentHash *common.Hash `json:"parentHash" gencodec:"required"` - UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` - Coinbase *common.Address `json:"miner" gencodec:"required"` - Root *common.Hash `json:"stateRoot" gencodec:"required"` - TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` - ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` - Bloom *Bloom `json:"logsBloom" gencodec:"required"` - Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` - Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` - Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` - Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase *common.Address `json:"miner" gencodec:"required"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom *Bloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` MixDigest *common.Hash `json:"mixHash"` Nonce *BlockNonce `json:"nonce"` - Randomness *hexutil.Bytes `json:"randomness" gencodec:"required"` - Position *types.Position `json:"position" gencodec:"required"` - Round *hexutil.Uint64 `json:"round" gencodec:"required"` - DexconMeta *hexutil.Bytes `json:"dexconMeta" gencodec:"required"` + Randomness *hexutil.Bytes `json:"randomness" gencodec:"required"` + Position *types.Position `json:"position" gencodec:"required"` + Round *hexutil.Uint64 `json:"round" gencodec:"required"` + DexconMeta *hexutil.Bytes `json:"dexconMeta" gencodec:"required"` + BlockReward *big.Int `json:"blockReward" gencodec:"required"` } var dec Header if err := json.Unmarshal(input, &dec); err != nil { @@ -163,5 +166,9 @@ func (h *Header) UnmarshalJSON(input []byte) error { return errors.New("missing required field 'dexconMeta' for Header") } h.DexconMeta = *dec.DexconMeta + if dec.BlockReward == nil { + return errors.New("missing required field 'blockReward' for Header") + } + h.BlockReward = dec.BlockReward return nil } |