Skip to content

Commit f5fea96

Browse files
authored
feat: normalized events & pwr collector (#70)
1 parent 56afc96 commit f5fea96

File tree

12 files changed

+389
-29
lines changed

12 files changed

+389
-29
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,22 @@ erDiagram
123123
serial id
124124
jsonb data
125125
}
126+
"api.events_raw" {
127+
varchar(64) id
128+
bigint event_index
129+
jsonb data
130+
}
131+
"api.events_main" {
132+
varchar(64) id
133+
bigint event_index
134+
bigint attr_index
135+
text event_type
136+
text attr_key
137+
text attr_value
138+
bigint msg_index
139+
}
140+
"api.transactions_raw" ||--o{ "api.events_raw": "trigger insert/update"
141+
"api.events_raw" ||--|| "api.events_main" : "trigger insert/update"
126142
```
127143

128144
#### Usage

cmd/yaci/postgres_test.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ func testExtractBlocksAndTxs(t *testing.T) {
6060

6161
transactions := getJSONResponse(t, RestTxEndpoint, nil)
6262
require.NotEmpty(t, transactions)
63-
// The number of transactions is 32 as defined in the `compose.yaml` file under the `manifest-ledger-tx` service
64-
require.Len(t, transactions, 32)
63+
// The number of transactions is 42 as defined in the `compose.yaml` file under the `manifest-ledger-tx` service
64+
require.Len(t, transactions, 42)
6565
})
6666
}
6767

@@ -180,10 +180,14 @@ func testPrometheusMetrics(t *testing.T) {
180180
require.Equal(t, 200, resp.StatusCode())
181181
body := string(resp.Body())
182182
require.Contains(t, body, "yaci_addresses_total_unique_user{source=\"postgres\"} 3")
183-
require.Contains(t, body, "yaci_addresses_total_unique_group{source=\"postgres\"} 2")
184-
require.Contains(t, body, "yaci_transactions_total_count{source=\"postgres\"} 32")
185-
require.Contains(t, body, "yaci_tokenomics_total_burn_amount{source=\"postgres\"} 123")
183+
require.Contains(t, body, "yaci_addresses_total_unique_group{source=\"postgres\"} 3")
184+
require.Contains(t, body, "yaci_transactions_total_count{source=\"postgres\"} 42")
185+
// 3000000umfx were burned by the MFX to PWR conversion
186+
// 123umfx were burned by a POA proposal
187+
require.Contains(t, body, "yaci_tokenomics_total_burn_amount{source=\"postgres\"} 3.000123e+06")
186188
require.Contains(t, body, "yaci_tokenomics_total_payout_amount{source=\"postgres\"} 7.54321e+06")
189+
// 6000000factory/.../upwr were minted by the MFX to PWR conversion
190+
require.Contains(t, body, "yaci_tokenomics_total_pwr_minted_amount{source=\"postgres\"} 6e+06")
187191
require.Contains(t, body, "yaci_locked_tokens_count{amount=\"2000000000\",denom=\"umfx\",source=\"postgres\"} 1")
188192
})
189193
}

docker/.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ P2P="26656"
1919
GRPC="9090"
2020
GRPC_WEB="9091"
2121
ROSETTA="8080"
22-
TIMEOUT_COMMIT="2s"
22+
TIMEOUT_COMMIT="3s"
2323
VOTING_TIMEOUT="5s"
2424
DENOM=umfx
2525
BOND_DENOM=upoa
@@ -32,3 +32,4 @@ TX_COUNT_DIR=/tx-count
3232
TX_COUNT_FILE=tx-count.txt
3333
TX_COUNT_PATH="${TX_COUNT_DIR}/${TX_COUNT_FILE}"
3434
POSTGREST_HOST=postgrest
35+
CONVERT_WASM_ADDRESS="manifest14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4zfs7u"

docker/infra/compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ services:
3030
- ./scripts/init_manifest_ledger.sh:/usr/local/bin/init_manifest_ledger.sh:ro
3131
ports:
3232
- "9090:9090"
33+
- "26657:26657"
3334
entrypoint: ["/bin/bash", "-c"]
3435
env_file: ../.env
3536
command: /usr/local/bin/init_manifest_ledger.sh
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"group_policy_address": "${POA_ADMIN_ADDRESS}",
3+
"messages": [
4+
{
5+
"@type": "/cosmos.authz.v1beta1.MsgGrant",
6+
"granter": "${POA_ADMIN_ADDRESS}",
7+
"grantee": "${CONVERT_WASM_ADDRESS}",
8+
"grant": {
9+
"authorization": {
10+
"@type": "/cosmos.authz.v1beta1.GenericAuthorization",
11+
"msg": "/osmosis.tokenfactory.v1beta1.MsgMint"
12+
},
13+
"expiration": "2030-01-01T00:00:00Z"
14+
}
15+
},
16+
{
17+
"@type": "/cosmos.authz.v1beta1.MsgGrant",
18+
"granter": "${POA_ADMIN_ADDRESS}",
19+
"grantee": "${CONVERT_WASM_ADDRESS}",
20+
"grant": {
21+
"authorization": {
22+
"@type": "/cosmos.authz.v1beta1.GenericAuthorization",
23+
"msg": "/liftedinit.manifest.v1.MsgBurnHeldBalance"
24+
},
25+
"expiration": "2030-01-01T00:00:00Z"
26+
}
27+
}
28+
],
29+
"metadata": "",
30+
"title": "Grant converter contract mint and burn permissions",
31+
"summary": "We want to allow the converter contract to mint PWR and burn MFX for testing purposes",
32+
"proposers": ["manifest1hj5fveer5cjtn4wd6wstzugjfdxzl0xp8ws9ct"]
33+
}

docker/infra/scripts/init_manifest_ledger.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33

44
set -e
55

6-
update_test_genesis() {
7-
cat $HOME_DIR/config/genesis.json | jq $1 > $HOME_DIR/config/tmp_genesis.json
8-
mv $HOME_DIR/config/tmp_genesis.json $HOME_DIR/config/genesis.json
6+
update_test_genesis () {
7+
cat $HOME_DIR/config/genesis.json | jq "$1" > $HOME_DIR/config/tmp_genesis.json && mv $HOME_DIR/config/tmp_genesis.json $HOME_DIR/config/genesis.json
98
}
109

1110
echo "$MNEMO1" | $BINARY keys add "$KEY" --home="$HOME_DIR" --keyring-backend "$KEYRING" --recover
1211
echo "$MNEMO2" | $BINARY keys add "$KEY2" --home="$HOME_DIR" --keyring-backend "$KEYRING" --recover
1312
$BINARY init $MONIKER --home=$HOME_DIR --chain-id $CHAIN_ID
1413
update_test_genesis '.consensus["params"]["block"]["max_gas"]="1000000000"'
14+
update_test_genesis '.app_state["bank"]["denom_metadata"]=[{"base":"umfx","denom_units":[{"aliases":[],"denom":"umfx","exponent":0},{"aliases":[],"denom":"MFX","exponent":6}],"description":"MFX","display":"MFX","name":"MFX","symbol":"MFX","uri":"","uri_hash":""}]'
1515
update_test_genesis '.app_state["gov"]["params"]["min_deposit"]=[{"denom":"'$DENOM'","amount":"1000000"}]'
1616
update_test_genesis '.app_state["gov"]["params"]["voting_period"]="15s"'
1717
update_test_genesis '.app_state["gov"]["params"]["expedited_voting_period"]="10s"'
@@ -27,6 +27,10 @@ update_test_genesis '.app_state["group"]["groups"]=[{"id":"1","admin":"'${POA_AD
2727
update_test_genesis '.app_state["group"]["group_members"]=[{"group_id":"1","member":{"address":"'${ADDR1}'","weight":"1","metadata":"user1","added_at":"2024-05-16T15:10:54.372190727Z"}},{"group_id":"1","member":{"address":"'${ADDR2}'","weight":"1","metadata":"user2","added_at":"2024-05-16T15:10:54.372190727Z"}}]'
2828
update_test_genesis '.app_state["group"]["group_policy_seq"]="1"'
2929
update_test_genesis '.app_state["group"]["group_policies"]=[{"address":"'${POA_ADMIN_ADDRESS}'","group_id":"1","admin":"'${POA_ADMIN_ADDRESS}'","metadata":"AQ==","version":"2","decision_policy":{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period":"5s","min_execution_period":"0s"}},"created_at":"2024-05-16T15:10:54.372190727Z"}]'
30+
update_test_genesis '.app_state["tokenfactory"]["factory_denoms"]=[{"denom":"factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr","authority_metadata":{"admin":"manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj"}}]'
31+
update_test_genesis '.app_state["bank"]["denom_metadata"] |= . + [{"description":"PWR","denom_units":[{"denom":"factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr","exponent":0,"aliases":["PWR"]},{"denom":"PWR","exponent":6,"aliases":["factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr"]}],"base":"factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr","display":"PWR","name":"POWER","symbol":"PWR","uri":"","uri_hash":""}]'
32+
update_test_genesis '.app_state["wasm"]["params"]["code_upload_access"]["permission"]="Everybody"'
33+
update_test_genesis '.app_state["wasm"]["params"]["instantiate_default_permission"]="Everybody"'
3034
$BINARY genesis add-genesis-account $KEY 100000000000000000${BOND_DENOM},100000000000000000000000000000${DENOM} --keyring-backend $KEYRING --home=$HOME_DIR
3135
$BINARY genesis add-genesis-account $KEY2 100000000000000000${DENOM} --keyring-backend $KEYRING --home=$HOME_DIR
3236
$BINARY genesis gentx $KEY 1000000${BOND_DENOM} --keyring-backend $KEYRING --home=$HOME_DIR --chain-id $CHAIN_ID --commission-rate=0.0 --commission-max-rate=1.0 --commission-max-change-rate=0.1

docker/infra/scripts/init_manifest_ledger_txs.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ set -e
55

66
TX_COUNT=0
77
PROPOSAL_ID=1
8+
CONTRACT_VERSION=v0.1.0
9+
10+
# Download the wasm contract
11+
echo "Downloading converter.wasm contract version ${CONTRACT_VERSION}"
12+
curl -sL https://github.com/manifest-network/manifest-contracts/releases/download/${CONTRACT_VERSION}/converter.wasm --output /tmp/converter.wasm
813

914
# We want to keep track of the transaction count in a file; check if the directory containing the file exists
1015
if [ -d "${TX_COUNT_DIR}" ]; then
@@ -30,6 +35,20 @@ function run_proposal() {
3035
TX_COUNT=$((TX_COUNT + 3))
3136
}
3237

38+
## Wasm module
39+
echo "-> Storing converter.wasm contract"
40+
run_tx tx wasm store /tmp/converter.wasm --from $KEY --note "tx-store-converter"
41+
42+
echo "-> Instantiating converter.wasm contract"
43+
run_tx tx wasm instantiate 1 '{"admin":"'${POA_ADMIN_ADDRESS}'","poa_admin":"'${POA_ADMIN_ADDRESS}'","rate":"2","source_denom":"umfx","target_denom":"factory/'${POA_ADMIN_ADDRESS}'/upwr","paused":false}' --from $KEY --admin $ADDR1 --label "converter" --note "tx-instantiate-converter"
44+
45+
echo "-> Granting converter contract mint/burn permissions"
46+
run_proposal "grant.json" "$ADDR1" "tx-grant-proposal" --from $KEY
47+
48+
# Converter contract address is `manifest14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4zfs7u`
49+
echo "-> Converting 3 MFX to 6 PWR"
50+
run_tx tx wasm execute ${CONVERT_WASM_ADDRESS} '{"convert":{}}' --from $KEY --note "tx-mint-from-converter" --amount 3000000umfx
51+
3352
## Bank module
3453
run_tx tx bank send $ADDR1 ${POA_ADMIN_ADDRESS} 10000${DENOM} --from $KEY --note "tx-send-to-poa-admin"
3554
run_tx tx bank multi-send $ADDR1 $ADDR2 ${POA_ADMIN_ADDRESS} 10000${DENOM} --from $KEY --note "tx-multi-send-to-poa-admin"
@@ -48,6 +67,14 @@ run_tx tx tokenfactory change-admin factory/$ADDR1/ufoobar $ADDR2 --from $KEY --
4867
run_proposal "payout.json" "$ADDR1" "tx-payout-proposal" --from $KEY
4968
run_proposal "burn.json" "$ADDR1" "tx-burn-proposal" --from $KEY
5069

70+
# Submit and withdraw payout and burn proposals to make sure collector works properly
71+
run_tx tx group submit-proposal "/proposals/payout.json" --note "tx-payout-proposal-submit-2" --from $KEY
72+
run_tx tx group withdraw-proposal $PROPOSAL_ID $ADDR1 --note "tx-payout-proposal-withdraw" --from $KEY
73+
PROPOSAL_ID=$((PROPOSAL_ID + 1))
74+
run_tx tx group submit-proposal "/proposals/burn.json" --note "tx-burn-proposal-submit-2" --from $KEY
75+
run_tx tx group withdraw-proposal $PROPOSAL_ID $ADDR1 --note "tx-burn-proposal-withdraw" --from $KEY
76+
PROPOSAL_ID=$((PROPOSAL_ID + 1))
77+
5178
### Group module
5279
echo ${GROUP_MEMBERS} > members.json && cat members.json
5380
echo ${DECISION_POLICY} > policy.json && cat policy.json

docker/yaci/scripts/yaci_tx_check.sh

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ function check_addr_txs() {
4848

4949
# Address-specific configurations
5050
declare -A ADDRESS_EXPECTED_TXS=(
51-
["${ADDR1}"]="33"
52-
["${ADDR2}"]="11"
51+
["${ADDR1}"]="43"
52+
["${ADDR2}"]="12"
5353
["${USER_GROUP_ADDRESS}"]="15"
54-
["${POA_ADMIN_ADDRESS}"]="8"
54+
["${POA_ADMIN_ADDRESS}"]="14"
5555
["${VESTING_ADDR}"]="1"
5656
)
5757

@@ -92,6 +92,16 @@ declare -a ADDRESS1_TX_CHECKS=(
9292
"tx-send-proposal-error-vote:false"
9393
"tx-send-proposal-error-exec:false"
9494
"tx-create-periodic-vesting-account:false"
95+
"tx-store-converter:false"
96+
"tx-instantiate-converter:false"
97+
"tx-grant-proposal-submit:false"
98+
"tx-grant-proposal-vote:false"
99+
"tx-grant-proposal-exec:false"
100+
"tx-mint-from-converter:false"
101+
"tx-payout-proposal-submit-2:false"
102+
"tx-payout-proposal-withdraw:false"
103+
"tx-burn-proposal-submit-2:false"
104+
"tx-burn-proposal-withdraw:false"
95105
)
96106

97107
declare -a ADDRESS2_TX_CHECKS=(
@@ -135,6 +145,10 @@ declare -a POA_ADMIN_ADDRESS_TX_CHECKS=(
135145
"tx-burn-proposal-submit:false"
136146
"tx-burn-proposal-submit:true"
137147
"tx-burn-proposal-exec:false"
148+
"tx-grant-proposal-submit:false"
149+
"tx-grant-proposal-submit:true"
150+
"tx-payout-proposal-submit-2:false"
151+
"tx-burn-proposal-submit-2:false"
138152
)
139153

140154
declare -A ADDRESS_TX_CHECKS=(

internal/metrics/collectors/total_payout_burn.go

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,65 @@ import (
88
"github.com/prometheus/client_golang/prometheus"
99
)
1010

11+
// TotalPayoutBurnQuery expected format of the cosmwasm event attribute for burn amounts, e.g., 123456umfx
1112
const TotalPayoutBurnQuery = `
12-
WITH payout_amount AS (
13-
SELECT
14-
COALESCE(SUM((pp.element->'coin'->>'amount')::numeric), 0) AS amount
15-
FROM api.messages_main m
16-
CROSS JOIN LATERAL jsonb_array_elements(m.metadata->'payoutPairs') AS pp(element)
17-
WHERE m.type = '/liftedinit.manifest.v1.MsgPayout'
18-
),
19-
burn_amount AS (
20-
SELECT
21-
COALESCE(SUM((pp.element->>'amount')::numeric), 0) AS amount
22-
FROM api.messages_main m
23-
CROSS JOIN LATERAL jsonb_array_elements(m.metadata->'burnCoins') AS pp(element)
24-
WHERE type = '/liftedinit.manifest.v1.MsgBurnHeldBalance'
13+
WITH mfx_burned AS (
14+
WITH burn_events AS (
15+
SELECT
16+
e.id,
17+
e.event_index,
18+
MAX(CASE WHEN e.attr_key = 'amount' THEN e.attr_value END) AS amount_raw,
19+
MAX(e.msg_index) AS msg_index
20+
FROM api.events_main e
21+
WHERE e.event_type = 'burn'
22+
GROUP BY e.id, e.event_index
23+
)
24+
SELECT COALESCE(SUM((rm.captures)[1]::numeric), 0) AS amount
25+
FROM burn_events b
26+
JOIN api.messages_main m
27+
ON m.id = b.id
28+
AND m.message_index = b.msg_index
29+
JOIN api.transactions_main tx
30+
ON tx.id = b.id
31+
AND tx.error IS NULL
32+
JOIN LATERAL regexp_matches(
33+
b.amount_raw,
34+
'^([0-9]+)([[:alnum:]_\/\.]+)$'
35+
) AS rm(captures) ON TRUE
36+
WHERE (rm.captures)[2] = 'umfx'
37+
),
38+
payout_amount AS (
39+
SELECT
40+
COALESCE(SUM((pp.element->'coin'->>'amount')::numeric), 0) AS amount
41+
FROM api.messages_main m
42+
JOIN api.transactions_main t
43+
ON t.id = m.id
44+
AND t.error IS NULL
45+
CROSS JOIN LATERAL jsonb_array_elements(
46+
COALESCE(m.metadata->'payoutPairs', '[]'::jsonb)
47+
) AS pp(element)
48+
WHERE m.type = '/liftedinit.manifest.v1.MsgPayout'
49+
AND (pp.element->'coin'->>'denom') = 'umfx' -- keep only umfx
50+
AND (
51+
m.message_index < 10000
52+
OR (
53+
m.message_index >= 10000
54+
AND EXISTS (
55+
SELECT 1
56+
FROM api.transactions_main tx2
57+
JOIN api.messages_main m2 ON tx2.id = m2.id
58+
WHERE tx2.error IS NULL
59+
AND m2.type = '/cosmos.group.v1.MsgExec'
60+
AND tx2.proposal_ids IS NOT NULL
61+
AND tx2.proposal_ids && t.proposal_ids
62+
)
63+
)
2564
)
26-
SELECT
27-
(SELECT amount FROM payout_amount) AS payout_amount,
28-
(SELECT amount FROM burn_amount) AS burn_amount
29-
`
65+
)
66+
SELECT
67+
(SELECT amount FROM payout_amount) AS total_payout_umfx,
68+
(SELECT amount FROM mfx_burned) AS total_burned_umfx;
69+
`
3070

3171
type TotalPayoutBurnCollector struct {
3272
db *sql.DB
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//go:build manifest
2+
3+
package collectors
4+
5+
import (
6+
"database/sql"
7+
8+
"github.com/prometheus/client_golang/prometheus"
9+
)
10+
11+
// TotalPwrMintAmountQuery expected format of the cosmwasm event attribute for mint amounts, e.g., 123456upwr
12+
// Note: only counts PWR minted via the tf_mint event (i.e., via the tf_mint function)
13+
const TotalPwrMintAmountQuery = `
14+
WITH pwr_minted AS (
15+
WITH tf_mint_events AS (
16+
SELECT
17+
e.id,
18+
e.event_index,
19+
MAX(CASE WHEN e.attr_key = 'amount' THEN e.attr_value END) AS amount_raw,
20+
MAX(e.msg_index) AS msg_index
21+
FROM api.events_main e
22+
WHERE e.event_type = 'tf_mint'
23+
GROUP BY e.id, e.event_index
24+
)
25+
SELECT COALESCE(SUM((rm.captures)[1]::numeric), 0) AS amount
26+
FROM tf_mint_events b
27+
JOIN api.messages_main m
28+
ON m.id = b.id
29+
AND m.message_index = b.msg_index
30+
AND m.type = '/cosmwasm.wasm.v1.MsgExecuteContract'
31+
JOIN LATERAL regexp_matches(
32+
b.amount_raw,
33+
'^([0-9]+)([[:alnum:]_\/\.]+)$'
34+
) AS rm(captures) ON TRUE
35+
WHERE (rm.captures)[2] = 'factory/manifest1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfmy9qj/upwr'
36+
)
37+
SELECT amount FROM pwr_minted;
38+
`
39+
40+
type TotalPwrMintedCollector struct {
41+
totalPwrMintedAmount *prometheus.Desc
42+
db *sql.DB
43+
}
44+
45+
func NewTotalPwrMintedCollector(db *sql.DB) *TotalPwrMintedCollector {
46+
return &TotalPwrMintedCollector{
47+
db: db,
48+
totalPwrMintedAmount: prometheus.NewDesc(
49+
prometheus.BuildFQName("yaci", "tokenomics", "total_pwr_minted_amount"),
50+
"Total PWR minted",
51+
nil,
52+
prometheus.Labels{"source": "postgres"},
53+
),
54+
}
55+
}
56+
57+
func (c *TotalPwrMintedCollector) Describe(ch chan<- *prometheus.Desc) {
58+
ch <- c.totalPwrMintedAmount
59+
}
60+
61+
func (c *TotalPwrMintedCollector) Collect(ch chan<- prometheus.Metric) {
62+
var mintAmount float64
63+
err := c.db.QueryRow(TotalPwrMintAmountQuery).Scan(&mintAmount)
64+
if err != nil {
65+
ch <- prometheus.NewInvalidMetric(c.totalPwrMintedAmount, err)
66+
return
67+
}
68+
69+
ch <- prometheus.MustNewConstMetric(c.totalPwrMintedAmount, prometheus.CounterValue, mintAmount)
70+
}
71+
72+
func init() {
73+
RegisterCollectorFactory(func(db *sql.DB, extraParams ...interface{}) (prometheus.Collector, error) {
74+
return NewTotalPwrMintedCollector(db), nil
75+
})
76+
}

0 commit comments

Comments
 (0)