Skip to content

Commit

Permalink
Merge branch 'main' into rp/fix-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
rootulp committed Nov 15, 2024
2 parents eddfd64 + 62ec215 commit 8d72690
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 28 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/buf-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: buf-ci
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
buf:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: bufbuild/buf-setup-action@v1
- uses: bufbuild/buf-breaking-action@v1
with:
input: pb
against: 'https://github.com/celestiaorg/nmt.git#branch=main,subdir=pb'
- uses: bufbuild/buf-lint-action@v1
with:
input: pb
23 changes: 23 additions & 0 deletions .github/workflows/buf-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: buf-release
on:
push:
tags:
- "v*"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: bufbuild/buf-setup-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
version: "1.44.0"
# Push the protobuf definitions to the BSR
- uses: bufbuild/buf-push-action@v1
with:
buf_token: ${{ secrets.BUF_TOKEN }}
- name: "push the tag label to BSR"
run: |
set -euo pipefail
echo ${{ secrets.BUF_TOKEN }} | buf registry login --token-stdin
buf push --label ${{ github.ref_name }}
12 changes: 12 additions & 0 deletions buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: v2
modules:
- path: pb
name: buf.build/celestia/nmt
lint:
ignore_only:
PACKAGE_DIRECTORY_MATCH:
# ignoring because fixing means we will do a breaking change
- pb/proof.proto
PACKAGE_VERSION_SUFFIX:
# ignoring because fixing means we will do a breaking change
- pb/proof.proto
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/google/gofuzz v1.2.0
github.com/stretchr/testify v1.9.0
github.com/tidwall/gjson v1.17.1
github.com/tidwall/gjson v1.18.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U=
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
Expand Down
10 changes: 5 additions & 5 deletions pb/proof.proto
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
syntax="proto3";
syntax = "proto3";

package proof.pb;

option go_package = "github.com/celestiaorg/nmt/pb";

message Proof {
// Start index of the leaves that match the queried namespace.ID.
int64 start = 1;
int64 start = 1;
// End index (non-inclusive) of the leaves that match the queried
// namespace.ID.
int64 end = 2;
int64 end = 2;
// Nodes hold the tree nodes necessary for the Merkle range proof.
repeated bytes nodes = 3;
// leaf_hash contains the namespace.ID if NMT does not have it and
Expand All @@ -18,5 +18,5 @@ message Proof {
bytes leaf_hash = 4;
// The is_max_namespace_ignored flag influences the calculation of the
// namespace ID range for intermediate nodes in the tree.
bool is_max_namespace_ignored=5;
}
bool is_max_namespace_ignored = 5;
}
15 changes: 14 additions & 1 deletion proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,13 @@ func (proof Proof) VerifySubtreeRootInclusion(nth *NmtHasher, subtreeRoots [][]b
return popIfNonEmpty(&subtreeRoots), nil
}

if end-start == 1 {
// At this level, we reached a leaf, but we couldn't find any range corresponding
// to needed leaf [start, end).
// This means that the initial provided [start, end) range was invalid.
return nil, fmt.Errorf("the provided range [%d, %d) does not reference a valid inner node", proof.start, proof.end)
}

// Recursively get left and right subtree
k := getSplitPoint(end - start)
left, err := computeRoot(start, start+k)
Expand Down Expand Up @@ -634,7 +641,13 @@ func nextLeafRange(currentStart, currentEnd, subtreeWidth int) (LeafRange, error
if err != nil {
return LeafRange{}, err
}
return LeafRange{Start: currentStart, End: currentStart + currentRange}, nil
rangeEnd := currentStart + currentRange
idealTreeSize := nextSubtreeSize(uint64(currentStart), uint64(rangeEnd))
if currentStart+idealTreeSize != rangeEnd {
// this will happen if the calculated range does not correctly reference an inner node in the tree.
return LeafRange{}, fmt.Errorf("provided subtree width %d doesn't allow creating a valid leaf range [%d, %d)", subtreeWidth, currentStart, rangeEnd)
}
return LeafRange{Start: currentStart, End: rangeEnd}, nil
}

// largestPowerOfTwo calculates the largest power of two
Expand Down
77 changes: 58 additions & 19 deletions proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1332,18 +1332,6 @@ func TestNextLeafRange(t *testing.T) {
subtreeRootMaximumLeafRange: 8,
expectedRange: LeafRange{Start: 4, End: 8},
},
{
currentStart: 4,
currentEnd: 20,
subtreeRootMaximumLeafRange: 16,
expectedRange: LeafRange{Start: 4, End: 20},
},
{
currentStart: 4,
currentEnd: 20,
subtreeRootMaximumLeafRange: 1,
expectedRange: LeafRange{Start: 4, End: 5},
},
{
currentStart: 4,
currentEnd: 20,
Expand All @@ -1356,12 +1344,6 @@ func TestNextLeafRange(t *testing.T) {
subtreeRootMaximumLeafRange: 4,
expectedRange: LeafRange{Start: 4, End: 8},
},
{
currentStart: 4,
currentEnd: 20,
subtreeRootMaximumLeafRange: 8,
expectedRange: LeafRange{Start: 4, End: 12},
},
{
currentStart: 0,
currentEnd: 1,
Expand Down Expand Up @@ -1392,6 +1374,36 @@ func TestNextLeafRange(t *testing.T) {
subtreeRootMaximumLeafRange: 0,
expectError: true,
},
{ // A range not referencing any inner node
currentStart: 1,
currentEnd: 3,
subtreeRootMaximumLeafRange: 4,
expectError: true,
},
{ // A range not referencing any inner node
currentStart: 1,
currentEnd: 5,
subtreeRootMaximumLeafRange: 4,
expectError: true,
},
{ // A range not referencing any inner node
currentStart: 1,
currentEnd: 6,
subtreeRootMaximumLeafRange: 4,
expectError: true,
},
{ // A range not referencing any inner node
currentStart: 1,
currentEnd: 7,
subtreeRootMaximumLeafRange: 4,
expectError: true,
},
{ // A range not referencing any inner node
currentStart: 2,
currentEnd: 8,
subtreeRootMaximumLeafRange: 4,
expectError: true,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -1798,7 +1810,6 @@ func TestVerifySubtreeRootInclusion(t *testing.T) {
root: root,
expectError: true,
},

{
proof: func() Proof {
p, err := tree.ProveRange(0, 8)
Expand Down Expand Up @@ -1828,3 +1839,31 @@ func TestVerifySubtreeRootInclusion(t *testing.T) {
})
}
}

// TestVerifySubtreeRootInclusion_infiniteRecursion is motivated by a failing test
// case in celestia-node
func TestVerifySubtreeRootInclusion_infiniteRecursion(t *testing.T) {
namespaceIDs := bytes.Repeat([]byte{1}, 64)
tree := exampleNMT(1, true, namespaceIDs...)
root, err := tree.Root()
require.NoError(t, err)

nmthasher := tree.treeHasher
hasher := nmthasher.(*NmtHasher)
subtreeRoot, err := tree.ComputeSubtreeRoot(0, 4)
require.NoError(t, err)
subtreeRoots := [][]byte{subtreeRoot, subtreeRoot, subtreeRoot, subtreeRoot, subtreeRoot, subtreeRoot, subtreeRoot}
subtreeWidth := 8

proof, err := tree.ProveRange(19, 64)
require.NoError(t, err)

require.NotPanics(t, func() {
// This previously hits:
// runtime: goroutine stack exceeds 1000000000-byte limit
// runtime: sp=0x14020160480 stack=[0x14020160000, 0x14040160000]
// fatal error: stack overflow
_, err = proof.VerifySubtreeRootInclusion(hasher, subtreeRoots, subtreeWidth, root)
require.Error(t, err)
})
}

0 comments on commit 8d72690

Please sign in to comment.