Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 73 additions & 4 deletions internal/migrations/045-high-low-attestation-actions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
* Both actions return exactly 1 row (LIMIT 1), making them safe for the
* attestation path. The precompile validates a max 90-day date range.
*
* Each primitive action anchors before $from, so a range in which the stream
* published nothing reports the value that was standing rather than no rows.
* Without that, a stream that only publishes when its value moves answers an
* escrow's high/low question with an empty attestation.
*
* Action IDs:
* 10 = get_high_value (max value in [from, to])
* 11 = get_low_value (min value in [from, to])
Expand Down Expand Up @@ -61,8 +66,32 @@ CREATE OR REPLACE ACTION get_high_value_primitive(
AND pe.event_time >= $effective_from
AND pe.event_time <= $effective_to
AND pe.created_at <= $effective_frozen_at
),
-- A stream that did not move during [from, to] has no rows in range, but the
-- value it published last still stood for the whole window. Reach back for it
-- the way get_record_primitive's anchor_record does, so a quiet range reports
-- that value instead of nothing. Strictly '<' because the range above is
-- inclusive of $effective_from, so this cannot double-count the row at $from.
anchor AS (
SELECT pe.event_time, pe.value
FROM primitive_events pe
WHERE pe.stream_ref = $stream_ref
AND pe.event_time < $effective_from
AND pe.created_at <= $effective_frozen_at
ORDER BY pe.event_time DESC, pe.created_at DESC
LIMIT 1
),
candidates AS (
SELECT event_time, value FROM deduped WHERE rn = 1
UNION ALL
SELECT event_time, value FROM anchor
)
SELECT event_time, value FROM deduped WHERE rn = 1
-- On a tie the earliest event_time wins, which is the anchor. That is what the
-- composed branch below already reports: it walks get_record in event_time
-- order and keeps the first maximum, and get_record leads with its own anchor.
-- The two branches have to agree, so the tie is not broken in favour of the
-- in-range row.
SELECT event_time, value FROM candidates
ORDER BY value DESC, event_time ASC
LIMIT 1;
};
Expand Down Expand Up @@ -109,8 +138,32 @@ CREATE OR REPLACE ACTION get_low_value_primitive(
AND pe.event_time >= $effective_from
AND pe.event_time <= $effective_to
AND pe.created_at <= $effective_frozen_at
),
-- A stream that did not move during [from, to] has no rows in range, but the
-- value it published last still stood for the whole window. Reach back for it
-- the way get_record_primitive's anchor_record does, so a quiet range reports
-- that value instead of nothing. Strictly '<' because the range above is
-- inclusive of $effective_from, so this cannot double-count the row at $from.
anchor AS (
SELECT pe.event_time, pe.value
FROM primitive_events pe
WHERE pe.stream_ref = $stream_ref
AND pe.event_time < $effective_from
AND pe.created_at <= $effective_frozen_at
ORDER BY pe.event_time DESC, pe.created_at DESC
LIMIT 1
),
candidates AS (
SELECT event_time, value FROM deduped WHERE rn = 1
UNION ALL
SELECT event_time, value FROM anchor
)
SELECT event_time, value FROM deduped WHERE rn = 1
-- On a tie the earliest event_time wins, which is the anchor. That is what the
-- composed branch below already reports: it walks get_record in event_time
-- order and keeps the first maximum, and get_record leads with its own anchor.
-- The two branches have to agree, so the tie is not broken in favour of the
-- in-range row.
SELECT event_time, value FROM candidates
ORDER BY value ASC, event_time ASC
LIMIT 1;
};
Expand Down Expand Up @@ -140,7 +193,15 @@ CREATE OR REPLACE ACTION get_high_value(
$max_value NUMERIC(36,18) := NULL;
$max_event_time INT8 := NULL;
for $row in get_record($data_provider, $stream_id, $from, $to, $frozen_at, FALSE) {
if $max_value IS NULL OR $row.value > $max_value {
-- Split from the comparison on purpose. The interpreter does not
-- implement three-valued logic: `$max_value IS NULL OR $row.value >
-- $max_value` evaluates TRUE OR NULL to NULL on the first row, which
-- reads as not-taken, so the combined guard never assigns and this
-- branch returned nothing for every composed stream.
if $max_value IS NULL {
$max_value := $row.value;
$max_event_time := $row.event_time;
} ELSEIF $row.value > $max_value {
$max_value := $row.value;
$max_event_time := $row.event_time;
}
Expand Down Expand Up @@ -176,7 +237,15 @@ CREATE OR REPLACE ACTION get_low_value(
$min_value NUMERIC(36,18) := NULL;
$min_event_time INT8 := NULL;
for $row in get_record($data_provider, $stream_id, $from, $to, $frozen_at, FALSE) {
if $min_value IS NULL OR $row.value < $min_value {
-- Split from the comparison on purpose. The interpreter does not
-- implement three-valued logic: `$min_value IS NULL OR $row.value <
-- $min_value` evaluates TRUE OR NULL to NULL on the first row, which
-- reads as not-taken, so the combined guard never assigns and this
-- branch returned nothing for every composed stream.
if $min_value IS NULL {
$min_value := $row.value;
$min_event_time := $row.event_time;
} ELSEIF $row.value < $min_value {
$min_value := $row.value;
$min_event_time := $row.event_time;
}
Expand Down
Loading
Loading