Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG:Inconsistent block state when EVM reorganize #421

Merged
merged 2 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (s *consensus) Init() error {
}
s.blockchain = blockchain
//
vmService, err := vm.NewService(s.Config(), s.Events())
vmService, err := vm.NewService(s)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions consensus/model/block_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ type BlockChain interface {
BlockByOrder(blockOrder uint64) (*types.SerializedBlock, error)
Rebuild() error
GetMiningTips(expectPriority int) []*hash.Hash
GetBlockState(order uint64) BlockState
}
11 changes: 10 additions & 1 deletion consensus/model/block_state.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package model

import "github.com/Qitmeer/qng/common/hash"
import (
"github.com/Qitmeer/qng/common/hash"
"github.com/ethereum/go-ethereum/common"
etypes "github.com/ethereum/go-ethereum/core/types"
)

type BlockState interface {
GetID() uint64
Expand All @@ -14,4 +18,9 @@ type BlockState interface {
Invalid()
Root() *hash.Hash
Bytes() ([]byte, error)
GetEVMRoot() common.Hash
GetEVMHash() common.Hash
GetEVMNumber() uint64
SetEVM(header *etypes.Header)
GetDuplicateTxs() []int
}
8 changes: 5 additions & 3 deletions consensus/model/vm_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,27 @@ import (
"github.com/Qitmeer/qng/common/hash"
"github.com/Qitmeer/qng/core/types"
"github.com/ethereum/go-ethereum/common"
etypes "github.com/ethereum/go-ethereum/core/types"
)

type VMI interface {
VerifyTx(tx Tx) (int64, error)
VerifyTxSanity(tx Tx) error
CheckConnectBlock(block *types.SerializedBlock) error
ConnectBlock(block *types.SerializedBlock) (uint64, error)
CheckConnectBlock(block *types.SerializedBlock, state BlockState) error
ConnectBlock(block *types.SerializedBlock, state BlockState) (uint64, error)
DisconnectBlock(block *types.SerializedBlock) (uint64, error)
AddTxToMempool(tx *types.Transaction, local bool) (int64, error)
RemoveTxFromMempool(tx *types.Transaction) error
GetTxsFromMempool() ([]*types.Transaction, []*hash.Hash, error)
GetMempoolSize() int64
ResetTemplate() error
Genesis(txs []*types.Tx) *hash.Hash
GetBlockID(bh *hash.Hash) uint64
GetBlockIDByTxHash(txhash *hash.Hash) uint64
GetBalance(addr string) (int64, error)
SetLogLevel(level string)
GetBlockByNumber(num uint64) (interface{}, error)
GetCurStateRoot() common.Hash
GetCurHeader() *etypes.Header
IsShutdown() bool
RewindTo(state BlockState) error
}
11 changes: 8 additions & 3 deletions consensus/vm/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import (
)

type Block struct {
Id *hash.Hash
Txs []model.Tx
Time time.Time
Id *hash.Hash
Txs []model.Tx
Time time.Time
ParentBlockState model.BlockState
}

func (b *Block) ID() *hash.Hash {
Expand Down Expand Up @@ -69,3 +70,7 @@ func (b *Block) String() string {
func (b *Block) Transactions() []model.Tx {
return b.Txs
}

func (b *Block) ParentState() model.BlockState {
return b.ParentBlockState
}
13 changes: 9 additions & 4 deletions consensus/vm/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import (

type Context struct {
context.Context
Cfg *config.Config
Tp model.TxPool
Notify consensus.Notify
Cfg *config.Config
Tp model.TxPool
Notify consensus.Notify
Consensus model.Consensus
}

func (ctx *Context) GetConfig() *config.Config {
Expand All @@ -24,4 +25,8 @@ func (ctx *Context) GetTxPool() model.TxPool {

func (ctx *Context) GetNotify() consensus.Notify {
return ctx.Notify
}
}

func (ctx Context) GetConsensus() model.Consensus {
return ctx.Consensus
}
49 changes: 49 additions & 0 deletions consensus/vm/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package vm

import (
"github.com/Qitmeer/qng/consensus/model"
"github.com/Qitmeer/qng/core/types"
"github.com/Qitmeer/qng/vm/consensus"
)

func BuildEVMBlock(block *types.SerializedBlock, prevState model.BlockState) (consensus.Block, error) {
result := &Block{Id: block.Hash(), Txs: []model.Tx{}, Time: block.Block().Header.Timestamp, ParentBlockState: prevState}

for idx, tx := range block.Transactions() {
if idx == 0 {
continue
}
if tx.IsDuplicate {
continue
}

if types.IsCrossChainExportTx(tx.Tx) {
ctx, err := NewExportTx(tx.Tx)
if err != nil {
return nil, err
}
result.Txs = append(result.Txs, ctx)
} else if types.IsCrossChainImportTx(tx.Tx) {
ctx, err := NewImportTx(tx.Tx)
if err != nil {
return nil, err
}
err = ctx.SetCoinbaseTx(block.Transactions()[0].Tx)
if err != nil {
return nil, err
}
result.Txs = append(result.Txs, ctx)
} else if types.IsCrossChainVMTx(tx.Tx) {
ctx, err := NewVMTx(tx.Tx)
if err != nil {
return nil, err
}
err = ctx.SetCoinbaseTx(block.Transactions()[0].Tx)
if err != nil {
return nil, err
}
result.Txs = append(result.Txs, ctx)
}
}
return result, nil
}
18 changes: 4 additions & 14 deletions core/blockchain/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"github.com/Qitmeer/qng/core/types"
"github.com/Qitmeer/qng/engine/txscript"
"github.com/Qitmeer/qng/meerdag"
"github.com/Qitmeer/qng/meerevm/evm"
rapi "github.com/Qitmeer/qng/rpc/api"
"github.com/Qitmeer/qng/rpc/client/cmds"
"strconv"
Expand Down Expand Up @@ -489,27 +488,18 @@ func (api *PublicBlockAPI) GetStateRoot(order int64, verbose *bool) (interface{}
if ib == nil {
return nil, internalError(fmt.Errorf("no block").Error(), fmt.Sprintf("Block not found: %d", order))
}
eb, err := api.chain.GetMeerBlock(ib.GetOrder())
if err != nil {
return nil, err
}
sr := ""
num := uint64(0)
if eblock, ok := eb.(*evm.Block); ok {
sr = eblock.StateRoot().String()
num = eblock.Number()
}
if vb {
ret := qjson.OrderedResult{
qjson.KV{Key: "Hash", Val: ib.GetHash().String()},
qjson.KV{Key: "Order", Val: order},
qjson.KV{Key: "Height", Val: ib.GetHeight()},
qjson.KV{Key: "Valid", Val: !ib.GetState().GetStatus().KnownInvalid()},
qjson.KV{Key: "EVMStateRoot", Val: sr},
qjson.KV{Key: "EVMHeight", Val: num},
qjson.KV{Key: "EVMStateRoot", Val: ib.GetState().GetEVMRoot().String()},
qjson.KV{Key: "EVMHeight", Val: ib.GetState().GetEVMNumber()},
qjson.KV{Key: "EVMHead", Val: ib.GetState().GetEVMHash().String()},
qjson.KV{Key: "StateRoot", Val: ib.GetState().Root().String()},
}
return ret, nil
}
return sr, nil
return ib.GetState().Root().String(), nil
}
26 changes: 24 additions & 2 deletions core/blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,13 +321,14 @@ func (b *BlockChain) createChainState() error {
header := &genesisBlock.Block().Header
node := NewBlockNode(genesisBlock)
_, _, ib, _ := b.bd.AddBlock(node)
ib.GetState().SetEVM(b.VMService().GetCurHeader())
//node.FlushToDB(b)
// Initialize the state related to the best block. Since it is the
// genesis block, use its timestamp for the median time.
numTxns := uint64(len(genesisBlock.Block().Transactions))
blockSize := uint64(genesisBlock.Block().SerializeSize())
b.stateSnapshot = newBestState(node.GetHash(), node.Difficulty(), blockSize, numTxns,
time.Unix(node.GetTimestamp(), 0), numTxns, 0, b.bd.GetGraphState(), node.GetHash(), hash.ZeroHash)
time.Unix(node.GetTimestamp(), 0), numTxns, 0, b.bd.GetGraphState(), node.GetHash(), *ib.GetState().Root())
b.TokenTipID = 0
// Create the initial the database chain state including creating the
// necessary index buckets and inserting the genesis block.
Expand Down Expand Up @@ -665,7 +666,7 @@ func (b *BlockChain) reorganizeChain(ib meerdag.IBlock, detachNodes *list.List,
if err != nil {
panic(err)
}

log.Debug("detach block", "hash", n.Block.GetHash().String(), "old order", n.OldOrder, "status", n.Block.GetState().GetStatus().String())
block.SetOrder(uint64(n.OldOrder))
// Load all of the utxos referenced by the block that aren't
// already in the view.
Expand Down Expand Up @@ -705,6 +706,18 @@ func (b *BlockChain) reorganizeChain(ib meerdag.IBlock, detachNodes *list.List,
return err
}
}
for e := attachNodes.Front(); e != nil; e = e.Next() {
nodeBlock := e.Value.(meerdag.IBlock)
if !nodeBlock.IsOrdered() {
continue
}
startState := b.bd.GetBlockByOrder(nodeBlock.GetOrder() - 1).GetState()
err = b.VMService().RewindTo(startState)
if err != nil {
return err
}
break
}

for e := attachNodes.Front(); e != nil; e = e.Next() {
nodeBlock := e.Value.(meerdag.IBlock)
Expand Down Expand Up @@ -755,6 +768,7 @@ func (b *BlockChain) reorganizeChain(ib meerdag.IBlock, detachNodes *list.List,
if er != nil {
log.Error(er.Error())
}
log.Debug("attach block", "hash", nodeBlock.GetHash().String(), "order", nodeBlock.GetOrder(), "status", nodeBlock.GetState().GetStatus().String())
}

// Log the point where the chain forked and old and new best chain
Expand Down Expand Up @@ -1173,6 +1187,14 @@ func (b *BlockChain) Rebuild() error {
return nil
}

func (b *BlockChain) GetBlockState(order uint64) model.BlockState {
block := b.BlockDAG().GetBlockByOrder(uint(order))
if block == nil {
return nil
}
return block.GetState()
}

// New returns a BlockChain instance using the provided configuration details.
func New(consensus model.Consensus) (*BlockChain, error) {
// Enforce required config fields.
Expand Down
26 changes: 0 additions & 26 deletions core/blockchain/blockindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,29 +191,3 @@ func (b *BlockChain) GetMiningTips(expectPriority int) []*hash.Hash {
func (b *BlockChain) HasTx(txid *hash.Hash) bool {
return b.indexManager.HasTx(txid)
}

func (b *BlockChain) GetMeerBlock(order uint) (interface{}, error) {
if b.VMService() == nil {
return nil, nil
}
number := uint64(0)
for i := uint(order); i > 0; i-- {
ib := b.bd.GetBlockByOrder(i)
if ib == nil {
return nil, fmt.Errorf("No meer block number:%d", i)
}
if forks.IsBeforeMeerEVMForkHeight(int64(ib.GetHeight())) {
break
}
num := b.VMService().GetBlockID(ib.GetHash())
if num != 0 {
number = num
break
}
}
eb, err := b.VMService().GetBlockByNumber(number)
if err != nil {
return nil, err
}
return eb, nil
}
27 changes: 14 additions & 13 deletions core/blockchain/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,8 @@ func (b *BlockChain) connectBlock(node meerdag.IBlock, block *types.SerializedBl
pkss = append(pkss, stxo.PkScript)
}
if !node.GetState().GetStatus().KnownInvalid() {
vmbid, err := b.VMService().ConnectBlock(block)
prevState := b.bd.GetBlockByOrder(node.GetOrder() - 1).GetState()
vmbid, err := b.VMService().ConnectBlock(block, prevState)
if err != nil {
return err
}
Expand Down Expand Up @@ -494,12 +495,8 @@ func (b *BlockChain) connectBlock(node meerdag.IBlock, block *types.SerializedBl
//
// This function MUST be called with the chain state lock held (for writes).
func (b *BlockChain) disconnectBlock(ib meerdag.IBlock, block *types.SerializedBlock, view *utxo.UtxoViewpoint, stxos []utxo.SpentTxOut) error {
vmbid, err := b.VMService().DisconnectBlock(block)
if err != nil {
return err
}
// Calculate the exact subsidy produced by adding the block.
err = b.db.Update(func(dbTx database.Tx) error {
err := b.db.Update(func(dbTx database.Tx) error {
// Update the utxo set using the state of the utxo view. This
// entails restoring all of the utxos spent and removing the new
// ones created by the block.
Expand All @@ -526,7 +523,7 @@ func (b *BlockChain) disconnectBlock(ib meerdag.IBlock, block *types.SerializedB
for _, stxo := range stxos {
pkss = append(pkss, stxo.PkScript)
}
err := b.indexManager.DisconnectBlock(block, pkss, ib, vmbid)
err := b.indexManager.DisconnectBlock(block, pkss, ib, 0)
dindinw marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("%v. (Attempt to execute --droptxindex)", err)
}
Expand Down Expand Up @@ -753,18 +750,22 @@ func (b *BlockChain) updateBestState(ib meerdag.IBlock, block *types.SerializedB
}

func (b *BlockChain) updateBlockState(ib meerdag.IBlock, block *types.SerializedBlock) error {
if ib.GetState() == nil {
if !ib.IsOrdered() {
return b.updateDefaultBlockState(ib)
}
if ib.GetState() == nil ||
ib.GetOrder() <= 0 {
return fmt.Errorf("block state is nill:%d %s", ib.GetID(), ib.GetHash().String())
}
bs, ok := ib.GetState().(*state.BlockState)
if !ok {
return fmt.Errorf("block state is nill:%d %s", ib.GetID(), ib.GetHash().String())
}
mp := b.bd.GetBlockById(ib.GetMainParent())
if mp == nil {
return fmt.Errorf("No main parent:%d %s", ib.GetID(), ib.GetHash().String())
prev := b.bd.GetBlockByOrder(ib.GetOrder() - 1)
if prev == nil {
return fmt.Errorf("No prev block:%d %s", ib.GetID(), ib.GetHash().String())
}
bs.Update(block, mp.GetState().Root(), b.VMService().GetCurStateRoot())
bs.Update(block, prev.GetState().(*state.BlockState), b.VMService().GetCurHeader())
b.BlockDAG().AddToCommit(ib)
return nil
}
Expand All @@ -781,7 +782,7 @@ func (b *BlockChain) updateDefaultBlockState(ib meerdag.IBlock) error {
if mp == nil {
return fmt.Errorf("No main parent:%d %s", ib.GetID(), ib.GetHash().String())
}
bs.SetRoot(mp.GetState().Root())
bs.SetDefault(mp.GetState().(*state.BlockState))
b.BlockDAG().AddToCommit(ib)
return nil
}
Expand Down
Loading