2

I recently read this paper on designing secure smart contracts, and it gives the following modifier to ensure that when an EOA (or contract address) interacts with your original contract that the values of the variables stored in the contract are predictable and do not change before their transaction is mined.

uint private transitionCounter = 0;

modifier transitionCounting(uint nextTransitionNumber) {
require(nextTransitionNumber == transitionCounter);
transitionCounter += 1;
_;}

Is there a way to write a test in JavaScript or Solidity for Truffle that would test the modifier above? Overall, you would need to simulate two transactions mined varying speeds, but is that possible with these tests? Or else how would you properly test this?

1 Answer 1

1

Having looked at the doc you linked, I don't think you need to simulate transactions happening at varying speeds. Since you also submit the nextTransitionCounter to the functions that you declare that modifier on, you can just submit two transactions each with the same nextTransitionCounter and assert that the second one fails.

To assert that a transaction has failed you can use this function which should work for both testrpc and live chains:

const assertThrows = (contractMethodCall) => {
    return new Promise((resolve, reject) => {
        try {
            resolve(contractMethodCall())
        } catch (error) {
            reject(error)
        }
    })
        .then(transaction => {
            // This asserts the mined transaction has failed, this occurs on live chains
            // or when a transaction is successful on testrpc.
            assert.equal(transaction.receipt.status, 0, "Transaction successful")
        })
        .catch(error => {
            // On testrpc a failed transaction is not mined but throws an error instead.
            // This checks for the term "revert" in the error and ignores it if it contains
            // it, declaring the test successful. It will re-throw any other errors.
            if ((error + "").indexOf("revert") < 0) {
                throw error
            }
        }) 
}

Example use in a test:

it("Test function reverts", async () => {
    await assertThrows(() => testContract.failingFunc())
})

Where testContract is an instance of your contract and failingFunc() is a function expected to fail/revert.

4
  • Thank you, really good idea, hadn't thought about it this way. Since transitionCounter is what is being fed into the modifier via nextTransitionNumber, what I am thinking is to use Solidity tests to create a proxy contract to change transitionCounter prior to attempting to execute the second transaction so that the first & second transaction would both have the same transitionCounter. This also brings to mind how I can test order of transactions generally. In regards to testing, I still wonder how robust this test would be considered, but this is a great way to work with it, thank you!
    – Karen S
    Jan 22, 2018 at 18:48
  • No worries! In response though, in reality, the transitionCounter will never be the same for both the first & second transactions, even if they're executed in the same block, as all transactions are executed sequentially by the EVM. The modifier also relies on this fact to be true otherwise it would not restrict access to the execution of a function when it should. Also given the sequential nature of the EVM, you can test the outcome for different orders of two transactions by creating two tests, one for each order. Can you comment on what makes you feel the above isn't very robust?
    – willjgriff
    Jan 22, 2018 at 20:50
  • Right, that's why I'm curious if there's any other way to possibly test. Really I just have a penchant for validation through testing and given some variability with gas prices, I extrapolated to thinking about whether there is a way to ensure transactions can be mined sequentially as well at various gas prices, so just experimenting here. With legal implications and discussion about when to consider something in the Ethereum blockchain finite/immutable, its an interesting case to consider.
    – Karen S
    Jan 23, 2018 at 14:45
  • Fair enough, I believe the modifier you've linked to will enable this. However, regarding varying gas prices, if there are transactions with a high, mineable gas price with a transitionCounter that is higher than a transaction with a low, unmineable gas price then the higher gas price transaction will be mined and gas will be wasted. I'm not sure if you can force transactions to happen in a specific order, without wasting gas, without some degree of centralisation.
    – willjgriff
    Jan 23, 2018 at 15:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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