diff options
-rw-r--r-- | core/blockchain.go | 81 | ||||
-rw-r--r-- | core/tx_pool.go | 4 | ||||
-rw-r--r-- | dex/app.go | 132 |
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 } |