Skip to content

Commit 1b34b2a

Browse files
core, miner: cover pipelined SRC branches
1 parent 0880769 commit 1b34b2a

4 files changed

Lines changed: 364 additions & 0 deletions

File tree

core/block_validator_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"testing"
2222
"time"
2323

24+
"github.com/stretchr/testify/require"
25+
2426
"github.com/ethereum/go-ethereum/common"
2527
"github.com/ethereum/go-ethereum/consensus"
2628
"github.com/ethereum/go-ethereum/consensus/beacon"
@@ -30,6 +32,7 @@ import (
3032
"github.com/ethereum/go-ethereum/core/types"
3133
"github.com/ethereum/go-ethereum/crypto"
3234
"github.com/ethereum/go-ethereum/params"
35+
"github.com/ethereum/go-ethereum/trie"
3336
)
3437

3538
// Tests that simple header verification works, for both good and bad blocks.
@@ -38,6 +41,50 @@ func TestHeaderVerification(t *testing.T) {
3841
testHeaderVerification(t, rawdb.PathScheme)
3942
}
4043

44+
func TestValidateStateCheap(t *testing.T) {
45+
validator := NewBlockValidator(params.TestChainConfig, nil)
46+
receipts := []*types.Receipt{{Status: types.ReceiptStatusSuccessful, CumulativeGasUsed: 21_000}}
47+
receiptHash := types.DeriveSha(types.Receipts(receipts), trie.NewStackTrie(nil))
48+
bloom := types.MergeBloom(receipts)
49+
50+
newBlock := func() *types.Block {
51+
return types.NewBlockWithHeader(&types.Header{
52+
Number: big.NewInt(1),
53+
GasUsed: 21_000,
54+
Bloom: bloom,
55+
ReceiptHash: receiptHash,
56+
})
57+
}
58+
valid := &ProcessResult{Receipts: receipts, GasUsed: 21_000}
59+
require.NoError(t, validator.ValidateStateCheap(newBlock(), nil, valid))
60+
require.Error(t, validator.ValidateStateCheap(newBlock(), nil, nil))
61+
62+
gasMismatch := *valid
63+
gasMismatch.GasUsed++
64+
require.ErrorIs(t, validator.ValidateStateCheap(newBlock(), nil, &gasMismatch), ErrGasUsedMismatch)
65+
66+
bloomMismatch := *newBlock().Header()
67+
bloomMismatch.Bloom[0] = 1
68+
require.ErrorIs(t, validator.ValidateStateCheap(types.NewBlockWithHeader(&bloomMismatch), nil, valid), ErrBloomMismatch)
69+
70+
receiptMismatch := *newBlock().Header()
71+
receiptMismatch.ReceiptHash = common.HexToHash("0x01")
72+
require.ErrorIs(t, validator.ValidateStateCheap(types.NewBlockWithHeader(&receiptMismatch), nil, valid), ErrReceiptRootMismatch)
73+
74+
requests := [][]byte{{1, 2, 3}}
75+
requestHash := types.CalcRequestsHash(requests)
76+
withRequests := *newBlock().Header()
77+
withRequests.RequestsHash = &requestHash
78+
validRequests := &ProcessResult{Receipts: receipts, GasUsed: 21_000, Requests: requests}
79+
require.NoError(t, validator.ValidateStateCheap(types.NewBlockWithHeader(&withRequests), nil, validRequests))
80+
81+
requestMismatch := requestHash
82+
requestMismatch[0] ^= 1
83+
withRequests.RequestsHash = &requestMismatch
84+
require.ErrorIs(t, validator.ValidateStateCheap(types.NewBlockWithHeader(&withRequests), nil, validRequests), ErrRequestsHashMismatch)
85+
require.EqualError(t, validator.ValidateStateCheap(newBlock(), nil, validRequests), "block has requests before prague fork")
86+
}
87+
4188
func testHeaderVerification(t *testing.T, scheme string) {
4289
// Create a simple chain to verify
4390
var (

core/blockchain_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4304,6 +4304,68 @@ func TestHasStateTreatsRecentPipelinedRootAsAvailable(t *testing.T) {
43044304
require.False(t, chain.HasRecentPipelinedHeadState(block.Hash(), block.Root()))
43054305
}
43064306

4307+
func TestPipelinedWitnessWaitPaths(t *testing.T) {
4308+
_, _, chain, err := newCanonical(ethash.NewFaker(), 0, true, rawdb.HashScheme)
4309+
require.NoError(t, err)
4310+
t.Cleanup(chain.Stop)
4311+
chain.cfg.EnablePipelinedImportSRC = true
4312+
4313+
block := types.NewBlockWithHeader(&types.Header{Number: big.NewInt(1)})
4314+
hash := block.Hash()
4315+
4316+
chain.pendingImportSRC = &pendingImportSRCState{
4317+
block: block,
4318+
makeWitness: false,
4319+
collectedCh: make(chan struct{}),
4320+
}
4321+
witness, matched := chain.waitForPendingSRCWitness(hash)
4322+
require.True(t, matched)
4323+
require.Nil(t, witness)
4324+
require.Nil(t, chain.waitForPipelinedWitness(hash))
4325+
4326+
chain.pendingImportSRC = &pendingImportSRCState{
4327+
block: block,
4328+
makeWitness: true,
4329+
collectedCh: make(chan struct{}),
4330+
}
4331+
chain.CacheWitness(hash, []byte("witness"))
4332+
close(chain.pendingImportSRC.collectedCh)
4333+
witness, matched = chain.waitForPendingSRCWitness(hash)
4334+
require.True(t, matched)
4335+
require.Equal(t, []byte("witness"), witness)
4336+
4337+
chain.pendingImportSRC = nil
4338+
chain.pipelinedMakeWitness.Store(false)
4339+
require.Nil(t, chain.waitForPipelinedWitness(common.HexToHash("0x1234")))
4340+
4341+
polledHash := common.HexToHash("0x5678")
4342+
go func() {
4343+
time.Sleep(10 * time.Millisecond)
4344+
chain.CacheWitness(polledHash, []byte("polled"))
4345+
}()
4346+
require.Equal(t, []byte("polled"), chain.pollWitnessCache(polledHash, time.Second, time.Millisecond))
4347+
}
4348+
4349+
func TestWithinPipelinedImportStateGrace(t *testing.T) {
4350+
now := time.Now()
4351+
tests := []struct {
4352+
name string
4353+
start time.Time
4354+
want bool
4355+
}{
4356+
{name: "zero", start: time.Time{}, want: false},
4357+
{name: "future", start: now.Add(time.Nanosecond), want: false},
4358+
{name: "current", start: now, want: true},
4359+
{name: "boundary", start: now.Add(-pipelinedImportStateAvailabilityGrace), want: true},
4360+
{name: "expired", start: now.Add(-pipelinedImportStateAvailabilityGrace - time.Nanosecond), want: false},
4361+
}
4362+
for _, test := range tests {
4363+
t.Run(test.name, func(t *testing.T) {
4364+
require.Equal(t, test.want, withinPipelinedImportStateGrace(test.start, now))
4365+
})
4366+
}
4367+
}
4368+
43074369
func TestCreateThenDeletePostByzantium(t *testing.T) {
43084370
t.Parallel()
43094371
testCreateThenDelete(t, params.TestChainConfig)

core/state/warm_snapshot_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,47 @@ func TestWarmSnapshot_OwnerScoped(t *testing.T) {
274274
_, ok = snap.Lookup(storageOwner, path, crypto.Keccak256Hash(accountBlob))
275275
require.False(t, ok, "must not serve account blob to storage owner even when that blob's hash matches expectedHash")
276276
}
277+
278+
func TestWarmSnapshotInputAndBounds(t *testing.T) {
279+
t.Parallel()
280+
281+
owner := common.HexToHash("0x44")
282+
path := []byte{0x01, 0x02}
283+
blob := []byte("warm-node")
284+
tooLong := make([]byte, 65)
285+
286+
key, ok := makeWarmKey(owner, path, crypto.Keccak256Hash(blob))
287+
require.True(t, ok)
288+
require.Equal(t, uint8(len(path)), key.pathLen)
289+
_, ok = makeWarmKey(owner, tooLong, common.Hash{})
290+
require.False(t, ok)
291+
292+
require.Nil(t, NewWarmSnapshotInput(nil))
293+
var nilInput *WarmSnapshotInput
294+
require.Nil(t, nilInput.Build())
295+
296+
input := NewWarmSnapshotInput([]TrieWarmNodes{{
297+
Owner: owner,
298+
Nodes: map[string][]byte{
299+
string(path): blob,
300+
"empty": nil,
301+
string(tooLong): []byte("ignored"),
302+
},
303+
}})
304+
snapshot := input.Build()
305+
require.NotNil(t, snapshot)
306+
require.Equal(t, 1, snapshot.Len())
307+
require.Equal(t, len(blob), snapshot.SizeBytes())
308+
309+
got, ok := snapshot.Lookup(owner, path, crypto.Keccak256Hash(blob))
310+
require.True(t, ok)
311+
require.Equal(t, blob, got)
312+
blob[0] = 'X'
313+
require.Equal(t, []byte("warm-node"), got)
314+
_, ok = snapshot.Lookup(owner, tooLong, common.Hash{})
315+
require.False(t, ok)
316+
317+
var nilSnapshot *WarmSnapshot
318+
require.Zero(t, nilSnapshot.Len())
319+
require.Zero(t, nilSnapshot.SizeBytes())
320+
}

0 commit comments

Comments
 (0)