aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBojie Wu <bojie@dexon.org>2018-10-09 13:28:45 +0800
committerWei-Ning Huang <w@dexon.org>2019-03-12 12:19:09 +0800
commit84d04454db640bc730445be3ec536d4100ae6ec1 (patch)
tree9e23acdd738c9de4f5fb8b800187932b501476ee
parent947a2b720d966efae8aa8564cbe948f8eb6d5d38 (diff)
downloaddexon-84d04454db640bc730445be3ec536d4100ae6ec1.tar.gz
dexon-84d04454db640bc730445be3ec536d4100ae6ec1.tar.zst
dexon-84d04454db640bc730445be3ec536d4100ae6ec1.zip
app: add cache mechanism to increase performance
-rw-r--r--consensus/dexcon/dexcon.go2
-rw-r--r--core/blockchain.go178
-rw-r--r--core/types/block.go33
-rw-r--r--core/types/gen_header_json.go71
-rw-r--r--dex/app.go166
-rw-r--r--internal/ethapi/api.go3
6 files changed, 200 insertions, 253 deletions
diff --git a/consensus/dexcon/dexcon.go b/consensus/dexcon/dexcon.go
index d8c181432..67bf33bbf 100644
--- a/consensus/dexcon/dexcon.go
+++ b/consensus/dexcon/dexcon.go
@@ -113,6 +113,8 @@ func (d *Dexcon) Finalize(chain consensus.ChainReader, header *types.Header, sta
config := d.configFetcher.DexconConfiguration(header.Round)
reward := new(big.Int).Div(config.BlockReward, big.NewInt(int64(config.NumChains)))
state.AddBalance(header.Coinbase, reward)
+
+ header.BlockReward = reward
header.Root = state.IntermediateRoot(true)
return types.NewBlock(header, txs, uncles, receipts), nil
}
diff --git a/core/blockchain.go b/core/blockchain.go
index ae3370b22..4c5fb3c25 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 4a0135bdc..dadcfb4c1 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 *big.Int `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 *big.Int `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"`
+ 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"`
+ 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 74694a38e..35c308c4a 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.Big `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.Big `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"`
+ 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"`
+ 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.Big `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.Big `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"`
+ 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"`
+ 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
}
diff --git a/dex/app.go b/dex/app.go
index 867c10361..7730ba22f 100644
--- a/dex/app.go
+++ b/dex/app.go
@@ -47,12 +47,13 @@ type DexconApp struct {
vmConfig vm.Config
notifyChan map[uint64]*notify
- mutex *sync.Mutex
+ notifyMu *sync.Mutex
lastPendingHeight uint64
insertMu sync.Mutex
- chainHeight map[uint32]uint64
+ chainLocksInitMu *sync.Mutex
+ chainLocks map[uint32]*sync.Mutex
}
type notify struct {
@@ -67,21 +68,22 @@ type witnessData struct {
func NewDexconApp(txPool *core.TxPool, blockchain *core.BlockChain, gov *DexconGovernance, chainDB ethdb.Database, config *Config, vmConfig vm.Config) *DexconApp {
return &DexconApp{
- txPool: txPool,
- blockchain: blockchain,
- gov: gov,
- chainDB: chainDB,
- config: config,
- vmConfig: vmConfig,
- notifyChan: make(map[uint64]*notify),
- mutex: &sync.Mutex{},
- chainHeight: make(map[uint32]uint64),
+ txPool: txPool,
+ blockchain: blockchain,
+ gov: gov,
+ chainDB: chainDB,
+ config: config,
+ vmConfig: vmConfig,
+ notifyChan: make(map[uint64]*notify),
+ notifyMu: &sync.Mutex{},
+ chainLocksInitMu: &sync.Mutex{},
+ chainLocks: make(map[uint32]*sync.Mutex),
}
}
func (d *DexconApp) addNotify(height uint64) <-chan uint64 {
- d.mutex.Lock()
- defer d.mutex.Unlock()
+ d.notifyMu.Lock()
+ defer d.notifyMu.Unlock()
result := make(chan uint64)
if n, exist := d.notifyChan[height]; exist {
n.results = append(n.results, result)
@@ -93,8 +95,8 @@ func (d *DexconApp) addNotify(height uint64) <-chan uint64 {
}
func (d *DexconApp) notify(height uint64) {
- d.mutex.Lock()
- defer d.mutex.Unlock()
+ d.notifyMu.Lock()
+ defer d.notifyMu.Unlock()
for h, n := range d.notifyChan {
if height >= h {
for _, ch := range n.results {
@@ -113,21 +115,12 @@ func (d *DexconApp) checkChain(address common.Address, chainSize, chainID *big.I
// PreparePayload is called when consensus core is preparing payload for block.
func (d *DexconApp) PreparePayload(position coreTypes.Position) (payload []byte, err error) {
- d.insertMu.Lock()
- defer d.insertMu.Unlock()
+ d.chainLock(position.ChainID)
+ defer d.chainUnlock(position.ChainID)
if position.Height != 0 {
- chainLastHeight, empty := d.blockchain.GetChainLastConfirmedHeight(position.ChainID)
- if empty {
- var exist bool
- chainLastHeight, exist = d.chainHeight[position.ChainID]
- if !exist {
- log.Error("Something wrong")
- return nil, fmt.Errorf("something wrong")
- }
- }
-
// check if chain block height is sequential
+ chainLastHeight := d.blockchain.GetChainLastConfirmedHeight(position.ChainID)
if chainLastHeight != position.Height-1 {
log.Error("Check confirmed block height fail", "chain", position.ChainID, "height", position.Height-1, "cache height", chainLastHeight)
return nil, fmt.Errorf("check confirmed block height fail")
@@ -170,11 +163,8 @@ addressMap:
var expectNonce uint64
// get last nonce from confirmed blocks
- lastConfirmedNonce, empty, err := d.blockchain.GetLastNonceFromConfirmedBlocks(position.ChainID, address)
- if err != nil {
- log.Error("Get last nonce from confirmed blocks", "error", err)
- return nil, fmt.Errorf("get last nonce from confirmed blocks error: %v", err)
- } else if empty {
+ lastConfirmedNonce, exist := d.blockchain.GetLastNonceInConfirmedBlocks(address)
+ if !exist {
// get expect nonce from latest state when confirmed block is empty
expectNonce = latestState.GetNonce(address)
} else {
@@ -182,20 +172,14 @@ addressMap:
}
if expectNonce != txs[0].Nonce() {
- log.Warn("Nonce check error", "expect", expectNonce, "nonce", txs[0].Nonce())
+ log.Debug("Nonce check error", "expect", expectNonce, "nonce", txs[0].Nonce())
continue
}
balance := latestState.GetBalance(address)
- confirmedTxs, err := d.blockchain.GetConfirmedTxsByAddress(position.ChainID, address)
- if err != nil {
- return nil, fmt.Errorf("get confirmed txs error: %v", err)
- }
-
- for _, tx := range confirmedTxs {
- maxGasUsed := new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())
- balance = new(big.Int).Sub(balance, maxGasUsed)
- balance = new(big.Int).Sub(balance, tx.Value())
+ cost, exist := d.blockchain.GetCostInConfirmedBlocks(address)
+ if exist {
+ balance = new(big.Int).Sub(balance, cost)
}
for _, tx := range txs {
@@ -210,8 +194,7 @@ addressMap:
break
}
- balance = new(big.Int).Sub(balance, maxGasUsed)
- balance = new(big.Int).Sub(balance, tx.Value())
+ balance = new(big.Int).Sub(balance, tx.Cost())
if balance.Cmp(big.NewInt(0)) < 0 {
log.Error("Tx fail", "reason", "not enough balance")
break
@@ -275,15 +258,13 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) coreTypes.BlockVerifySta
return coreTypes.VerifyInvalidBlock
}
- log.Info("Ready to verify witness block", "height", block.Witness.Height)
-
- for i := 0; i < 3 && err != nil; i++ {
+ for i := 0; i < 6 && err != nil; i++ {
// check witness root exist
err = nil
_, err = d.blockchain.StateAt(witnessData.Root)
if err != nil {
- log.Warn("Sleep 2 seconds and try again", "error", err)
- time.Sleep(2 * time.Second)
+ log.Debug("Sleep 0.5 seconds and try again", "error", err)
+ time.Sleep(500 * time.Millisecond)
}
}
if err != nil {
@@ -291,23 +272,14 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) coreTypes.BlockVerifySta
return coreTypes.VerifyRetryLater
}
- d.insertMu.Lock()
- defer d.insertMu.Unlock()
+ d.chainLock(block.Position.ChainID)
+ defer d.chainUnlock(block.Position.ChainID)
if block.Position.Height != 0 {
- chainLastHeight, empty := d.blockchain.GetChainLastConfirmedHeight(block.Position.ChainID)
- if empty {
- var exist bool
- chainLastHeight, exist = d.chainHeight[block.Position.ChainID]
- if !exist {
- log.Error("Something wrong")
- return coreTypes.VerifyInvalidBlock
- }
- }
-
// check if chain block height is sequential
+ chainLastHeight := d.blockchain.GetChainLastConfirmedHeight(block.Position.ChainID)
if chainLastHeight != block.Position.Height-1 {
- log.Error("Check confirmed block height fail", "chain", block.Position.ChainID, "height", block.Position.Height-1)
+ log.Error("Check confirmed block height fail", "chain", block.Position.ChainID, "height", block.Position.Height-1, "cache height", chainLastHeight)
return coreTypes.VerifyRetryLater
}
}
@@ -353,11 +325,8 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) coreTypes.BlockVerifySta
var expectNonce uint64
// get last nonce from confirmed blocks
- lastConfirmedNonce, empty, err := d.blockchain.GetLastNonceFromConfirmedBlocks(block.Position.ChainID, address)
- if err != nil {
- log.Error("Get last nonce from confirmed blocks", "error", err)
- return coreTypes.VerifyInvalidBlock
- } else if empty {
+ lastConfirmedNonce, exist := d.blockchain.GetLastNonceInConfirmedBlocks(address)
+ if !exist {
// get expect nonce from latest state when confirmed block is empty
expectNonce = latestState.GetNonce(address)
} else {
@@ -373,37 +342,12 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) coreTypes.BlockVerifySta
// get balance from state
addressesBalance := map[common.Address]*big.Int{}
for address := range addresses {
- addressesBalance[address] = latestState.GetBalance(address)
- }
-
- // replay confirmed block tx to correct balance
- confirmedBlocks := d.blockchain.GetConfirmedBlocksByChainID(block.Position.ChainID)
- for _, block := range confirmedBlocks {
- var txs types.Transactions
- err := rlp.Decode(bytes.NewReader(block.Payload), &txs)
- if err != nil {
- log.Error("Decode confirmed block", "error", err)
- return coreTypes.VerifyInvalidBlock
- }
-
- for _, tx := range txs {
- msg, err := tx.AsMessage(types.MakeSigner(d.blockchain.Config(), new(big.Int)))
- if err != nil {
- log.Error("Tx to message", "error", err)
- return coreTypes.VerifyInvalidBlock
- }
-
- balance, exist := addressesBalance[msg.From()]
- if exist {
- maxGasUsed := new(big.Int).Mul(new(big.Int).SetUint64(msg.Gas()), msg.GasPrice())
- balance = new(big.Int).Sub(balance, maxGasUsed)
- balance = new(big.Int).Sub(balance, msg.Value())
- if balance.Cmp(big.NewInt(0)) <= 0 {
- log.Error("Replay confirmed tx fail", "reason", "not enough balance")
- return coreTypes.VerifyInvalidBlock
- }
- addressesBalance[msg.From()] = balance
- }
+ // replay confirmed block tx to correct balance
+ cost, exist := d.blockchain.GetCostInConfirmedBlocks(address)
+ if exist {
+ addressesBalance[address] = new(big.Int).Sub(latestState.GetBalance(address), cost)
+ } else {
+ addressesBalance[address] = latestState.GetBalance(address)
}
}
@@ -428,8 +372,7 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) coreTypes.BlockVerifySta
return coreTypes.VerifyInvalidBlock
}
- balance = new(big.Int).Sub(balance, maxGasUsed)
- balance = new(big.Int).Sub(balance, msg.Value())
+ balance = new(big.Int).Sub(balance, tx.Cost())
if balance.Cmp(big.NewInt(0)) < 0 {
log.Error("Tx fail", "reason", "not enough balance")
return coreTypes.VerifyInvalidBlock
@@ -457,6 +400,9 @@ func (d *DexconApp) BlockDelivered(blockHash coreCommon.Hash, result coreTypes.F
panic("Can not get confirmed block")
}
+ d.chainLock(block.Position.ChainID)
+ defer d.chainUnlock(block.Position.ChainID)
+
var transactions types.Transactions
err := rlp.Decode(bytes.NewReader(block.Payload), &transactions)
if err != nil {
@@ -489,15 +435,14 @@ func (d *DexconApp) BlockDelivered(blockHash coreCommon.Hash, result coreTypes.F
}
log.Info("Insert pending block success", "height", result.Height)
- d.chainHeight[block.Position.ChainID] = block.Position.Height
d.blockchain.RemoveConfirmedBlock(blockHash)
d.notify(result.Height)
}
// BlockConfirmed is called when a block is confirmed and added to lattice.
func (d *DexconApp) BlockConfirmed(block coreTypes.Block) {
- d.insertMu.Lock()
- defer d.insertMu.Unlock()
+ d.chainLock(block.Position.ChainID)
+ defer d.chainUnlock(block.Position.ChainID)
d.blockchain.AddConfirmedBlock(&block)
}
@@ -525,3 +470,18 @@ func (d *DexconApp) validateNonce(txs types.Transactions) (map[common.Address]ui
return addressFirstNonce, nil
}
+
+func (d *DexconApp) chainLock(chainID uint32) {
+ d.chainLocksInitMu.Lock()
+ _, exist := d.chainLocks[chainID]
+ if !exist {
+ d.chainLocks[chainID] = &sync.Mutex{}
+ }
+ d.chainLocksInitMu.Unlock()
+
+ d.chainLocks[chainID].Lock()
+}
+
+func (d *DexconApp) chainUnlock(chainID uint32) {
+ d.chainLocks[chainID].Unlock()
+}
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index bd76d5e79..e43b672f7 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -765,7 +765,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
hi = uint64(args.Gas)
} else {
// Retrieve the current pending block to act as the gas ceiling
- block, err := s.b.BlockByNumber(ctx, rpc.PendingBlockNumber)
+ block, err := s.b.BlockByNumber(ctx, rpc.LatestBlockNumber)
if err != nil {
return 0, err
}
@@ -888,6 +888,7 @@ func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]inter
"randomness": hexutil.Bytes(head.Randomness),
"round": hexutil.Uint64(head.Round),
"dexconMeta": hexutil.Bytes(head.DexconMeta),
+ "blockReward": (*hexutil.Big)(head.BlockReward),
}
if inclTx {