From 94d966eba641f5db96d473b1dc1fe198e664c1f8 Mon Sep 17 00:00:00 2001 From: Kartik Chopra Date: Mon, 27 Nov 2023 10:28:57 -0800 Subject: [PATCH 1/3] Adds bundles to oracle matching. --- contracts/Oracle.sol | 23 ++++++++++++++++++++--- test/OracleTest.sol | 9 ++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/contracts/Oracle.sol b/contracts/Oracle.sol index ff9a618..8ad6ce0 100644 --- a/contracts/Oracle.sol +++ b/contracts/Oracle.sol @@ -44,7 +44,7 @@ contract Oracle is Ownable { // mapping of txns to bool to check if txns exists // Stores all proccessed txns for onw // TODO(@ckartik): This may be too restricvie in the log run as an appraoch - mapping(string => bool) txnHashes; + mapping(string => uint) txnHashes; // Event to request block data @@ -82,7 +82,7 @@ contract Oracle is Ownable { address builder = blockBuilderNameToAddress[blockBuilderName]; for (uint256 i = 0; i < txnList.length; i++) { - txnHashes[txnList[i]] = true; + txnHashes[txnList[i]] = i+1; } // Placeholder: Process the block data and determine the commitment's validity @@ -91,7 +91,24 @@ contract Oracle is Ownable { for (uint256 i = 0; i < commitmentHashes.length; i++) { IPreConfCommitmentStore.PreConfCommitment memory commitment = preConfContract.getCommitment(commitmentHashes[i]); if (commitment.commiter == builder) { - if (txnHashes[commitment.txnHash]){ + bool commitmentSucceeded = true; + + // TODO(@ckartik): Ensure we check for correct encoding during commtiment storage. + (string[] memory commitedTransactions) = abi.decode(bytes(commitment.txnHash), (string[])); + + // Determine if bundle order was satisfied + for (uint256 j = 0; j < commitedTransactions.length; j++) { + if (txnHashes[commitedTransactions[j]] == 0) { + commitmentSucceeded = false; + break; + } + if (j+1 < commitedTransactions.length && txnHashes[commitedTransactions[j]] + 1 == txnHashes[commitedTransactions[j+1]]) { + commitmentSucceeded = false; + break; + } + } + + if (commitmentSucceeded){ this.processCommitment(commitmentHashes[i], false); } else { diff --git a/test/OracleTest.sol b/test/OracleTest.sol index 629d985..0ec7cb8 100644 --- a/test/OracleTest.sol +++ b/test/OracleTest.sol @@ -199,7 +199,9 @@ contract OracleTest is Test { providerRegistry.registerAndStake{value: 250 ether}(); vm.stopPrank(); - constructAndStoreCommitment(bid, blockNumber, txnList[0], userPk, providerPk); + bytes memory txnhashList = abi.encode(txnList); + + constructAndStoreCommitment(bid, blockNumber, string(txnhashList), userPk, providerPk); vm.prank(address(0x6d503Fd50142C7C469C7c6B64794B55bfa6883f3)); oracle.addBuilderAddress("kartik builder", provider); vm.expectEmit(true, true, false, true); @@ -235,8 +237,9 @@ contract OracleTest is Test { uint256 ogStake = providerRegistry.checkStake(provider); - string memory commitedTxn = string(abi.encodePacked(keccak256("0xSlash"))); - constructAndStoreCommitment(bid, blockNumber, commitedTxn, userPk, providerPk); + string[] memory commitedTxnList = new string[](1); + commitedTxnList[0] = string(abi.encodePacked(keccak256("0xSlash"))); + constructAndStoreCommitment(bid, blockNumber, string(abi.encode(commitedTxnList)), userPk, providerPk); vm.prank(address(0x6d503Fd50142C7C469C7c6B64794B55bfa6883f3)); oracle.addBuilderAddress("kartik builder", provider); vm.expectEmit(true, true, false, true); From d58747f1d93ef0e859cb7c1b03959d5413ab4dc0 Mon Sep 17 00:00:00 2001 From: Kartik Chopra Date: Mon, 27 Nov 2023 10:35:39 -0800 Subject: [PATCH 2/3] nit bug fix to ensure bundle proccesed correctly. --- contracts/Oracle.sol | 4 ++-- test/OracleTest.sol | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/contracts/Oracle.sol b/contracts/Oracle.sol index 8ad6ce0..507853b 100644 --- a/contracts/Oracle.sol +++ b/contracts/Oracle.sol @@ -95,14 +95,14 @@ contract Oracle is Ownable { // TODO(@ckartik): Ensure we check for correct encoding during commtiment storage. (string[] memory commitedTransactions) = abi.decode(bytes(commitment.txnHash), (string[])); - // Determine if bundle order was satisfied for (uint256 j = 0; j < commitedTransactions.length; j++) { if (txnHashes[commitedTransactions[j]] == 0) { + commitmentSucceeded = false; break; } - if (j+1 < commitedTransactions.length && txnHashes[commitedTransactions[j]] + 1 == txnHashes[commitedTransactions[j+1]]) { + if (j+1 < commitedTransactions.length && txnHashes[commitedTransactions[j]] + 1 != txnHashes[commitedTransactions[j+1]]) { commitmentSucceeded = false; break; } diff --git a/test/OracleTest.sol b/test/OracleTest.sol index 0ec7cb8..a0e5620 100644 --- a/test/OracleTest.sol +++ b/test/OracleTest.sol @@ -215,6 +215,45 @@ contract OracleTest is Test { } + function test_ReceiveBlockDataWithCommitmentsBundle() public { + string[] memory txnList = new string[](3); + txnList[0] = string(abi.encodePacked(keccak256("0xfrontrun"))); + txnList[1] = string(abi.encodePacked(keccak256("0xmev"))); + txnList[2] = string(abi.encodePacked(keccak256("0xbackrun"))); + + uint64 blockNumber = 200; + uint64 bid = 2; + string memory blockBuilderName = "kartik builder"; + (address user, uint256 userPk) = makeAddrAndKey("alice"); + (address provider, uint256 providerPk) = makeAddrAndKey("kartik"); + + vm.deal(user, 200000 ether); + vm.startPrank(user); + userRegistry.registerAndStake{value: 250 ether }(); + vm.stopPrank(); + + vm.deal(provider, 200000 ether); + vm.startPrank(provider); + providerRegistry.registerAndStake{value: 250 ether}(); + vm.stopPrank(); + + bytes memory txnhashList = abi.encode(txnList); + + constructAndStoreCommitment(bid, blockNumber, string(txnhashList), userPk, providerPk); + vm.prank(address(0x6d503Fd50142C7C469C7c6B64794B55bfa6883f3)); + oracle.addBuilderAddress("kartik builder", provider); + vm.expectEmit(true, true, false, true); + emit BlockDataReceived(txnList, blockNumber, blockBuilderName); + oracle.receiveBlockData(txnList, blockNumber, blockBuilderName); + + bytes32[] memory commitmentHashes = preConfCommitmentStore.getCommitmentsByBlockNumber(blockNumber); + assertEq(commitmentHashes.length, 1); + assertEq(userRegistry.getProviderAmount(provider), bid); + + } + + + function test_ReceiveBlockDataWithCommitmentsSlashed() public { string[] memory txnList = new string[](1); txnList[0] = string(abi.encodePacked(keccak256("0xkartik"))); From 068ef3df946e8e9df5463f7d255dba908a18d7f6 Mon Sep 17 00:00:00 2001 From: Kartik Chopra Date: Mon, 27 Nov 2023 10:42:27 -0800 Subject: [PATCH 3/3] add test for unbundling attack slashing. --- test/OracleTest.sol | 50 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/test/OracleTest.sol b/test/OracleTest.sol index a0e5620..c52db4e 100644 --- a/test/OracleTest.sol +++ b/test/OracleTest.sol @@ -253,6 +253,56 @@ contract OracleTest is Test { } + function test_ReceiveBlockDataWithCommitmentsBundleNotAtomicMustSlash() public { + string[] memory commitedTxnList = new string[](3); + commitedTxnList[0] = string(abi.encodePacked(keccak256("0xfrontrun"))); + commitedTxnList[1] = string(abi.encodePacked(keccak256("0xmev"))); + commitedTxnList[2] = string(abi.encodePacked(keccak256("0xbackrun"))); + + string[] memory builderPayload = new string[](4); + builderPayload[0] = string(abi.encodePacked(keccak256("0xfrontrun"))); + builderPayload[1] = string(abi.encodePacked(keccak256("0xmev"))); + builderPayload[2] = string(abi.encodePacked(keccak256("0xbuilderbackrun"))); + builderPayload[3] = string(abi.encodePacked(keccak256("0xbackrun"))); + + uint64 blockNumber = 200; + uint64 bid = 2; + string memory blockBuilderName = "kartik builder"; + (address user, uint256 userPk) = makeAddrAndKey("alice"); + (address provider, uint256 providerPk) = makeAddrAndKey("bob"); + + vm.deal(user, 200000 ether); + vm.deal(provider, 200000 ether); + + vm.startPrank(user); + userRegistry.registerAndStake{value: 250 ether }(); + vm.stopPrank(); + + vm.startPrank(provider); + providerRegistry.registerAndStake{value: 250 ether}(); + vm.stopPrank(); + + uint256 ogStake = providerRegistry.checkStake(provider); + + constructAndStoreCommitment(bid, blockNumber, string(abi.encode(commitedTxnList)), userPk, providerPk); + vm.prank(address(0x6d503Fd50142C7C469C7c6B64794B55bfa6883f3)); + oracle.addBuilderAddress("kartik builder", provider); + vm.expectEmit(true, true, false, true); + emit BlockDataReceived(builderPayload, blockNumber, blockBuilderName); + oracle.receiveBlockData(builderPayload, blockNumber, blockBuilderName); + + bytes32[] memory commitmentHashes = preConfCommitmentStore.getCommitmentsByBlockNumber(blockNumber); + assertEq(commitmentHashes.length, 1); + + // Ensuring no rewards + assertEq(userRegistry.getProviderAmount(provider), 0); + + // Detect slashing + uint256 postSlashStake = providerRegistry.checkStake(provider); + assertEq(postSlashStake + bid, ogStake); + assertEq(userRegistry.checkStake(user), 250 ether); + + } function test_ReceiveBlockDataWithCommitmentsSlashed() public { string[] memory txnList = new string[](1);