Skip to content

Commit 8c72b18

Browse files
authored
Fixes bug where HotArchive buckets ommited by Buckets() (#5856)
1 parent 0bd7280 commit 8c72b18

File tree

3 files changed

+108
-11
lines changed

3 files changed

+108
-11
lines changed

historyarchive/history_archive_state.go

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ type HistoryArchiveState struct {
5757
HotArchiveBuckets BucketList `json:"hotArchiveBuckets"`
5858
}
5959

60-
func (h *HistoryArchiveState) LevelSummary() (string, int, error) {
60+
func summarizeBucketList(buckets BucketList) (string, int, error) {
6161
summ := ""
6262
nz := 0
63-
for _, b := range h.CurrentBuckets {
63+
for _, b := range buckets {
6464
state := '_'
6565
for _, bs := range []string{
6666
b.Curr, b.Snap, b.Next.Output,
@@ -87,26 +87,66 @@ func (h *HistoryArchiveState) LevelSummary() (string, int, error) {
8787
return summ, nz, nil
8888
}
8989

90-
func (h *HistoryArchiveState) Buckets() ([]Hash, error) {
91-
r := []Hash{}
92-
for _, b := range h.CurrentBuckets {
93-
for _, bs := range []string{
94-
b.Curr, b.Snap, b.Next.Output,
95-
} {
90+
func (h *HistoryArchiveState) LevelSummary() (string, int, error) {
91+
currentSummary, currentNz, err := summarizeBucketList(h.CurrentBuckets)
92+
if err != nil {
93+
return "", 0, err
94+
}
95+
96+
// For V2+, include hot archive buckets
97+
if h.Version >= HistoryArchiveStateVersionForProtocol23 {
98+
hotSummary, hotNz, err := summarizeBucketList(h.HotArchiveBuckets)
99+
if err != nil {
100+
return "", 0, err
101+
}
102+
return currentSummary + "|" + hotSummary, currentNz + hotNz, nil
103+
}
104+
105+
return currentSummary, currentNz, nil
106+
}
107+
108+
func extractBucketHashes(buckets BucketList) ([]Hash, error) {
109+
var result []Hash
110+
for _, b := range buckets {
111+
for _, bs := range []string{b.Curr, b.Snap, b.Next.Output} {
96112
// Ignore empty values
97113
if bs == "" {
98114
continue
99115
}
100116

101117
h, err := DecodeHash(bs)
102118
if err != nil {
103-
return r, err
119+
return result, err
104120
}
105121
if !h.IsZero() {
106-
r = append(r, h)
122+
result = append(result, h)
107123
}
108124
}
109125
}
126+
return result, nil
127+
}
128+
129+
// Returns all Buckets reference by the HistoryArchiveState. This includes
130+
// both the live Buckets and hot archive Buckets (for HAS version 2+).
131+
func (h *HistoryArchiveState) Buckets() ([]Hash, error) {
132+
r := []Hash{}
133+
134+
// Extract current buckets
135+
currentBuckets, err := extractBucketHashes(h.CurrentBuckets)
136+
if err != nil {
137+
return r, err
138+
}
139+
r = append(r, currentBuckets...)
140+
141+
// Include hot archive buckets for version 2+ (protocol 23+)
142+
if h.Version >= HistoryArchiveStateVersionForProtocol23 {
143+
hotArchiveBuckets, err := extractBucketHashes(h.HotArchiveBuckets)
144+
if err != nil {
145+
return r, err
146+
}
147+
r = append(r, hotArchiveBuckets...)
148+
}
149+
110150
return r, nil
111151
}
112152

historyarchive/history_archive_state_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,60 @@ func TestHashValidation(t *testing.T) {
8181
})
8282
}
8383
}
84+
85+
func countBuckets(buckets BucketList) int {
86+
count := 0
87+
for _, level := range buckets {
88+
for _, bs := range []string{level.Curr, level.Snap, level.Next.Output} {
89+
if bs != "" && bs != "0000000000000000000000000000000000000000000000000000000000000000" {
90+
count++
91+
}
92+
}
93+
}
94+
return count
95+
}
96+
97+
func TestBucketsIncludesHotArchiveBuckets(t *testing.T) {
98+
for _, testCase := range []struct {
99+
inputFile string
100+
expectedVersion int
101+
}{
102+
{
103+
inputFile: "testdata/historyV1.json",
104+
expectedVersion: 1,
105+
},
106+
{
107+
inputFile: "testdata/historyV2.json",
108+
expectedVersion: HistoryArchiveStateVersionForProtocol23,
109+
},
110+
} {
111+
t.Run(testCase.inputFile, func(t *testing.T) {
112+
inputBytes, err := os.ReadFile(testCase.inputFile)
113+
require.NoError(t, err)
114+
115+
var state HistoryArchiveState
116+
require.NoError(t, json.Unmarshal(inputBytes, &state))
117+
118+
// Verify the version
119+
assert.Equal(t, testCase.expectedVersion, state.Version)
120+
121+
// Verify that the Buckets() method includes hot archive buckets for V2
122+
buckets, err := state.Buckets()
123+
require.NoError(t, err)
124+
125+
currentBucketCount := countBuckets(state.CurrentBuckets)
126+
hotArchiveBucketCount := countBuckets(state.HotArchiveBuckets)
127+
128+
if testCase.expectedVersion >= HistoryArchiveStateVersionForProtocol23 {
129+
expectedTotal := currentBucketCount + hotArchiveBucketCount
130+
assert.Equal(t, expectedTotal, len(buckets),
131+
"Buckets() should include both currentBuckets and hotArchiveBuckets for V2+")
132+
} else {
133+
assert.Equal(t, 0, hotArchiveBucketCount,
134+
"V1 should have 0 hot archive buckets")
135+
assert.Equal(t, currentBucketCount, len(buckets),
136+
"Buckets() should only include currentBuckets for V1")
137+
}
138+
})
139+
}
140+
}

historyarchive/testdata/historyV2.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@
176176
"curr": "ae7e4814b50e176d8e3532e462e2e9db02f218adebd74603d7e349cc19f489e2",
177177
"next": {
178178
"state": 1,
179-
"output": "50abed8a9d86c072cfe8388246b7a378dc355fe996fd7384a5ee57e8da2ad52"
179+
"output": "50abed8a9d86c072cfe8388246b7a378dc355fe996fd7384a5ee57e8da2ad520"
180180
},
181181
"snap": "0000000000000000000000000000000000000000000000000000000000000000"
182182
}

0 commit comments

Comments
 (0)