Skip to content

Commit

Permalink
feat: commit to original square size in data commitments (#1001)
Browse files Browse the repository at this point in the history
* feat: commit to original block size in data commitments

* chore: block => square size

* Update rpc/core/blocks.go

Co-authored-by: Rootul P <rootulp@gmail.com>

* Update rpc/core/blocks_test.go

Co-authored-by: Rootul P <rootulp@gmail.com>

* chore: original square size => square size

* chore: add uint32 check

* Revert "chore: add uint32 check"

This reverts commit ca0aa95.

* chore: format json

---------

Co-authored-by: Rootul P <rootulp@gmail.com>
  • Loading branch information
rach-id and rootulp authored Apr 19, 2023
1 parent d23c70f commit 0aace0e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 36 deletions.
83 changes: 51 additions & 32 deletions rpc/core/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,35 +237,10 @@ func padBytes(byt []byte, length int) ([]byte, error) {
return tmp, nil
}

// EncodeDataRootTuple takes a height and a data root and returns the equivalent of
// `abi.encode(...)` in Ethereum.
// The encoded type is a DataRootTuple, which has the following ABI:
// ```
//
// {
// "components": [
// {
// "internalType": "uint256",
// "name": "height",
// "type": "uint256"
// },
// {
// "internalType": "bytes32",
// "name": "dataRoot",
// "type": "bytes32"
// }
// ],
// "internalType": "structDataRootTuple",
// "name": "_tuple",
// "type": "tuple"
// },
//
// ```
// padding the hex representation of the height to 32 bytes and concatenating the data root to it
// For more information, refer to:
// https://github.com/celestiaorg/quantum-gravity-bridge/blob/master/src/DataRootTuple.sol
func EncodeDataRootTuple(height uint64, dataRoot [32]byte) ([]byte, error) {
hexRepresentation := strconv.FormatUint(height, 16)
// To32PaddedHexBytes takes a number and returns its hex representation padded to 32 bytes.
// Used to mimic the result of `abi.encode(number)` in Ethereum.
func To32PaddedHexBytes(number uint64) ([]byte, error) {
hexRepresentation := strconv.FormatUint(number, 16)
// Make sure hex representation has even length.
// The `strconv.FormatUint` can return odd length hex encodings.
// For example, `strconv.FormatUint(10, 16)` returns `a`.
Expand All @@ -281,9 +256,53 @@ func EncodeDataRootTuple(height uint64, dataRoot [32]byte) ([]byte, error) {
if padErr != nil {
return nil, padErr
}
return paddedBytes, nil
}

// EncodeDataRootTuple takes a height, a data root and the square size, and returns the equivalent of
// `abi.encode(...)` in Ethereum.
// The encoded type is a DataRootTuple, which has the following ABI:
//
// {
// "components":[
// {
// "internalType":"uint256",
// "name":"height",
// "type":"uint256"
// },
// {
// "internalType":"bytes32",
// "name":"dataRoot",
// "type":"bytes32"
// },
// {
// "internalType":"uint256",
// "name":"squareSize",
// "type":"uint256"
// },
// {
// "internalType":"structDataRootTuple",
// "name":"_tuple",
// "type":"tuple"
// }
// ]
// }
//
// padding the hex representation of the height padded to 32 bytes concatenated to the data root concatenated
// to the hex representation of the square size padded to 32 bytes.
// For more information, refer to:
// https://github.com/celestiaorg/quantum-gravity-bridge/blob/master/src/DataRootTuple.sol
func EncodeDataRootTuple(height uint64, dataRoot [32]byte, squareSize uint64) ([]byte, error) {
paddedHeight, err := To32PaddedHexBytes(height)
if err != nil {
return nil, err
}
dataSlice := dataRoot[:]
return append(paddedBytes, dataSlice...), nil
paddedSquareSize, err := To32PaddedHexBytes(squareSize)
if err != nil {
return nil, err
}
return append(paddedHeight, append(dataSlice, paddedSquareSize...)...), nil
}

// generateHeightsList takes a begin and end block, then generates a list of heights
Expand Down Expand Up @@ -337,7 +356,7 @@ func validateDataCommitmentRange(firstBlock uint64, lastBlock uint64) error {
func hashDataRootTuples(blocks []*ctypes.ResultBlock) ([]byte, error) {
dataRootEncodedTuples := make([][]byte, 0, len(blocks))
for _, block := range blocks {
encodedTuple, err := EncodeDataRootTuple(uint64(block.Block.Height), *(*[32]byte)(block.Block.DataHash))
encodedTuple, err := EncodeDataRootTuple(uint64(block.Block.Height), *(*[32]byte)(block.Block.DataHash), block.Block.SquareSize)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -369,7 +388,7 @@ func validateDataRootInclusionProofRequest(height uint64, firstBlock uint64, las
func proveDataRootTuples(blocks []*ctypes.ResultBlock, height int64) (*merkle.Proof, error) {
dataRootEncodedTuples := make([][]byte, 0, len(blocks))
for _, block := range blocks {
encodedTuple, err := EncodeDataRootTuple(uint64(block.Block.Height), *(*[32]byte)(block.Block.DataHash))
encodedTuple, err := EncodeDataRootTuple(uint64(block.Block.Height), *(*[32]byte)(block.Block.DataHash), block.Block.SquareSize)
if err != nil {
return nil, err
}
Expand Down
17 changes: 13 additions & 4 deletions rpc/core/blocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,26 @@ func TestBlockResults(t *testing.T) {
func TestEncodeDataRootTuple(t *testing.T) {
height := uint64(2)
dataRoot, err := hex.DecodeString("82dc1607d84557d3579ce602a45f5872e821c36dbda7ec926dfa17ebc8d5c013")
squareSize := uint64(64)
require.NoError(t, err)

expectedEncoding, err := hex.DecodeString(
// hex representation of height padded to 32 bytes
"0000000000000000000000000000000000000000000000000000000000000002" +
// data root
"82dc1607d84557d3579ce602a45f5872e821c36dbda7ec926dfa17ebc8d5c013")
"82dc1607d84557d3579ce602a45f5872e821c36dbda7ec926dfa17ebc8d5c013" +
// original square size
"0000000000000000000000000000000000000000000000000000000000000040",
)
require.NoError(t, err)
require.NotNil(t, expectedEncoding)

actualEncoding, err := EncodeDataRootTuple(height, *(*[32]byte)(dataRoot))
actualEncoding, err := EncodeDataRootTuple(height, *(*[32]byte)(dataRoot), squareSize)
require.NoError(t, err)
require.NotNil(t, actualEncoding)

// Check that the length of packed data is correct
assert.Equal(t, len(actualEncoding), 64)
assert.Equal(t, len(actualEncoding), 96)
assert.Equal(t, expectedEncoding, actualEncoding)
}

Expand Down Expand Up @@ -185,7 +189,11 @@ func TestDataCommitmentResults(t *testing.T) {
size := tc.endQuery - tc.beginQuery + 1
dataRootEncodedTuples := make([][]byte, size)
for i := 0; i < size; i++ {
encodedTuple, err := EncodeDataRootTuple(uint64(blocks[tc.beginQuery+i].Height), *(*[32]byte)(blocks[tc.beginQuery+i].DataHash))
encodedTuple, err := EncodeDataRootTuple(
uint64(blocks[tc.beginQuery+i].Height),
*(*[32]byte)(blocks[tc.beginQuery+i].DataHash),
blocks[tc.beginQuery+i].SquareSize,
)
require.NoError(t, err)
dataRootEncodedTuples[i] = encodedTuple
}
Expand Down Expand Up @@ -255,6 +263,7 @@ func TestDataRootInclusionProofResults(t *testing.T) {
encodedTuple, err := EncodeDataRootTuple(
uint64(blocks[tc.firstQuery+i].Height),
*(*[32]byte)(blocks[tc.firstQuery+i].DataHash),
blocks[tc.firstQuery+i].SquareSize,
)
require.NoError(t, err)
dataRootEncodedTuples[i] = encodedTuple
Expand Down

0 comments on commit 0aace0e

Please sign in to comment.