Skip to content

Commit

Permalink
New message id hashing (#115)
Browse files Browse the repository at this point in the history
* compact variables passed into abi encode

* using fixed uint256 array in hash params

* use nested hashing

* fix hasher test

* update metadata hash prefix

* update snapshot and test spec

* update wrappers

* adding comments on hashing

* address comments
  • Loading branch information
matYang authored Sep 25, 2023
1 parent 0031e07 commit 990fc59
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 143 deletions.
166 changes: 83 additions & 83 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

37 changes: 20 additions & 17 deletions contracts/src/v0.8/ccip/libraries/Internal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,28 +81,31 @@ library Internal {
});
}

bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageEvent");
bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageHashV2");

function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
/// @dev Fields split into 2 abi.encode calls due to number of parameters triggering stack too deep.
/// If a dynamic type, e.g. an array is to be added, make sure it is placed in the last abi.encode call.
// Fixed-size message fields are included in nested hash to reduce stack pressure.
// This hashing scheme is also used by RMN. If changing it, please notify RMN.
return
keccak256(
bytes.concat(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
original.sequenceNumber,
original.nonce,
original.sender,
original.receiver,
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
keccak256(abi.encode(original.sourceTokenData)),
original.gasLimit,
original.strict
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.sender,
original.receiver,
original.sequenceNumber,
original.gasLimit,
original.strict,
original.nonce,
original.feeToken,
original.feeTokenAmount
)
),
abi.encode(original.feeToken, original.feeTokenAmount)
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
keccak256(abi.encode(original.sourceTokenData))
)
);
}
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ burn_mint_token_pool: ../../../contracts/solc/v0.8.19/BurnMintTokenPool.abi ../.
commit_store: ../../../contracts/solc/v0.8.19/CommitStore.abi ../../../contracts/solc/v0.8.19/CommitStore.bin 7d80f085f8249ef15e0850bf03698806c972125156f3476a1dafca54598f7f4d
commit_store_helper: ../../../contracts/solc/v0.8.19/CommitStoreHelper.abi ../../../contracts/solc/v0.8.19/CommitStoreHelper.bin 0891a1662bda54db424d12e80a56533cfd9859f7d94a3be147ad3caa46cad072
custom_token_pool: ../../../contracts/solc/v0.8.19/CustomTokenPool.abi ../../../contracts/solc/v0.8.19/CustomTokenPool.bin 79ab937aa4493bf31fb0e57affd00555aad75205c90268e89674c28ea9e5e48f
evm_2_evm_offramp: ../../../contracts/solc/v0.8.19/EVM2EVMOffRamp.abi ../../../contracts/solc/v0.8.19/EVM2EVMOffRamp.bin 961730100a969932fc978daef9e2671b83097296fb8c6e6bea72eb02a772ea09
evm_2_evm_offramp_helper: ../../../contracts/solc/v0.8.19/EVM2EVMOffRampHelper.abi ../../../contracts/solc/v0.8.19/EVM2EVMOffRampHelper.bin f1c84550cfad0faf5c92109a105a4d75260f994d21b5d681a69de681fba0d822
evm_2_evm_onramp: ../../../contracts/solc/v0.8.19/EVM2EVMOnRamp.abi ../../../contracts/solc/v0.8.19/EVM2EVMOnRamp.bin ef9d29e8ee6a380d64396f69e4612f1c0e1a5f5a1fc6abb5f9b7a545d254eab5
evm_2_evm_offramp: ../../../contracts/solc/v0.8.19/EVM2EVMOffRamp.abi ../../../contracts/solc/v0.8.19/EVM2EVMOffRamp.bin 8a0bd8a428ae8d071d326a2d4e1f7a2d35da08fef7307b6e1f15e108eb23770e
evm_2_evm_offramp_helper: ../../../contracts/solc/v0.8.19/EVM2EVMOffRampHelper.abi ../../../contracts/solc/v0.8.19/EVM2EVMOffRampHelper.bin 9e06fb409bcc9b1728c1a327d404640796c2834e7798728224b8ad4e5745c4a7
evm_2_evm_onramp: ../../../contracts/solc/v0.8.19/EVM2EVMOnRamp.abi ../../../contracts/solc/v0.8.19/EVM2EVMOnRamp.bin 9623760aeacc020a7c5b1ebf67147db69a361b1344b23ad540df49c4b668c408
lock_release_token_pool: ../../../contracts/solc/v0.8.19/LockReleaseTokenPool.abi ../../../contracts/solc/v0.8.19/LockReleaseTokenPool.bin 7f7a28f55f9fb63669cd8038a7f99e31431acd6d15ddeeb6a77188eb0bf85d58
maybe_revert_message_receiver: ../../../contracts/solc/v0.8.19/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.19/MaybeRevertMessageReceiver.bin aaa90eac8cc555ee4b0fbe57d1fb8d72d6689b29510b238177c97ab9b7979ac5
mock_arm_contract: ../../../contracts/solc/v0.8.19/MockARM.abi ../../../contracts/solc/v0.8.19/MockARM.bin efcf4cb260a2b6a6e189639f62bb50ab650a135715c1fcd42c92dfa9d04aa0e3
Expand Down
11 changes: 6 additions & 5 deletions core/scripts/ccip/manual-execution/helpers/contractmodels.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@ type ICommitStoreInterval struct {

type InternalEVM2EVMMessage struct {
SourceChainSelector uint64
SequenceNumber uint64
FeeTokenAmount *big.Int
Sender common.Address
Nonce uint64
Receiver common.Address
SequenceNumber uint64
GasLimit *big.Int
Strict bool
Receiver common.Address
Nonce uint64
FeeToken common.Address
FeeTokenAmount *big.Int
Data []byte
TokenAmounts []ClientEVMTokenAmount
FeeToken common.Address
SourceTokenData [][]byte
MessageId [32]byte
}

Expand Down
51 changes: 37 additions & 14 deletions core/scripts/ccip/manual-execution/helpers/execReport.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,37 +83,60 @@ func (t *LeafHasher) HashLeaf(log types.Log) ([32]byte, error) {
return [32]byte{}, err
}

packedValues, err := ABIEncode(
bytesArray, err := abi.NewType("bytes[]", "bytes[]", nil)
if err != nil {
return [32]byte{}, err
}

encodedSourceTokenData, err := abi.Arguments{abi.Argument{Type: bytesArray}}.PackValues([]interface{}{event.Message.SourceTokenData})
if err != nil {
return [32]byte{}, err
}

packedFixedSizeValues, err := ABIEncode(
`[
{"name": "leafDomainSeparator","type":"bytes1"},
{"name": "metadataHash", "type":"bytes32"},
{"name": "sequenceNumber", "type":"uint64"},
{"name": "nonce", "type":"uint64"},
{"name": "sender", "type":"address"},
{"name": "receiver", "type":"address"},
{"name": "dataHash", "type":"bytes32"},
{"name": "tokenAmountsHash", "type":"bytes32"},
{"name": "sequenceNumber", "type":"uint64"},
{"name": "gasLimit", "type":"uint256"},
{"name": "strict", "type":"bool"},
{"name": "nonce", "type":"uint64"},
{"name": "feeToken","type": "address"},
{"name": "feeTokenAmount","type": "uint256"}
]`,
LeafDomainSeparator,
t.metaDataHash,
event.Message.SequenceNumber,
event.Message.Nonce,
event.Message.Sender,
event.Message.Receiver,
t.ctx.Hash(event.Message.Data),
t.ctx.Hash(encodedTokens),
event.Message.SequenceNumber,
event.Message.GasLimit,
event.Message.Strict,
event.Message.Nonce,
event.Message.FeeToken,
event.Message.FeeTokenAmount,
)
if err != nil {
return [32]byte{}, err
}
fixedSizeValuesHash := t.ctx.Hash(packedFixedSizeValues)

packedValues, err := ABIEncode(
`[
{"name": "leafDomainSeparator","type":"bytes1"},
{"name": "metadataHash", "type":"bytes32"},
{"name": "fixedSizeValuesHash", "type":"bytes32"},
{"name": "dataHash", "type":"bytes32"},
{"name": "tokenAmountsHash", "type":"bytes32"},
{"name": "sourceTokenDataHash", "type":"bytes32"}
]`,
LeafDomainSeparator,
t.metaDataHash,
fixedSizeValuesHash,
t.ctx.Hash(event.Message.Data),
t.ctx.Hash(encodedTokens),
t.ctx.Hash(encodedSourceTokenData),
)
if err != nil {
return [32]byte{}, err
}
return t.ctx.Hash(packedValues), nil
}

Expand All @@ -127,7 +150,7 @@ func NewLeafHasher(sourceChainId uint64, destChainId uint64, onRampId common.Add
geABI, _ := abi.JSON(strings.NewReader(OnRampABI))
return &LeafHasher{
geABI: geABI,
metaDataHash: getMetaDataHash(ctx, ctx.Hash([]byte("EVM2EVMMessageEvent")), sourceChainId, onRampId, destChainId),
metaDataHash: getMetaDataHash(ctx, ctx.Hash([]byte("EVM2EVMMessageHashV2")), sourceChainId, onRampId, destChainId),
ctx: ctx,
}
}
Expand Down
43 changes: 27 additions & 16 deletions core/services/ocr2/plugins/ccip/internal/hashlib/leaf_hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type LeafHasher struct {

func NewLeafHasher(sourceChainSelector uint64, destChainSelector uint64, onRampId common.Address, ctx Ctx[[32]byte]) *LeafHasher {
return &LeafHasher{
metaDataHash: GetMetaDataHash(ctx, ctx.Hash([]byte("EVM2EVMMessageEvent")), sourceChainSelector, onRampId, destChainSelector),
metaDataHash: GetMetaDataHash(ctx, ctx.Hash([]byte("EVM2EVMMessageHashV2")), sourceChainSelector, onRampId, destChainSelector),
ctx: ctx,
}
}
Expand Down Expand Up @@ -58,38 +58,49 @@ func (t *LeafHasher) HashLeaf(log types.Log) ([32]byte, error) {
return [32]byte{}, err
}

packedValues, err := utils.ABIEncode(
packedFixedSizeValues, err := utils.ABIEncode(
`[
{"name": "leafDomainSeparator","type":"bytes1"},
{"name": "metadataHash", "type":"bytes32"},
{"name": "sequenceNumber", "type":"uint64"},
{"name": "nonce", "type":"uint64"},
{"name": "sender", "type":"address"},
{"name": "receiver", "type":"address"},
{"name": "dataHash", "type":"bytes32"},
{"name": "tokenAmountsHash", "type":"bytes32"},
{"name": "sourceTokenDataHash", "type":"bytes32"},
{"name": "sequenceNumber", "type":"uint64"},
{"name": "gasLimit", "type":"uint256"},
{"name": "strict", "type":"bool"},
{"name": "nonce", "type":"uint64"},
{"name": "feeToken","type": "address"},
{"name": "feeTokenAmount","type": "uint256"}
]`,
LeafDomainSeparator,
t.metaDataHash,
message.SequenceNumber,
message.Nonce,
message.Sender,
message.Receiver,
t.ctx.Hash(message.Data),
t.ctx.Hash(encodedTokens),
t.ctx.Hash(encodedSourceTokenData),
message.SequenceNumber,
message.GasLimit,
message.Strict,
message.Nonce,
message.FeeToken,
message.FeeTokenAmount,
)
if err != nil {
return [32]byte{}, err
}
fixedSizeValuesHash := t.ctx.Hash(packedFixedSizeValues)

packedValues, err := utils.ABIEncode(
`[
{"name": "leafDomainSeparator","type":"bytes1"},
{"name": "metadataHash", "type":"bytes32"},
{"name": "fixedSizeValuesHash", "type":"bytes32"},
{"name": "dataHash", "type":"bytes32"},
{"name": "tokenAmountsHash", "type":"bytes32"},
{"name": "sourceTokenDataHash", "type":"bytes32"}
]`,
LeafDomainSeparator,
t.metaDataHash,
fixedSizeValuesHash,
t.ctx.Hash(message.Data),
t.ctx.Hash(encodedTokens),
t.ctx.Hash(encodedSourceTokenData),
)
if err != nil {
return [32]byte{}, err
}
return t.ctx.Hash(packedValues), nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestHasher(t *testing.T) {
require.NoError(t, err)

// NOTE: Must match spec
require.Equal(t, "e0f22328cc83d50c2861629eaabcad5b39e8d30ba163228ff3574a0a229f5c9f", hex.EncodeToString(hash[:]))
require.Equal(t, "46ad031bfb052db2e4a2514fed8dc480b98e5ce4acb55d5640d91407e0d8a3e9", hex.EncodeToString(hash[:]))

message = evm_2_evm_onramp.InternalEVM2EVMMessage{
SourceChainSelector: sourceChainSelector,
Expand All @@ -70,7 +70,7 @@ func TestHasher(t *testing.T) {
require.NoError(t, err)

// NOTE: Must match spec
require.Equal(t, "7de96e00e1cf9753877faf459a68e9ee4fd901e50c2a3cd524586bf0cb3accf5", hex.EncodeToString(hash[:]))
require.Equal(t, "4362a13a42e52ff5ce4324e7184dc7aa41704c3146bc842d35d95b94b32a78b6", hex.EncodeToString(hash[:]))
}

func TestMetaDataHash(t *testing.T) {
Expand Down

0 comments on commit 990fc59

Please sign in to comment.