Skip to content

Commit 5c84468

Browse files
authored
Use begin/end block instead of query to fix the height indexing issue with commitments (#838)
* adds heights validation when generating data commtiments * better data commitment validation * changes query to begin/end block for data commitment * add docs * fix test * cosmetics * Update light/rpc/client.go * Update rpc/client/http/http.go * Update rpc/client/http/http.go * Update rpc/client/http/http.go * Update rpc/client/http/http.go
1 parent 100cf0a commit 5c84468

File tree

10 files changed

+83
-33
lines changed

10 files changed

+83
-33
lines changed

light/proxy/routes.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func RPCRoutes(c *lrpc.Client) map[string]*rpcserver.RPCFunc {
2828
"block_by_hash": rpcserver.NewRPCFunc(makeBlockByHashFunc(c), "hash"),
2929
"block_results": rpcserver.NewRPCFunc(makeBlockResultsFunc(c), "height"),
3030
"commit": rpcserver.NewRPCFunc(makeCommitFunc(c), "height"),
31-
"data_commitment": rpcserver.NewRPCFunc(makeDataCommitmentFunc(c), "query"),
31+
"data_commitment": rpcserver.NewRPCFunc(makeDataCommitmentFunc(c), "beginBlock,endBlock"),
3232
"tx": rpcserver.NewRPCFunc(makeTxFunc(c), "hash,prove"),
3333
"tx_search": rpcserver.NewRPCFunc(makeTxSearchFunc(c), "query,prove,page,per_page,order_by"),
3434
"block_search": rpcserver.NewRPCFunc(makeBlockSearchFunc(c), "query,page,per_page,order_by"),
@@ -136,15 +136,17 @@ func makeCommitFunc(c *lrpc.Client) rpcCommitFunc {
136136

137137
type rpcDataCommitmentFunc func(
138138
ctx *rpctypes.Context,
139-
query string,
139+
beginBlock uint64,
140+
endBlock uint64,
140141
) (*ctypes.ResultDataCommitment, error)
141142

142143
func makeDataCommitmentFunc(c *lrpc.Client) rpcDataCommitmentFunc {
143144
return func(
144145
ctx *rpctypes.Context,
145-
query string,
146+
beginBlock uint64,
147+
endBlock uint64,
146148
) (*ctypes.ResultDataCommitment, error) {
147-
return c.DataCommitment(ctx.Context(), query)
149+
return c.DataCommitment(ctx.Context(), beginBlock, endBlock)
148150
}
149151
}
150152

light/rpc/client.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,12 @@ func (c *Client) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommi
454454
}, nil
455455
}
456456

457-
func (c *Client) DataCommitment(ctx context.Context, query string) (*ctypes.ResultDataCommitment, error) {
458-
return c.next.DataCommitment(ctx, query)
457+
func (c *Client) DataCommitment(
458+
ctx context.Context,
459+
beginBlock uint64,
460+
endBlock uint64,
461+
) (*ctypes.ResultDataCommitment, error) {
462+
return c.next.DataCommitment(ctx, beginBlock, endBlock)
459463
}
460464

461465
// Tx calls rpcclient#Tx method and then verifies the proof if such was

rpc/client/http/http.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,10 +457,15 @@ func (c *baseRPCClient) Commit(ctx context.Context, height *int64) (*ctypes.Resu
457457
return result, nil
458458
}
459459

460-
func (c *baseRPCClient) DataCommitment(ctx context.Context, query string) (*ctypes.ResultDataCommitment, error) {
460+
func (c *baseRPCClient) DataCommitment(
461+
ctx context.Context,
462+
beginBlock uint64,
463+
endBlock uint64,
464+
) (*ctypes.ResultDataCommitment, error) {
461465
result := new(ctypes.ResultDataCommitment)
462466
params := map[string]interface{}{
463-
"query": query,
467+
"beginBlock": beginBlock,
468+
"endBlock": endBlock,
464469
}
465470

466471
_, err := c.caller.Call(ctx, "data_commitment", params, result)

rpc/client/interface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ type SignClient interface {
6969
BlockResults(ctx context.Context, height *int64) (*ctypes.ResultBlockResults, error)
7070
Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error)
7171

72-
DataCommitment(ctx context.Context, query string) (*ctypes.ResultDataCommitment, error)
72+
DataCommitment(ctx context.Context, beginBlock uint64, endBlock uint64) (*ctypes.ResultDataCommitment, error)
7373

7474
Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error)
7575
Tx(ctx context.Context, hash []byte, prove bool) (*ctypes.ResultTx, error)

rpc/client/local/local.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,12 @@ func (c *Local) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit
173173
return core.Commit(c.ctx, height)
174174
}
175175

176-
func (c *Local) DataCommitment(_ context.Context, query string) (*ctypes.ResultDataCommitment, error) {
177-
return core.DataCommitment(c.ctx, query)
176+
func (c *Local) DataCommitment(
177+
_ context.Context,
178+
beginBlock uint64,
179+
endBlock uint64,
180+
) (*ctypes.ResultDataCommitment, error) {
181+
return core.DataCommitment(c.ctx, beginBlock, endBlock)
178182
}
179183

180184
func (c *Local) Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) {

rpc/client/mock/client.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ var _ client.Client = Client{}
4747

4848
// Call is used by recorders to save a call and response.
4949
// It can also be used to configure mock responses.
50-
//
5150
type Call struct {
5251
Name string
5352
Args interface{}
@@ -170,8 +169,12 @@ func (c Client) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit
170169
return core.Commit(&rpctypes.Context{}, height)
171170
}
172171

173-
func (c Client) DataCommitment(ctx context.Context, query string) (*ctypes.ResultDataCommitment, error) {
174-
return core.DataCommitment(&rpctypes.Context{}, query)
172+
func (c Client) DataCommitment(
173+
ctx context.Context,
174+
beginBlock uint64,
175+
endBlock uint64,
176+
) (*ctypes.ResultDataCommitment, error) {
177+
return core.DataCommitment(&rpctypes.Context{}, beginBlock, endBlock)
175178
}
176179

177180
func (c Client) Validators(ctx context.Context, height *int64, page, perPage *int) (*ctypes.ResultValidators, error) {

rpc/client/rpc_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ func TestDataCommitment(t *testing.T) {
648648

649649
// check if data commitment is not nil.
650650
// Checking if the commitment is correct is done in `core/blocks_test.go`.
651-
dataCommitment, err := c.DataCommitment(ctx, fmt.Sprintf("block.height <= %d", expectedHeight))
651+
dataCommitment, err := c.DataCommitment(ctx, 0, uint64(expectedHeight))
652652
require.NotNil(t, dataCommitment, "data commitment shouldn't be nul.")
653653
require.Nil(t, err, "%+v when creating data commitment.", err)
654654
}

rpc/core/blocks.go

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,28 +136,59 @@ func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, erro
136136

137137
// DataCommitment collects the data roots over a provided ordered range of blocks,
138138
// and then creates a new Merkle root of those data roots.
139-
func DataCommitment(ctx *rpctypes.Context, query string) (*ctypes.ResultDataCommitment, error) {
140-
heights, err := heightsByQuery(ctx, query)
139+
func DataCommitment(ctx *rpctypes.Context, beginBlock uint64, endBlock uint64) (*ctypes.ResultDataCommitment, error) {
140+
err := validateDataCommitmentRange(beginBlock, endBlock)
141141
if err != nil {
142142
return nil, err
143143
}
144+
heights := generateHeightsList(beginBlock, endBlock)
145+
blockResults := fetchBlocks(heights, len(heights), 0)
146+
root := hashDataRoots(blockResults)
147+
// Create data commitment
148+
return &ctypes.ResultDataCommitment{DataCommitment: root}, nil
149+
}
144150

145-
if len(heights) > consts.DataCommitmentBlocksLimit {
146-
return nil, fmt.Errorf("the query exceeds the limit of allowed blocks %d", consts.DataCommitmentBlocksLimit)
147-
} else if len(heights) == 0 {
148-
return nil, fmt.Errorf("cannot create the data commitments for an empty set of blocks")
151+
// generateHeightsList takes a begin and end block, then generates a list of heights
152+
// containing the elements of the range [beginBlock, endBlock].
153+
func generateHeightsList(beginBlock uint64, endBlock uint64) []int64 {
154+
heights := make([]int64, endBlock-beginBlock+1)
155+
for i := beginBlock; i <= endBlock; i++ {
156+
heights[i-beginBlock] = int64(i)
149157
}
158+
return heights
159+
}
150160

151-
err = sortBlocks(heights, "asc")
161+
// validateDataCommitmentRange runs basic checks on the asc sorted list of heights
162+
// that will be used subsequently in generating data commitments over the defined set of heights.
163+
func validateDataCommitmentRange(beginBlock uint64, endBlock uint64) error {
164+
heightsRange := endBlock - beginBlock + 1
165+
if heightsRange > uint64(consts.DataCommitmentBlocksLimit) {
166+
return fmt.Errorf("the query exceeds the limit of allowed blocks %d", consts.DataCommitmentBlocksLimit)
167+
}
168+
if heightsRange == 0 {
169+
return fmt.Errorf("cannot create the data commitments for an empty set of blocks")
170+
}
171+
if beginBlock > endBlock {
172+
return fmt.Errorf("end block is smaller than begin block")
173+
}
174+
if endBlock > uint64(env.BlockStore.Height()) {
175+
return fmt.Errorf(
176+
"end block %d is higher than current chain height %d",
177+
endBlock,
178+
env.BlockStore.Height(),
179+
)
180+
}
181+
has, err := env.BlockIndexer.Has(int64(endBlock))
152182
if err != nil {
153-
return nil, err
183+
return err
154184
}
155-
156-
blockResults := fetchBlocks(heights, len(heights), 0)
157-
root := hashDataRoots(blockResults)
158-
159-
// Create data commitment
160-
return &ctypes.ResultDataCommitment{DataCommitment: root}, nil
185+
if !has {
186+
return fmt.Errorf(
187+
"end block %d is still not indexed",
188+
endBlock,
189+
)
190+
}
191+
return nil
161192
}
162193

163194
// hashDataRoots hashes a list of blocks data hashes and returns their merkle root.

rpc/core/blocks_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func TestBlockResults(t *testing.T) {
122122

123123
func TestDataCommitmentResults(t *testing.T) {
124124
env = &Environment{}
125-
height := int64(100)
125+
height := int64(2826)
126126

127127
blocks := randomBlocks(height)
128128
blockStore := mockBlockStore{
@@ -137,19 +137,20 @@ func TestDataCommitmentResults(t *testing.T) {
137137
expectPass bool
138138
}{
139139
{10, 15, true},
140+
{2727, 2828, false},
140141
{10, 9, false},
141142
{0, 1000, false},
143+
{10, 8, false},
142144
}
143145

144146
for _, tc := range testCases {
145-
mockedQuery := fmt.Sprintf("block.height >= %d AND block.height <= %d", tc.beginQuery, tc.endQuery)
146147
env.BlockIndexer = mockBlockIndexer{
147148
height: height,
148149
beginQueryBlock: tc.beginQuery,
149150
endQueryBlock: tc.endQuery,
150151
}
151152

152-
actualCommitment, err := DataCommitment(&rpctypes.Context{}, mockedQuery)
153+
actualCommitment, err := DataCommitment(&rpctypes.Context{}, uint64(tc.beginQuery), uint64(tc.endQuery))
153154
if tc.expectPass {
154155
require.Nil(t, err, "should generate the needed data commitment.")
155156

rpc/core/routes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var Routes = map[string]*rpc.RPCFunc{
2424
"block_by_hash": rpc.NewRPCFunc(BlockByHash, "hash"),
2525
"block_results": rpc.NewRPCFunc(BlockResults, "height"),
2626
"commit": rpc.NewRPCFunc(Commit, "height"),
27-
"data_commitment": rpc.NewRPCFunc(DataCommitment, "query"),
27+
"data_commitment": rpc.NewRPCFunc(DataCommitment, "beginBlock,endBlock"),
2828
"check_tx": rpc.NewRPCFunc(CheckTx, "tx"),
2929
"tx": rpc.NewRPCFunc(Tx, "hash,prove"),
3030
"tx_search": rpc.NewRPCFunc(TxSearch, "query,prove,page,per_page,order_by"),

0 commit comments

Comments
 (0)