2

I'm using redspot for integration tests. I have some contracts features involving with block timestamp. How can I manipulate the block timestamp in substrate-contracts-node?

2 Answers 2

3

You can't do this via an existing method in an integration test as none exists but there is a workaround for ink unit tests.

The test environment increases the block timestamp by a known amount each block:

    /// Advances the chain by a single block.
    pub fn advance_block(&mut self) {
        self.exec_context.block_number += 1;
        self.exec_context.block_timestamp += self.chain_spec.block_time;
    }

This means you will be able to determine the block_timestamp if you know the number of blocks that have passed. The substrate-contracts-node does not auto produce blocks in its default setup. It only produces blocks when it receives a transaction (this is known as instant seal). Therefore, if you begin your test at block X at block_timestamp_start and you have issued 5 transactions by the end of your test, the block_timtestamp_end could be calculated by something similar to this:

block_timestamp_end = block_timestamp_start + 5 * chain_spec.block_time

Block timestamp could therefore be manipulated to a known value using the same process.

5
  • Where does the chainspec.block_time comes from? I thought that the timestamp of each block is the now() timestamp.
    – Daniel Lam
    Commented May 31, 2022 at 14:18
  • Hi @forgetso, can you please check my comment. Tks
    – Daniel Lam
    Commented Jun 1, 2022 at 15:48
  • Apologies Daniel, I was referring to the ink unit test environment but I now see that you are looking to run integration tests. The solution above will not work for integration tests and I've highlighted this
    – forgetso
    Commented Jun 1, 2022 at 16:13
  • The reason why I used integration test is because the contracts needs cross-call to another contracts. AFAIK, we can't do this in unit test. To be more specific, we actually re-implement UniswapV2 in ink!. We have a pool contract that depends on two psp22 tokens contract. Is there a way to mock these two psp22 token contracts in unit tests? Tks alot @forgetso
    – Daniel Lam
    Commented Jun 1, 2022 at 17:21
  • Cross contract calls are not possible in ink unit tests currently. If you need to use block timestamps in integration tests you will have to setup your contract data so that the timestamps reflect the test outcome you require. You won't be able to manipulate the timestamps of blocks without manually editing the database or switching the chain data between tests.
    – forgetso
    Commented Jun 1, 2022 at 19:31
3

The Timestamp pallet has a helper function for tests and benchmarks called set_timestamp:

https://github.com/paritytech/substrate/blob/master/frame/timestamp/src/lib.rs#L283

/// Set the timestamp to something in particular. Only used for tests.
#[cfg(any(feature = "runtime-benchmarks", feature = "std"))]
pub fn set_timestamp(now: T::Moment) {
    Now::<T>::put(now);
}

This may be what you are looking for, at least within writing integration tests on a Substrate node.

2
  • Tks for the suggestion. I'm trying to find a solution that can set the timestamp from the client as part of the test. It should behave as evm_increaseTime rpc supported in hardhat node.
    – Daniel Lam
    Commented Jun 2, 2022 at 8:06
  • 1
    Perhaps you could create a custom RPC that can be called by the JS environment. This custom RPC call could make use of the Timestamp pallet, as suggested by Shawn.
    – forgetso
    Commented Jun 2, 2022 at 9:07

Your Answer

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

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