Skip to content

Commit ad8e650

Browse files
committed
fix: another convergence issues
1 parent 72f0200 commit ad8e650

2 files changed

Lines changed: 24 additions & 24 deletions

File tree

pkg/storer/internal/reserve/convergence_test.go

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,11 @@ func TestPutOrderConvergence(t *testing.T) {
270270
},
271271
},
272272
{
273-
// UNRESOLVED on this branch: same SOC address, same slot and
274-
// timestamp, but separately stamped (distinct signatures, hence
275-
// distinct stamp hashes). Bypasses resolveDivergence (stamp hashes
276-
// differ) and the CAC tie-break (wrong type): last write wins.
277-
name: "divergent socs, equal timestamp, distinct stamps",
278-
unresolved: true,
273+
// Same SOC address, same slot and timestamp, but separately stamped
274+
// (distinct signatures, hence distinct stamp hashes). The SOC
275+
// stamp-overwrite guard settles on the lower stamp hash, so the
276+
// shared payload converges regardless of order.
277+
name: "divergent socs, equal timestamp, distinct stamps",
279278
chunks: func(t *testing.T) []swarm.Chunk {
280279
t.Helper()
281280
return []swarm.Chunk{
@@ -285,11 +284,9 @@ func TestPutOrderConvergence(t *testing.T) {
285284
},
286285
},
287286
{
288-
// UNRESOLVED on this branch: different SOC addresses in the same
289-
// slot at the same timestamp. Not content addressed, so the
290-
// tie-break is skipped: last write wins.
291-
name: "soc vs soc, different addresses, same slot, equal timestamp",
292-
unresolved: true,
287+
// Different SOC addresses in the same slot at the same timestamp.
288+
// The lower-address tie-break now applies to all chunk types.
289+
name: "soc vs soc, different addresses, same slot, equal timestamp",
293290
chunks: func(t *testing.T) []swarm.Chunk {
294291
t.Helper()
295292
return []swarm.Chunk{
@@ -299,12 +296,9 @@ func TestPutOrderConvergence(t *testing.T) {
299296
},
300297
},
301298
{
302-
// UNRESOLVED on this branch: mixed types in the same slot at the
303-
// same timestamp. The tie-break fires only when the INCOMING chunk
304-
// is content addressed, so the two directions disagree whenever
305-
// the CAC has the lower address.
306-
name: "cac vs soc, same slot, equal timestamp, cac address lower",
307-
unresolved: true,
299+
// Mixed types in the same slot at the same timestamp. The
300+
// lower-address tie-break is type-agnostic, so convergence holds.
301+
name: "cac vs soc, same slot, equal timestamp, cac address lower",
308302
chunks: func(t *testing.T) []swarm.Chunk {
309303
t.Helper()
310304
socCh := newTestSOC(t, signer, id1, []byte("soc payload"))
@@ -323,12 +317,10 @@ func TestPutOrderConvergence(t *testing.T) {
323317
},
324318
},
325319
{
326-
// UNRESOLVED on this branch: byte-identical CAC re-stamped in the
327-
// same slot at the same timestamp with a different signature. The
328-
// entries swap stamp hashes depending on order, so peers holding
329-
// different stampings keep exchanging and replacing forever.
330-
name: "identical cac, same slot, equal timestamp, distinct stamps",
331-
unresolved: true,
320+
// Byte-identical CAC re-stamped in the same slot at the same
321+
// timestamp with a different signature. The stamp-hash tie-break
322+
// settles on one stamping deterministically.
323+
name: "identical cac, same slot, equal timestamp, distinct stamps",
332324
chunks: func(t *testing.T) []swarm.Chunk {
333325
t.Helper()
334326
payload := []byte("identical cac payload")

pkg/storer/internal/reserve/reserve.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func (r *Reserve) putChunk(ctx context.Context, chunk swarm.Chunk) (socReplaced
199199

200200
// Same stamp index and timestamp, different chunk addresses: both
201201
// claims are otherwise valid, so settle on the lower address.
202-
if prev == curr && chunkType == swarm.ChunkTypeContentAddressed && !oldStampIndex.ChunkAddress.Equal(chunk.Address()) {
202+
if prev == curr && !oldStampIndex.ChunkAddress.Equal(chunk.Address()) {
203203
if bytes.Compare(chunk.Address().Bytes(), oldStampIndex.ChunkAddress.Bytes()) >= 0 {
204204
r.logger.Debug(
205205
"discarding stamp index collision",
@@ -239,6 +239,14 @@ func (r *Reserve) putChunk(ctx context.Context, chunk swarm.Chunk) (socReplaced
239239

240240
// same chunk address
241241
if oldStampIndex.ChunkAddress.Equal(chunk.Address()) {
242+
// Same address, same timestamp: settle on the lower stamp hash.
243+
if prev == curr && bytes.Compare(oldStampIndex.StampHash, stampHash) <= 0 {
244+
return fmt.Errorf(
245+
"stamp index collision chunk %s lost stamp-hash tie-break: %w",
246+
chunk.Address(),
247+
storage.ErrOverwriteNewerChunk,
248+
)
249+
}
242250

243251
oldStamp, err := chunkstamp.LoadWithStampHash(s.IndexStore(), reserveScope, oldStampIndex.ChunkAddress, oldStampIndex.StampHash)
244252
if err != nil {

0 commit comments

Comments
 (0)