The goal of this oracle is to provide an on-ledger duration of all passed epoch since creation of the component as well as a way to compute time elapsed between an epoch and the current epoch.
This does not mean to be a precise clock ticking every seconds, but more of an on-ledger information on whether a time milestone was reached or not. This can not be used as a precise timer for short delays, but can show useful to request time between multiple epochs (the bigger the range, the less significant will be the potential error).
All durations are currently in milliseconds.
An example of usage could be a timed auction. We would:
- create the auction with a duration
- during creation, mark the current epoch
- when doing various auction actions, we could call the oracle to know whether the time spent between current timestamp and creation timestamp is higher than auction duration, in which case we would end the auction
Instead of providing an "erratic" epoch duration, this would make that auction more precise in terms of human intelligible duration.
To run and test the epoch oracle, you can run one of the following:
- update the oracle only once per epoch (epochs are synchronized with PTE):
me@os:~$ (cd scrypto/epoch_duration_oracle && ./tick_on_epoch.sh) Current epoch 633, last epoch 633... Current epoch 633, last epoch 633... Current epoch set! Transaction Status: SUCCESS Execution Time: 16 ms Instructions: ├─ CallMethod { component_address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a, method: "create_proof_by_amount", args: [Decimal("1"), ResourceAddress("03f1820412ec5c07b54ff0407eb00bfc54f58d0784f3eabc2df9c7")] } └─ CallMethod { component_address: 028b858b202333e09f6bf24756b17e51cb6f6882d8bde08a47bdf1, method: "tick", args: [1035068u64] } Instruction Outputs: ├─ Proof(1024u32) └─ 634u64 Logs: 0 New Entities: 0 Current epoch 634, last epoch 634... Current epoch 634, last epoch 634...
- update the oracle each second (starts with epoch from PTE then increments epoch each seconds):
me@os:~$ (cd scrypto/epoch_duration_oracle && ./tick_asap.sh) Current epoch set! Transaction Status: SUCCESS Execution Time: 14 ms Instructions: ├─ CallMethod { component_address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a, method: "create_proof_by_amount", args: > [Decimal("1"), ResourceAddress("0384a3fa191c5506fe5df8a4622cb6eead59deab9d7fc48f64fc98")] } └─ CallMethod { component_address: 0244e8cb7761a9b1980e52d70999b4075f182839cec77bfffc1f6c, method: "tick", args: [781u64] } Instruction Outputs: ├─ Proof(1024u32) └─ 10u64 Logs: 0 New Entities: 0 Current epoch set! Transaction Status: SUCCESS Execution Time: 17 ms Instructions: ├─ CallMethod { component_address: 020d3869346218a5e8deaaf2001216dc00fcacb79fb43e30ded79a, method: "create_proof_by_amount", args: > [Decimal("1"), ResourceAddress("0384a3fa191c5506fe5df8a4622cb6eead59deab9d7fc48f64fc98")] } └─ CallMethod { component_address: 0244e8cb7761a9b1980e52d70999b4075f182839cec77bfffc1f6c, method: "tick", args: [1063u64] } Instruction Outputs: ├─ Proof(1024u32) └─ 10u64 Logs: 0 New Entities: 0
To query from the start of the oracle state, you can use:
resim run scrypto/epoch_duration_oracle/manifests/since_epoch_0.manifest
To see the difference, there is also a since_epoch_{current_epoch_on_pte01 + 1}.manifest
to compute time elapsed from different epoch and a since_epoch_0.manifest
to query elapsed time from the start of the oracle.
e.g.:
resim run scrypto/epoch_duration_oracle/manifests/since_epoch_9.manifest | grep 'Instruction Outputs' -A 1; resim run scrypto/epoch_duration_oracle/manifests/since_epoch_10.manifest | grep 'Instruction Outputs' -A 1;
The available functions are:
EpochDurationOracle::new
: creates a new oracle starting from now and disregarding already elapsed time (does not consider elapsed time of the passed epochs).EpochDurationOracle::new_with_bootstrap(last_epoch: u64, millis_in_last_epoch: u64)
: creates a new oracle starting fromlast_epoch
which lastedmillis_in_last_epoch
. This is useful if you want to start the oracle at a given point in time (but after January 1st 1970).
The available method for oracle creator is:
EpochDurationOracle::tick(millis_since_last_tick: u64)
: ticks the internal clock by the provided milliseconds. This can:- end the current epoch, categorize it with its duration and start counting down for a new epoch if previous epoch just ended
- add the tick amount to the epoch being currently counted down
- this always return the current ledger epoch
The available open methods are:
-
EpochDurationOracle::millis_since_epoch(epoch: u64)
: measure time passed between providedepoch
and current epoch. This can give birth to few cases:- the provided
epoch
is higher than on-ledger epoch: we will return an error - the provided
epoch
is equal to the on-ledger epoch: we will return the time spent on the current epoch - the provided
epoch
is lower than the on-ledger epoch: we will return the time spent between provided epoch and current epoch - the provided
epoch
does not appear for oracle was not created yet: we will return the time spent from the closest lower bound epoch and current epoch (e.g.: if you request time spent from epoch10
and oracle missed it, but we have epoch11
and12
and are in epoch13
, we will compute time spent between epoch13
and11
and consider epoch10
lasted0
. This is acceptable since we are using timestamp, the actual duration will remain correct)
- the provided
-
EpochDurationOracle::millis_in_epoch(epoch: u64)
: measure duration of providedepoch
. This can give birth to few cases:- the provided
epoch
is higher than on-ledger epoch: we return an error - the provided
epoch
is equal to the on-ledger epoch: we will return the time spent on the current epoch - the provided
epoch
is lower than the on-ledger epoch: we will return the time spent between provided epoch and current epoch - the provided
epoch
is passed but not present on oracle: we will return 0 and suggest calling themillis_since_epoch
method
- the provided
Note: we will be adding a method to get duration between two epochs provided.