diff options
author | bojie <bojie@dexon.org> | 2018-12-03 16:30:53 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@dexon.org> | 2019-04-09 21:32:54 +0800 |
commit | c4ee0ef189bc00661c7ca8c1d3e94e929aa5eee1 (patch) | |
tree | 3e6105d45ca1bc71c9117864eb91b59998d03d58 /core | |
parent | d3c9496ee0256154477d0c74397a28c93a26af6f (diff) | |
download | dexon-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.go | 26 | ||||
-rw-r--r-- | core/blockchain.go | 16 | ||||
-rw-r--r-- | core/blockchain_test.go | 239 |
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 ( |