Skip to content

Commit cc788a9

Browse files
committed
graph, runtime: Override user-supplied timestamp in store.set
For timeseries, users can not set the timestamp. Instead, the time for the current block is used.
1 parent fa3ad33 commit cc788a9

File tree

5 files changed

+41
-9
lines changed

5 files changed

+41
-9
lines changed

graph/src/blockchain/types.rs

+6
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,12 @@ impl BlockTime {
350350
}
351351
}
352352

353+
impl From<BlockTime> for Value {
354+
fn from(block_time: BlockTime) -> Self {
355+
Value::Int8(block_time.as_secs_since_epoch())
356+
}
357+
}
358+
353359
impl TryFrom<&Value> for BlockTime {
354360
type Error = anyhow::Error;
355361

graph/src/schema/input_schema.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ pub struct ObjectType {
262262
/// The name of the aggregation to which this object type belongs if it
263263
/// is part of an aggregation
264264
aggregation: Option<Atom>,
265-
timeseries: bool,
265+
pub timeseries: bool,
266266
interfaces: Box<[Word]>,
267267
shared_interfaces: Box<[Atom]>,
268268
}

runtime/test/src/test.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use graph::blockchain::BlockTime;
12
use graph::components::metrics::gas::GasMetrics;
23
use graph::data::store::{scalar, Id, IdType};
34
use graph::data::subgraph::*;
@@ -1608,7 +1609,7 @@ async fn test_store_ts() {
16081609
timestamp: Int8!
16091610
amount: BigDecimal!
16101611
}
1611-
1612+
16121613
type Stats @aggregation(intervals: ["hour"], source: "Data") {
16131614
id: Bytes!
16141615
timestamp: Int8!
@@ -1617,15 +1618,27 @@ async fn test_store_ts() {
16171618

16181619
let mut host = Host::new(schema, "hostStoreTs", "boolean.wasm", None).await;
16191620

1621+
let block_time = host.ctx.timestamp;
1622+
let other_time = BlockTime::since_epoch(7000, 0);
1623+
// If this fails, something is wrong with the test setup
1624+
assert_ne!(block_time, other_time);
1625+
16201626
let b20 = Value::BigDecimal(20.into());
16211627

16221628
host.store_setv(
16231629
DATA,
16241630
DID,
1625-
vec![("timestamp", Value::Int8(23)), ("amount", b20.clone())],
1631+
vec![
1632+
("timestamp", Value::from(other_time)),
1633+
("amount", b20.clone()),
1634+
],
16261635
)
16271636
.expect("Setting 'Data' is allowed");
16281637

1638+
// Set overrides the user-supplied timestamp for timeseries
1639+
let data = host.store_get(DATA, DID).unwrap().unwrap();
1640+
assert_eq!(Some(&Value::from(block_time)), data.get("timestamp"));
1641+
16291642
let err = host
16301643
.store_setv(STATS, SID, vec![("amount", b20)])
16311644
.expect_err("store_set must fail for aggregations");

runtime/wasm/src/host_exports.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use semver::Version;
1313
use wasmtime::Trap;
1414
use web3::types::H160;
1515

16-
use graph::blockchain::Blockchain;
16+
use graph::blockchain::{BlockTime, Blockchain};
1717
use graph::components::store::{EnsLookup, GetScope, LoadRelatedRequest};
1818
use graph::components::subgraph::{
1919
PoICausalityRegion, ProofOfIndexingEvent, SharedProofOfIndexing,
@@ -218,6 +218,7 @@ impl<C: Blockchain> HostExports<C> {
218218
state: &mut BlockState<C>,
219219
block: BlockNumber,
220220
proof_of_indexing: &SharedProofOfIndexing,
221+
block_time: BlockTime,
221222
entity_type: String,
222223
entity_id: String,
223224
mut data: HashMap<Word, Value>,
@@ -251,6 +252,10 @@ impl<C: Blockchain> HostExports<C> {
251252
"store_set",
252253
)?;
253254

255+
if entity_type.object_type()?.timeseries {
256+
data.insert(Word::from("timestamp"), block_time.into());
257+
}
258+
254259
// Set the id if there isn't one yet, and make sure that a
255260
// previously set id agrees with the one in the `key`
256261
match data.get(&store::ID) {
@@ -1095,7 +1100,7 @@ pub mod test_support {
10951100
use std::{borrow::Cow, collections::HashMap, sync::Arc};
10961101

10971102
use graph::{
1098-
blockchain::Blockchain,
1103+
blockchain::{BlockTime, Blockchain},
10991104
components::{
11001105
store::{BlockNumber, GetScope},
11011106
subgraph::SharedProofOfIndexing,
@@ -1108,11 +1113,17 @@ pub mod test_support {
11081113

11091114
use crate::MappingContext;
11101115

1111-
pub struct HostExports<C: Blockchain>(Arc<super::HostExports<C>>);
1116+
pub struct HostExports<C: Blockchain> {
1117+
host_exports: Arc<super::HostExports<C>>,
1118+
block_time: BlockTime,
1119+
}
11121120

11131121
impl<C: Blockchain> HostExports<C> {
11141122
pub fn new(ctx: &MappingContext<C>) -> Self {
1115-
HostExports(ctx.host_exports.clone())
1123+
HostExports {
1124+
host_exports: ctx.host_exports.clone(),
1125+
block_time: ctx.timestamp,
1126+
}
11161127
}
11171128

11181129
pub fn store_set(
@@ -1127,11 +1138,12 @@ pub mod test_support {
11271138
stopwatch: &StopwatchMetrics,
11281139
gas: &GasCounter,
11291140
) -> Result<(), HostExportError> {
1130-
self.0.store_set(
1141+
self.host_exports.store_set(
11311142
logger,
11321143
state,
11331144
block,
11341145
proof_of_indexing,
1146+
self.block_time,
11351147
entity_type,
11361148
entity_id,
11371149
data,
@@ -1147,7 +1159,7 @@ pub mod test_support {
11471159
entity_id: String,
11481160
gas: &GasCounter,
11491161
) -> Result<Option<Cow<'a, Entity>>, anyhow::Error> {
1150-
self.0
1162+
self.host_exports
11511163
.store_get(state, entity_type, entity_id, gas, GetScope::Store)
11521164
}
11531165
}

runtime/wasm/src/module/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,7 @@ impl<C: Blockchain> WasmInstanceContext<C> {
11541154
&mut self.ctx.state,
11551155
self.ctx.block_ptr.number,
11561156
&self.ctx.proof_of_indexing,
1157+
self.ctx.timestamp,
11571158
entity,
11581159
id,
11591160
data,

0 commit comments

Comments
 (0)