mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 07:06:42 +00:00
miner: add commit interrupt tests for non-validator mode (#1441)
This PR adds a test which verifies the working of miner module when running on a sentry (non-validator) node. It tries to disable the normal mining flow and trigger it via the new transactions subscription channel and asserts mainly 2 things - Interrupt commit works and breaks execution when the time crosses deadline (i.e. header.Timestamp) - Mining is not triggered when we've already crossed the deadline
This commit is contained in:
parent
466ff66f4e
commit
1f2529fa0f
1 changed files with 94 additions and 3 deletions
|
|
@ -708,8 +708,9 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: paralleltest
|
// nolint: paralleltest
|
||||||
// TestCommitInterruptExperimentBor tests the commit interrupt experiment for bor consensus by inducing an artificial delay at transaction level.
|
// TestCommitInterruptExperimentBor_NormalFlow tests the commit interrupt experiment for bor consensus by inducing
|
||||||
func TestCommitInterruptExperimentBor(t *testing.T) {
|
// an artificial delay at transaction level. It runs the normal mining flow triggered via new head.
|
||||||
|
func TestCommitInterruptExperimentBor_NormalFlow(t *testing.T) {
|
||||||
// with 1 sec block time and 200 millisec tx delay we should get 5 txs per block
|
// with 1 sec block time and 200 millisec tx delay we should get 5 txs per block
|
||||||
testCommitInterruptExperimentBor(t, 200, 5, 0)
|
testCommitInterruptExperimentBor(t, 200, 5, 0)
|
||||||
|
|
||||||
|
|
@ -834,6 +835,96 @@ func testCommitInterruptExperimentBor(t *testing.T, delay uint, txCount int, opc
|
||||||
assert.Check(t, 0 < w.chain.GetBlockByNumber(currentBlockNumber-1).Transactions().Len())
|
assert.Check(t, 0 < w.chain.GetBlockByNumber(currentBlockNumber-1).Transactions().Len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestCommitInterruptExperimentBor_NewTxFlow tests the commit interrupt experiment for bor consensus by inducing
|
||||||
|
// an artificial delay at transaction level. It runs the mining flow triggered via new transactions channel. The tests
|
||||||
|
// are a bit unconventional compared to normal flow as the situations are only possible in non-validator mode.
|
||||||
|
func TestCommitInterruptExperimentBor_NewTxFlow(t *testing.T) {
|
||||||
|
var (
|
||||||
|
engine consensus.Engine
|
||||||
|
chainConfig *params.ChainConfig
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
)
|
||||||
|
|
||||||
|
chainConfig = params.BorUnittestChainConfig
|
||||||
|
|
||||||
|
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||||
|
|
||||||
|
engine, ctrl = getFakeBorFromConfig(t, chainConfig)
|
||||||
|
|
||||||
|
w, b, _ := newTestWorker(t, chainConfig, engine, rawdb.NewMemoryDatabase(), true, uint(0), uint(0))
|
||||||
|
defer func() {
|
||||||
|
w.close()
|
||||||
|
engine.Close()
|
||||||
|
db.Close()
|
||||||
|
ctrl.Finish()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Create random transactions (contract interaction)
|
||||||
|
tx1, addr := b.newStorageCreateContractTx()
|
||||||
|
tx2 := b.newStorageContractCallTx(addr, 1)
|
||||||
|
tx3 := b.newStorageContractCallTx(addr, 2)
|
||||||
|
|
||||||
|
// Create a chain head subscription for tests
|
||||||
|
chainHeadCh := make(chan core.ChainHeadEvent, 10)
|
||||||
|
w.chain.SubscribeChainHeadEvent(chainHeadCh)
|
||||||
|
|
||||||
|
// Start mining!
|
||||||
|
w.start()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
head := <-chainHeadCh
|
||||||
|
// We skip the initial 2 blocks as the mining timings are a bit skewed up
|
||||||
|
if head.Block.NumberU64() == 2 {
|
||||||
|
// Stop the miner so that worker assumes it's a sentry and not a validator
|
||||||
|
w.stop()
|
||||||
|
|
||||||
|
// Add the first transaction to be mined normally via `txsCh`
|
||||||
|
b.TxPool().Add([]*types.Transaction{tx1}, false, false)
|
||||||
|
|
||||||
|
// Set it to syncing mode so that it doesn't mine via the `commitWork` flow
|
||||||
|
w.syncing.Store(true)
|
||||||
|
|
||||||
|
// Wait until the mining window (2s) is almost about to reach leaving
|
||||||
|
// a very small time (~10ms) to try to commit transaction before timing out.
|
||||||
|
delay := time.Until(time.Unix(int64(w.current.header.Time), 0))
|
||||||
|
delay -= 10 * time.Millisecond
|
||||||
|
|
||||||
|
// Case 1: This transaction should not be included due to commit interrupt
|
||||||
|
// at opcode level. It will start the EVM execution but will end in between.
|
||||||
|
<-time.After(delay)
|
||||||
|
|
||||||
|
// Set an artificial delay at opcode level
|
||||||
|
w.setInterruptCtx(vm.InterruptCtxOpcodeDelayKey, uint(500))
|
||||||
|
|
||||||
|
// Send the second transaction
|
||||||
|
b.TxPool().Add([]*types.Transaction{tx2}, false, false)
|
||||||
|
|
||||||
|
// Reset the delay again. By this time, we're sure that it has timed out.
|
||||||
|
delay = time.Until(time.Unix(int64(w.current.header.Time), 0))
|
||||||
|
|
||||||
|
// Case 2: This transaction should not be included because the miner loop
|
||||||
|
// won't accept any transactions post the deadline (i.e. header.Timestamp).
|
||||||
|
<-time.After(delay)
|
||||||
|
|
||||||
|
// Reset the artificial opcode delay just to be sure of the exclusion of tx
|
||||||
|
w.setInterruptCtx(vm.InterruptCtxOpcodeDelayKey, uint(0))
|
||||||
|
|
||||||
|
// Send the third transaction
|
||||||
|
b.TxPool().Add([]*types.Transaction{tx3}, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for enough time to mine 3 blocks
|
||||||
|
time.Sleep(6 * time.Second)
|
||||||
|
|
||||||
|
// Ensure that the last block was 3 and only 1 transactions out of 3 were included
|
||||||
|
assert.Equal(t, w.current.header.Number.Uint64(), uint64(3))
|
||||||
|
assert.Equal(t, w.current.tcount, 1)
|
||||||
|
assert.Equal(t, len(w.current.txs), 1)
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkBorMining(b *testing.B) {
|
func BenchmarkBorMining(b *testing.B) {
|
||||||
chainConfig := params.BorUnittestChainConfig
|
chainConfig := params.BorUnittestChainConfig
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue