
IntegrityProof
Proof of Bundle Integrity allows bundle senders to express exact slot he/she wants his/her bundle to be placed on a block and trustlessly prove whether a block builder has tempered with the bundle leveraging zero knowledge proof
About
## Goals - prove that bundle has not been tempered with - enable trustless slot selection --- ## Requirements - A challenger should be able to prove the block builder has tempered with the bundle - Bundle sender should not be able to game the system - Block builder should not be able to game the system - A bundle sender should be able to express slot preference to a block builder --- ## Description - There will be only one contract, call it `proofOfIntegrity.sol` - When new bundle is submitted, a sender should include a tx calling the `stamp()` function of the `proofOfIntegrity.sol` contract - `stamp(Txs tx, uint blockNumber, uint bundleIndex)` - take in all of the transactions in a bundle. `Txs` is an array that takes in a contract defined `Transaction` type i.e. `struct Transaction` - the function calculate the hash using `keccak256` , count the tx number in the bundle, and use `blockNumber` and `msg.sender` to update to mappings - `mapping(address => (mapping(uint = > uint))) public bundleSizeMap` - this is a mapping `senderAddress` ⇒ `blockNumber` ⇒ `bundleSize` - `mapping(address => (mapping(uint => bytes))) public bundleHash` - this is a mapping `senderAddress` ⇒ `blockNumber` ⇒ `bundleHash` - Additionally, function will update another mapping - `mapping(address => (mapping uint => uint)) bundleIndexMap` - this is a mapping `senderAddress` ⇒ `blockNumber` ⇒ `bundleIndex` - Note: `bundleIndex` is to express the slot number a bundle wants to be placed in the block. The top slot a bundle can express is 2, since the slot 1 will always be taken by the `verifyBundle()` function invoked by the block builder(more on this later) - Then, the function will check the value in the `mapping(address => (mapping uint => bool)) bundleVerificationMap` . If the ending `bool` is the default value `0`, then the function reverts with log `bundleVerificationMap not updated` - Note: the reason why it needs to revert is because it forces the block builder to insert a `verifyBundle()` transaction call on the top of the bundle. This will also let the block builder know that the sender has requested that he/she wants the bundle to be later subject to proof-of-integrity - this is a mapping `senderAddress` ⇒ `blockNumber` ⇒ `verified` - this mapping can only be updated by the `verifyBundle()` function(more on this in the following section) - when the bundle is submitted, the block builder needs to call the `verifyBundle()` function, and this function can only be called by a whitelisted block builders in a `whitelist` mapping - `verifyBundle(Txs txs, address sender, uint blockNumber) onlyBlockBuilder returns(bundleIndex)` - Note:`onlyBlockBuilder` is a modifier checking whether the caller is in the `whitelist` - the purpose of this function is to make sure that the value in the `bundleSize` , `bundleHash`, inputted by the bundle sender is correct because bundle sender could game the system by randomly putting the arbitrary `bundleSize` and `bundleHash` - The block builder will need to supply the three arguments `txs`, `sender`, `blockNumber`. All three of these values can be found the in the bundle submitted by the bundle sender - in the function, it’ll do the following: - get the length of `txs`, and use `sender` and `blockNumber` to query the `bundleSizeMap` . If match, continue; otherwise revert - calculate the `bundleHash` from the `txs`, and use `sender` and `blockNumber` to query the `bundleHashMap`. if match, continue; otherwise revert - Update the `bundleVerificationMap` to true by providing the `sender` and `blockNumber` - returns the `bundleIndexMap` to get the index a bundle sender wants - If the bundle index is accepted by the block builder, the block builder will add the bundle, with the tx calling `verifyBundle()` on the top of the bundle, to the block. Otherwise, the block builder discard the bundle. - Note: `verifyBundle()` can be called in a simulation to get the `bundleIndexMap` 💡 Technically, a block builder can still temper the bundle after this step. A malicious block builder could call the `verifyBundle()` function first, then to change the ordering, or insert its own transaction in the middle of the bundle, and include the tempered bundle into the block. All of the previous steps are for a block builder to verify the arguments supplied by the bundle sender in `stamp()`function is correct. This is why we need the following steps - After the block has been built and mined on-chain. A third party could challenge by submitting a proof of integrity using Axiom V2 - In a challenge, a user could use a front-end application to query two values leveraging Axiom V2 - bundle hash: - The front end app would require a user to provide two values: `senderAddress` and `blockNumber` - the address is the bundle sender’s address, and `blockNumber` is the block when bundle was submitted - the front-end app will call the Axiom V2 API to query the block info. In the payload, the front-end app would find the bundle submitted by the `sender` by indexing the `senderAddress`. - Then, the front-end app would query the `bundleSizeMap` and `bundleHashMap` to get the `bundleSize` and `bundleHash`, given the `senderAddress` and `blockNumber` - By using the index number on a block, plus the bundle size, the front-end app could generate a `bundleHash` value in the browser. If it matches the `bundleHash` result from the Axiom V2 API, then it mean bundle was not tempered with; otherwise, it means the bundle has been tempered - submit the proof to a staking contract where block builder’s stake will be slashed - Bundle index: - using similar method, the front-end app could get the `bundleIndex` to see if the block builder actually put the bundle at the slot number a bundle sender requested in the `stamp()` function
How it's made
It's made using Axiom's V2 to trustlessly prove the behavior of a block builder. Front-end is generated using Axiom V2's repl export feature. Additionally, a mock block builder to test the mechanism has also been provided. The mechanism works mostly by allowing sender and blockbuilder respectively insert transactions at the bottom and top of a bundle