diff --git a/packages/contracts-communication/contracts/InterchainClientV1.sol b/packages/contracts-communication/contracts/InterchainClientV1.sol index 135f54c1e3..b36861adf4 100644 --- a/packages/contracts-communication/contracts/InterchainClientV1.sol +++ b/packages/contracts-communication/contracts/InterchainClientV1.sol @@ -10,7 +10,8 @@ import {IInterchainClientV1} from "./interfaces/IInterchainClientV1.sol"; import {IInterchainDB} from "./interfaces/IInterchainDB.sol"; import {AppConfigV1, AppConfigLib} from "./libs/AppConfig.sol"; -import {InterchainEntry} from "./libs/InterchainEntry.sol"; +import {BatchingV1Lib} from "./libs/BatchingV1.sol"; +import {InterchainBatch} from "./libs/InterchainBatch.sol"; import { InterchainTransaction, InterchainTxDescriptor, InterchainTransactionLib } from "./libs/InterchainTransaction.sol"; @@ -324,13 +325,16 @@ contract InterchainClientV1 is Ownable, InterchainClientV1Events, IInterchainCli if (_txExecutor[transactionId] != address(0)) { revert InterchainClientV1__TxAlreadyExecuted(transactionId); } - // Construct expected entry based on icTransaction data - InterchainEntry memory icEntry = InterchainEntry({ + // Construct expected batch based on interchain transaction data + InterchainBatch memory batch = InterchainBatch({ srcChainId: icTx.srcChainId, dbNonce: icTx.dbNonce, - entryIndex: icTx.entryIndex, - srcWriter: linkedClient, - dataHash: transactionId + batchRoot: BatchingV1Lib.getBatchRoot({ + srcWriter: linkedClient, + dataHash: transactionId, + entryIndex: icTx.entryIndex, + proof: proof + }) }); (bytes memory encodedAppConfig, address[] memory approvedDstModules) = IInterchainApp(TypeCasts.bytes32ToAddress(icTx.dstReceiver)).getReceivingConfig(); @@ -338,7 +342,7 @@ contract InterchainClientV1 is Ownable, InterchainClientV1Events, IInterchainCli if (appConfig.requiredResponses == 0) { revert InterchainClientV1__ZeroRequiredResponses(); } - uint256 responses = _getFinalizedResponsesCount(approvedDstModules, icEntry, proof, appConfig.optimisticPeriod); + uint256 responses = _getFinalizedResponsesCount(approvedDstModules, batch, appConfig.optimisticPeriod); if (responses < appConfig.requiredResponses) { revert InterchainClientV1__NotEnoughResponses(responses, appConfig.requiredResponses); } @@ -358,14 +362,13 @@ contract InterchainClientV1 is Ownable, InterchainClientV1Events, IInterchainCli /** * @dev Calculates the number of responses that are considered finalized within the optimistic time period. * @param approvedModules Approved modules that could have confirmed the entry. - * @param icEntry The InterchainEntry to confirm. + * @param batch The Interchain Batch to confirm. * @param optimisticPeriod The time period in seconds within which a response is considered valid. * @return finalizedResponses The count of responses that are finalized within the optimistic time period. */ function _getFinalizedResponsesCount( address[] memory approvedModules, - InterchainEntry memory icEntry, - bytes32[] calldata proof, + InterchainBatch memory batch, uint256 optimisticPeriod ) internal @@ -373,7 +376,7 @@ contract InterchainClientV1 is Ownable, InterchainClientV1Events, IInterchainCli returns (uint256 finalizedResponses) { for (uint256 i = 0; i < approvedModules.length; ++i) { - uint256 confirmedAt = IInterchainDB(INTERCHAIN_DB).checkVerification(approvedModules[i], icEntry, proof); + uint256 confirmedAt = IInterchainDB(INTERCHAIN_DB).checkBatchVerification(approvedModules[i], batch); // checkVerification() returns 0 if entry hasn't been confirmed by the module, so we check for that as well if (confirmedAt != 0 && confirmedAt + optimisticPeriod < block.timestamp) { ++finalizedResponses; diff --git a/packages/contracts-communication/contracts/InterchainDB.sol b/packages/contracts-communication/contracts/InterchainDB.sol index 36298e3dba..7c7602b263 100644 --- a/packages/contracts-communication/contracts/InterchainDB.sol +++ b/packages/contracts-communication/contracts/InterchainDB.sol @@ -5,6 +5,7 @@ import {InterchainDBEvents} from "./events/InterchainDBEvents.sol"; import {IInterchainDB} from "./interfaces/IInterchainDB.sol"; import {IInterchainModule} from "./interfaces/IInterchainModule.sol"; +import {BatchingV1Lib} from "./libs/BatchingV1.sol"; import {InterchainBatch, InterchainBatchLib, BatchKey} from "./libs/InterchainBatch.sol"; import {InterchainEntry, InterchainEntryLib} from "./libs/InterchainEntry.sol"; import {VersionedPayloadLib} from "./libs/VersionedPayload.sol"; @@ -13,6 +14,15 @@ import {TypeCasts} from "./libs/TypeCasts.sol"; contract InterchainDB is InterchainDBEvents, IInterchainDB { using VersionedPayloadLib for bytes; + /// @notice Struct representing a batch of entries from the remote Interchain DataBase, + /// verified by the Interchain Module. + /// @param verifiedAt The block timestamp at which the entry was verified by the module + /// @param batchRoot The Merkle root of the batch + struct RemoteBatch { + uint256 verifiedAt; + bytes32 batchRoot; + } + uint16 public constant DB_VERSION = 1; bytes32[] internal _entryValues; @@ -132,31 +142,29 @@ contract InterchainDB is InterchainDBEvents, IInterchainDB { } /// @inheritdoc IInterchainDB - function checkVerification( + function checkBatchVerification( address dstModule, - InterchainEntry memory entry, - bytes32[] calldata proof + InterchainBatch memory batch ) external view - onlyRemoteChainId(entry.srcChainId) + onlyRemoteChainId(batch.srcChainId) returns (uint256 moduleVerifiedAt) { - // In "no batching" mode: the batch root is the same as the entry value, hence the proof is empty - if (proof.length != 0) { - // If proof is not empty, the batch root is not verified - return 0; - } - // In "no batching" mode: entry index is 0, batch size is 1 - if (entry.entryIndex != 0) { - // If entry index is not 0, it does not belong to the batch - return 0; - } - BatchKey batchKey = InterchainBatchLib.encodeBatchKey({srcChainId: entry.srcChainId, dbNonce: entry.dbNonce}); + BatchKey batchKey = InterchainBatchLib.encodeBatchKey({srcChainId: batch.srcChainId, dbNonce: batch.dbNonce}); RemoteBatch memory remoteBatch = _remoteBatches[dstModule][batchKey]; - bytes32 entryValue = InterchainEntryLib.entryValue(entry); - // Check entry value against the batch root verified by the module - return remoteBatch.batchRoot == entryValue ? remoteBatch.verifiedAt : 0; + // Check batch root against the batch root verified by the module + return remoteBatch.batchRoot == batch.batchRoot ? remoteBatch.verifiedAt : 0; + } + + /// @inheritdoc IInterchainDB + function getBatchRoot(InterchainEntry memory entry, bytes32[] calldata proof) external pure returns (bytes32) { + return BatchingV1Lib.getBatchRoot({ + srcWriter: entry.srcWriter, + dataHash: entry.dataHash, + entryIndex: entry.entryIndex, + proof: proof + }); } /// @inheritdoc IInterchainDB diff --git a/packages/contracts-communication/contracts/interfaces/IInterchainClientV1.sol b/packages/contracts-communication/contracts/interfaces/IInterchainClientV1.sol index ce136fc5cc..84455d9a86 100644 --- a/packages/contracts-communication/contracts/interfaces/IInterchainClientV1.sol +++ b/packages/contracts-communication/contracts/interfaces/IInterchainClientV1.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; import {InterchainTxDescriptor} from "../libs/InterchainTransaction.sol"; interface IInterchainClientV1 { + // TODO: standardize error names across interfaces error InterchainClientV1__FeeAmountTooLow(uint256 actual, uint256 required); error InterchainClientV1__IncorrectDstChainId(uint64 chainId); error InterchainClientV1__IncorrectMsgValue(uint256 actual, uint256 required); diff --git a/packages/contracts-communication/contracts/interfaces/IInterchainDB.sol b/packages/contracts-communication/contracts/interfaces/IInterchainDB.sol index e3c113d8af..233f67d97b 100644 --- a/packages/contracts-communication/contracts/interfaces/IInterchainDB.sol +++ b/packages/contracts-communication/contracts/interfaces/IInterchainDB.sol @@ -1,19 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {InterchainEntry} from "../libs/InterchainEntry.sol"; import {InterchainBatch} from "../libs/InterchainBatch.sol"; +import {InterchainEntry} from "../libs/InterchainEntry.sol"; interface IInterchainDB { - /// @notice Struct representing a batch of entries from the remote Interchain DataBase, - /// verified by the Interchain Module. - /// @param verifiedAt The block timestamp at which the entry was verified by the module - /// @param batchRoot The Merkle root of the batch - struct RemoteBatch { - uint256 verifiedAt; - bytes32 batchRoot; - } - error InterchainDB__BatchDoesNotExist(uint64 dbNonce); error InterchainDB__BatchNotFinalized(uint64 dbNonce); error InterchainDB__ConflictingBatches(address module, bytes32 existingBatchRoot, InterchainBatch newBatch); @@ -144,22 +135,25 @@ interface IInterchainDB { /// @return entryIndex The index of the next entry within that batch function getNextEntryIndex() external view returns (uint64 dbNonce, uint64 entryIndex); - /// @notice Read the data written on specific source chain by a specific writer, - /// and verify it on the destination chain using the provided Interchain Module. - /// Note: returned zero value indicates that the module has not verified the entry. - /// @param entry The Interchain Entry to read + /// @notice Check if the batch is verified by the Interchain Module on the destination chain. + /// Note: returned zero value indicates that the module has not verified the batch. /// @param dstModule The destination chain addresses of the Interchain Modules to use for verification - /// @return moduleVerifiedAt The block timestamp at which the entry was verified by the module, - /// or ZERO if the module has not verified the entry. - function checkVerification( + /// @param batch The Interchain Batch to check + /// @return moduleVerifiedAt The block timestamp at which the batch was verified by the module, + /// or ZERO if the module has not verified the batch. + function checkBatchVerification( address dstModule, - InterchainEntry memory entry, - bytes32[] memory proof + InterchainBatch memory batch ) external view returns (uint256 moduleVerifiedAt); + /// @notice Get the batch root containing the Interchain Entry with the given index. + /// @param entry The Interchain Entry to get the batch root for + /// @param proof The Merkle proof of inclusion for the entry in the batch + function getBatchRoot(InterchainEntry memory entry, bytes32[] memory proof) external pure returns (bytes32); + /// @notice Get the version of the Interchain DataBase. // solhint-disable-next-line func-name-mixedcase function DB_VERSION() external pure returns (uint16); diff --git a/packages/contracts-communication/contracts/libs/BatchingV1.sol b/packages/contracts-communication/contracts/libs/BatchingV1.sol new file mode 100644 index 0000000000..2dae74024a --- /dev/null +++ b/packages/contracts-communication/contracts/libs/BatchingV1.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {InterchainEntryLib} from "./InterchainEntry.sol"; + +library BatchingV1Lib { + error BatchingV1__IncorrectEntryIndex(uint64 entryIndex); + error BatchingV1__IncorrectProof(); + + /// @notice Get the batch root containing the Interchain Entry with the given index. + /// @param srcWriter The entry writer of the source chain + /// @param dataHash The hash of the data of the entry + /// @param entryIndex The index of the entry in the batch + /// @param proof The Merkle proof of inclusion for the entry in the batch + /// @return batchRoot The root of the batch containing the entry + function getBatchRoot( + bytes32 srcWriter, + bytes32 dataHash, + uint64 entryIndex, + bytes32[] calldata proof + ) + internal + pure + returns (bytes32 batchRoot) + { + // In "no batching" mode: entry index is 0, proof is empty + if (entryIndex != 0) { + revert BatchingV1__IncorrectEntryIndex(entryIndex); + } + if (proof.length != 0) { + revert BatchingV1__IncorrectProof(); + } + // In "no batching" mode: the batch root is the same as the entry value + return InterchainEntryLib.getEntryValue({srcWriter: srcWriter, dataHash: dataHash}); + } +} diff --git a/packages/contracts-communication/contracts/libs/InterchainEntry.sol b/packages/contracts-communication/contracts/libs/InterchainEntry.sol index 358d2cfdf6..8315e65b7f 100644 --- a/packages/contracts-communication/contracts/libs/InterchainEntry.sol +++ b/packages/contracts-communication/contracts/libs/InterchainEntry.sol @@ -51,6 +51,11 @@ library InterchainEntryLib { /// @notice Returns the value of the entry: writer + dataHash hashed together function entryValue(InterchainEntry memory entry) internal pure returns (bytes32) { - return keccak256(abi.encode(entry.srcWriter, entry.dataHash)); + return getEntryValue(entry.srcWriter, entry.dataHash); + } + + /// @notice Returns the value of the entry: writer + dataHash hashed together + function getEntryValue(bytes32 srcWriter, bytes32 dataHash) internal pure returns (bytes32) { + return keccak256(abi.encode(srcWriter, dataHash)); } } diff --git a/packages/contracts-communication/test/InterchainClientV1.Base.t.sol b/packages/contracts-communication/test/InterchainClientV1.Base.t.sol index bb066568d4..423458e2bd 100644 --- a/packages/contracts-communication/test/InterchainClientV1.Base.t.sol +++ b/packages/contracts-communication/test/InterchainClientV1.Base.t.sol @@ -2,11 +2,8 @@ pragma solidity 0.8.20; import {InterchainClientV1, InterchainClientV1Events, IInterchainClientV1} from "../contracts/InterchainClientV1.sol"; -import { - InterchainTxDescriptor, - InterchainTransaction, - InterchainTransactionLib -} from "../contracts/libs/InterchainTransaction.sol"; +import {InterchainTxDescriptor, InterchainTransaction} from "../contracts/libs/InterchainTransaction.sol"; +import {BatchingV1Lib} from "../contracts/libs/BatchingV1.sol"; import {OptionsLib} from "../contracts/libs/Options.sol"; import {InterchainTransactionLibHarness} from "./harnesses/InterchainTransactionLibHarness.sol"; @@ -80,12 +77,20 @@ abstract contract InterchainClientV1BaseTest is Test, InterchainClientV1Events { ); } + function expectRevertIncorrectEntryIndex(uint64 entryIndex) internal { + vm.expectRevert(abi.encodeWithSelector(BatchingV1Lib.BatchingV1__IncorrectEntryIndex.selector, entryIndex)); + } + function expectRevertIncorrectMsgValue(uint256 actual, uint256 required) internal { vm.expectRevert( abi.encodeWithSelector(IInterchainClientV1.InterchainClientV1__IncorrectMsgValue.selector, actual, required) ); } + function expectRevertIncorrectProof() internal { + vm.expectRevert(BatchingV1Lib.BatchingV1__IncorrectProof.selector); + } + function expectRevertInvalidTransactionVersion(uint16 version) internal { vm.expectRevert( abi.encodeWithSelector(IInterchainClientV1.InterchainClientV1__InvalidTransactionVersion.selector, version) diff --git a/packages/contracts-communication/test/InterchainClientV1.Dst.t.sol b/packages/contracts-communication/test/InterchainClientV1.Dst.t.sol index b7aa9d7f67..54a3defe7c 100644 --- a/packages/contracts-communication/test/InterchainClientV1.Dst.t.sol +++ b/packages/contracts-communication/test/InterchainClientV1.Dst.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.20; import {AppConfigV1} from "../contracts/libs/AppConfig.sol"; -import {InterchainEntry} from "../contracts/libs/InterchainEntry.sol"; +import {InterchainBatch} from "../contracts/libs/InterchainBatch.sol"; import {OptionsV1} from "../contracts/libs/Options.sol"; import {VersionedPayloadLib} from "../contracts/libs/VersionedPayload.sol"; @@ -29,10 +29,10 @@ import {InterchainDBMock} from "./mocks/InterchainDBMock.sol"; /// 5. Mark transaction as executed and emit an event. contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { uint64 public constant MOCK_DB_NONCE = 444; - uint64 public constant MOCK_ENTRY_INDEX = 4; + uint64 public constant MOCK_ENTRY_INDEX = 0; uint64 public constant MOCK_LOCAL_DB_NONCE = 123; - uint64 public constant MOCK_LOCAL_ENTRY_INDEX = 5; + uint64 public constant MOCK_LOCAL_ENTRY_INDEX = 0; uint256 public constant MOCK_GAS_LIMIT = 100_000; uint256 public constant MOCK_GAS_AIRDROP = 1 ether; @@ -103,20 +103,17 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { function mockCheckVerification( address dstModule, InterchainTxDescriptor memory desc, - bytes32[] memory proof, uint256 verifiedAt ) internal { - InterchainEntry memory entry = InterchainEntry({ + InterchainBatch memory batch = InterchainBatch({ srcChainId: REMOTE_CHAIN_ID, dbNonce: desc.dbNonce, - entryIndex: desc.entryIndex, - srcWriter: MOCK_REMOTE_CLIENT, - dataHash: desc.transactionId + batchRoot: keccak256(abi.encode(MOCK_REMOTE_CLIENT, desc.transactionId)) }); vm.mockCall( - icDB, abi.encodeCall(InterchainDBMock.checkVerification, (dstModule, entry, proof)), abi.encode(verifiedAt) + icDB, abi.encodeCall(InterchainDBMock.checkBatchVerification, (dstModule, batch)), abi.encode(verifiedAt) ); } @@ -182,7 +179,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { function prepareExecuteTest( bytes memory encodedOptions, AppConfigV1 memory appConfig, - bytes32[] memory proof, address[] memory modules, uint256[] memory verificationTimes ) @@ -194,7 +190,7 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (icTx, desc) = constructInterchainTx(encodedOptions); mockReceivingConfig(appConfig, modules); for (uint256 i = 0; i < modules.length; i++) { - mockCheckVerification(modules[i], desc, proof, verificationTimes[i]); + mockCheckVerification(modules[i], desc, verificationTimes[i]); } } @@ -205,7 +201,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (icTx, desc) = prepareExecuteTest({ encodedOptions: options.encodeOptionsV1(), appConfig: oneConfWithOP, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); @@ -240,7 +235,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx, InterchainTxDescriptor memory desc) = prepareExecuteTest({ encodedOptions: options.encodeOptionsV1(), appConfig: appConfig, - proof: emptyProof, modules: oneModuleA, verificationTimes: verificationTimes }); @@ -257,7 +251,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx, InterchainTxDescriptor memory desc) = prepareExecuteTest({ encodedOptions: options.encodeOptionsV1(), appConfig: appConfig, - proof: emptyProof, modules: twoModules, verificationTimes: verificationTimes }); @@ -275,7 +268,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: options.encodeOptionsV1(), appConfig: appConfig, - proof: emptyProof, modules: oneModuleA, verificationTimes: verificationTimes }); @@ -297,7 +289,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: options.encodeOptionsV1(), appConfig: appConfig, - proof: emptyProof, modules: twoModules, verificationTimes: verificationTimes }); @@ -779,7 +770,7 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { transactionId: keccak256(getEncodedTx(icTx)) }); mockReceivingConfig(oneConfWithOP, oneModuleA); - mockCheckVerification(icModuleA, desc, new bytes32[](0), JUST_VERIFIED); + mockCheckVerification(icModuleA, desc, JUST_VERIFIED); } function test_interchainExecute_revert_invalidTransactionVersion(uint16 version) public { @@ -792,7 +783,7 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { transactionId: keccak256(invalidVersionTx) }); mockReceivingConfig(oneConfWithOP, oneModuleA); - mockCheckVerification(icModuleA, desc, new bytes32[](0), JUST_VERIFIED); + mockCheckVerification(icModuleA, desc, JUST_VERIFIED); expectRevertInvalidTransactionVersion(version); vm.prank(executor); icClient.interchainExecute(optionsNoAirdrop.gasLimit, invalidVersionTx, new bytes32[](0)); @@ -825,6 +816,21 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { executeTransaction(encodedTx, optionsNoAirdrop, emptyProof); } + function test_interchainExecute_revert_nonZeroEntryIndex() public { + (InterchainTransaction memory icTx,) = constructInterchainTx(optionsNoAirdrop.encodeOptionsV1()); + icTx.entryIndex = 1; + bytes memory encodedTx = getEncodedTx(icTx); + expectRevertIncorrectEntryIndex(icTx.entryIndex); + executeTransaction(encodedTx, optionsNoAirdrop, emptyProof); + } + + function test_interchainExecute_revert_nonEmptyProof() public { + (InterchainTransaction memory icTx,) = constructInterchainTx(optionsNoAirdrop.encodeOptionsV1()); + bytes memory encodedTx = getEncodedTx(icTx); + expectRevertIncorrectProof(); + executeTransaction(encodedTx, optionsNoAirdrop, new bytes32[](1)); + } + function test_interchainExecute_revert_emptyOptions() public { (InterchainTransaction memory icTx,) = constructInterchainTx(""); bytes memory encodedTx = getEncodedTx(icTx); @@ -873,7 +879,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: optionsAirdrop.encodeOptionsV1(), appConfig: oneConfWithOP, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); @@ -888,7 +893,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: optionsAirdrop.encodeOptionsV1(), appConfig: oneConfWithOP, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); @@ -903,7 +907,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: optionsAirdrop.encodeOptionsV1(), appConfig: oneConfWithOP, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); @@ -918,7 +921,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: optionsNoAirdrop.encodeOptionsV1(), appConfig: oneConfWithOP, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); @@ -934,7 +936,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: optionsNoAirdrop.encodeOptionsV1(), appConfig: appConfig, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); @@ -978,6 +979,21 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { icClient.isExecutable(encodedTx, emptyProof); } + function test_isExecutable_revert_nonZeroEntryIndex() public { + (InterchainTransaction memory icTx,) = constructInterchainTx(optionsNoAirdrop.encodeOptionsV1()); + icTx.entryIndex = 1; + bytes memory encodedTx = getEncodedTx(icTx); + expectRevertIncorrectEntryIndex(icTx.entryIndex); + icClient.isExecutable(encodedTx, emptyProof); + } + + function test_isExecutable_revert_nonEmptyProof() public { + (InterchainTransaction memory icTx,) = constructInterchainTx(optionsNoAirdrop.encodeOptionsV1()); + bytes memory encodedTx = getEncodedTx(icTx); + expectRevertIncorrectProof(); + icClient.isExecutable(encodedTx, new bytes32[](1)); + } + function test_isExecutable_revert_emptyOptions() public { (InterchainTransaction memory icTx,) = constructInterchainTx(""); bytes memory encodedTx = getEncodedTx(icTx); @@ -1018,7 +1034,6 @@ contract InterchainClientV1DestinationTest is InterchainClientV1BaseTest { (InterchainTransaction memory icTx,) = prepareExecuteTest({ encodedOptions: optionsNoAirdrop.encodeOptionsV1(), appConfig: appConfig, - proof: emptyProof, modules: oneModuleA, verificationTimes: toArray(JUST_VERIFIED) }); diff --git a/packages/contracts-communication/test/InterchainDB.Dst.t.sol b/packages/contracts-communication/test/InterchainDB.Dst.t.sol index 913102e9e0..bb3acb8994 100644 --- a/packages/contracts-communication/test/InterchainDB.Dst.t.sol +++ b/packages/contracts-communication/test/InterchainDB.Dst.t.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.20; import { InterchainDB, InterchainBatch, - InterchainBatchLib, InterchainEntry, IInterchainDB, InterchainDBEvents @@ -165,35 +164,22 @@ contract InterchainDBDestinationTest is Test, InterchainDBEvents { // ═══════════════════════════════════════════════ TEST HELPERS ════════════════════════════════════════════════════ - function assertCorrectInitialVerificationTime(InterchainModuleMock module, InterchainEntry memory entry) internal { - InterchainBatch memory batch = - InterchainBatch(entry.srcChainId, entry.dbNonce, keccak256(abi.encode(entry.srcWriter, entry.dataHash))); + function assertCorrectInitialVerificationTime(InterchainModuleMock module, InterchainBatch memory batch) internal { bytes memory versionedBatch = getVersionedBatch(batch); uint256 savedVerificationTime = verifiedAt[address(module)][keccak256(abi.encode(versionedBatch))]; // We never save 0 as a verification time during initial setup assertGt(savedVerificationTime, 0); - checkVerification(module, entry, savedVerificationTime); + checkVerification(module, batch, savedVerificationTime); } function checkVerification( InterchainModuleMock module, - InterchainEntry memory entry, + InterchainBatch memory batch, uint256 expectedVerificationTime ) internal { - checkVerification(module, entry, new bytes32[](0), expectedVerificationTime); - } - - function checkVerification( - InterchainModuleMock module, - InterchainEntry memory entry, - bytes32[] memory proof, - uint256 expectedVerificationTime - ) - internal - { - uint256 timestamp = icDB.checkVerification(address(module), entry, proof); + uint256 timestamp = icDB.checkBatchVerification(address(module), batch); assertEq(timestamp, expectedVerificationTime); } @@ -238,11 +224,10 @@ contract InterchainDBDestinationTest is Test, InterchainDBEvents { } function test_verifyBatch_new_savesVerificationTime() public { - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 20); InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 20); bytes memory versionedBatch = getVersionedBatch(batch); verifyBatch(moduleA, versionedBatch); - checkVerification(moduleA, entry, block.timestamp); + checkVerification(moduleA, batch, block.timestamp); } function test_verifyBatch_existing_diffModule_emitsEvent() public { @@ -255,20 +240,18 @@ contract InterchainDBDestinationTest is Test, InterchainDBEvents { function test_verifyBatch_existing_diffModule_doesNotUpdateExistingVerificationTime() public { // {1: 0} was already verified by module B - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_1, 0); InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_1, 0); bytes memory versionedBatch = getVersionedBatch(batch); verifyBatch(moduleA, versionedBatch); - assertCorrectInitialVerificationTime(moduleB, entry); + assertCorrectInitialVerificationTime(moduleB, batch); } function test_verifyBatch_existing_diffModule_savesVerificationTime() public { // {1: 0} was already verified by module B - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_1, 0); InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_1, 0); bytes memory versionedBatch = getVersionedBatch(batch); verifyBatch(moduleA, versionedBatch); - checkVerification(moduleA, entry, block.timestamp); + checkVerification(moduleA, batch, block.timestamp); } function test_verifyBatch_existing_sameModule_doesNotEmitEvent() public { @@ -282,12 +265,11 @@ contract InterchainDBDestinationTest is Test, InterchainDBEvents { function test_verifyBatch_existing_sameModule_doesNotUpdateExistingVerificationTime() public { // {0:0} was already verified by module A - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 0); bytes memory versionedBatch = getVersionedBatch(batch); uint256 moduleAVerificationTime = verifiedAt[address(moduleA)][keccak256(abi.encode(versionedBatch))]; verifyBatch(moduleA, versionedBatch); - checkVerification(moduleA, entry, moduleAVerificationTime); + checkVerification(moduleA, batch, moduleAVerificationTime); } function test_verifyBatch_conflict_diffModule_emitsEvent() public { @@ -301,19 +283,18 @@ contract InterchainDBDestinationTest is Test, InterchainDBEvents { function test_verifyBatch_conflict_diffModule_doesNotUpdateExistingVerificationTime() public { // {1: 0} was already verified by module B InterchainBatch memory batch = getFakeBatch(SRC_CHAIN_ID_1, 0); - InterchainEntry memory realEntry = getMockEntry(SRC_CHAIN_ID_1, 0); + InterchainBatch memory realBatch = getMockBatch(SRC_CHAIN_ID_1, 0); bytes memory versionedBatch = getVersionedBatch(batch); verifyBatch(moduleA, versionedBatch); - assertCorrectInitialVerificationTime(moduleB, realEntry); + assertCorrectInitialVerificationTime(moduleB, realBatch); } function test_verifyBatch_conflict_diffModule_savesVerificationTime() public { // {1: 0} was already verified by module B - InterchainEntry memory entry = getFakeEntry(SRC_CHAIN_ID_1, 0); InterchainBatch memory batch = getFakeBatch(SRC_CHAIN_ID_1, 0); bytes memory versionedBatch = getVersionedBatch(batch); verifyBatch(moduleA, versionedBatch); - checkVerification(moduleA, entry, block.timestamp); + checkVerification(moduleA, batch, block.timestamp); } // ════════════════════════════════════ TESTS: VERIFYING BATCHES (REVERTS) ═════════════════════════════════════════ @@ -348,185 +329,158 @@ contract InterchainDBDestinationTest is Test, InterchainDBEvents { function test_checkVerification_existingA_existingB() public { // {1: 10} was verified by module A and module B - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_1, 10); - assertCorrectInitialVerificationTime(moduleA, entry); - assertCorrectInitialVerificationTime(moduleB, entry); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_1, 10); + assertCorrectInitialVerificationTime(moduleA, batch); + assertCorrectInitialVerificationTime(moduleB, batch); } function test_checkVerification_existingA_unknownB() public { // {0: 0} was verified by module A, but not by module B - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); - assertCorrectInitialVerificationTime(moduleA, entry); - checkVerification(moduleB, entry, 0); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 0); + assertCorrectInitialVerificationTime(moduleA, batch); + checkVerification(moduleB, batch, 0); } function test_checkVerification_existingA_differentB() public { introduceConflicts(); // {0: 10} was verified by module A, but a "fake" batch was verified by module B - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 10); - assertCorrectInitialVerificationTime(moduleA, entry); - checkVerification(moduleB, entry, 0); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 10); + assertCorrectInitialVerificationTime(moduleA, batch); + checkVerification(moduleB, batch, 0); } function test_checkVerification_existingA_emptyB() public { introduceEmptyBatches(); // {0: 10} was verified by module A, but an "empty" batch was verified by module B - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 10); - assertCorrectInitialVerificationTime(moduleA, entry); - checkVerification(moduleB, entry, 0); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 10); + assertCorrectInitialVerificationTime(moduleA, batch); + checkVerification(moduleB, batch, 0); } function test_checkVerification_unknownA_existingB() public { // {1: 0} was verified by module B, but not by module A - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_1, 0); - checkVerification(moduleA, entry, 0); - assertCorrectInitialVerificationTime(moduleB, entry); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_1, 0); + checkVerification(moduleA, batch, 0); + assertCorrectInitialVerificationTime(moduleB, batch); } function test_checkVerification_unknownA_unknownB() public { // {0: 20} was not verified by any module - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 20); - checkVerification(moduleA, entry, 0); - checkVerification(moduleB, entry, 0); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 20); + checkVerification(moduleA, batch, 0); + checkVerification(moduleB, batch, 0); } function test_checkVerification_unknownA_differentB() public { // {1: 0} was verified by module B, but not by module A // Check the fake batch that neither module verified - InterchainEntry memory fakeEntry = getFakeEntry(SRC_CHAIN_ID_1, 0); - checkVerification(moduleA, fakeEntry, 0); - checkVerification(moduleB, fakeEntry, 0); + InterchainBatch memory fakeBatch = getFakeBatch(SRC_CHAIN_ID_1, 0); + checkVerification(moduleA, fakeBatch, 0); + checkVerification(moduleB, fakeBatch, 0); } function test_checkVerification_unknownA_emptyB() public { introduceEmptyBatches(); // {0: 30} was not verified by module A, but an "empty" batch was verified by module B - InterchainEntry memory emptyEntry = getEmptyEntry(SRC_CHAIN_ID_0, 30); - checkVerification(moduleA, emptyEntry, 0); - assertCorrectInitialVerificationTime(moduleB, emptyEntry); + InterchainBatch memory emptyBatch = getEmptyBatch(SRC_CHAIN_ID_0, 30); + checkVerification(moduleA, emptyBatch, 0); + assertCorrectInitialVerificationTime(moduleB, emptyBatch); } function test_checkVerification_differentA_existingB() public { introduceConflicts(); // {0: 10} was verified by module A, but a "fake" batch was verified by module B // Check the fake batch that A never verified - InterchainEntry memory fakeEntry = getFakeEntry(SRC_CHAIN_ID_0, 10); - checkVerification(moduleA, fakeEntry, 0); - assertCorrectInitialVerificationTime(moduleB, fakeEntry); + InterchainBatch memory fakeBatch = getFakeBatch(SRC_CHAIN_ID_0, 10); + checkVerification(moduleA, fakeBatch, 0); + assertCorrectInitialVerificationTime(moduleB, fakeBatch); } function test_checkVerification_differentA_unknownB() public { // {0: 10} was verified by module A, but not by module B // Check the fake batch that neither module verified - InterchainEntry memory fakeEntry = getFakeEntry(SRC_CHAIN_ID_0, 10); - checkVerification(moduleA, fakeEntry, 0); - checkVerification(moduleB, fakeEntry, 0); + InterchainBatch memory fakeBatch = getFakeBatch(SRC_CHAIN_ID_0, 10); + checkVerification(moduleA, fakeBatch, 0); + checkVerification(moduleB, fakeBatch, 0); } function test_checkVerification_differentA_differentB() public { // {1: 10} was verified by module A and module B // Check the fake batch that neither module verified - InterchainEntry memory fakeEntry = getFakeEntry(SRC_CHAIN_ID_1, 10); - checkVerification(moduleA, fakeEntry, 0); - checkVerification(moduleB, fakeEntry, 0); + InterchainBatch memory fakeBatch = getFakeBatch(SRC_CHAIN_ID_1, 10); + checkVerification(moduleA, fakeBatch, 0); + checkVerification(moduleB, fakeBatch, 0); } function test_checkVerification_differentA_emptyB() public { introduceEmptyBatches(); // {0: 10} was verified by module A, but an "empty" batch was verified by module B - InterchainEntry memory emptyEntry = getEmptyEntry(SRC_CHAIN_ID_0, 10); - checkVerification(moduleA, emptyEntry, 0); - assertCorrectInitialVerificationTime(moduleB, emptyEntry); + InterchainBatch memory emptyBatch = getEmptyBatch(SRC_CHAIN_ID_0, 10); + checkVerification(moduleA, emptyBatch, 0); + assertCorrectInitialVerificationTime(moduleB, emptyBatch); } function test_checkVerification_emptyA_existingB() public { introduceEmptyBatches(); // {1: 0} was verified by module B, but an "empty" batch was verified by module A - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_1, 0); - checkVerification(moduleA, entry, 0); - assertCorrectInitialVerificationTime(moduleB, entry); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_1, 0); + checkVerification(moduleA, batch, 0); + assertCorrectInitialVerificationTime(moduleB, batch); } function test_checkVerification_emptyA_unknownB() public { introduceEmptyBatches(); // {0: 20} was verified as "empty" by module A, but not by module B - InterchainEntry memory emptyEntry = getEmptyEntry(SRC_CHAIN_ID_0, 20); - assertCorrectInitialVerificationTime(moduleA, emptyEntry); - checkVerification(moduleB, emptyEntry, 0); + InterchainBatch memory emptyBatch = getEmptyBatch(SRC_CHAIN_ID_0, 20); + assertCorrectInitialVerificationTime(moduleA, emptyBatch); + checkVerification(moduleB, emptyBatch, 0); } function test_checkVerification_emptyA_differentB() public { introduceEmptyBatches(); // {1: 0} was verified by module B, but an "empty" batch was verified by module A - InterchainEntry memory emptyEntry = getEmptyEntry(SRC_CHAIN_ID_1, 0); - assertCorrectInitialVerificationTime(moduleA, emptyEntry); - checkVerification(moduleB, emptyEntry, 0); + InterchainBatch memory emptyBatch = getEmptyBatch(SRC_CHAIN_ID_1, 0); + assertCorrectInitialVerificationTime(moduleA, emptyBatch); + checkVerification(moduleB, emptyBatch, 0); } function test_checkVerification_emptyA_emptyB() public { introduceEqualEmptyBatches(); // {0: 20} was verified as "empty" by module A and module B - InterchainEntry memory emptyEntry = getEmptyEntry(SRC_CHAIN_ID_0, 20); - assertCorrectInitialVerificationTime(moduleA, emptyEntry); - assertCorrectInitialVerificationTime(moduleB, emptyEntry); - } - - function test_checkVerification_nonEmptyProof() public { - bytes32[] memory proof = new bytes32[](1); - proof[0] = hex"deadbeaf"; - // Should return 0 for batches that were verified or not - checkVerification(moduleA, getMockEntry(SRC_CHAIN_ID_0, 0), proof, 0); - checkVerification(moduleA, getFakeEntry(SRC_CHAIN_ID_0, 0), proof, 0); - proof[0] = 0; - checkVerification(moduleB, getMockEntry(SRC_CHAIN_ID_1, 0), proof, 0); - checkVerification(moduleB, getFakeEntry(SRC_CHAIN_ID_1, 0), proof, 0); + InterchainBatch memory emptyBatch = getEmptyBatch(SRC_CHAIN_ID_0, 20); + assertCorrectInitialVerificationTime(moduleA, emptyBatch); + assertCorrectInitialVerificationTime(moduleB, emptyBatch); } function test_checkVerification_modifySrcChainId() public { - // Valid entry - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); - assertCorrectInitialVerificationTime(moduleA, entry); - entry.srcChainId ^= 1; - checkVerification(moduleA, entry, 0); + // Valid batch + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 0); + assertCorrectInitialVerificationTime(moduleA, batch); + batch.srcChainId ^= 1; + checkVerification(moduleA, batch, 0); } function test_checkVerification_modifyDbNonce() public { - // Valid entry - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); - assertCorrectInitialVerificationTime(moduleA, entry); - entry.dbNonce ^= 1; - checkVerification(moduleA, entry, 0); - } - - function test_checkVerification_modifyEntryIndex() public { - // Valid entry - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); - assertCorrectInitialVerificationTime(moduleA, entry); - entry.entryIndex ^= 1; - checkVerification(moduleA, entry, 0); - } - - function test_checkVerification_modifySrcWriter() public { - // Valid entry - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); - assertCorrectInitialVerificationTime(moduleA, entry); - entry.srcWriter ^= bytes32(uint256(1)); - checkVerification(moduleA, entry, 0); + // Valid batch + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 0); + assertCorrectInitialVerificationTime(moduleA, batch); + batch.dbNonce ^= 1; + checkVerification(moduleA, batch, 0); } - function test_checkVerification_modifyDataHash() public { + function test_checkVerification_modifyBatchRoot() public { // Valid entry - InterchainEntry memory entry = getMockEntry(SRC_CHAIN_ID_0, 0); - assertCorrectInitialVerificationTime(moduleA, entry); - entry.dataHash ^= bytes32(uint256(1)); - checkVerification(moduleA, entry, 0); + InterchainBatch memory batch = getMockBatch(SRC_CHAIN_ID_0, 0); + assertCorrectInitialVerificationTime(moduleA, batch); + batch.batchRoot ^= bytes32(uint256(1)); + checkVerification(moduleA, batch, 0); } // ═════════════════════════════════════ TESTS: READING BATCHES (REVERTS) ══════════════════════════════════════════ function test_checkVerification_revert_sameChainId() public { - InterchainEntry memory entry = getMockEntry(DST_CHAIN_ID, 0); + InterchainBatch memory batch = getMockBatch(DST_CHAIN_ID, 0); expectSameChainId(DST_CHAIN_ID); - icDB.checkVerification(address(moduleA), entry, new bytes32[](0)); + icDB.checkBatchVerification(address(moduleA), batch); } } diff --git a/packages/contracts-communication/test/InterchainDB.Src.t.sol b/packages/contracts-communication/test/InterchainDB.Src.t.sol index 6165523d47..1f5f0254c8 100644 --- a/packages/contracts-communication/test/InterchainDB.Src.t.sol +++ b/packages/contracts-communication/test/InterchainDB.Src.t.sol @@ -4,11 +4,11 @@ pragma solidity 0.8.20; import { InterchainDB, InterchainBatch, - InterchainBatchLib, InterchainEntry, InterchainEntryLib, IInterchainDB, - InterchainDBEvents + InterchainDBEvents, + BatchingV1Lib } from "../contracts/InterchainDB.sol"; import {InterchainBatchLibHarness} from "./harnesses/InterchainBatchLibHarness.sol"; @@ -190,12 +190,20 @@ contract InterchainDBSourceTest is Test, InterchainDBEvents { ); } + function expectRevertIncorrectEntryIndex(uint64 entryIndex) internal { + vm.expectRevert(abi.encodeWithSelector(BatchingV1Lib.BatchingV1__IncorrectEntryIndex.selector, entryIndex)); + } + function expectRevertIncorrectFeeAmount(uint256 actualFee, uint256 expectedFee) internal { vm.expectRevert( abi.encodeWithSelector(IInterchainDB.InterchainDB__IncorrectFeeAmount.selector, actualFee, expectedFee) ); } + function expectRevertIncorrectProof() internal { + vm.expectRevert(BatchingV1Lib.BatchingV1__IncorrectProof.selector); + } + function expectRevertInvalidEntryRange(uint64 dbNonce, uint64 start, uint64 end) internal { vm.expectRevert( abi.encodeWithSelector(IInterchainDB.InterchainDB__InvalidEntryRange.selector, dbNonce, start, end) @@ -749,4 +757,25 @@ contract InterchainDBSourceTest is Test, InterchainDBEvents { function test_getDBNonce() public { assertEq(icDB.getDBNonce(), INITIAL_DB_NONCE); } + + // ═══════════════════════════════════════════ TESTS: GET BATCH ROOT ═══════════════════════════════════════════════ + + function test_getBatchRoot(InterchainEntry memory entry) public { + entry.entryIndex = 0; + bytes32 batchRoot = icDB.getBatchRoot(entry, new bytes32[](0)); + assertEq(batchRoot, InterchainEntryLib.entryValue(entry)); + } + + function test_getBatchRoot_revert_nonZeroEntryIndex() public { + InterchainEntry memory entry = getInitialEntry(0); + entry.entryIndex = 1; + expectRevertIncorrectEntryIndex(1); + icDB.getBatchRoot(entry, new bytes32[](0)); + } + + function test_getBatchRoot_revert_nonEmptyProof() public { + InterchainEntry memory entry = getInitialEntry(0); + expectRevertIncorrectProof(); + icDB.getBatchRoot(entry, new bytes32[](1)); + } } diff --git a/packages/contracts-communication/test/harnesses/InterchainClientV1Harness.sol b/packages/contracts-communication/test/harnesses/InterchainClientV1Harness.sol deleted file mode 100644 index b679ffb650..0000000000 --- a/packages/contracts-communication/test/harnesses/InterchainClientV1Harness.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; - -import {InterchainClientV1} from "../../contracts/InterchainClientV1.sol"; -import {InterchainEntry} from "../../contracts/libs/InterchainEntry.sol"; - -contract InterchainClientV1Harness is InterchainClientV1 { - constructor(address interchainDB, address owner_) InterchainClientV1(interchainDB, owner_) {} - - /** - * @dev Harness for testing _getFinalizedResponsesCount function - */ - function getFinalizedResponsesCountHarness( - address[] memory approvedModules, - InterchainEntry memory icEntry, - bytes32[] calldata proof, - uint256 optimisticPeriod - ) - public - view - returns (uint256) - { - return _getFinalizedResponsesCount(approvedModules, icEntry, proof, optimisticPeriod); - } -} diff --git a/packages/contracts-communication/test/harnesses/InterchainEntryLibHarness.sol b/packages/contracts-communication/test/harnesses/InterchainEntryLibHarness.sol index 60811d657c..034e8e3a9f 100644 --- a/packages/contracts-communication/test/harnesses/InterchainEntryLibHarness.sol +++ b/packages/contracts-communication/test/harnesses/InterchainEntryLibHarness.sol @@ -20,4 +20,8 @@ contract InterchainEntryLibHarness { function entryValue(InterchainEntry memory entry) external pure returns (bytes32) { return InterchainEntryLib.entryValue(entry); } + + function getEntryValue(bytes32 srcWriter, bytes32 dataHash) external pure returns (bytes32) { + return InterchainEntryLib.getEntryValue(srcWriter, dataHash); + } } diff --git a/packages/contracts-communication/test/integration/PingPong.Dst.t.sol b/packages/contracts-communication/test/integration/PingPong.Dst.t.sol index 185815c8df..68a7d97bd2 100644 --- a/packages/contracts-communication/test/integration/PingPong.Dst.t.sol +++ b/packages/contracts-communication/test/integration/PingPong.Dst.t.sol @@ -88,7 +88,7 @@ contract PingPongDstIntegrationTest is PingPongIntegrationTest { function test_verifyRemoteBatch_state_db() public { module.verifyRemoteBatch(moduleBatch, moduleSignatures); skip(LONG_PERIOD); - assertEq(icDB.checkVerification(address(module), srcEntry, new bytes32[](0)), INITIAL_TS); + assertEq(icDB.checkBatchVerification(address(module), srcBatch), INITIAL_TS); } function test_interchainExecute_callPingPongApp() public { diff --git a/packages/contracts-communication/test/integration/legacy/LegacyPingPong.Dst.t.sol b/packages/contracts-communication/test/integration/legacy/LegacyPingPong.Dst.t.sol index 5cef5aea47..00c5d0280b 100644 --- a/packages/contracts-communication/test/integration/legacy/LegacyPingPong.Dst.t.sol +++ b/packages/contracts-communication/test/integration/legacy/LegacyPingPong.Dst.t.sol @@ -84,7 +84,7 @@ contract LegacyPingPongDstIntegrationTest is LegacyPingPongIntegrationTest { function test_verifyRemoteBatch_state_db() public { module.verifyRemoteBatch(moduleBatch, moduleSignatures); skip(LONG_PERIOD); - assertEq(icDB.checkVerification(address(module), srcEntry, new bytes32[](0)), INITIAL_TS); + assertEq(icDB.checkBatchVerification(address(module), srcBatch), INITIAL_TS); } function test_interchainExecute_callMessageBusAndLegacyPP() public { diff --git a/packages/contracts-communication/test/libs/InterchainEntryLib.t.sol b/packages/contracts-communication/test/libs/InterchainEntryLib.t.sol index ad65ca3d3e..33cdf9dafc 100644 --- a/packages/contracts-communication/test/libs/InterchainEntryLib.t.sol +++ b/packages/contracts-communication/test/libs/InterchainEntryLib.t.sol @@ -69,4 +69,16 @@ contract InterchainEntryLibTest is Test { bytes32 expected = keccak256(abi.encode(entry.srcWriter, entry.dataHash)); assertEq(libHarness.entryValue(entry), expected); } + + function test_getEntryValue() public { + bytes32 srcWriter = bytes32(uint256(4)); + bytes32 dataHash = bytes32(uint256(5)); + bytes32 expected = keccak256(abi.encode(srcWriter, dataHash)); + assertEq(libHarness.getEntryValue(srcWriter, dataHash), expected); + } + + function test_getEntryValue(bytes32 srcWriter, bytes32 dataHash) public { + bytes32 expected = keccak256(abi.encode(srcWriter, dataHash)); + assertEq(libHarness.getEntryValue(srcWriter, dataHash), expected); + } } diff --git a/packages/contracts-communication/test/mocks/InterchainDBMock.sol b/packages/contracts-communication/test/mocks/InterchainDBMock.sol index 98ba41f32f..434cb772c1 100644 --- a/packages/contracts-communication/test/mocks/InterchainDBMock.sol +++ b/packages/contracts-communication/test/mocks/InterchainDBMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.20; -import {IInterchainDB, InterchainEntry, InterchainBatch} from "../../contracts/interfaces/IInterchainDB.sol"; +import {IInterchainDB, InterchainBatch, InterchainEntry} from "../../contracts/interfaces/IInterchainDB.sol"; // solhint-disable no-empty-blocks contract InterchainDBMock is IInterchainDB { @@ -56,13 +56,14 @@ contract InterchainDBMock is IInterchainDB { function getNextEntryIndex() external view returns (uint64 dbNonce, uint64 entryIndex) {} - function checkVerification( + function checkBatchVerification( address dstModule, - InterchainEntry memory entry, - bytes32[] memory proof + InterchainBatch memory batch ) external view returns (uint256 moduleVerifiedAt) {} + + function getBatchRoot(InterchainEntry memory entry, bytes32[] memory proof) external pure returns (bytes32) {} } diff --git a/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol b/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol index fd37d9fdb2..486a15ae58 100644 --- a/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol +++ b/packages/contracts-communication/test/modules/SynapseModule.Destination.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.20; import {InterchainModuleEvents} from "../../contracts/events/InterchainModuleEvents.sol"; import {SynapseModuleEvents} from "../../contracts/events/SynapseModuleEvents.sol"; import {IInterchainModule} from "../../contracts/interfaces/IInterchainModule.sol"; -import {InterchainBatch, InterchainBatchLib} from "../../contracts/libs/InterchainBatch.sol"; +import {InterchainBatch} from "../../contracts/libs/InterchainBatch.sol"; import {ThresholdECDSALib} from "../../contracts/libs/ThresholdECDSA.sol"; import {SynapseModule} from "../../contracts/modules/SynapseModule.sol"; diff --git a/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol b/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol index 0abb1c1316..748758af0e 100644 --- a/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol +++ b/packages/contracts-communication/test/modules/SynapseModule.Source.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.20; import {InterchainModuleEvents} from "../../contracts/events/InterchainModuleEvents.sol"; import {SynapseModuleEvents} from "../../contracts/events/SynapseModuleEvents.sol"; import {IInterchainModule} from "../../contracts/interfaces/IInterchainModule.sol"; -import {InterchainBatch, InterchainBatchLib} from "../../contracts/libs/InterchainBatch.sol"; +import {InterchainBatch} from "../../contracts/libs/InterchainBatch.sol"; import {SynapseModule, ISynapseModule} from "../../contracts/modules/SynapseModule.sol"; import {InterchainBatchLibHarness} from "../harnesses/InterchainBatchLibHarness.sol";