diff --git a/tools/evaluation/cmd/malt-eval-rq3-malt-worker/direct.go b/tools/evaluation/cmd/malt-eval-rq3-malt-worker/direct.go index 5e6cea9..0679fd3 100644 --- a/tools/evaluation/cmd/malt-eval-rq3-malt-worker/direct.go +++ b/tools/evaluation/cmd/malt-eval-rq3-malt-worker/direct.go @@ -534,6 +534,13 @@ func directFlatSnapshotChanges(state map[string]logicalFile) ([]gatewaytransport if len(state) > maximumMALTSnapshotFiles { return nil, fmt.Errorf("flat snapshot exceeds file bound") } + return flatSnapshotChanges(state) +} + +// flatSnapshotChanges projects every live file into the complete flat state. +// Gateway request limits belong to directFlatSnapshotChanges: a history can +// grow beyond its initial request size and still needs a complete final oracle. +func flatSnapshotChanges(state map[string]logicalFile) ([]gatewaytransport.FlatPrefixChange, error) { sentinel, err := flatSentinelEntry() if err != nil { return nil, err diff --git a/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat.go b/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat.go index 420a66f..46b1fc9 100644 --- a/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat.go +++ b/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat.go @@ -73,9 +73,10 @@ func (o *flatRootOracle) apply(ctx context.Context, changes []gatewaytransport.F } // fullFlatRoot reconstructs the complete post-image from live source files, -// without using the mutation deltas or any Gateway response/state. +// without using the mutation deltas or any Gateway response/state. Its local +// reconstruction is independent of the single-request Gateway snapshot limit. func fullFlatRoot(ctx context.Context, files map[string]logicalFile) (cid.Cid, error) { - initial, err := directFlatSnapshotChanges(files) + initial, err := flatSnapshotChanges(files) if err != nil { return cid.Undef, err } diff --git a/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat_oracle_test.go b/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat_oracle_test.go new file mode 100644 index 0000000..ff91973 --- /dev/null +++ b/tools/evaluation/cmd/malt-eval-rq3-malt-worker/flat_oracle_test.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "testing" + + clientcas "github.com/dewebprotocol/malt-client/internal/cas" + cid "github.com/ipfs/go-cid" +) + +func TestFullFlatRootAcceptsStateBeyondSnapshotRequestLimit(t *testing.T) { + payload, err := clientcas.CIDForBlock(clientcas.Block{Codec: cid.Raw, Data: []byte("retained payload")}) + if err != nil { + t.Fatal(err) + } + // Model live disk-backed source metadata: the full oracle must use each + // retained payload CID, without loading file bodies or using Gateway state. + file := logicalFile{payload: payload, mode: 0o644} + files := make(map[string]logicalFile, maximumMALTSnapshotFiles+1) + var lastPath string + for i := 0; i <= maximumMALTSnapshotFiles; i++ { + lastPath = fmt.Sprintf("src/file-%06d.txt", i) + files[lastPath] = file + } + if _, err := directFlatSnapshotChanges(files); err == nil { + t.Fatal("oversized Gateway snapshot request was accepted") + } + changes, err := flatSnapshotChanges(files) + if err != nil { + t.Fatal(err) + } + if got, want := len(changes), 1+2*len(files); got != want { + t.Fatalf("full projection has %d bindings; want %d", got, want) + } + full, err := fullFlatRoot(t.Context(), files) + if err != nil { + t.Fatalf("full oracle for %d live files: %v", len(files), err) + } + if !full.Defined() { + t.Fatal("full oracle returned an undefined Root") + } + + // The exact request boundary still accepts a complete initial snapshot. + // Incremental/full Root agreement is covered by the small-state oracle test; + // avoid a second large KZG construction in the default test suite. + delete(files, lastPath) + initial, err := directFlatSnapshotChanges(files) + if err != nil { + t.Fatal(err) + } + if got, want := len(initial), 1+2*len(files); got != want { + t.Fatalf("request projection has %d bindings; want %d", got, want) + } +}