From 665958e95b2854332e44ca039d4c5979f9ccbe07 Mon Sep 17 00:00:00 2001 From: Al Cutter Date: Mon, 21 Oct 2024 12:51:56 +0100 Subject: [PATCH] Handle special case prev < next (#280) --- internal/witness/witness.go | 7 ++++++ internal/witness/witness_test.go | 39 ++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/internal/witness/witness.go b/internal/witness/witness.go index 0d08309..0474cc0 100644 --- a/internal/witness/witness.go +++ b/internal/witness/witness.go @@ -224,6 +224,13 @@ func (w *Witness) Update(ctx context.Context, logID string, nextRaw []byte, cPro counterUpdateSuccess.Inc(logID) return signed, nil } + if next.Size != prev.Size && len(cProof) == 0 { + // We require a proof, but we were given an empty one - the submitter likely thinks we've not seen a checkpoint for this log + // before and is trying to get us to TOFU. + // This is a special case of "prev > next" above, so return the same code so higher layers can handle similarly (e.g. by telling + // the submitter our view of prev.size). + return prevRaw, status.Errorf(codes.AlreadyExists, "we already have a non-zero checkpoint") + } // The only remaining option is next.Size > prev.Size. This might be // valid so we use either plain consistency proofs or compact ranges to diff --git a/internal/witness/witness_test.go b/internal/witness/witness_test.go index 3f3db9d..826b64d 100644 --- a/internal/witness/witness_test.go +++ b/internal/witness/witness_test.go @@ -28,6 +28,8 @@ import ( "github.com/transparency-dev/witness/internal/persistence/inmemory" "github.com/transparency-dev/witness/monitoring" "golang.org/x/mod/sumdb/note" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) var ( @@ -281,13 +283,14 @@ func mustCreateCheckpoint(t *testing.T, sk string, size uint64, rootHash []byte) func TestUpdate(t *testing.T) { for _, test := range []struct { - desc string - initC []byte - newC []byte - pf [][]byte - useCR bool - initCR [][]byte - isGood bool + desc string + initC []byte + newC []byte + pf [][]byte + useCR bool + initCR [][]byte + isGood bool + wantCode codes.Code }{ { desc: "vanilla consistency happy path", @@ -313,6 +316,23 @@ func TestUpdate(t *testing.T) { useCR: false, isGood: true, }, + { + desc: "vanilla resubmit known CP", + initC: mustCreateCheckpoint(t, mSK, 5, dh("e35b268c1522014ef412d2a54fa94838862d453631617b0307e5c77dcbeefc11", 32)), + newC: mustCreateCheckpoint(t, mSK, 5, dh("e35b268c1522014ef412d2a54fa94838862d453631617b0307e5c77dcbeefc11", 32)), + pf: [][]byte{}, + useCR: false, + isGood: true, + }, + { + desc: "vanilla attempt to re-TOFU", + initC: mustCreateCheckpoint(t, mSK, 4, dh("e35b268c1522014ef412d2a54fa94838862d453631617b0307e5c77dcbeefc11", 32)), + newC: mustCreateCheckpoint(t, mSK, 5, dh("e35b268c1522014ef412d2a54fa94838862d453631617b0307e5c77dcbeefc11", 32)), + pf: [][]byte{}, + useCR: false, + isGood: false, + wantCode: codes.AlreadyExists, + }, { desc: "vanilla path, but the first line changed", initC: mInit, @@ -384,6 +404,11 @@ func TestUpdate(t *testing.T) { if err == nil { t.Fatal("should have gotten an error but didn't") } + if test.wantCode != 0 { + if gotCode := status.Code(err); gotCode != test.wantCode { + t.Fatalf("Got status code %v, want %v", gotCode, test.wantCode) + } + } } }) }