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-04-09 21:32:50 +0800
commit0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9 (patch)
tree44bd75234980ed4f401b304b7f796608f9947e98
parentd0d1869fa4f4a0a5c1ddc3d4b8d2899cca43fc6a (diff)
downloaddexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.tar
dexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.tar.gz
dexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.tar.bz2
dexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.tar.lz
dexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.tar.xz
dexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.tar.zst
dexon-0050e7ffb8dbf0b9e02e3a00e7c4634ae0ce30a9.zip
app: correct dexon application logic
-rw-r--r--core/blockchain.go81
-rw-r--r--core/tx_pool.go4
-rw-r--r--dex/app.go132
3 files changed, 88 insertions, 129 deletions
diff --git a/core/blockchain.go b/core/blockchain.go
index 8d90c9348..9775f9e16 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -141,9 +141,9 @@ 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
- confirmedBlock map[coreCommon.Hash]*coreTypes.Block
- filteredConfirmedBlock map[uint32]map[coreCommon.Hash]*coreTypes.Block
+ confirmedBlockMu sync.Mutex
+ confirmedBlocks map[coreCommon.Hash]*coreTypes.Block
+ chainConfirmedBlocks map[uint32][]*coreTypes.Block
}
// NewBlockChain returns a fully initialised block chain using information
@@ -165,23 +165,24 @@ 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.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,
- confirmedBlock: make(map[coreCommon.Hash]*coreTypes.Block),
- filteredConfirmedBlock: make(map[uint32]map[coreCommon.Hash]*coreTypes.Block),
+ 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),
}
bc.SetValidator(NewBlockValidator(chainConfig, bc, engine))
bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine))
@@ -229,55 +230,47 @@ func (bc *BlockChain) AddConfirmedBlock(block *coreTypes.Block) {
bc.confirmedBlockMu.Lock()
defer bc.confirmedBlockMu.Unlock()
- bc.confirmedBlock[block.Hash] = block
- if bc.filteredConfirmedBlock[block.Position.ChainID] == nil {
- bc.filteredConfirmedBlock[block.Position.ChainID] = make(map[coreCommon.Hash]*coreTypes.Block)
- }
- bc.filteredConfirmedBlock[block.Position.ChainID][block.Hash] = block
+ bc.confirmedBlocks[block.Hash] = block
+ chainBlocks := bc.chainConfirmedBlocks[block.Position.ChainID]
+ bc.chainConfirmedBlocks[block.Position.ChainID] = append(chainBlocks, block)
}
func (bc *BlockChain) RemoveConfirmedBlock(hash coreCommon.Hash) {
bc.confirmedBlockMu.Lock()
defer bc.confirmedBlockMu.Unlock()
- block := bc.confirmedBlock[hash]
- delete(bc.filteredConfirmedBlock[block.Position.ChainID], block.Hash)
- delete(bc.confirmedBlock, block.Hash)
+ block := bc.confirmedBlocks[hash]
+ delete(bc.confirmedBlocks, block.Hash)
- if len(bc.filteredConfirmedBlock[block.Position.ChainID]) == 0 {
- bc.filteredConfirmedBlock[block.Position.ChainID] = nil
- }
+ chainBlocks := bc.chainConfirmedBlocks[block.Position.ChainID]
+ bc.chainConfirmedBlocks[block.Position.ChainID] = chainBlocks[1:]
}
func (bc *BlockChain) GetConfirmedBlockByHash(hash coreCommon.Hash) *coreTypes.Block {
- return bc.confirmedBlock[hash]
+ return bc.confirmedBlocks[hash]
}
-func (bc *BlockChain) GetNonceInConfirmedBlock(chainID uint32, address common.Address) (uint64, bool, error) {
- var nonce uint64
- var init bool
- for _, block := range bc.filteredConfirmedBlock[chainID] {
+func (bc *BlockChain) GetConfirmedTxsByAddress(chainID uint32, address common.Address) (types.Transactions, error) {
+ var addressTxs types.Transactions
+ for _, block := range bc.chainConfirmedBlocks[chainID] {
var transactions types.Transactions
err := rlp.Decode(bytes.NewReader(block.Payload), &transactions)
if err != nil {
- return 0, init, err
+ return nil, err
}
for _, tx := range transactions {
msg, err := tx.AsMessage(types.MakeSigner(bc.chainConfig, new(big.Int)))
if err != nil {
- return 0, init, err
+ return nil, err
}
- if msg.From() == address && (tx.Nonce() > nonce || !init) {
- if !init {
- init = true
- }
- nonce = tx.Nonce()
+ if msg.From() == address {
+ addressTxs = append(addressTxs, tx)
}
}
}
- return nonce, init, nil
+ return addressTxs, nil
}
// loadLastState loads the last known chain state from the database. This method
diff --git a/core/tx_pool.go b/core/tx_pool.go
index d79512d9c..eccf82e93 100644
--- a/core/tx_pool.go
+++ b/core/tx_pool.go
@@ -1157,10 +1157,6 @@ func (pool *TxPool) demoteUnexecutables() {
}
}
-func (pool *TxPool) ValidateTx(tx *types.Transaction, local bool) error {
- return pool.validateTx(tx, local)
-}
-
// addressByHeartbeat is an account address tagged with its last activity timestamp.
type addressByHeartbeat struct {
address common.Address
diff --git a/dex/app.go b/dex/app.go
index 1e97c4859..78e8a0260 100644
--- a/dex/app.go
+++ b/dex/app.go
@@ -24,18 +24,18 @@ import (
"sync"
"time"
- "github.com/dexon-foundation/dexon/log"
-
coreCommon "github.com/dexon-foundation/dexon-consensus-core/common"
coreTypes "github.com/dexon-foundation/dexon-consensus-core/core/types"
"github.com/dexon-foundation/dexon/common"
+ "github.com/dexon-foundation/dexon/common/math"
"github.com/dexon-foundation/dexon/core"
"github.com/dexon-foundation/dexon/core/rawdb"
"github.com/dexon-foundation/dexon/core/state"
"github.com/dexon-foundation/dexon/core/types"
"github.com/dexon-foundation/dexon/core/vm"
"github.com/dexon-foundation/dexon/ethdb"
+ "github.com/dexon-foundation/dexon/log"
"github.com/dexon-foundation/dexon/rlp"
)
@@ -116,7 +116,6 @@ func (d *DexconApp) PreparePayload(position coreTypes.Position) (payload []byte,
currentBlock := d.blockchain.CurrentBlock()
gasLimit := core.CalcGasLimit(currentBlock, d.config.GasFloor, d.config.GasCeil)
gp := new(core.GasPool).AddGas(gasLimit)
-
stateDB, err := state.New(currentBlock.Root(), state.NewDatabase(d.chainDB))
if err != nil {
return
@@ -125,50 +124,37 @@ func (d *DexconApp) PreparePayload(position coreTypes.Position) (payload []byte,
chainID := new(big.Int).SetUint64(uint64(position.ChainID))
chainSize := new(big.Int).SetUint64(uint64(d.gov.Configuration(position.Round).NumChains))
var allTxs types.Transactions
- var gasUsed uint64
+ var totalGasUsed uint64
for addr, txs := range txsMap {
// every address's transactions will appear in fixed chain
if !d.checkChain(addr, chainSize, chainID) {
continue
}
- var nonce uint64
- for i, tx := range txs {
- // validate start nonce
- // check undelivered block first
- // or else check compaction chain state
- if i == 0 {
- nonce = tx.Nonce()
- msg, err := tx.AsMessage(types.MakeSigner(d.blockchain.Config(), currentBlock.Header().Number))
- if err != nil {
- return nil, err
- }
- undeliveredNonce, exist, err := d.blockchain.GetNonceInConfirmedBlock(position.ChainID, msg.From())
- if err != nil {
- return nil, err
- } else if exist {
- if msg.Nonce() != undeliveredNonce+1 {
- break
- }
- } else {
- stateDB, err := d.blockchain.State()
- if err != nil {
- return nil, err
- }
- if msg.Nonce() != stateDB.GetNonce(msg.From())+1 {
- break
- }
- }
- } else if tx.Nonce() != nonce+1 { // check if nonce is sequential
- break
+ undeliveredTxs, err := d.blockchain.GetConfirmedTxsByAddress(position.ChainID, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, tx := range undeliveredTxs {
+ // confirmed txs must apply successfully
+ var gasUsed uint64
+ gp := new(core.GasPool).AddGas(math.MaxUint64)
+ _, _, err = core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), tx, &gasUsed, d.vmConfig)
+ if err != nil {
+ log.Error("apply confirmed transaction error: %v", err)
+ return nil, err
}
+ }
- core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), tx, &gasUsed, d.vmConfig)
- if gasUsed > gasLimit {
+ for _, tx := range txs {
+ // apply transaction to calculate total gas used, validate nonce and check available balance
+ _, _, err = core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), tx, &totalGasUsed, d.vmConfig)
+ if err != nil || totalGasUsed > gasLimit {
+ log.Debug("apply transaction fail error: %v, totalGasUsed: %d, gasLimit: %d", err, totalGasUsed, gasLimit)
break
}
allTxs = append(allTxs, tx)
- nonce = tx.Nonce()
}
}
payload, err = rlp.EncodeToBytes(&allTxs)
@@ -221,72 +207,56 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) bool {
currentBlock := d.blockchain.CurrentBlock()
chainID := new(big.Int).SetUint64(uint64(block.Position.ChainID))
chainSize := new(big.Int).SetUint64(uint64(d.gov.Configuration(block.Position.Round).NumChains))
+ stateDB, err := state.New(currentBlock.Root(), state.NewDatabase(d.chainDB))
+ if err != nil {
+ return false
+ }
// verify transactions
- addressNonce := map[common.Address]*struct {
- Min uint64
- Max uint64
- }{}
+ addressMap := map[common.Address]interface{}{}
+ gasLimit := core.CalcGasLimit(currentBlock, d.config.GasFloor, d.config.GasCeil)
+ gp := new(core.GasPool).AddGas(gasLimit)
+ var totalGasUsed uint64
for _, transaction := range transactions {
- if d.txPool.ValidateTx(transaction, false) != nil {
- return false
- }
-
msg, err := transaction.AsMessage(types.MakeSigner(d.blockchain.Config(), currentBlock.Header().Number))
if err != nil {
return false
}
if !d.checkChain(msg.From(), chainSize, chainID) {
+ log.Error("%s can not be delivered on chain %d", msg.From().String(), chainID)
return false
}
- nonce, exist := addressNonce[msg.From()]
+ _, exist := addressMap[msg.From()]
if !exist {
- addressNonce[msg.From()] = &struct {
- Min uint64
- Max uint64
- }{Min: msg.Nonce(), Max: msg.Nonce()}
- } else if msg.Nonce() != nonce.Max+1 {
- // address nonce is not sequential
- return false
- }
- nonce.Max++
- }
-
- for address, nonce := range addressNonce {
- undeliveredNonce, exist, err := d.blockchain.GetNonceInConfirmedBlock(block.Position.ChainID, address)
- if err != nil {
- return false
- } else if exist {
- if nonce.Min != undeliveredNonce+1 {
- return false
- }
- } else {
- stateDB, err := d.blockchain.State()
+ txs, err := d.blockchain.GetConfirmedTxsByAddress(block.Position.ChainID, msg.From())
if err != nil {
+ log.Error("get confirmed txs by address error: %v", err)
return false
}
- if nonce.Min != stateDB.GetNonce(address)+1 {
- return false
+
+ gp := new(core.GasPool).AddGas(math.MaxUint64)
+ for _, tx := range txs {
+ var gasUsed uint64
+ // confirmed txs must apply successfully
+ _, _, err := core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), tx, &gasUsed, d.vmConfig)
+ if err != nil {
+ log.Error("apply confirmed transaction error: %v", err)
+ return false
+ }
}
+ addressMap[msg.From()] = nil
}
- }
-
- gasLimit := core.CalcGasLimit(currentBlock, d.config.GasFloor, d.config.GasCeil)
- gp := new(core.GasPool).AddGas(gasLimit)
-
- stateDB, err := state.New(currentBlock.Root(), state.NewDatabase(d.chainDB))
- if err != nil {
- return false
- }
- var gasUsed uint64
- for _, tx := range transactions {
- core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), tx, &gasUsed, d.vmConfig)
+ _, _, err = core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), transaction, &totalGasUsed, d.vmConfig)
+ if err != nil {
+ log.Error("apply block transaction error: %v", err)
+ return false
+ }
}
- if gasUsed > gasLimit+d.config.GasLimitTolerance {
+ if totalGasUsed > gasLimit+d.config.GasLimitTolerance {
return false
}