[Test] Unable to use `Test.moveTime`
Opened this issue ยท 4 comments
Current Behavior
Using Test.moveTime
doesn't seem to impact the timestamp of a block
Expected Behavior
Test.moveTime should result in getCurrentBlock().timestamp
changing
Steps To Reproduce
pub fun testMoveTime() {
let before = getCurrentBlock().timestamp
Test.moveTime(by: 1.0)
let after = getCurrentBlock().timestamp
assert(after - before >= 1.0) // this always fails
}
Also fails if you use scripts to obtain the time instead of using the testing framework directly:
pub fun getCurrentTime(): UFix64 {
return scriptExecutor("util/get_current_time.cdc", [])! as! UFix64
}
pub fun testMoveTime() {
let before = getCurrentTime()
Test.moveTime(by: 1.0)
heartbeat()
let after = getCurrentTime()
assert(after - before == 1.0)
}
Script:
pub fun main(): UFix64 {
return getCurrentBlock().timestamp
}
Environment
- Cadence version: v1.9.2
- Network: Testing Framework
Did some further debugging. Seems like this actually works when you grab time directly from the Blockchain itself, you cannot use the testing framework's time. So anyone who uses Test.moveTime
needs to ensure they're grabbing time with a helper script like what I had to do.
It seems like the use of log threw some of this off when running directly in the vscode extension, once I removed all logs, things passed as expected so long as I only grabbed timestamps using a script of some kind
Final piece I've found is that Test.moveTime
seems to only work with whole numbers, but it accepts a UFix64
pub fun testMoveTime() {
let before = getCurrentTime()
Test.moveTime(by: 1.5)
let after = getCurrentTime()
log(before)
log(after)
assert(after - before >= 1.5)
}
Logs out:
9:33AM INF LOG: 1703698412.00000000
9:33AM INF LOG: 1703698413.00000000
Thanks for the report @austinkline ๐ ,
You are in fact correct in both of your findings. Test.moveTime
only affects the Blockchain's time, and the reason behind it is that contracts under testing are deployed on the Blockchain, so they would fetch the current block data from the Blockchain, e.g.:
access(all) contract TimeLocker {
access(all) let lockPeriod: UFix64
access(all) let lockedAt: UFix64
init(lockedAt: UFix64) {
self.lockedAt = lockedAt
// Lock period is 30 days, in the form of seconds.
self.lockPeriod = UFix64(30 * 24 * 60 * 60)
}
access(all)
fun isOpen(): Bool {
let currentTime = getCurrentBlock().timestamp
return currentTime > (self.lockedAt + self.lockPeriod)
}
}
In the above sample contract, isOpen()
would check the timestamp from the Blockchain's current block.
The stdlib
functions in the script environment that runs test scripts, are not wired to that Blockchain, that's why you would get different results. I am not sure if it is possible to achieve that functionality. I will check it out though.
The reason for accepting UFix64
as the delta. in Test.moveTime
is because the timestamp
field from getCurrentBlock()
is also of UFix64
type. However, we can only advance the system clock in whole seconds. I am not sure if we can have smaller granularity than seconds, I can understand your confusion though ๐
I hope this clarifies things better ๐
EDIT: We cannot have granularity smaller than seconds, neither in testnet/mainnet.
The clock should probably be changed to support sub-second granularity.