Skip to content

Commit d4bb379

Browse files
rjl493456442fjl
authored andcommitted
miner: add generate and import unit test (#20111)
This PR adds a new unit test in miner package which will create some blocks from miner and then import into another chain. In this way, we can ensure all blocks generated by Geth miner obey consensus rules.
1 parent 08953e4 commit d4bb379

File tree

1 file changed

+140
-18
lines changed

1 file changed

+140
-18
lines changed

miner/worker_test.go

Lines changed: 140 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ package miner
1818

1919
import (
2020
"math/big"
21+
"math/rand"
2122
"testing"
2223
"time"
2324

25+
"github.com/ethereum/go-ethereum/accounts"
2426
"github.com/ethereum/go-ethereum/common"
2527
"github.com/ethereum/go-ethereum/consensus"
2628
"github.com/ethereum/go-ethereum/consensus/clique"
@@ -35,6 +37,15 @@ import (
3537
"github.com/ethereum/go-ethereum/params"
3638
)
3739

40+
const (
41+
// testCode is the testing contract binary code which will initialises some
42+
// variables in constructor
43+
testCode = "0x60806040527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0060005534801561003457600080fd5b5060fc806100436000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80630c4dae8814603757806398a213cf146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055507fe9e44f9f7da8c559de847a3232b57364adc0354f15a2cd8dc636d54396f9587a6000546040518082815260200191505060405180910390a15056fea265627a7a723058208ae31d9424f2d0bc2a3da1a5dd659db2d71ec322a17db8f87e19e209e3a1ff4a64736f6c634300050a0032"
44+
45+
// testGas is the gas required for contract deployment.
46+
testGas = 144109
47+
)
48+
3849
var (
3950
// Test chain configurations
4051
testTxPoolConfig core.TxPoolConfig
@@ -81,29 +92,30 @@ type testWorkerBackend struct {
8192
txPool *core.TxPool
8293
chain *core.BlockChain
8394
testTxFeed event.Feed
95+
genesis *core.Genesis
8496
uncleBlock *types.Block
8597
}
8698

87-
func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, n int) *testWorkerBackend {
88-
var (
89-
db = rawdb.NewMemoryDatabase()
90-
gspec = core.Genesis{
91-
Config: chainConfig,
92-
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
93-
}
94-
)
99+
func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend {
100+
var gspec = core.Genesis{
101+
Config: chainConfig,
102+
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
103+
}
95104

96-
switch engine.(type) {
105+
switch e := engine.(type) {
97106
case *clique.Clique:
98107
gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
99-
copy(gspec.ExtraData[32:], testBankAddress[:])
108+
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
109+
e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) {
110+
return crypto.Sign(crypto.Keccak256(data), testBankKey)
111+
})
100112
case *ethash.Ethash:
101113
default:
102114
t.Fatalf("unexpected consensus engine type: %T", engine)
103115
}
104116
genesis := gspec.MustCommit(db)
105117

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

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

140-
func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, blocks int) (*worker, *testWorkerBackend) {
141-
backend := newTestWorkerBackend(t, chainConfig, engine, blocks)
153+
func (b *testWorkerBackend) newRandomUncle() *types.Block {
154+
var parent *types.Block
155+
cur := b.chain.CurrentBlock()
156+
if cur.NumberU64() == 0 {
157+
parent = b.chain.Genesis()
158+
} else {
159+
parent = b.chain.GetBlockByHash(b.chain.CurrentBlock().ParentHash())
160+
}
161+
blocks, _ := core.GenerateChain(b.chain.Config(), parent, b.chain.Engine(), b.db, 1, func(i int, gen *core.BlockGen) {
162+
var addr common.Address
163+
rand.Read(addr.Bytes())
164+
gen.SetCoinbase(addr)
165+
})
166+
return blocks[0]
167+
}
168+
169+
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
170+
var tx *types.Transaction
171+
if creation {
172+
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
173+
} else {
174+
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey)
175+
}
176+
return tx
177+
}
178+
179+
func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*worker, *testWorkerBackend) {
180+
backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks)
142181
backend.txPool.AddLocals(pendingTxs)
143182
w := newWorker(testConfig, chainConfig, engine, backend, new(event.TypeMux), nil)
144183
w.setEtherbase(testBankAddress)
145184
return w, backend
146185
}
147186

187+
func TestGenerateBlockAndImportEthash(t *testing.T) {
188+
testGenerateBlockAndImport(t, false)
189+
}
190+
191+
func TestGenerateBlockAndImportClique(t *testing.T) {
192+
testGenerateBlockAndImport(t, true)
193+
}
194+
195+
func testGenerateBlockAndImport(t *testing.T, isClique bool) {
196+
var (
197+
engine consensus.Engine
198+
chainConfig *params.ChainConfig
199+
db = rawdb.NewMemoryDatabase()
200+
)
201+
if isClique {
202+
chainConfig = params.AllCliqueProtocolChanges
203+
engine = clique.New(chainConfig.Clique, db)
204+
} else {
205+
chainConfig = params.AllEthashProtocolChanges
206+
engine = ethash.NewFaker()
207+
}
208+
209+
w, b := newTestWorker(t, chainConfig, engine, db, 0)
210+
defer w.close()
211+
212+
db2 := rawdb.NewMemoryDatabase()
213+
b.genesis.MustCommit(db2)
214+
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil)
215+
defer chain.Stop()
216+
217+
newBlock := make(chan struct{})
218+
listenNewBlock := func() {
219+
sub := w.mux.Subscribe(core.NewMinedBlockEvent{})
220+
defer sub.Unsubscribe()
221+
222+
for item := range sub.Chan() {
223+
block := item.Data.(core.NewMinedBlockEvent).Block
224+
_, err := chain.InsertChain([]*types.Block{block})
225+
if err != nil {
226+
t.Fatalf("Failed to insert new mined block:%d, error:%v", block.NumberU64(), err)
227+
}
228+
newBlock <- struct{}{}
229+
}
230+
}
231+
232+
// Ensure worker has finished initialization
233+
for {
234+
b := w.pendingBlock()
235+
if b != nil && b.NumberU64() == 1 {
236+
break
237+
}
238+
}
239+
w.start() // Start mining!
240+
241+
// Ignore first 2 commits caused by start operation
242+
ignored := make(chan struct{}, 2)
243+
w.skipSealHook = func(task *task) bool {
244+
ignored <- struct{}{}
245+
return true
246+
}
247+
for i := 0; i < 2; i++ {
248+
<-ignored
249+
}
250+
251+
go listenNewBlock()
252+
253+
// Ignore empty commit here for less noise
254+
w.skipSealHook = func(task *task) bool {
255+
return len(task.receipts) == 0
256+
}
257+
for i := 0; i < 50; i++ {
258+
b.txPool.AddLocal(b.newRandomTx(true))
259+
b.txPool.AddLocal(b.newRandomTx(false))
260+
b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.newRandomUncle()}})
261+
b.PostChainEvents([]interface{}{core.ChainSideEvent{Block: b.newRandomUncle()}})
262+
select {
263+
case <-newBlock:
264+
case <-time.NewTimer(time.Millisecond * 1500).C: // Worker needs 1s to include new changes.
265+
t.Fatalf("timeout")
266+
}
267+
}
268+
}
269+
148270
func TestPendingStateAndBlockEthash(t *testing.T) {
149271
testPendingStateAndBlock(t, ethashChainConfig, ethash.NewFaker())
150272
}
@@ -155,7 +277,7 @@ func TestPendingStateAndBlockClique(t *testing.T) {
155277
func testPendingStateAndBlock(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine) {
156278
defer engine.Close()
157279

158-
w, b := newTestWorker(t, chainConfig, engine, 0)
280+
w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
159281
defer w.close()
160282

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

190-
w, _ := newTestWorker(t, chainConfig, engine, 0)
312+
w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
191313
defer w.close()
192314

193315
var (
@@ -241,7 +363,7 @@ func TestStreamUncleBlock(t *testing.T) {
241363
ethash := ethash.NewFaker()
242364
defer ethash.Close()
243365

244-
w, b := newTestWorker(t, ethashChainConfig, ethash, 1)
366+
w, b := newTestWorker(t, ethashChainConfig, ethash, rawdb.NewMemoryDatabase(), 1)
245367
defer w.close()
246368

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

307-
w, b := newTestWorker(t, chainConfig, engine, 0)
429+
w, b := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
308430
defer w.close()
309431

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

372-
w, _ := newTestWorker(t, chainConfig, engine, 0)
494+
w, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), 0)
373495
defer w.close()
374496

375497
w.skipSealHook = func(task *task) bool {

0 commit comments

Comments
 (0)