Skip to content

Commit 9dcf8aa

Browse files
authored
eth/protocols/snap: skip retrieval for completed storages (#29378)
* eth/protocols/snap: skip retrieval for completed storages * eth/protocols/snap: address comments from peter * eth/protocols/snap: add comments
1 parent 34aac1d commit 9dcf8aa

File tree

3 files changed

+281
-20
lines changed

3 files changed

+281
-20
lines changed

eth/protocols/snap/metrics.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,9 @@ var (
5454
// skipStorageHealingGauge is the metric to track how many storages are retrieved
5555
// in multiple requests but healing is not necessary.
5656
skipStorageHealingGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/noheal", nil)
57+
58+
// largeStorageDiscardGauge is the metric to track how many chunked storages are
59+
// discarded during the snap sync.
60+
largeStorageDiscardGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/chunk/discard", nil)
61+
largeStorageResumedGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/chunk/resume", nil)
5762
)

eth/protocols/snap/progress_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Copyright 2024 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package snap
18+
19+
import (
20+
"encoding/json"
21+
"testing"
22+
23+
"github.com/ethereum/go-ethereum/common"
24+
)
25+
26+
// Legacy sync progress definitions
27+
type legacyStorageTask struct {
28+
Next common.Hash // Next account to sync in this interval
29+
Last common.Hash // Last account to sync in this interval
30+
}
31+
32+
type legacyAccountTask struct {
33+
Next common.Hash // Next account to sync in this interval
34+
Last common.Hash // Last account to sync in this interval
35+
SubTasks map[common.Hash][]*legacyStorageTask // Storage intervals needing fetching for large contracts
36+
}
37+
38+
type legacyProgress struct {
39+
Tasks []*legacyAccountTask // The suspended account tasks (contract tasks within)
40+
}
41+
42+
func compareProgress(a legacyProgress, b SyncProgress) bool {
43+
if len(a.Tasks) != len(b.Tasks) {
44+
return false
45+
}
46+
for i := 0; i < len(a.Tasks); i++ {
47+
if a.Tasks[i].Next != b.Tasks[i].Next {
48+
return false
49+
}
50+
if a.Tasks[i].Last != b.Tasks[i].Last {
51+
return false
52+
}
53+
// new fields are not checked here
54+
55+
if len(a.Tasks[i].SubTasks) != len(b.Tasks[i].SubTasks) {
56+
return false
57+
}
58+
for addrHash, subTasksA := range a.Tasks[i].SubTasks {
59+
subTasksB, ok := b.Tasks[i].SubTasks[addrHash]
60+
if !ok || len(subTasksB) != len(subTasksA) {
61+
return false
62+
}
63+
for j := 0; j < len(subTasksA); j++ {
64+
if subTasksA[j].Next != subTasksB[j].Next {
65+
return false
66+
}
67+
if subTasksA[j].Last != subTasksB[j].Last {
68+
return false
69+
}
70+
}
71+
}
72+
}
73+
return true
74+
}
75+
76+
func makeLegacyProgress() legacyProgress {
77+
return legacyProgress{
78+
Tasks: []*legacyAccountTask{
79+
{
80+
Next: common.Hash{},
81+
Last: common.Hash{0x77},
82+
SubTasks: map[common.Hash][]*legacyStorageTask{
83+
common.Hash{0x1}: {
84+
{
85+
Next: common.Hash{},
86+
Last: common.Hash{0xff},
87+
},
88+
},
89+
},
90+
},
91+
{
92+
Next: common.Hash{0x88},
93+
Last: common.Hash{0xff},
94+
},
95+
},
96+
}
97+
}
98+
99+
func convertLegacy(legacy legacyProgress) SyncProgress {
100+
var progress SyncProgress
101+
for i, task := range legacy.Tasks {
102+
subTasks := make(map[common.Hash][]*storageTask)
103+
for owner, list := range task.SubTasks {
104+
var cpy []*storageTask
105+
for i := 0; i < len(list); i++ {
106+
cpy = append(cpy, &storageTask{
107+
Next: list[i].Next,
108+
Last: list[i].Last,
109+
})
110+
}
111+
subTasks[owner] = cpy
112+
}
113+
accountTask := &accountTask{
114+
Next: task.Next,
115+
Last: task.Last,
116+
SubTasks: subTasks,
117+
}
118+
if i == 0 {
119+
accountTask.StorageCompleted = []common.Hash{{0xaa}, {0xbb}} // fulfill new fields
120+
}
121+
progress.Tasks = append(progress.Tasks, accountTask)
122+
}
123+
return progress
124+
}
125+
126+
func TestSyncProgressCompatibility(t *testing.T) {
127+
// Decode serialized bytes of legacy progress, backward compatibility
128+
legacy := makeLegacyProgress()
129+
blob, err := json.Marshal(legacy)
130+
if err != nil {
131+
t.Fatalf("Failed to marshal progress %v", err)
132+
}
133+
var dec SyncProgress
134+
if err := json.Unmarshal(blob, &dec); err != nil {
135+
t.Fatalf("Failed to unmarshal progress %v", err)
136+
}
137+
if !compareProgress(legacy, dec) {
138+
t.Fatal("sync progress is not backward compatible")
139+
}
140+
141+
// Decode serialized bytes of new format progress
142+
progress := convertLegacy(legacy)
143+
blob, err = json.Marshal(progress)
144+
if err != nil {
145+
t.Fatalf("Failed to marshal progress %v", err)
146+
}
147+
var legacyDec legacyProgress
148+
if err := json.Unmarshal(blob, &legacyDec); err != nil {
149+
t.Fatalf("Failed to unmarshal progress %v", err)
150+
}
151+
if !compareProgress(legacyDec, progress) {
152+
t.Fatal("sync progress is not forward compatible")
153+
}
154+
}

0 commit comments

Comments
 (0)