dapptools icon indicating copy to clipboard operation
dapptools copied to clipboard

hevm: enchanced control over blockchain context

Open d-xo opened this issue 4 years ago • 7 comments

  • Adds a DAPP_TEST_NONCE env var that allows users to control the nonce assigned to the test contract
  • Adds unit tests for the various DAPP_TEST_* env vars

cc: @kmbarry1 you were asking for this a while back I believe?

d-xo avatar Jul 29 '21 10:07 d-xo

cc: @kmbarry1 you were asking for this a while back I believe?

Hey! Yeah, this gets partially at what I was thinking of. The even more powerful thing would actually be what you suggested in chat, a general hevm cheat code for setting any env value, i.e. hevm.set("nonce", N) or hevm.set("currentAddress", 0x1234), etc.

kmbarry1 avatar Jul 29 '21 20:07 kmbarry1

Yeah definitely agree re: the cheat code, but that's a bit of a bigger job for another day.

d-xo avatar Jul 29 '21 20:07 d-xo

Yeah definitely agree re: the cheat code, but that's a bit of a bigger job for another day.

Sounds good--and I might still take a crack at it if ever I have some free time :sweat_smile: .

kmbarry1 avatar Jul 29 '21 21:07 kmbarry1

So I ended up adding the cheatcodes.

I played around with a cheatcode that could change the address of any contract (hevm.file("address", usr, newAddress)), but there are quite a few places in hevm where we expect addresses to stay constant (e.g. we make multiple calls into the same address when running unit tests), and it just felt like it was gonna be more trouble than it was worth to add.

In the end I added the following:

/*
    allows setting the nonce and balance of an arbitrary account:

      hevm.file("nonce", usr, amt)
      hevm.file("balance", usr, amt)
*/
hevm.file(bytes32, address, uint)

/*
    allows setting the caller, origin, and coinbase:

      hevm.file("caller", usr)
      hevm.file("origin", usr)
      hevm.file("coinbase", usr)
*/
hevm.file(bytes32, address)

/*
    allows setting gas price, tx gas limit, block gas limit, and difficulty:

      hevm.file("gasPrice", amt)
      hevm.file("txGasLimit", amt)
      hevm.file("blockGasLimit", amt)
      hevm.file("difficulty", amt)
*/
hevm.file(bytes32, uint)

/*
    allows reading the nonce for any address:

      hevm.look("nonce", usr);
*/
hevm.look(bytes32, address)

/*
    allows reading the txGasLimit

      hevm.look("txGasLimit");
*/
hevm.look(bytes32)

/*
    allows replacing the code at any address (except the currently executing contract)
*/
hevm.replace(address, bytes)

I think these give almost exactly the same level of control as the DAPP_TEST* env vars, but inside of unit tests via cheat codes. I wasn't completely sure about the interface for the look cheat codes, since they both only have one allowed value for the bytes32 param, but I kinda liked the consistency of the interface, open to suggestions if someone has a better idea.

@kmbarry1 I think with replace and file("nonce", val) you should be able to do what you wanted with bytecode verification? I think you should be able to use replace to set the code of the adress you want to deploy from to a contract that just deploys the contract you want to verify and use file to set the nonce. Is that enough or did you need something more?

d-xo avatar Aug 02 '21 19:08 d-xo

hollllyyyy cow this is amazing @d-xo. only thing that i think is left out that i would kill to have is the ability to change the address of the test contract like you can with DAPP_TEST_ADDRESS but I know you said thats infeasible 😭

transmissions11 avatar Aug 02 '21 19:08 transmissions11

only thing that i think is left out that i would kill to have is the ability to change the address of the test contract like you can with DAPP_TEST_ADDRESS

@TransmissionsDev Do you have an example of something that you could do with mutable adresses that you cannot do with mutable code?

d-xo avatar Aug 03 '21 11:08 d-xo

only thing that i think is left out that i would kill to have is the ability to change the address of the test contract like you can with DAPP_TEST_ADDRESS

@TransmissionsDev Do you have an example of something that you could do with mutable adresses that you cannot do with mutable code?

no, just more convenient hehe. if i was forking mainnet and wanted to adopt the address of some authorized user, much easier to just go hevm.become(0xaa); thing.auth(); vs having to deploy a new contract, that has a method to call auth, etc

will still be awesome tho, forgot about the type(TestContract).creationCode syntax, was imagining it would be harder to load in bytecode

transmissions11 avatar Aug 03 '21 15:08 transmissions11