Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: commit to original square size in data commitments #1001

Merged
merged 8 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 42 additions & 23 deletions rpc/core/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,29 @@ func padBytes(byt []byte, length int) ([]byte, error) {
return tmp, nil
}

// EncodeDataRootTuple takes a height and a data root and returns the equivalent of
// 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) {
rach-id marked this conversation as resolved.
Show resolved Hide resolved
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`.
// Thus, we need to pad it.
if len(hexRepresentation)%2 == 1 {
hexRepresentation = "0" + hexRepresentation
}
hexBytes, hexErr := hex.DecodeString(hexRepresentation)
if hexErr != nil {
return nil, hexErr
}
paddedBytes, padErr := padBytes(hexBytes, 32)
if padErr != nil {
return nil, padErr
}
return paddedBytes, nil
}

// EncodeDataRootTuple takes a height, a data root and the original square size, and returns the equivalent of
// `abi.encode(...)` in Ethereum.
// The encoded type is a DataRootTuple, which has the following ABI:
// ```
Expand All @@ -253,37 +275,34 @@ func padBytes(byt []byte, length int) ([]byte, error) {
// "internalType": "bytes32",
// "name": "dataRoot",
// "type": "bytes32"
// }
// },
// {
// "internalType": "uint256",
// "name": "squareSize",
// "type": "uint256"
// }
rootulp marked this conversation as resolved.
Show resolved Hide resolved
// ],
// "internalType": "structDataRootTuple",
// "name": "_tuple",
// "type": "tuple"
// },
//
// ```
// padding the hex representation of the height to 32 bytes and concatenating the data root to it
// padding the hex representation of the height padded to 32 bytes concatenated to the data root concatenated
// to the hex representation of the block size padded to 32 bytes.
rach-id marked this conversation as resolved.
Show resolved Hide resolved
// 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)
// Make sure hex representation has even length.
// The `strconv.FormatUint` can return odd length hex encodings.
// For example, `strconv.FormatUint(10, 16)` returns `a`.
// Thus, we need to pad it.
if len(hexRepresentation)%2 == 1 {
hexRepresentation = "0" + hexRepresentation
}
hexBytes, hexErr := hex.DecodeString(hexRepresentation)
if hexErr != nil {
return nil, hexErr
}
paddedBytes, padErr := padBytes(hexBytes, 32)
if padErr != nil {
return nil, padErr
func EncodeDataRootTuple(height uint64, dataRoot [32]byte, originalSquareSize uint64) ([]byte, error) {
rach-id marked this conversation as resolved.
Show resolved Hide resolved
paddedHeight, err := To32PaddedHexBytes(height)
if err != nil {
return nil, err
}

dataSlice := dataRoot[:]
return append(paddedBytes, dataSlice...), nil
paddedSquareSize, err := To32PaddedHexBytes(originalSquareSize)
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 block size
rach-id marked this conversation as resolved.
Show resolved Hide resolved
"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