4

I was wondering if anyone knows a way of how to prove that a certain function of a solidity smart contract was executable (i.e. not reverting) after the fact without calling the function itself, e.g. by proving that a past state would have resulted in the function to execute successfully.


EDIT:

Complexity arises due to the fact that the proof should be done on-chain, after the function was executable in the past. I.e. one would require some sort of proof that can be verified on-chain that the EVMs state in the past would have allowed a particular function to return a certain value, without sending a tx to the function at the time it should become available.


Example:

contract Test 
{

    uint256 public testNum;
    address public owner;

    constructor () public 
    {
        owner = msg.sender;
        testNum = 1;
    }



    function returnTrueIfGreaterThanTen()
        public view returns(bool)
    {
        require(testNum > 10);
        return true;
    }
    // WE DONT KNOW AT WHAT BLOCK THIS FUNCTION WILL BE CALLED and CANNOT CHANGE ITS CONTENT
    function setTestNum(uint256 _newNum) 
        onlyOwner
    {
        testNum = _newNum;
    }
}

In this case, is there a way to prove on-chain at block height 100 that returnTrueIfGreaterThanTen() was returning true at block height 90 in the past, without actually calling the function at the time it becomes executable (at block height 90)?

In other words, can I check whether someone should call a function without calling it myself and punish this person for not calling the function retrospectively by proving that the person could have indeed successfully called that function in the past?

An idea would be for example implementing a view function that, given the correct state of the EVM at block 90, returns a value that proves when submitted at block 100, that the function was indeed executable and returning true.

  • 1
    Are you looking for a solution that offers this information on-chain (within the smart contract)? Or one to verify it off-chain? – iamdefinitelyahuman Nov 4 '19 at 18:19
  • 1
    @iamdefinitelyahuman the fact that the tx was executable in the past needs to be proven on-chain (within the smart contract), in order to slash the stake of the party that did not transact. The proof could however be created off-chain and then later be submitted on-chain. – hilmarx Nov 4 '19 at 18:25
1

Simply use the call function with the blockIdentifier parameter, point at the block you prefer, like this:

const blockNumber = 100000;
myContract.returnTrueIfGreaterThanTen().call({from: "0x........"}, blockNumber,
     (err, result) => {
        if (err) { 
          console.log(err);
        } else {
          console.log(result);
        }
});

This will be executed locally in any node, so all participants can check it out as well.

| improve this answer | |
  • But how do you cryptographically prove on-chain that the function actually returned true at some block height in the past without running risk of someone submitting a false claim? – hilmarx Nov 5 '19 at 12:07
  • There's no need to store an online cryptographic proof when all participants can know offline whether the execution would succeed or not, isn't it? In any case, you could store sha3(blockNumber, result, [other parameters...]) as a cryptographic proof in a bytes32 solidity type. All nodes can compute that operation and obtain the exact same hash. Does this suffice? – Molina Nov 5 '19 at 13:25
  • That is exactly the crux of the problem, to be able to verify "on-chain" that something was executable "without" having to send a transaction and store data on-chain, but rather by somehow being able to prove that a past state would have allowed a function to be executed successfully. Thanks for trying anyway, it is a hard one, I know. – hilmarx Nov 11 '19 at 16:35
0

In your specific example, I would add another storage variable historicTestNum that updates when setTestNum is called, only if the block height is currently <=90. This way, regardless of actions after block 90, you can always know what the value of testNum was at block 90. You can add a view function to verify that at 90 it was in fact greater than ten.

Here is a modified example of your contract that implements what I describe. This approach is not the most elegant or gas efficient, but I hope it serves as a starting point for you to develop your own model to achieve your goal.

contract Test {

    uint256 public testNum;
    uint256 public historicTestNum;
    address public owner;

    constructor () public 
    {
        owner = msg.sender;
        testNum = 1;
        historicTestNum = 1;
    }

    function returnTrueIfGreaterThanTen()
        public view returns(bool)
    {
        require(testNum > 10);
        return true;
    }

    function setTestNum(uint256 _newNum) 
        onlyOwner
    {
        testNum = _newNum;
        if (block.number <= 90) {
            historicTestNum = testNum;
        }
    }

    function returnTrueIfHistoricGreaterThanTen()
        public view returns(bool)
    {
        return (block.number > 90 && historicTestNum > 10);
    }

}
| improve this answer | |
  • Thanks, but I gave the example of the known blocknumber only to illustrate the problem. What I'm asking is, if there is a way to prove retrospectively, without knowing at what block number the function becomes executable, that a function became executable at a given block height. Let's say no one knows when returnTrueIfGreaterThanTen() will return true and we cannot change anything in the function that actually sets the value determining the outcome of the function (in this case setTestNum). Would there be a way to know that the former function would return true in a past evm state? – hilmarx Nov 5 '19 at 12:05
  • + We cannot change the function that actually changes the value (in this case setTestNum) which makes the function that we care about (returnTrueIfGreaterThanTen) executable. – hilmarx Nov 5 '19 at 12:11
  • Ahh ok. Sorry, I read your question too literally perhaps. Will have to rethink. – iamdefinitelyahuman Nov 5 '19 at 12:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.