diff --git a/go/CHANGELOG.md b/go/CHANGELOG.md index d49eff71..984175e1 100644 --- a/go/CHANGELOG.md +++ b/go/CHANGELOG.md @@ -4,6 +4,8 @@ - deps: bump golang to v1.22 ([#363](https://github.com/cosmos/ics23/pull/363)). - fix: guarantee that `spec.InnerSpec.MaxPrefixLength` < `spec.InnerSpec.MinPrefixLength` + `spec.InnerSpec.ChildSize` ([#369](https://github.com/cosmos/ics23/pull/369)) +- refactor: support for `BatchProof` and `CompressedBatchProof` is being dropped. + * The API's `BatchVerifyMembership`, `BatchVerifyNonMembership`, and `CombineProofs` have been removed. ([#390](https://github.com/cosmos/ics23/pull/390)) # v0.11.0 diff --git a/go/fuzz_test.go b/go/fuzz_test.go index f972fde5..8ae45aa3 100644 --- a/go/fuzz_test.go +++ b/go/fuzz_test.go @@ -172,37 +172,3 @@ func FuzzVerifyMembership(f *testing.F) { _ = VerifyMembership(spec, ref.RootHash, proof, ref.Key, ref.Value) }) } - -func FuzzCombineProofs(f *testing.F) { - // 1. Load in the CommitmentProofs - baseDirs := []string{"iavl", "tendermint", "smt"} - filenames := []string{ - "exist_left.json", - "exist_right.json", - "exist_middle.json", - "nonexist_left.json", - "nonexist_right.json", - "nonexist_middle.json", - } - - for _, baseDir := range baseDirs { - dir := filepath.Join("..", "testdata", baseDir) - for _, filename := range filenames { - proofs, _ := LoadFile(new(testing.T), dir, filename) - blob, err := json.Marshal(proofs) - if err != nil { - f.Fatal(err) - } - f.Add(blob) - } - } - - // 2. Now let's run the fuzzer. - f.Fuzz(func(t *testing.T, proofsJSON []byte) { - var proofs []*CommitmentProof - if err := json.Unmarshal(proofsJSON, &proofs); err != nil { - return - } - _, _ = CombineProofs(proofs) - }) -} diff --git a/go/ics23.go b/go/ics23.go index 709094d6..db129753 100644 --- a/go/ics23.go +++ b/go/ics23.go @@ -25,7 +25,6 @@ package ics23 import ( "bytes" - "fmt" ) // CommitmentRoot is a byte slice that represents the merkle root of a tree that can be used to validate proofs @@ -61,77 +60,6 @@ func VerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *Commitment return err == nil } -// BatchVerifyMembership will ensure all items are also proven by the CommitmentProof (which should be a BatchProof, -// unless there is one item, when a ExistenceProof may work) -func BatchVerifyMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, items map[string][]byte) bool { - // decompress it before running code (no-op if not compressed) - once for batch - proof = Decompress(proof) - for k, v := range items { - valid := VerifyMembership(spec, root, proof, []byte(k), v) - if !valid { - return false - } - } - return true -} - -// BatchVerifyNonMembership will ensure all items are also proven to not be in the Commitment by the CommitmentProof -// (which should be a BatchProof, unless there is one item, when a NonExistenceProof may work) -func BatchVerifyNonMembership(spec *ProofSpec, root CommitmentRoot, proof *CommitmentProof, keys [][]byte) bool { - // decompress it before running code (no-op if not compressed) - once for batch - proof = Decompress(proof) - for _, k := range keys { - valid := VerifyNonMembership(spec, root, proof, k) - if !valid { - return false - } - } - return true -} - -// CombineProofs takes a number of commitment proofs (simple or batch) and -// converts them into a batch and compresses them. -// -// This is designed for proof generation libraries to create efficient batches -func CombineProofs(proofs []*CommitmentProof) (*CommitmentProof, error) { - var entries []*BatchEntry - - for _, proof := range proofs { - if ex := proof.GetExist(); ex != nil { - entry := &BatchEntry{ - Proof: &BatchEntry_Exist{ - Exist: ex, - }, - } - entries = append(entries, entry) - } else if non := proof.GetNonexist(); non != nil { - entry := &BatchEntry{ - Proof: &BatchEntry_Nonexist{ - Nonexist: non, - }, - } - entries = append(entries, entry) - } else if batch := proof.GetBatch(); batch != nil { - entries = append(entries, batch.Entries...) - } else if comp := proof.GetCompressed(); comp != nil { - decomp := Decompress(proof) - entries = append(entries, decomp.GetBatch().Entries...) - } else { - return nil, fmt.Errorf("proof neither exist or nonexist: %#v", proof.GetProof()) - } - } - - batch := &CommitmentProof{ - Proof: &CommitmentProof_Batch{ - Batch: &BatchProof{ - Entries: entries, - }, - }, - } - - return Compress(batch), nil -} - func getExistProofForKey(proof *CommitmentProof, key []byte) *ExistenceProof { if proof == nil { return nil diff --git a/go/vectors_data_test.go b/go/vectors_data_test.go index f6e453cc..15a86ecc 100644 --- a/go/vectors_data_test.go +++ b/go/vectors_data_test.go @@ -73,91 +73,15 @@ type BatchVectorData struct { Invalid bool // default is valid } -func BatchVectorsTestData(t *testing.T) map[string]BatchVectorData { - t.Helper() - iavl := filepath.Join("..", "testdata", "iavl") - tendermint := filepath.Join("..", "testdata", "tendermint") - smt := filepath.Join("..", "testdata", "smt") - // Note that each item has a different commitment root, - // so maybe not ideal (cannot check multiple entries) - batchIAVL, refsIAVL := buildBatch(t, iavl, []string{ - "exist_left.json", - "exist_right.json", - "exist_middle.json", - "nonexist_left.json", - "nonexist_right.json", - "nonexist_middle.json", - }) - refsTML, refsTM := buildBatch(t, tendermint, []string{ - "exist_left.json", - "exist_right.json", - "exist_middle.json", - "nonexist_left.json", - "nonexist_right.json", - "nonexist_middle.json", - }) - batchSMT, refsSMT := buildBatch(t, smt, []string{ - "exist_left.json", - "exist_right.json", - "exist_middle.json", - "nonexist_left.json", - "nonexist_right.json", - "nonexist_middle.json", - }) - - batchTMExist, refsTMExist := loadBatch(t, tendermint, "batch_exist.json") - batchTMNonexist, refsTMNonexist := loadBatch(t, tendermint, "batch_nonexist.json") - batchIAVLExist, refsIAVLExist := loadBatch(t, iavl, "batch_exist.json") - batchIAVLNonexist, refsIAVLNonexist := loadBatch(t, iavl, "batch_nonexist.json") - batchSMTexist, refsSMTexist := loadBatch(t, smt, "batch_exist.json") - batchSMTnonexist, refsSMTnonexist := loadBatch(t, smt, "batch_nonexist.json") - - return map[string]BatchVectorData{ - "iavl 0": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[0]}, - "iavl 1": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[1]}, - "iavl 2": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[2]}, - "iavl 3": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[3]}, - "iavl 4": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[4]}, - "iavl 5": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsIAVL[5]}, - // Note this spec only differs for non-existence proofs - "iavl invalid 1": {Spec: TendermintSpec, Proof: batchIAVL, Ref: refsIAVL[4], Invalid: true}, - "iavl invalid 2": {Spec: IavlSpec, Proof: batchIAVL, Ref: refsTM[0], Invalid: true}, - "iavl batch exist": {Spec: IavlSpec, Proof: batchIAVLExist, Ref: refsIAVLExist[17]}, - "iavl batch nonexist": {Spec: IavlSpec, Proof: batchIAVLNonexist, Ref: refsIAVLNonexist[7]}, - "tm 0": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[0]}, - "tm 1": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[1]}, - "tm 2": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[2]}, - "tm 3": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[3]}, - "tm 4": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[4]}, - "tm 5": {Spec: TendermintSpec, Proof: refsTML, Ref: refsTM[5]}, - // Note this spec only differs for non-existence proofs - "tm invalid 1": {Spec: IavlSpec, Proof: refsTML, Ref: refsTM[4], Invalid: true}, - "tm invalid 2": {Spec: TendermintSpec, Proof: refsTML, Ref: refsIAVL[0], Invalid: true}, - "tm batch exist": {Spec: TendermintSpec, Proof: batchTMExist, Ref: refsTMExist[10]}, - "tm batch nonexist": {Spec: TendermintSpec, Proof: batchTMNonexist, Ref: refsTMNonexist[3]}, - "smt 0": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[0]}, - "smt 1": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[1]}, - "smt 2": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[2]}, - "smt 3": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[3]}, - "smt 4": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[4]}, - "smt 5": {Spec: SmtSpec, Proof: batchSMT, Ref: refsSMT[5]}, - // Note this spec only differs for non-existence proofs - "smt invalid 1": {Spec: IavlSpec, Proof: batchSMT, Ref: refsSMT[4], Invalid: true}, - "smt invalid 2": {Spec: SmtSpec, Proof: batchSMT, Ref: refsIAVL[0], Invalid: true}, - "smt batch exist": {Spec: SmtSpec, Proof: batchSMTexist, Ref: refsSMTexist[10]}, - "smt batch nonexist": {Spec: SmtSpec, Proof: batchSMTnonexist, Ref: refsSMTnonexist[3]}, - } -} - func DecompressBatchVectorsTestData(t *testing.T) map[string]*CommitmentProof { t.Helper() iavl := filepath.Join("..", "testdata", "iavl") tendermint := filepath.Join("..", "testdata", "tendermint") smt := filepath.Join("..", "testdata", "smt") // note that these batches are already compressed - batchIAVL, _ := loadBatch(t, iavl, "batch_exist.json") - batchTM, _ := loadBatch(t, tendermint, "batch_nonexist.json") - batchSMT, _ := loadBatch(t, smt, "batch_nonexist.json") + batchIAVL := loadBatch(t, iavl, "batch_exist.json") + batchTM := loadBatch(t, tendermint, "batch_nonexist.json") + batchSMT := loadBatch(t, smt, "batch_nonexist.json") return map[string]*CommitmentProof{ "iavl": batchIAVL, "tendermint": batchTM, @@ -205,21 +129,7 @@ func mustHex(tb testing.TB, data string) []byte { return res } -func buildBatch(t *testing.T, dir string, filenames []string) (*CommitmentProof, []*RefData) { - t.Helper() - refs := make([]*RefData, len(filenames)) - proofs := make([]*CommitmentProof, len(filenames)) - for i, fn := range filenames { - proofs[i], refs[i] = LoadFile(t, dir, fn) - } - batch, err := CombineProofs(proofs) - if err != nil { - t.Fatalf("Generating batch: %v", err) - } - return batch, refs -} - -func loadBatch(t *testing.T, dir string, filename string) (*CommitmentProof, []*RefData) { +func loadBatch(t *testing.T, dir string, filename string) *CommitmentProof { t.Helper() // load the file into a json struct name := filepath.Join(dir, filename) @@ -238,14 +148,5 @@ func loadBatch(t *testing.T, dir string, filename string) (*CommitmentProof, []* if err != nil { t.Fatalf("Unmarshal protobuf: %+v", err) } - root := mustHex(t, data.RootHash) - refs := make([]*RefData, len(data.Items)) - for i, item := range data.Items { - refs[i] = &RefData{ - RootHash: root, - Key: mustHex(t, item.Key), - Value: mustHex(t, item.Value), - } - } - return &proof, refs + return &proof } diff --git a/go/vectors_test.go b/go/vectors_test.go index b6e0e909..9b6282a8 100644 --- a/go/vectors_test.go +++ b/go/vectors_test.go @@ -38,42 +38,6 @@ func TestVectors(t *testing.T) { } } -func TestBatchVectors(t *testing.T) { - cases := BatchVectorsTestData(t) - for name, tc := range cases { - tc := tc - t.Run(name, func(t *testing.T) { - // try one proof - if tc.Ref.Value == nil { - // non-existence - valid := VerifyNonMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, tc.Ref.Key) - if valid == tc.Invalid { - t.Logf("name: %+v", name) - t.Logf("ref: %+v", tc.Ref) - t.Logf("spec: %+v", tc.Spec) - t.Errorf("Expected proof validity: %t", !tc.Invalid) - } - keys := [][]byte{tc.Ref.Key} - valid = BatchVerifyNonMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, keys) - if valid == tc.Invalid { - t.Errorf("Expected batch proof validity: %t", !tc.Invalid) - } - } else { - valid := VerifyMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, tc.Ref.Key, tc.Ref.Value) - if valid == tc.Invalid { - t.Errorf("Expected proof validity: %t", !tc.Invalid) - } - items := make(map[string][]byte) - items[string(tc.Ref.Key)] = tc.Ref.Value - valid = BatchVerifyMembership(tc.Spec, tc.Ref.RootHash, tc.Proof, items) - if valid == tc.Invalid { - t.Errorf("Expected batch proof validity: %t", !tc.Invalid) - } - } - }) - } -} - func TestDecompressBatchVectors(t *testing.T) { cases := DecompressBatchVectorsTestData(t) for name, tc := range cases {