Skip to content

Dryrunning a Trap ⛓️

Ideally you would be able to test your trap with real block/state data before deploying it for real, on-chain. Well, with the dryrun command you can. In normal trap operation, a trap will be "monitored" by one or more opted-in operators, but with the dryrun command you can easily test two lifecycles (a bootstrap and a normal lifecycle) of this same process on your local machine with what is for all intents and purposes, a locally spun-up ad-hoc operator.

Under The Hood

The lifecycle will be performed with block(s) pulled from your specified evm endpoint, ethereum_rpc in your drosera.toml config file. The number of blocks pulled is determined by your configured block_sample_size (also drosera.toml) for the trap.

Lifecycle

  1. The block_sample_size latest blocks are processed by the trap's collect function:

    • Bootstrap Lifecycle: For the first lifecycle, the system starts from scratch with no cached data. It fetches each block from your RPC endpoint and runs the collect function on it. During this process, account and slot data are fetched one by one, as needed during trap (solidity contract) execution. All collect results are then cached for future use.

    • Runtime Lifecycle: For subsequent lifecycles, the system has cached results for collect calls on previous blocks. This way it only needs to run collect for the one new block. This one collect also runs faster as potential needed account and slot data are pre-fetched in a batch call, so the trap runs much faster due to significantly less RPC calls being made.

  2. The outputs of the collect calls are passed as input to one call of the should_respond function.

  3. should_respond will return a value of false for do nothing, or true for execute the specified response_function (drosera.toml).

You've now been able to verify that your trap is functioning end-to-end, as if it was already deployed to the Drosera network.

Example

Command: drosera dryrun dryrun example run This trap has a block_sample_size of 3 in this example, so each lifecycle performs 3 collects. The 1st (bootstrap) lifecycle starts with no cached collect results so it has to perform all of the computation and block fetching, resulting in a longer lifecycle time of 5.25 seconds compared to the 2nd lifecycle's 2.42 seconds. In the 2nd (normal) lifecycle, it speeds through collects for blocks 4,203,641 and 4,203,642 because the collect results for those blocks were already computed in the previous lifecycle, saving RPC network call time and collect computation time. Only until it reaches the new block of 4,203,643 that it hasn't encountered before, does it have to fetch it from the RPC and run the collect function on it. So the bootstrap lifecycle always takes longer than normal lifecycles.

Theory-crafting

With the optional --block-number argument, dryrun can be used to test traps on past state. This allows anything from more robust testing of a trap, all the way to verifying that a trap successfully catches a past exploit. An excellent addition to the security researcher tool belt.

How To Run

drosera dryrun --block-number <block_number>

where --block-number is optional. Without, it defaults to the current block number.

Lifecycle Limitations

With traps, you have significantly more gas to work with than a contract on-chain. Blocks on Ethereum currently have a total block.gasLimit of ~30 million gas units. So the sum of gas used by all transactions in a block cannot excede this number. In another stratosphere, Drosera is configured to allow up to 1 billion gas units per collect function and 1 billion gas units per shouldRespond function. This means that one trap lifecycle with a block_sample_size of 1 could use up to 2 billion gas units, or approximately 66x more gas than what can fit in an entire Ethereum block.

But, with great power comes great responsibility. Ethereum blocks average about 12 seconds per block, and so in order for a trap to retain its ability of responding in the next block after the configured condition is detected (shouldRespond returns true), it needs to be able to be executed within a few seconds by the recommended system requirements. If the trap takes too long to execute on recommended spec operator hardware, then the operators running the trap will struggle or be unable to keep up with Ethereum block times and begin falling further and further behind.

dryrun long running warning

Therefore dryrun has a safety check built in. If a trap's normal lifecycle (>= 2nd lifecycle) takes longer than a recommended upper time limit, it will emit a warning. dryrun is running on your local computer, so if your computer specs are equal to or lower than the recommended operator specs, this trap (when deployed) may struggle or entirely fail to keep up with on-chain blocks, thus falling behind and either reducing the effectivness of the trap or defeating its security use case entirely. If your computer specs are better than the recommended operator specs, and dryrun yields this warning, the trap will most certainly have the previously mentioned issues when deployed. Additionally, for certain trap designs querying many accounts/slots, RPC latency may be a factor at play here as well.