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
2 changes: 1 addition & 1 deletion docker/indexer.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ COPY . .

# Install indexer
RUN poetry install --no-root
RUN yarnpkg install
RUN yarnpkg install
2 changes: 1 addition & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@
index_retires()
# index_proposals()
index_class_issuers()
index_votes()
index_votes()
54 changes: 54 additions & 0 deletions migrations/committed/000008.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
--! Previous: sha1:a1f8ae0941fd8511e513577d60572126b2525f57
--! Hash: sha1:dea81b93fa574159ed977154ed6a84cde77bcc9d

-- Add transfers view
-- Solves multi-batch correlation issue by extracting data directly
-- from the msg.data JSON which preserves the proper credits array structure
-- One row per unique batch_denom per MsgSend (aggregates duplicate batch_denoms)

CREATE OR REPLACE VIEW public.transfers AS
SELECT
'regen.ecocredit.v1.EventTransfer'::text AS type,
SUM(
CASE
WHEN credit->>'tradable_amount' = '' THEN 0
ELSE (credit->>'tradable_amount')::numeric
Comment on lines +14 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat missing amount fields as zero in transfers view

The CASE only handles empty strings, but credit->>'tradable_amount' (and the similar retired_amount expression) returns NULL when the key is omitted; in that case the ELSE branch casts NULL and SUM(...) can produce NULL for an entire transfer group instead of 0. This can surface as null amounts for valid MsgSend rows where one amount field is absent (e.g., zero-valued proto fields), which breaks consumers that expect numeric strings for both amount columns.

Useful? React with 👍 / 👎.

END
)::text AS tradable_amount,
SUM(
CASE
WHEN credit->>'retired_amount' = '' THEN 0
ELSE (credit->>'retired_amount')::numeric
END
)::text AS retired_amount,
Comment on lines +12 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CASE statements used to handle empty strings for tradable_amount and retired_amount can be simplified. Using COALESCE with NULLIF is a more concise and idiomatic way to achieve the same result in SQL, which improves code readability.

  SUM(COALESCE(NULLIF(credit->>'tradable_amount', '')::numeric, 0))::text AS tradable_amount,
  SUM(COALESCE(NULLIF(credit->>'retired_amount', '')::numeric, 0))::text AS retired_amount,

credit->>'batch_denom' AS batch_denom,
msg.data->>'sender' AS sender,
msg.data->>'recipient' AS recipient,
(TRIM(BOTH '"' FROM (tx.data->'tx_response'->'timestamp')::text))::timestamp with time zone AS "timestamp",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The expression for extracting the timestamp can be simplified. Using the ->> operator will extract the JSON field as text directly, which removes the need for an explicit cast to text and the subsequent TRIM function call.

  (tx.data->'tx_response'->>'timestamp')::timestamp with time zone AS "timestamp",

msg.block_height,
msg.chain_num,
msg.tx_idx,
msg.msg_idx,
encode(tx.hash, 'hex') AS tx_hash
FROM msg
CROSS JOIN LATERAL jsonb_array_elements(msg.data->'credits') AS credit
JOIN tx ON
msg.block_height = tx.block_height
AND msg.tx_idx = tx.tx_idx
AND msg.chain_num = tx.chain_num
WHERE msg.data->>'@type' = '/regen.ecocredit.v1.MsgSend'
GROUP BY
credit->>'batch_denom',
msg.data->>'sender',
msg.data->>'recipient',
tx.data->'tx_response'->'timestamp',
msg.block_height,
msg.chain_num,
msg.tx_idx,
msg.msg_idx,
tx.hash;

-- Add indexes on underlying tables for view performance
CREATE INDEX IF NOT EXISTS msg_data_type_idx ON public.msg USING btree (((data->>'@type')));
CREATE INDEX IF NOT EXISTS msg_data_sender_idx ON public.msg USING btree ((data->>'sender'));
CREATE INDEX IF NOT EXISTS msg_data_recipient_idx ON public.msg USING btree ((data->>'recipient'));
Comment on lines +52 to +54

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The CREATE INDEX statements contain redundant parentheses around the index expressions. While this is valid syntax, it harms readability. For an expression index, the syntax is ((expression)), but here it is (((expression))). Removing the extra pair of parentheses will make the code cleaner.

CREATE INDEX IF NOT EXISTS msg_data_type_idx ON public.msg USING btree ((data->>'@type'));
CREATE INDEX IF NOT EXISTS msg_data_sender_idx ON public.msg USING btree ((data->>'sender'));
CREATE INDEX IF NOT EXISTS msg_data_recipient_idx ON public.msg USING btree ((data->>'recipient'));

64 changes: 60 additions & 4 deletions migrations/schema_snapshot.sql
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
--
--
-- PostgreSQL database dump
--

-- Dumped from database version 14.9 (Debian 14.9-1.pgdg110+1)
-- Dumped by pg_dump version 17.0
\restrict pHaWchwoAQDYgXS0e6qt12k5712zNIfbGq86fVWeZ7e2cruN9swVkOuXfAOnJ75

-- Dumped from database version 14.20 (Debian 14.20-1.pgdg13+1)
-- Dumped by pg_dump version 16.11 (Ubuntu 16.11-0ubuntu0.24.04.1)

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
Expand Down Expand Up @@ -434,6 +435,38 @@ CREATE TABLE public.retirements (
);


--
-- Name: transfers; Type: VIEW; Schema: public; Owner: -
--

CREATE VIEW public.transfers AS
SELECT 'regen.ecocredit.v1.EventTransfer'::text AS type,
(sum(
CASE
WHEN ((credit.value ->> 'tradable_amount'::text) = ''::text) THEN (0)::numeric
ELSE ((credit.value ->> 'tradable_amount'::text))::numeric
END))::text AS tradable_amount,
(sum(
CASE
WHEN ((credit.value ->> 'retired_amount'::text) = ''::text) THEN (0)::numeric
ELSE ((credit.value ->> 'retired_amount'::text))::numeric
END))::text AS retired_amount,
(credit.value ->> 'batch_denom'::text) AS batch_denom,
(msg.data ->> 'sender'::text) AS sender,
(msg.data ->> 'recipient'::text) AS recipient,
(TRIM(BOTH '"'::text FROM (((tx.data -> 'tx_response'::text) -> 'timestamp'::text))::text))::timestamp with time zone AS "timestamp",
msg.block_height,
msg.chain_num,
msg.tx_idx,
msg.msg_idx,
encode(tx.hash, 'hex'::text) AS tx_hash
FROM ((public.msg
CROSS JOIN LATERAL jsonb_array_elements((msg.data -> 'credits'::text)) credit(value))
JOIN public.tx ON (((msg.block_height = tx.block_height) AND (msg.tx_idx = tx.tx_idx) AND (msg.chain_num = tx.chain_num))))
WHERE ((msg.data ->> '@type'::text) = '/regen.ecocredit.v1.MsgSend'::text)
GROUP BY (credit.value ->> 'batch_denom'::text), (msg.data ->> 'sender'::text), (msg.data ->> 'recipient'::text), ((tx.data -> 'tx_response'::text) -> 'timestamp'::text), msg.block_height, msg.chain_num, msg.tx_idx, msg.msg_idx, tx.hash;


--
-- Name: unified_data_events; Type: VIEW; Schema: public; Owner: -
--
Expand Down Expand Up @@ -660,13 +693,34 @@ CREATE INDEX flyway_schema_history_s_idx ON public.flyway_schema_history USING b
CREATE INDEX idx_msg_event_attr_iri_data_v_partial ON public.msg_event_attr USING btree (value) WHERE (type ~~ 'regen.data.v%.Event%'::text);


--
-- Name: msg_data_recipient_idx; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX msg_data_recipient_idx ON public.msg USING btree (((data ->> 'recipient'::text)));


--
-- Name: msg_data_sender_idx; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX msg_data_sender_idx ON public.msg USING btree (((data ->> 'sender'::text)));


--
-- Name: msg_data_type_gin_idx; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX msg_data_type_gin_idx ON public.msg USING gin (((data ->> '@type'::text)) public.gin_trgm_ops);


--
-- Name: msg_data_type_idx; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX msg_data_type_idx ON public.msg USING btree (((data ->> '@type'::text)));


--
-- Name: msg_event_attr_type_idx; Type: INDEX; Schema: public; Owner: -
--
Expand Down Expand Up @@ -836,3 +890,5 @@ GRANT SELECT ON TABLE public.unified_data_events TO PUBLIC;
-- PostgreSQL database dump complete
--

\unrestrict pHaWchwoAQDYgXS0e6qt12k5712zNIfbGq86fVWeZ7e2cruN9swVkOuXfAOnJ75