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

miner: add generate and import unit test #20111

Merged
merged 3 commits into from
Oct 20, 2019
Merged
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
158 changes: 140 additions & 18 deletions miner/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ package miner

import (
"math/big"
"math/rand"
"testing"
"time"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/clique"
Expand All @@ -35,6 +37,15 @@ import (
"github.com/ethereum/go-ethereum/params"
)

const (
// testCode is the testing contract binary code which will initialises some
// variables in constructor
testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032"

// testGas is the gas required for contract deployment.
testGas = 144109
)

var (
// Test chain configurations
testTxPoolConfig core.TxPoolConfig
Expand Down Expand Up @@ -81,29 +92,30 @@ type testWorkerBackend struct {
txPool *core.TxPool
chain *core.BlockChain
testTxFeed event.Feed
genesis *core.Genesis
uncleBlock *types.Block
}

func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, n int) *testWorkerBackend {
var (
db = rawdb.NewMemoryDatabase()
gspec = core.Genesis{
Config: chainConfig,
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
}
)
func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend {
var gspec = core.Genesis{
Config: chainConfig,
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
}

switch engine.(type) {
switch e := engine.(type) {
case *clique.Clique:
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
copy(gspec.ExtraData[32:], testBankAddress[:])
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) {
return crypto.Sign(crypto.Keccak256(data), testBankKey)
})
case *ethash.Ethash:
default:
t.Fatalf("unexpected consensus engine type: %T", engine)
}
genesis := gspec.MustCommit(db)

chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{}, nil)
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)

// Generate a small n-block chain and an uncle block for it
Expand All @@ -127,6 +139,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
db: db,
chain: chain,
txPool: txpool,
genesis: &gspec,
uncleBlock: blocks[0],
}
}
Expand All @@ -137,14 +150,123 @@ func (b *testWorkerBackend) PostChainEvents(events []interface{}) {
b.chain.PostChainEvents(events, nil)
}

func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, blocks int) (*worker, *testWorkerBackend) {
backend := newTestWorkerBackend(t, chainConfig, engine, blocks)
func (b *testWorkerBackend) newRandomUncle() *types.Block {
var parent *types.Block
cur := b.chain.CurrentBlock()
if cur.NumberU64() == 0 {
parent = b.chain.Genesis()
} else {
parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash())
}
blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) {
var addr common.Address
rand.Read(addr.Bytes())
gen.SetCoinbase(addr)
})
return blocks[0]
}

func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
var tx *types.Transaction
if creation {
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
} else {
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
}
return tx
}

func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) {
backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks)
backend.txPool.AddLocals(pendingTxs)
w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil)
w.setEtherbase(testBankAddress)
return w, backend
}

func TestGenerateBlockAndImportEthash(t *testing.T) {
testGenerateBlockAndImport(t, false)
}

func TestGenerateBlockAndImportClique(t *testing.T) {
testGenerateBlockAndImport(t, true)
}

func testGenerateBlockAndImport(t *testing.T, isClique bool) {
var (
engine consensus.Engine
chainConfig *params.ChainConfig
db = rawdb.NewMemoryDatabase()
)
if isClique {
chainConfig = params.AllCliqueProtocolChanges
engine = clique.New(chainConfig.Clique, db)
} else {
chainConfig = params.AllEthashProtocolChanges
engine = ethash.NewFaker()
}

w, b := newTestWorker(t, chainConfig, engine, db, 0)
defer w.close()

db2 := rawdb.NewMemoryDatabase()
b.genesis.MustCommit(db2)
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil)
defer chain.Stop()

newBlock := make(chan struct{})
listenNewBlock := func() {
sub := w.mux.Subscribe(core.NewMinedBlockEvent{})
defer sub.Unsubscribe()

for item := range sub.Chan() {
block := item.Data.(core.NewMinedBlockEvent).Block
_, err := chain.InsertChain([]*types.Block{block})
if err != nil {
t.Fatalf("Failed to insert new mined block:%d, error:%v", block.NumberU64(), err)
}
newBlock <- struct{}{}
}
}

// Ensure worker has finished initialization
for {
b := w.pendingBlock()
if b != nil && b.NumberU64() == 1 {
break
}
}
w.start() // Start mining!

// Ignore first 2 commits caused by start operation
ignored := make(chan struct{}, 2)
w.skipSealHook = func(task *task) bool {
ignored <- struct{}{}
return true
}
for i := 0; i < 2; i++ {
<-ignored
}

go listenNewBlock()

// Ignore empty commit here for less noise
w.skipSealHook = func(task *task) bool {
return len(task.receipts) == 0
}
for i := 0; i < 50; i++ {
b.txPool.AddLocal(b.newRandomTx(true))
b.txPool.AddLocal(b.newRandomTx(false))
b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.newRandomUncle()}})
b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.newRandomUncle()}})
select {
case <-newBlock:
case <-time.NewTimer(time.Millisecond * 1500).C: // Worker needs 1s to include new changes.
t.Fatalf("timeout")
}
}
}

func TestPendingStateAndBlockEthash(t *testing.T) {
testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker())
}
Expand All @@ -155,7 +277,7 @@ func TestPendingStateAndBlockClique(t *testing.T) {
func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
defer engine.Close()

w, b := newTestWorker(t, chainConfig, engine, 0)
w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
defer w.close()

// Ensure snapshot has been updated.
Expand Down Expand Up @@ -187,7 +309,7 @@ func TestEmptyWorkClique(t *testing.T) {
func testEmptyWork(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
defer engine.Close()

w, _ := newTestWorker(t, chainConfig, engine, 0)
w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
defer w.close()

var (
Expand Down Expand Up @@ -241,7 +363,7 @@ func TestStreamUncleBlock(t *testing.T) {
ethash := ethash.NewFaker()
defer ethash.Close()

w, b := newTestWorker(t, ethashChainConfig, ethash, 1)
w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1)
defer w.close()

var taskCh = make(chan struct{})
Expand Down Expand Up @@ -304,7 +426,7 @@ func TestRegenerateMiningBlockClique(t *testing.T) {
func testRegenerateMiningBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
defer engine.Close()

w, b := newTestWorker(t, chainConfig, engine, 0)
w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
defer w.close()

var taskCh = make(chan struct{})
Expand Down Expand Up @@ -369,7 +491,7 @@ func TestAdjustIntervalClique(t *testing.T) {
func testAdjustInterval(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
defer engine.Close()

w, _ := newTestWorker(t, chainConfig, engine, 0)
w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
defer w.close()

w.skipSealHook = func(task *task) bool {
Expand Down