aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/blockchain.go56
-rw-r--r--dex/app.go131
2 files changed, 160 insertions, 27 deletions
diff --git a/core/blockchain.go b/core/blockchain.go
index 41b8764f7..30516f7f6 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -18,6 +18,7 @@
package core
import (
+ "bytes"
"errors"
"fmt"
"io"
@@ -27,6 +28,9 @@ import (
"sync/atomic"
"time"
+ 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/mclock"
"github.com/dexon-foundation/dexon/common/prque"
@@ -136,6 +140,10 @@ 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
}
// NewBlockChain returns a fully initialised block chain using information
@@ -215,6 +223,54 @@ func (bc *BlockChain) GetVMConfig() *vm.Config {
return &bc.vmConfig
}
+func (bc *BlockChain) AddConfirmedBlock(block *coreTypes.Block) {
+ bc.confirmedBlockMu.Lock()
+ defer bc.confirmedBlockMu.Unlock()
+
+ bc.confirmedBlock[block.Hash] = block
+ bc.filteredConfirmedBlock[block.Position.ChainID][block.Hash] = 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)
+}
+
+func (bc *BlockChain) GetConfirmedBlockByHash(hash coreCommon.Hash) *coreTypes.Block {
+ return bc.confirmedBlock[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] {
+ var transactions types.Transactions
+ err := rlp.Decode(bytes.NewReader(block.Payload), &transactions)
+ if err != nil {
+ return 0, init, err
+ }
+
+ for _, tx := range transactions {
+ msg, err := tx.AsMessage(types.MakeSigner(bc.chainConfig, new(big.Int)))
+ if err != nil {
+ return 0, init, err
+ }
+
+ if msg.From() == address && (tx.Nonce() > nonce || !init) {
+ if !init {
+ init = true
+ }
+ nonce = tx.Nonce()
+ }
+ }
+ }
+ return nonce, init, nil
+}
+
// loadLastState loads the last known chain state from the database. This method
// assumes that the chain manager mutex is held.
func (bc *BlockChain) loadLastState() error {
diff --git a/dex/app.go b/dex/app.go
index b34c9f553..521f2233e 100644
--- a/dex/app.go
+++ b/dex/app.go
@@ -19,12 +19,11 @@ package dex
import (
"bytes"
+ "github.com/dexon-foundation/dexon/core/rawdb"
"math/big"
"sync"
"time"
- "github.com/dexon-foundation/dexon/core/rawdb"
-
coreCommon "github.com/dexon-foundation/dexon-consensus-core/common"
coreTypes "github.com/dexon-foundation/dexon-consensus-core/core/types"
@@ -119,12 +118,43 @@ func (d *DexconApp) PreparePayload(position coreTypes.Position) (payload []byte)
continue
}
- for _, tx := range txs {
+ 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(nil, currentBlock.Header().Number))
+ if err != nil {
+ return
+ }
+ undeliveredNonce, exist, err := d.blockchain.GetNonceInConfirmedBlock(position.ChainID, msg.From())
+ if err != nil {
+ return
+ } else if exist {
+ if msg.Nonce() != undeliveredNonce+1 {
+ break
+ }
+ } else {
+ stateDB, err := d.blockchain.State()
+ if err != nil {
+ return
+ }
+ if msg.Nonce() != stateDB.GetNonce(msg.From())+1 {
+ break
+ }
+ }
+ } else if tx.Nonce() != nonce+1 { // check if nonce is sequential
+ break
+ }
+
core.ApplyTransaction(d.blockchain.Config(), d.blockchain, nil, gp, stateDB, currentBlock.Header(), tx, &gasUsed, d.vmConfig)
if gasUsed > gasLimit {
break
}
allTxs = append(allTxs, tx)
+ nonce = tx.Nonce()
}
}
payload, err = rlp.EncodeToBytes(&allTxs)
@@ -179,14 +209,54 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) bool {
return false
}
+ currentBlock := d.blockchain.CurrentBlock()
+
// verify transactions
+ addressNonce := map[common.Address]*struct {
+ Min uint64
+ Max uint64
+ }{}
for _, transaction := range transactions {
if d.txPool.ValidateTx(transaction, false) != nil {
return false
}
+
+ msg, err := transaction.AsMessage(types.MakeSigner(nil, currentBlock.Header().Number))
+ if err != nil {
+ return false
+ }
+ nonce, exist := addressNonce[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()
+ if err != nil {
+ return false
+ }
+ if nonce.Min != stateDB.GetNonce(address)+1 {
+ return false
+ }
+ }
}
- currentBlock := d.blockchain.CurrentBlock()
gasLimit := core.CalcGasLimit(currentBlock, d.config.GasFloor, d.config.GasCeil)
gp := new(core.GasPool).AddGas(gasLimit)
@@ -234,31 +304,38 @@ func (d *DexconApp) VerifyBlock(block *coreTypes.Block) bool {
return true
}
-func (d *DexconApp) BlockConfirmed(block coreTypes.Block) {
-}
-
// BlockDelivered is called when a block is add to the compaction chain.
func (d *DexconApp) BlockDelivered(blockHash coreCommon.Hash, result coreTypes.FinalizationResult) {
- /*
- var transactions types.Transactions
- err := rlp.Decode(bytes.NewReader(block.Payload), &transactions)
- if err != nil {
- return
- }
+ block := d.blockchain.GetConfirmedBlockByHash(blockHash)
+ if block == nil {
+ // do something
+ return
+ }
- _, err = d.blockchain.InsertChain(
- []*types.Block{types.NewBlock(&types.Header{
- ParentHash: common.Hash(block.ParentHash),
- Number: new(big.Int).SetUint64(result.Height),
- Time: new(big.Int).SetInt64(result.Timestamp.Unix()),
- TxHash: types.DeriveSha(transactions),
- Coinbase: common.BytesToAddress(block.ProposerID.Hash[:]),
- }, transactions, nil, nil)})
- if err != nil {
- // do something
- return
- }
+ var transactions types.Transactions
+ err := rlp.Decode(bytes.NewReader(block.Payload), &transactions)
+ if err != nil {
+ return
+ }
- d.notify(result.Height)
- */
+ _, err = d.blockchain.InsertChain(
+ []*types.Block{types.NewBlock(&types.Header{
+ ParentHash: common.Hash(block.ParentHash),
+ Number: new(big.Int).SetUint64(result.Height),
+ Time: new(big.Int).SetInt64(result.Timestamp.Unix()),
+ TxHash: types.DeriveSha(transactions),
+ Coinbase: common.BytesToAddress(block.ProposerID.Hash[:]),
+ }, transactions, nil, nil)})
+ if err != nil {
+ // do something
+ return
+ }
+
+ 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.blockchain.AddConfirmedBlock(&block)
}