aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorbojie <bojie@dexon.org>2018-12-03 16:30:53 +0800
committerWei-Ning Huang <w@dexon.org>2019-04-09 21:32:54 +0800
commitc4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1 (patch)
tree3e6105d45ca1bc71c9117864eb91b59998d03d58 /core
parentd3c9496ee0256154477d0c74397a28c93a26af6f (diff)
downloaddexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.tar
dexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.tar.gz
dexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.tar.bz2
dexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.tar.lz
dexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.tar.xz
dexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.tar.zst
dexon-c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1.zip
app: add app test case and benchmark (#66)
Diffstat (limited to 'core')
-rw-r--r--core/block_validator.go26
-rw-r--r--core/blockchain.go16
-rw-r--r--core/blockchain_test.go239
3 files changed, 268 insertions, 13 deletions
diff --git a/core/block_validator.go b/core/block_validator.go
index 09539790b..660bd09f8 100644
--- a/core/block_validator.go
+++ b/core/block_validator.go
@@ -102,19 +102,23 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
}
func (v *BlockValidator) ValidateWitnessData(height uint64, data types.WitnessData) error {
- currentBlock := v.bc.CurrentBlock()
- if height > currentBlock.NumberU64() && height != 0 {
- pendingBlock := v.bc.GetPendingBlockByNumber(height)
-
- if pendingBlock.Root() != data.Root {
- return fmt.Errorf("invalid witness root %s vs %s",
- pendingBlock.Root().String(), data.Root.String())
- }
- if pendingBlock.ReceiptHash() != data.ReceiptHash {
- return fmt.Errorf("invalid witness receipt hash %s vs %s",
- pendingBlock.ReceiptHash().String(), data.ReceiptHash.String())
+ b := v.bc.GetPendingBlockByNumber(height)
+ if b == nil {
+ b = v.bc.GetBlockByNumber(height)
+ if b == nil {
+ return fmt.Errorf("can not find block %v either pending or confirmed block", height)
}
}
+
+ if b.Root() != data.Root {
+ return fmt.Errorf("invalid witness root %s vs %s",
+ b.Root().String(), data.Root.String())
+ }
+
+ if b.ReceiptHash() != data.ReceiptHash {
+ return fmt.Errorf("invalid witness receipt hash %s vs %s",
+ b.ReceiptHash().String(), data.ReceiptHash.String())
+ }
return nil
}
diff --git a/core/blockchain.go b/core/blockchain.go
index b22da28ab..470f7ae28 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -356,6 +356,18 @@ func (bc *BlockChain) GetChainLastConfirmedHeight(chainID uint32) uint64 {
return val.(uint64)
}
+func (bc *BlockChain) GetAddressInfo(chainID uint32, address common.Address) (
+ info struct {
+ Nonce uint64
+ Cost *big.Int
+ Counter uint64
+ }) {
+ info.Nonce = bc.addressNonce[chainID][address]
+ info.Cost = bc.addressCost[chainID][address]
+ info.Counter = bc.addressCounter[chainID][address]
+ return
+}
+
// 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 {
@@ -1775,11 +1787,11 @@ func (bc *BlockChain) processPendingBlock(
var witnessData types.WitnessData
if err := rlp.Decode(bytes.NewReader(witness.Data), &witnessData); err != nil {
log.Error("Witness rlp decode failed", "error", err)
- panic(err)
+ return nil, nil, nil, fmt.Errorf("rlp decode fail: %v", err)
}
if err := bc.Validator().ValidateWitnessData(witness.Height, witnessData); err != nil {
- return nil, nil, nil, fmt.Errorf("valiadte witness data error: %v", err)
+ return nil, nil, nil, fmt.Errorf("validate witness data error: %v", err)
}
currentBlock := bc.CurrentBlock()
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 28119a226..867cfef5e 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -20,12 +20,16 @@ import (
"fmt"
"math/big"
"math/rand"
+ "strings"
"sync"
"testing"
"time"
+ coreTypes "github.com/dexon-foundation/dexon-consensus/core/types"
+
"github.com/dexon-foundation/dexon/common"
"github.com/dexon-foundation/dexon/consensus"
+ "github.com/dexon-foundation/dexon/consensus/dexcon"
"github.com/dexon-foundation/dexon/consensus/ethash"
"github.com/dexon-foundation/dexon/core/rawdb"
"github.com/dexon-foundation/dexon/core/state"
@@ -34,6 +38,7 @@ import (
"github.com/dexon-foundation/dexon/crypto"
"github.com/dexon-foundation/dexon/ethdb"
"github.com/dexon-foundation/dexon/params"
+ "github.com/dexon-foundation/dexon/rlp"
)
// So we can deterministically seed different blockchains
@@ -42,6 +47,8 @@ var (
forkSeed = 2
)
+const processNum = 9
+
// newCanonical creates a chain database, and injects a deterministic canonical
// chain. Depending on the full flag, if creates either a full block chain or a
// header only chain.
@@ -1594,6 +1601,238 @@ func TestLargeReorgTrieGC(t *testing.T) {
}
}
+type dexconTest struct {
+ dexcon.Dexcon
+
+ blockReward *big.Int
+ numChains uint32
+}
+
+// Finalize for skip governance access.
+func (d *dexconTest) Finalize(chain consensus.ChainReader, header *types.Header,
+ state *state.StateDB, txs []*types.Transaction, uncles []*types.Header,
+ receipts []*types.Receipt) (*types.Block, error) {
+ reward := new(big.Int).Div(d.blockReward, big.NewInt(int64(d.numChains)))
+ state.AddBalance(header.Coinbase, reward)
+
+ header.Reward = reward
+ header.Root = state.IntermediateRoot(true)
+ return types.NewBlock(header, txs, uncles, receipts), nil
+}
+
+func TestProcessPendingBlock(t *testing.T) {
+ db := ethdb.NewMemDatabase()
+
+ key, err := crypto.GenerateKey()
+ if err != nil {
+ t.Fatalf("new private key error: %v", err)
+ }
+
+ addr := crypto.PubkeyToAddress(key.PublicKey)
+ gspec := &Genesis{
+ Config: params.TestnetChainConfig,
+ Alloc: GenesisAlloc{
+ addr: {
+ Balance: big.NewInt(10000000000),
+ Staked: big.NewInt(0),
+ }},
+ }
+
+ chainConfig, _, genesisErr := SetupGenesisBlock(db, gspec)
+ if genesisErr != nil {
+ t.Fatalf("set up genesis block error: %v", genesisErr)
+ }
+
+ engine := &dexconTest{
+ blockReward: chainConfig.Dexcon.BlockReward,
+ numChains: chainConfig.Dexcon.NumChains,
+ }
+ chain, err := NewBlockChain(db, nil, chainConfig, engine, vm.Config{}, nil)
+ if err != nil {
+ t.Fatalf("failed to create tester chain: %v", err)
+ }
+
+ // Process 1 ~ N success blocks.
+ for i := 0; i < processNum; i++ {
+ var witnessDataBytes []byte
+ if i == 0 {
+ witnessData := types.WitnessData{
+ Root: gspec.ToBlock(nil).Root(),
+ TxHash: gspec.ToBlock(nil).TxHash(),
+ ReceiptHash: gspec.ToBlock(nil).ReceiptHash(),
+ }
+ witnessDataBytes, err = rlp.EncodeToBytes(&witnessData)
+ if err != nil {
+ t.Fatalf("rlp encode fail: %v", err)
+ }
+ } else {
+ witnessData := types.WitnessData{
+ Root: chain.pendingBlocks[uint64(i)].block.Root(),
+ TxHash: chain.pendingBlocks[uint64(i)].block.TxHash(),
+ ReceiptHash: chain.pendingBlocks[uint64(i)].block.ReceiptHash(),
+ }
+ witnessDataBytes, err = rlp.EncodeToBytes(&witnessData)
+ if err != nil {
+ t.Fatalf("rlp encode fail: %v", err)
+ }
+ }
+
+ tx := types.NewTransaction(uint64(i), common.Address{9}, big.NewInt(1),
+ 21000, big.NewInt(1), nil)
+ signer := types.NewEIP155Signer(chainConfig.ChainID)
+ tx, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ t.Fatalf("sign tx error: %v", err)
+ }
+
+ _, err = chain.ProcessPendingBlock(types.NewBlock(&types.Header{
+ Number: new(big.Int).SetUint64(uint64(i) + 1),
+ Time: uint64(time.Now().UnixNano() / 1000000),
+ GasLimit: 10000,
+ Difficulty: big.NewInt(1),
+ Round: 0,
+ }, types.Transactions{tx}, nil, nil), &coreTypes.Witness{
+ Height: uint64(i),
+ Data: witnessDataBytes,
+ })
+ if err != nil {
+ t.Fatalf("process pending block error: %v", err)
+ }
+
+ if chain.CurrentBlock().NumberU64() != uint64(i) {
+ t.Fatalf("expect current height %v but %v", uint64(i), chain.CurrentBlock().NumberU64())
+ }
+ }
+
+ // Witness rlp decode fail.
+ _, err = chain.ProcessPendingBlock(types.NewBlock(&types.Header{
+ Number: new(big.Int).SetUint64(processNum + 1),
+ Time: uint64(time.Now().UnixNano() / 1000000),
+ GasLimit: 10000,
+ Difficulty: big.NewInt(1),
+ Round: 0,
+ }, nil, nil, nil), &coreTypes.Witness{
+ Height: processNum,
+ })
+ if err == nil || !strings.Contains(err.Error(), "rlp decode fail") {
+ t.Fatalf("not expected fail: %v", err)
+ }
+
+ // Validate witness fail with unknown block.
+ witnessData := types.WitnessData{
+ Root: chain.pendingBlocks[processNum].block.Root(),
+ TxHash: chain.pendingBlocks[processNum].block.TxHash(),
+ ReceiptHash: chain.pendingBlocks[processNum].block.ReceiptHash(),
+ }
+ witnessDataBytes, err := rlp.EncodeToBytes(&witnessData)
+ if err != nil {
+ t.Fatalf("rlp encode fail: %v", err)
+ }
+ _, err = chain.ProcessPendingBlock(types.NewBlock(&types.Header{
+ Number: new(big.Int).SetUint64(processNum + 1),
+ Time: uint64(time.Now().UnixNano() / 1000000),
+ GasLimit: 10000,
+ Difficulty: big.NewInt(1),
+ Round: 0,
+ }, nil, nil, nil), &coreTypes.Witness{
+ Height: processNum + 1,
+ Data: witnessDataBytes,
+ })
+ if err == nil || !strings.Contains(err.Error(), "can not find block") {
+ t.Fatalf("not expected fail: %v", err)
+ }
+
+ // Validate witness fail with unexpected root.
+ witnessData = types.WitnessData{
+ Root: chain.pendingBlocks[processNum].block.Root(),
+ TxHash: chain.pendingBlocks[processNum].block.TxHash(),
+ ReceiptHash: chain.pendingBlocks[processNum].block.ReceiptHash(),
+ }
+ witnessDataBytes, err = rlp.EncodeToBytes(&witnessData)
+ if err != nil {
+ t.Fatalf("rlp encode fail: %v", err)
+ }
+ _, err = chain.ProcessPendingBlock(types.NewBlock(&types.Header{
+ Number: new(big.Int).SetUint64(processNum + 1),
+ Time: uint64(time.Now().UnixNano() / 1000000),
+ GasLimit: 10000,
+ Difficulty: big.NewInt(1),
+ Round: 0,
+ }, nil, nil, nil), &coreTypes.Witness{
+ Height: processNum - 1,
+ Data: witnessDataBytes,
+ })
+ if err == nil || !strings.Contains(err.Error(), "invalid witness root") {
+ t.Fatalf("not expected fail: %v", err)
+ }
+
+ // Apply transaction fail with insufficient fund.
+ witnessData = types.WitnessData{
+ Root: chain.pendingBlocks[processNum].block.Root(),
+ TxHash: chain.pendingBlocks[processNum].block.TxHash(),
+ ReceiptHash: chain.pendingBlocks[processNum].block.ReceiptHash(),
+ }
+ witnessDataBytes, err = rlp.EncodeToBytes(&witnessData)
+ if err != nil {
+ t.Fatalf("rlp encode fail: %v", err)
+ }
+
+ tx := types.NewTransaction(processNum, common.Address{9}, big.NewInt(99999999999999),
+ 21000, big.NewInt(1), nil)
+ signer := types.NewEIP155Signer(chainConfig.ChainID)
+ tx, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ t.Fatalf("sign tx error: %v", err)
+ }
+
+ _, err = chain.ProcessPendingBlock(types.NewBlock(&types.Header{
+ Number: new(big.Int).SetUint64(processNum + 1),
+ Time: uint64(time.Now().UnixNano() / 1000000),
+ GasLimit: 10000,
+ Difficulty: big.NewInt(1),
+ Round: 0,
+ }, types.Transactions{tx}, nil, nil), &coreTypes.Witness{
+ Height: processNum,
+ Data: witnessDataBytes,
+ })
+ if err == nil || !strings.Contains(err.Error(), "apply transaction error") {
+ t.Fatalf("not expected fail: %v", err)
+ }
+
+ // Apply transaction fail with nonce too height.
+ witnessData = types.WitnessData{
+ Root: chain.pendingBlocks[processNum].block.Root(),
+ TxHash: chain.pendingBlocks[processNum].block.TxHash(),
+ ReceiptHash: chain.pendingBlocks[processNum].block.ReceiptHash(),
+ }
+ witnessDataBytes, err = rlp.EncodeToBytes(&witnessData)
+ if err != nil {
+ t.Fatalf("rlp encode fail: %v", err)
+ }
+
+ tx = types.NewTransaction(999, common.Address{9}, big.NewInt(1),
+ 21000, big.NewInt(1), nil)
+ signer = types.NewEIP155Signer(chainConfig.ChainID)
+ tx, err = types.SignTx(tx, signer, key)
+ if err != nil {
+ t.Fatalf("sign tx error: %v", err)
+ }
+
+ _, err = chain.ProcessPendingBlock(types.NewBlock(&types.Header{
+ Number: new(big.Int).SetUint64(processNum + 1),
+ Time: uint64(time.Now().UnixNano() / 1000000),
+ GasLimit: 10000,
+ Difficulty: big.NewInt(1),
+ Round: 0,
+ }, types.Transactions{tx}, nil, nil), &coreTypes.Witness{
+ Height: processNum,
+ Data: witnessDataBytes,
+ })
+ if err == nil || !strings.Contains(err.Error(), "apply transaction error") {
+ t.Fatalf("not expected fail: %v", err)
+ }
+}
+
// Benchmarks large blocks with value transfers to non-existing accounts
func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
var (