aboutsummaryrefslogtreecommitdiffstats
path: root/dex/app_test.go
diff options
context:
space:
mode:
authorbojie <bojie@dexon.org>2018-12-03 16:30:53 +0800
committerWei-Ning Huang <w@dexon.org>2019-03-12 12:19:09 +0800
commitc7f9479a5c1fa013598da59cc56f60aa4d3bd5cb (patch)
treecb83a48c10489e93e66cb3a3258fe3346252b89d /dex/app_test.go
parentc334a14b56c5a9239e9839c8bf870cb2425dc08f (diff)
downloaddexon-c7f9479a5c1fa013598da59cc56f60aa4d3bd5cb.tar.gz
dexon-c7f9479a5c1fa013598da59cc56f60aa4d3bd5cb.tar.zst
dexon-c7f9479a5c1fa013598da59cc56f60aa4d3bd5cb.zip
app: add app test case and benchmark (#66)
Diffstat (limited to 'dex/app_test.go')
-rw-r--r--dex/app_test.go689
1 files changed, 689 insertions, 0 deletions
diff --git a/dex/app_test.go b/dex/app_test.go
new file mode 100644
index 000000000..cbd29d0dc
--- /dev/null
+++ b/dex/app_test.go
@@ -0,0 +1,689 @@
+package dex
+
+import (
+ "crypto/ecdsa"
+ "fmt"
+ "math/big"
+ "testing"
+ "time"
+
+ coreCommon "github.com/dexon-foundation/dexon-consensus/common"
+ coreTypes "github.com/dexon-foundation/dexon-consensus/core/types"
+
+ "github.com/dexon-foundation/dexon/common"
+ "github.com/dexon-foundation/dexon/consensus/dexcon"
+ "github.com/dexon-foundation/dexon/core"
+ "github.com/dexon-foundation/dexon/core/types"
+ "github.com/dexon-foundation/dexon/core/vm"
+ "github.com/dexon-foundation/dexon/crypto"
+ "github.com/dexon-foundation/dexon/ethdb"
+ "github.com/dexon-foundation/dexon/params"
+ "github.com/dexon-foundation/dexon/rlp"
+)
+
+func TestPreparePayload(t *testing.T) {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ t.Errorf("hex to ecdsa error: %v", err)
+ }
+
+ dex, err := newTestDexonWithGenesis(key)
+ if err != nil {
+ t.Errorf("new test dexon error: %v", err)
+ }
+
+ signer := types.NewEIP155Signer(dex.chainConfig.ChainID)
+
+ var expectTx types.Transactions
+ for i := 0; i < 5; i++ {
+ tx, err := addTx(dex, i, signer, key)
+ if err != nil {
+ t.Errorf("add tx error: %v", err)
+ }
+ expectTx = append(expectTx, tx)
+ }
+
+ // This transaction will not be included.
+ _, err = addTx(dex, 100, signer, key)
+ if err != nil {
+ t.Errorf("add tx error: %v", err)
+ }
+
+ chainID := new(big.Int).Mod(crypto.PubkeyToAddress(key.PublicKey).Big(),
+ big.NewInt(int64(dex.chainConfig.Dexcon.NumChains)))
+ var chainNum uint32
+ for chainNum = 0; chainNum < dex.chainConfig.Dexcon.NumChains; chainNum++ {
+
+ payload, err := dex.app.PreparePayload(coreTypes.Position{ChainID: chainNum})
+ if err != nil {
+ t.Errorf("prepare payload error: %v", err)
+ }
+
+ var transactions types.Transactions
+ err = rlp.DecodeBytes(payload, &transactions)
+ if err != nil {
+ t.Errorf("rlp decode error: %v", err)
+ }
+
+ // Only one chain id allow prepare transactions.
+ if chainID.Uint64() == uint64(chainNum) && len(transactions) != 5 {
+ t.Errorf("incorrect transaction num expect %v but %v", 5, len(transactions))
+ } else if chainID.Uint64() != uint64(chainNum) && len(transactions) != 0 {
+ t.Errorf("expect empty slice but %v", len(transactions))
+ }
+
+ for i, tx := range transactions {
+ if expectTx[i].Gas() != tx.Gas() {
+ t.Errorf("unexpected gas expect %v but %v", expectTx[i].Gas(), tx.Gas())
+ }
+
+ if expectTx[i].Hash() != tx.Hash() {
+ t.Errorf("unexpected hash expect %v but %v", expectTx[i].Hash(), tx.Hash())
+ }
+
+ if expectTx[i].Nonce() != tx.Nonce() {
+ t.Errorf("unexpected nonce expect %v but %v", expectTx[i].Nonce(), tx.Nonce())
+ }
+
+ if expectTx[i].GasPrice().Uint64() != tx.GasPrice().Uint64() {
+ t.Errorf("unexpected gas price expect %v but %v",
+ expectTx[i].GasPrice().Uint64(), tx.GasPrice().Uint64())
+ }
+ }
+ }
+}
+
+func TestPrepareWitness(t *testing.T) {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ t.Errorf("hex to ecdsa error: %v", err)
+ }
+
+ dex, err := newTestDexonWithGenesis(key)
+ if err != nil {
+ t.Errorf("new test dexon error: %v", err)
+ }
+
+ currentBlock := dex.blockchain.CurrentBlock()
+
+ witness, err := dex.app.PrepareWitness(0)
+ if err != nil {
+ t.Errorf("prepare witness error: %v", err)
+ }
+
+ if witness.Height != currentBlock.NumberU64() {
+ t.Errorf("unexpeted witness height %v", witness.Height)
+ }
+
+ var witnessData witnessData
+ err = rlp.DecodeBytes(witness.Data, &witnessData)
+ if err != nil {
+ t.Errorf("rlp decode error: %v", err)
+ }
+
+ if witnessData.TxHash != currentBlock.TxHash() {
+ t.Errorf("expect tx hash %v but %v", currentBlock.TxHash(), witnessData.TxHash)
+ }
+
+ if witnessData.Root != currentBlock.Root() {
+ t.Errorf("expect root %v but %v", currentBlock.Root(), witnessData.Root)
+ }
+
+ if witnessData.ReceiptHash != currentBlock.ReceiptHash() {
+ t.Errorf("expect receipt hash %v but %v", currentBlock.ReceiptHash(), witnessData.ReceiptHash)
+ }
+
+ if _, err := dex.app.PrepareWitness(999); err == nil {
+ t.Errorf("it must be get error from prepare")
+ } else {
+ t.Logf("Nice error: %v", err)
+ }
+}
+
+func TestVerifyBlock(t *testing.T) {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ t.Errorf("hex to ecdsa error: %v", err)
+ }
+
+ dex, err := newTestDexonWithGenesis(key)
+ if err != nil {
+ t.Errorf("new test dexon error: %v", err)
+ }
+
+ // Prepare first confirmed block.
+ prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 0)
+
+ chainID := new(big.Int).Mod(crypto.PubkeyToAddress(key.PublicKey).Big(),
+ big.NewInt(int64(dex.chainConfig.Dexcon.NumChains)))
+
+ // Prepare normal block.
+ block := coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 1
+ block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 100)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ // Expect ok.
+ status := dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyOK {
+ t.Errorf("verify fail: %v", status)
+ }
+
+ // Prepare invalid nonce tx.
+ block = coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 1
+ block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 1, 100)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ // Expect invalid block.
+ status = dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyInvalidBlock {
+ t.Errorf("verify fail: %v", status)
+ }
+
+ // Prepare invalid block height.
+ block = coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 2
+ block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 100)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ // Expect retry later.
+ status = dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyRetryLater {
+ t.Errorf("verify fail expect retry later but get %v", status)
+ }
+
+ // Prepare reach block limit.
+ block = coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 1
+ block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 10000)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ // Expect invalid block.
+ status = dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyInvalidBlock {
+ t.Errorf("verify fail expect invalid block but get %v", status)
+ }
+
+ // Prepare insufficient funds.
+ block = coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 1
+ _, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 0)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ signer := types.NewEIP155Signer(dex.chainConfig.ChainID)
+ tx := types.NewTransaction(
+ 0,
+ common.BytesToAddress([]byte{9}),
+ big.NewInt(50000000000000001),
+ params.TxGas,
+ big.NewInt(1),
+ nil)
+ tx, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ return
+ }
+
+ block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx})
+ if err != nil {
+ return
+ }
+
+ // expect invalid block
+ status = dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyInvalidBlock {
+ t.Errorf("verify fail expect invalid block but get %v", status)
+ }
+
+ // Prepare invalid intrinsic gas.
+ block = coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 1
+ _, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 0)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ signer = types.NewEIP155Signer(dex.chainConfig.ChainID)
+ tx = types.NewTransaction(
+ 0,
+ common.BytesToAddress([]byte{9}),
+ big.NewInt(1),
+ params.TxGas,
+ big.NewInt(1),
+ make([]byte, 1))
+ tx, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ return
+ }
+
+ block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx})
+ if err != nil {
+ return
+ }
+
+ // Expect invalid block.
+ status = dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyInvalidBlock {
+ t.Errorf("verify fail expect invalid block but get %v", status)
+ }
+
+ // Prepare invalid transactions with nonce.
+ block = coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Position.ChainID = uint32(chainID.Uint64())
+ block.Position.Height = 1
+ _, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 0)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+
+ signer = types.NewEIP155Signer(dex.chainConfig.ChainID)
+ tx1 := types.NewTransaction(
+ 0,
+ common.BytesToAddress([]byte{9}),
+ big.NewInt(1),
+ params.TxGas,
+ big.NewInt(1),
+ make([]byte, 1))
+ tx1, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ return
+ }
+
+ // Invalid nonce.
+ tx2 := types.NewTransaction(
+ 2,
+ common.BytesToAddress([]byte{9}),
+ big.NewInt(1),
+ params.TxGas,
+ big.NewInt(1),
+ make([]byte, 1))
+ tx2, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ return
+ }
+
+ block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx1, tx2})
+ if err != nil {
+ return
+ }
+
+ // Expect invalid block.
+ status = dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyInvalidBlock {
+ t.Errorf("verify fail expect invalid block but get %v", status)
+ }
+}
+
+func TestBlockConfirmed(t *testing.T) {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ t.Errorf("hex to ecdsa error: %v", err)
+ }
+
+ dex, err := newTestDexonWithGenesis(key)
+ if err != nil {
+ t.Errorf("new test dexon error: %v", err)
+ }
+
+ chainID := new(big.Int).Mod(crypto.PubkeyToAddress(key.PublicKey).Big(),
+ big.NewInt(int64(dex.chainConfig.Dexcon.NumChains)))
+
+ var (
+ expectCost big.Int
+ expectNonce uint64
+ expectCounter uint64
+ )
+ for i := 0; i < 10; i++ {
+ var startNonce int
+ if expectNonce != 0 {
+ startNonce = int(expectNonce) + 1
+ }
+ payload, witness, cost, nonce, err := prepareData(dex, key, startNonce, 50)
+ if err != nil {
+ t.Errorf("prepare data error: %v", err)
+ }
+ expectCost.Add(&expectCost, &cost)
+ expectNonce = nonce
+
+ block := coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Witness = witness
+ block.Payload = payload
+ block.Position.ChainID = uint32(chainID.Uint64())
+
+ dex.app.BlockConfirmed(*block)
+ expectCounter++
+ }
+
+ info := dex.app.blockchain.GetAddressInfo(uint32(chainID.Uint64()),
+ crypto.PubkeyToAddress(key.PublicKey))
+
+ if info.Counter != expectCounter {
+ t.Errorf("expect address counter is %v but %v", expectCounter, info.Counter)
+ }
+
+ if info.Cost.Cmp(&expectCost) != 0 {
+ t.Errorf("expect address cost is %v but %v", expectCost.Uint64(), info.Cost.Uint64())
+ }
+
+ if info.Nonce != expectNonce {
+ t.Errorf("expect address nonce is %v but %v", expectNonce, info.Nonce)
+ }
+}
+
+func TestBlockDelivered(t *testing.T) {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ t.Errorf("hex to ecdsa error: %v", err)
+ }
+
+ dex, err := newTestDexonWithGenesis(key)
+ if err != nil {
+ t.Errorf("new test dexon error: %v", err)
+ }
+
+ address := crypto.PubkeyToAddress(key.PublicKey)
+ firstBlocksInfo, err := prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 50)
+ if err != nil {
+ t.Errorf("preapare confirmed block error: %v", err)
+ }
+
+ dex.app.BlockDelivered(firstBlocksInfo[0].Block.Hash, firstBlocksInfo[0].Block.Position,
+ coreTypes.FinalizationResult{
+ Timestamp: time.Now(),
+ Height: 1,
+ })
+
+ pendingBlock, pendingState := dex.blockchain.GetPending()
+
+ r, ok := dex.app.chainLatestRoot.Load(firstBlocksInfo[0].Block.Position.ChainID)
+ if !ok {
+ t.Errorf("lastest root cache not exist")
+ }
+
+ if *r.(*common.Hash) != pendingBlock.Root() {
+ t.Errorf("incorrect pending root")
+ }
+
+ currentBlock := dex.blockchain.CurrentBlock()
+ if currentBlock.NumberU64() != 0 {
+ t.Errorf("unexpected current block number %v", currentBlock.NumberU64())
+ }
+
+ pendingNonce := pendingState.GetNonce(address)
+ if pendingNonce != firstBlocksInfo[0].Nonce+1 {
+ t.Errorf("unexpected pending state nonce %v", pendingNonce)
+ }
+
+ balance := pendingState.GetBalance(address)
+ if new(big.Int).Add(balance, &firstBlocksInfo[0].Cost).Cmp(big.NewInt(50000000000000000)) != 0 {
+ t.Errorf("unexpected pending state balance %v", balance)
+ }
+
+ // prepare second block to witness first block
+ secondBlocksInfo, err := prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 25)
+ if err != nil {
+ t.Errorf("preapare confirmed block error: %v", err)
+ }
+
+ dex.app.BlockDelivered(secondBlocksInfo[0].Block.Hash, secondBlocksInfo[0].Block.Position,
+ coreTypes.FinalizationResult{
+ Timestamp: time.Now(),
+ Height: 2,
+ })
+
+ // second block witness first block, so current block number should be 1
+ currentBlock = dex.blockchain.CurrentBlock()
+ if currentBlock.NumberU64() != 1 {
+ t.Errorf("unexpected current block number %v", currentBlock.NumberU64())
+ }
+
+ currentState, err := dex.blockchain.State()
+ if err != nil {
+ t.Errorf("current state error: %v", err)
+ }
+
+ currentNonce := currentState.GetNonce(address)
+ if currentNonce != firstBlocksInfo[0].Nonce+1 {
+ t.Errorf("unexpected current state nonce %v", currentNonce)
+ }
+
+ balance = currentState.GetBalance(address)
+ if new(big.Int).Add(balance, &firstBlocksInfo[0].Cost).Cmp(big.NewInt(50000000000000000)) != 0 {
+ t.Errorf("unexpected current state balance %v", balance)
+ }
+}
+
+func BenchmarkBlockDeliveredFlow(b *testing.B) {
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ b.Errorf("hex to ecdsa error: %v", err)
+ return
+ }
+
+ dex, err := newTestDexonWithGenesis(key)
+ if err != nil {
+ b.Errorf("new test dexon error: %v", err)
+ }
+
+ b.ResetTimer()
+ for i := 1; i <= b.N; i++ {
+ blocksInfo, err := prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 100)
+ if err != nil {
+ b.Errorf("preapare confirmed block error: %v", err)
+ return
+ }
+
+ dex.app.BlockDelivered(blocksInfo[0].Block.Hash, blocksInfo[0].Block.Position,
+ coreTypes.FinalizationResult{
+ Timestamp: time.Now(),
+ Height: uint64(i),
+ })
+ }
+}
+
+func newTestDexonWithGenesis(allocKey *ecdsa.PrivateKey) (*Dexon, error) {
+ db := ethdb.NewMemDatabase()
+
+ testBankAddress := crypto.PubkeyToAddress(allocKey.PublicKey)
+ genesis := core.DefaultTestnetGenesisBlock()
+ genesis.Alloc = core.GenesisAlloc{
+ testBankAddress: {
+ Balance: big.NewInt(100000000000000000),
+ Staked: big.NewInt(50000000000000000),
+ },
+ }
+ chainConfig, _, err := core.SetupGenesisBlock(db, genesis)
+ if err != nil {
+ return nil, err
+ }
+
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ return nil, err
+ }
+
+ config := Config{PrivateKey: key}
+ vmConfig := vm.Config{IsBlockProposer: true}
+
+ engine := dexcon.New()
+
+ dex := &Dexon{
+ chainDb: db,
+ chainConfig: chainConfig,
+ networkID: config.NetworkId,
+ engine: engine,
+ }
+
+ dex.blockchain, err = core.NewBlockChain(db, nil, chainConfig, engine, vmConfig, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ txPoolConfig := core.DefaultTxPoolConfig
+ dex.txPool = core.NewTxPool(txPoolConfig, chainConfig, dex.blockchain, true)
+
+ dex.APIBackend = &DexAPIBackend{dex, nil}
+ dex.governance = NewDexconGovernance(dex.APIBackend, dex.chainConfig, config.PrivateKey)
+ engine.SetConfigFetcher(dex.governance)
+ dex.app = NewDexconApp(dex.txPool, dex.blockchain, dex.governance, db, &config)
+
+ return dex, nil
+}
+
+// Add tx into tx pool.
+func addTx(dex *Dexon, nonce int, signer types.Signer, key *ecdsa.PrivateKey) (
+ *types.Transaction, error) {
+ tx := types.NewTransaction(
+ uint64(nonce),
+ common.BytesToAddress([]byte{9}),
+ big.NewInt(int64(nonce*1)),
+ params.TxGas,
+ big.NewInt(1),
+ nil)
+ tx, err := types.SignTx(tx, signer, key)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := dex.txPool.AddRemote(tx); err != nil {
+ return nil, err
+ }
+
+ return tx, nil
+}
+
+// Prepare data with given transaction number and start nonce.
+func prepareData(dex *Dexon, key *ecdsa.PrivateKey, startNonce, txNum int) (
+ payload []byte, witness coreTypes.Witness, cost big.Int, nonce uint64, err error) {
+ signer := types.NewEIP155Signer(dex.chainConfig.ChainID)
+ chainID := new(big.Int).Mod(crypto.PubkeyToAddress(key.PublicKey).Big(),
+ big.NewInt(int64(dex.chainConfig.Dexcon.NumChains)))
+
+ for n := startNonce; n < startNonce+txNum; n++ {
+ var tx *types.Transaction
+ tx, err = addTx(dex, n, signer, key)
+ if err != nil {
+ return
+ }
+
+ cost.Add(&cost, tx.Cost())
+ nonce = uint64(n)
+ }
+
+ payload, err = dex.app.PreparePayload(coreTypes.Position{ChainID: uint32(chainID.Uint64())})
+ if err != nil {
+ return
+ }
+
+ witness, err = dex.app.PrepareWitness(0)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+func prepareDataWithoutTxPool(dex *Dexon, key *ecdsa.PrivateKey, startNonce, txNum int) (
+ payload []byte, witness coreTypes.Witness, err error) {
+ signer := types.NewEIP155Signer(dex.chainConfig.ChainID)
+
+ var transactions types.Transactions
+ for n := startNonce; n < startNonce+txNum; n++ {
+ tx := types.NewTransaction(
+ uint64(n),
+ common.BytesToAddress([]byte{9}),
+ big.NewInt(int64(n*1)),
+ params.TxGas,
+ big.NewInt(1),
+ nil)
+ tx, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ return
+ }
+ transactions = append(transactions, tx)
+ }
+
+ payload, err = rlp.EncodeToBytes(&transactions)
+ if err != nil {
+ return
+ }
+
+ witness, err = dex.app.PrepareWitness(0)
+ if err != nil {
+ return
+ }
+
+ return
+}
+
+func prepareConfirmedBlocks(dex *Dexon, keys []*ecdsa.PrivateKey, txNum int) (blocksInfo []struct {
+ Block *coreTypes.Block
+ Cost big.Int
+ Nonce uint64
+}, err error) {
+ for _, key := range keys {
+ address := crypto.PubkeyToAddress(key.PublicKey)
+ chainID := new(big.Int).Mod(address.Big(),
+ big.NewInt(int64(dex.chainConfig.Dexcon.NumChains)))
+
+ // Prepare one block for pending.
+ var (
+ payload []byte
+ witness coreTypes.Witness
+ cost big.Int
+ nonce uint64
+ )
+ startNonce := dex.txPool.State().GetNonce(address)
+ payload, witness, cost, nonce, err = prepareData(dex, key, int(startNonce), txNum)
+ if err != nil {
+ err = fmt.Errorf("prepare data error: %v", err)
+ return
+ }
+
+ block := coreTypes.NewBlock()
+ block.Hash = coreCommon.NewRandomHash()
+ block.Witness = witness
+ block.Payload = payload
+ block.Position.ChainID = uint32(chainID.Uint64())
+
+ status := dex.app.VerifyBlock(block)
+ if status != coreTypes.VerifyOK {
+ err = fmt.Errorf("verify fail: %v", status)
+ return
+ }
+
+ dex.app.BlockConfirmed(*block)
+
+ blocksInfo = append(blocksInfo, struct {
+ Block *coreTypes.Block
+ Cost big.Int
+ Nonce uint64
+ }{Block: block, Cost: cost, Nonce: nonce})
+ }
+
+ return
+}