diff --git a/.env.example b/.env.example index c93adda..21a0e54 100644 --- a/.env.example +++ b/.env.example @@ -6,3 +6,5 @@ MINAMESH_GENESIS_BLOCK_IDENTIFIER_HEIGHT=359605 RUST_LOG=debug,error,mina_mesh=info RUST_ENV=production + +SNAP_CHECK=1 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1451f45..45bf5d2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @harrysolovay @joaosreis @johnmarcou +* @harrysolovay @joaosreis @johnmarcou @piotr-iohk diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index bbb0973..7a7311e 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -46,7 +46,6 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dsherret/rust-toolchain-file@v1 - - uses: extractions/setup-just@v2 - uses: actions/cache@v4 with: path: | @@ -57,7 +56,7 @@ jobs: - name: Test run: | sed "s|postgres://mina:whatever@localhost:5432/archive|$MINAMESH_ARCHIVE_DATABASE_URL_DEVNET|g" .env.example.devnet > .env - just test + cargo test env: MINAMESH_ARCHIVE_DATABASE_URL_DEVNET: ${{ secrets.MINAMESH_ARCHIVE_DATABASE_URL_DEVNET }} diff --git a/.sqlx/query-411a992540d9c8a1eaa3461adc67005bb4515d21a064c1ad13ab9746e23763da.json b/.sqlx/query-411a992540d9c8a1eaa3461adc67005bb4515d21a064c1ad13ab9746e23763da.json new file mode 100644 index 0000000..8bf03bd --- /dev/null +++ b/.sqlx/query-411a992540d9c8a1eaa3461adc67005bb4515d21a064c1ad13ab9746e23763da.json @@ -0,0 +1,156 @@ +{ + "db_name": "PostgreSQL", + "query": "WITH\n canonical_blocks AS (\n SELECT\n *\n FROM\n blocks\n WHERE\n chain_status='canonical'\n ),\n max_canonical_height AS (\n SELECT\n max(HEIGHT) AS max_height\n FROM\n canonical_blocks\n ),\n pending_blocks AS (\n SELECT\n b.*\n FROM\n blocks AS b,\n max_canonical_height AS m\n WHERE\n b.height>m.max_height\n AND b.chain_status='pending'\n ),\n blocks AS (\n SELECT\n *\n FROM\n canonical_blocks\n UNION ALL\n SELECT\n *\n FROM\n pending_blocks\n ),\n zkapp_commands_info AS (\n SELECT\n zc.id,\n zc.memo,\n zc.hash,\n pk_fee_payer.value AS fee_payer,\n pk_update_body.value AS pk_update_body,\n zfpb.fee,\n zfpb.valid_until,\n zfpb.nonce,\n bzc.sequence_no,\n bzc.status AS \"status: TransactionStatus\",\n zaub.balance_change,\n bzc.block_id,\n b.state_hash,\n b.height,\n token_update_body.value AS token,\n ARRAY(\n SELECT\n unnest(zauf.failures)\n FROM\n zkapp_account_update_failures AS zauf\n WHERE\n zauf.id=ANY (bzc.failure_reasons_ids)\n ) AS failure_reasons\n FROM\n zkapp_commands AS zc\n INNER JOIN blocks_zkapp_commands AS bzc ON zc.id=bzc.zkapp_command_id\n INNER JOIN zkapp_fee_payer_body AS zfpb ON zc.zkapp_fee_payer_body_id=zfpb.id\n INNER JOIN public_keys AS pk_fee_payer ON zfpb.public_key_id=pk_fee_payer.id\n INNER JOIN blocks AS b ON bzc.block_id=b.id\n LEFT JOIN zkapp_account_update AS zau ON zau.id=ANY (zc.zkapp_account_updates_ids)\n INNER JOIN zkapp_account_update_body AS zaub ON zau.body_id=zaub.id\n INNER JOIN account_identifiers AS ai_update_body ON zaub.account_identifier_id=ai_update_body.id\n INNER JOIN public_keys AS pk_update_body ON ai_update_body.public_key_id=pk_update_body.id\n INNER JOIN tokens AS token_update_body ON ai_update_body.token_id=token_update_body.id\n WHERE\n (\n $1>=b.height\n OR $1 IS NULL\n )\n AND (\n $2=zc.hash\n OR $2 IS NULL\n )\n AND (\n (\n (\n $3=pk_fee_payer.value\n AND $4=''\n )\n OR (\n $3=pk_update_body.value\n AND $4=token_update_body.value\n )\n )\n OR (\n $3 IS NULL\n AND $4 IS NULL\n )\n )\n AND (\n $5=bzc.status\n OR $5 IS NULL\n )\n AND (\n $6=bzc.status\n OR $6 IS NULL\n )\n AND (\n (\n $7=pk_fee_payer.value\n OR $7=pk_update_body.value\n )\n OR $7 IS NULL\n )\n ),\n zkapp_commands_ids AS (\n SELECT DISTINCT\n id,\n block_id,\n sequence_no\n FROM\n zkapp_commands_info\n ),\n id_count AS (\n SELECT\n count(*) AS total_count\n FROM\n zkapp_commands_ids\n )\nSELECT\n zc.*,\n id_count.total_count\nFROM\n id_count,\n (\n SELECT\n *\n FROM\n zkapp_commands_ids\n ORDER BY\n block_id,\n id,\n sequence_no\n LIMIT\n $8\n OFFSET\n $9\n ) AS ids\n INNER JOIN zkapp_commands_info AS zc ON ids.id=zc.id\n AND ids.block_id=zc.block_id\n AND ids.sequence_no=zc.sequence_no\nORDER BY\n ids.block_id,\n ids.id,\n ids.sequence_no\n", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "memo", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "hash", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "fee_payer", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "pk_update_body", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "fee", + "type_info": "Text" + }, + { + "ordinal": 6, + "name": "valid_until", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 8, + "name": "sequence_no", + "type_info": "Int4" + }, + { + "ordinal": 9, + "name": "status: TransactionStatus", + "type_info": { + "Custom": { + "name": "transaction_status", + "kind": { + "Enum": [ + "applied", + "failed" + ] + } + } + } + }, + { + "ordinal": 10, + "name": "balance_change", + "type_info": "Text" + }, + { + "ordinal": 11, + "name": "block_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "state_hash", + "type_info": "Text" + }, + { + "ordinal": 13, + "name": "height", + "type_info": "Int8" + }, + { + "ordinal": 14, + "name": "token", + "type_info": "Text" + }, + { + "ordinal": 15, + "name": "failure_reasons", + "type_info": "TextArray" + }, + { + "ordinal": 16, + "name": "total_count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8", + "Text", + "Text", + "Text", + { + "Custom": { + "name": "transaction_status", + "kind": { + "Enum": [ + "applied", + "failed" + ] + } + } + }, + { + "Custom": { + "name": "transaction_status", + "kind": { + "Enum": [ + "applied", + "failed" + ] + } + } + }, + "Text", + "Int8", + "Int8" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + null, + null, + false, + null, + null + ] + }, + "hash": "411a992540d9c8a1eaa3461adc67005bb4515d21a064c1ad13ab9746e23763da" +} diff --git a/.sqlx/query-52d18e4008bd0006fafee2f64d97c2ff75a1d9b210b99eed6f14e8a17d05530b.json b/.sqlx/query-52d18e4008bd0006fafee2f64d97c2ff75a1d9b210b99eed6f14e8a17d05530b.json new file mode 100644 index 0000000..0dc5cfd --- /dev/null +++ b/.sqlx/query-52d18e4008bd0006fafee2f64d97c2ff75a1d9b210b99eed6f14e8a17d05530b.json @@ -0,0 +1,129 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n zc.id,\n zc.memo,\n zc.hash,\n pk_fee_payer.value AS fee_payer,\n zfpb.fee,\n zfpb.valid_until,\n zfpb.nonce,\n bzc.sequence_no,\n bzc.status AS \"status: TransactionStatus\",\n b.state_hash,\n b.height,\n bzc.block_id,\n cast(0 AS BIGINT) AS total_count,\n ARRAY(\n SELECT\n unnest(zauf.failures)\n FROM\n zkapp_account_update_failures AS zauf\n WHERE\n zauf.id=ANY (bzc.failure_reasons_ids)\n ) AS failure_reasons,\n zaub.balance_change,\n pk_update_body.value AS pk_update_body,\n token_update_body.value AS token\nFROM\n blocks_zkapp_commands AS bzc\n INNER JOIN zkapp_commands AS zc ON bzc.zkapp_command_id=zc.id\n INNER JOIN zkapp_fee_payer_body AS zfpb ON zc.zkapp_fee_payer_body_id=zfpb.id\n INNER JOIN public_keys AS pk_fee_payer ON zfpb.public_key_id=pk_fee_payer.id\n INNER JOIN blocks AS b ON bzc.block_id=b.id\n LEFT JOIN zkapp_account_update AS zau ON zau.id=ANY (zc.zkapp_account_updates_ids)\n LEFT JOIN zkapp_account_update_body AS zaub ON zau.body_id=zaub.id\n LEFT JOIN account_identifiers AS ai_update_body ON zaub.account_identifier_id=ai_update_body.id\n LEFT JOIN public_keys AS pk_update_body ON ai_update_body.public_key_id=pk_update_body.id\n LEFT JOIN tokens AS token_update_body ON ai_update_body.token_id=token_update_body.id\nWHERE\n bzc.block_id=$1\n AND (\n token_update_body.value=$2\n OR token_update_body.id IS NULL\n )\nORDER BY\n zc.id,\n bzc.sequence_no\n", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "memo", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "hash", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "fee_payer", + "type_info": "Text" + }, + { + "ordinal": 4, + "name": "fee", + "type_info": "Text" + }, + { + "ordinal": 5, + "name": "valid_until", + "type_info": "Int8" + }, + { + "ordinal": 6, + "name": "nonce", + "type_info": "Int8" + }, + { + "ordinal": 7, + "name": "sequence_no", + "type_info": "Int4" + }, + { + "ordinal": 8, + "name": "status: TransactionStatus", + "type_info": { + "Custom": { + "name": "transaction_status", + "kind": { + "Enum": [ + "applied", + "failed" + ] + } + } + } + }, + { + "ordinal": 9, + "name": "state_hash", + "type_info": "Text" + }, + { + "ordinal": 10, + "name": "height", + "type_info": "Int8" + }, + { + "ordinal": 11, + "name": "block_id", + "type_info": "Int4" + }, + { + "ordinal": 12, + "name": "total_count", + "type_info": "Int8" + }, + { + "ordinal": 13, + "name": "failure_reasons", + "type_info": "TextArray" + }, + { + "ordinal": 14, + "name": "balance_change", + "type_info": "Text" + }, + { + "ordinal": 15, + "name": "pk_update_body", + "type_info": "Text" + }, + { + "ordinal": 16, + "name": "token", + "type_info": "Text" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + null, + null, + false, + false, + false + ] + }, + "hash": "52d18e4008bd0006fafee2f64d97c2ff75a1d9b210b99eed6f14e8a17d05530b" +} diff --git a/.sqlx/query-56485f1d902b775a7d9702dfe3da13b35f3ec2f47bdccd481116f663d3a5c3bc.json b/.sqlx/query-56485f1d902b775a7d9702dfe3da13b35f3ec2f47bdccd481116f663d3a5c3bc.json deleted file mode 100644 index df58d5f..0000000 --- a/.sqlx/query-56485f1d902b775a7d9702dfe3da13b35f3ec2f47bdccd481116f663d3a5c3bc.json +++ /dev/null @@ -1,262 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "WITH\n canonical_blocks AS (\n SELECT\n *\n FROM\n blocks\n WHERE\n chain_status='canonical'\n ),\n max_canonical_height AS (\n SELECT\n max(HEIGHT) AS max_height\n FROM\n canonical_blocks\n ),\n pending_blocks AS (\n SELECT\n b.*\n FROM\n blocks AS b,\n max_canonical_height AS m\n WHERE\n b.height>m.max_height\n AND b.chain_status='pending'\n ),\n blocks AS (\n SELECT\n *\n FROM\n canonical_blocks\n UNION ALL\n SELECT\n *\n FROM\n pending_blocks\n ),\n zkapp_commands_info AS (\n SELECT\n zc.id,\n zc.memo,\n zc.hash,\n pk_fee_payer.value AS fee_payer,\n pk_update_body.value AS pk_update_body,\n zfpb.fee,\n zfpb.valid_until,\n zfpb.nonce,\n bzc.sequence_no,\n bzc.status AS \"status: TransactionStatus\",\n zaub.account_identifier_id,\n zaub.update_id,\n zaub.balance_change,\n zaub.increment_nonce,\n zaub.events_id,\n zaub.actions_id,\n zaub.call_data_id,\n zaub.call_depth,\n zaub.zkapp_network_precondition_id,\n zaub.zkapp_account_precondition_id,\n zaub.zkapp_valid_while_precondition_id,\n zaub.use_full_commitment,\n zaub.implicit_account_creation_fee,\n zaub.may_use_token AS \"may_use_token: MayUseToken\",\n zaub.authorization_kind AS \"authorization_kind: AuthorizationKindType\",\n zaub.verification_key_hash_id,\n bzc.block_id,\n b.state_hash,\n b.height,\n ARRAY(\n SELECT\n unnest(zauf.failures)\n FROM\n zkapp_account_update_failures AS zauf\n WHERE\n zauf.id=ANY (bzc.failure_reasons_ids)\n ) AS failure_reasons\n FROM\n zkapp_commands AS zc\n INNER JOIN blocks_zkapp_commands AS bzc ON zc.id=bzc.zkapp_command_id\n INNER JOIN zkapp_fee_payer_body AS zfpb ON zc.zkapp_fee_payer_body_id=zfpb.id\n INNER JOIN public_keys AS pk_fee_payer ON zfpb.public_key_id=pk_fee_payer.id\n INNER JOIN blocks AS b ON bzc.block_id=b.id\n LEFT JOIN zkapp_account_update AS zau ON zau.id=ANY (zc.zkapp_account_updates_ids)\n INNER JOIN zkapp_account_update_body AS zaub ON zau.body_id=zaub.id\n INNER JOIN account_identifiers AS ai_update_body ON zaub.account_identifier_id=ai_update_body.id\n INNER JOIN public_keys AS pk_update_body ON ai_update_body.public_key_id=pk_update_body.id\n INNER JOIN tokens AS token_update_body ON ai_update_body.token_id=token_update_body.id\n WHERE\n (\n $1>=b.height\n OR $1 IS NULL\n )\n AND (\n $2=zc.hash\n OR $2 IS NULL\n )\n AND (\n (\n (\n $3=pk_fee_payer.value\n AND $4=''\n )\n OR (\n $3=pk_update_body.value\n AND $4=token_update_body.value\n )\n )\n OR (\n $3 IS NULL\n AND $4 IS NULL\n )\n )\n AND (\n $5=bzc.status\n OR $5 IS NULL\n )\n AND (\n $6=bzc.status\n OR $6 IS NULL\n )\n AND (\n (\n $7=pk_fee_payer.value\n OR $7=pk_update_body.value\n )\n OR $7 IS NULL\n )\n ),\n zkapp_commands_ids AS (\n SELECT DISTINCT\n id,\n block_id,\n sequence_no\n FROM\n zkapp_commands_info\n ),\n id_count AS (\n SELECT\n count(*) AS total_count\n FROM\n zkapp_commands_ids\n )\nSELECT\n zc.*,\n id_count.total_count\nFROM\n id_count,\n (\n SELECT\n *\n FROM\n zkapp_commands_ids\n ORDER BY\n block_id,\n id,\n sequence_no\n LIMIT\n $8\n OFFSET\n $9\n ) AS ids\n INNER JOIN zkapp_commands_info AS zc ON ids.id=zc.id\n AND ids.block_id=zc.block_id\n AND ids.sequence_no=zc.sequence_no\nORDER BY\n ids.block_id,\n ids.id,\n ids.sequence_no\n", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "memo", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "fee_payer", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "pk_update_body", - "type_info": "Text" - }, - { - "ordinal": 5, - "name": "fee", - "type_info": "Text" - }, - { - "ordinal": 6, - "name": "valid_until", - "type_info": "Int8" - }, - { - "ordinal": 7, - "name": "nonce", - "type_info": "Int8" - }, - { - "ordinal": 8, - "name": "sequence_no", - "type_info": "Int4" - }, - { - "ordinal": 9, - "name": "status: TransactionStatus", - "type_info": { - "Custom": { - "name": "transaction_status", - "kind": { - "Enum": [ - "applied", - "failed" - ] - } - } - } - }, - { - "ordinal": 10, - "name": "account_identifier_id", - "type_info": "Int4" - }, - { - "ordinal": 11, - "name": "update_id", - "type_info": "Int4" - }, - { - "ordinal": 12, - "name": "balance_change", - "type_info": "Text" - }, - { - "ordinal": 13, - "name": "increment_nonce", - "type_info": "Bool" - }, - { - "ordinal": 14, - "name": "events_id", - "type_info": "Int4" - }, - { - "ordinal": 15, - "name": "actions_id", - "type_info": "Int4" - }, - { - "ordinal": 16, - "name": "call_data_id", - "type_info": "Int4" - }, - { - "ordinal": 17, - "name": "call_depth", - "type_info": "Int4" - }, - { - "ordinal": 18, - "name": "zkapp_network_precondition_id", - "type_info": "Int4" - }, - { - "ordinal": 19, - "name": "zkapp_account_precondition_id", - "type_info": "Int4" - }, - { - "ordinal": 20, - "name": "zkapp_valid_while_precondition_id", - "type_info": "Int4" - }, - { - "ordinal": 21, - "name": "use_full_commitment", - "type_info": "Bool" - }, - { - "ordinal": 22, - "name": "implicit_account_creation_fee", - "type_info": "Bool" - }, - { - "ordinal": 23, - "name": "may_use_token: MayUseToken", - "type_info": { - "Custom": { - "name": "may_use_token", - "kind": { - "Enum": [ - "No", - "ParentsOwnToken", - "InheritFromParent" - ] - } - } - } - }, - { - "ordinal": 24, - "name": "authorization_kind: AuthorizationKindType", - "type_info": { - "Custom": { - "name": "authorization_kind_type", - "kind": { - "Enum": [ - "None_given", - "Signature", - "Proof" - ] - } - } - } - }, - { - "ordinal": 25, - "name": "verification_key_hash_id", - "type_info": "Int4" - }, - { - "ordinal": 26, - "name": "block_id", - "type_info": "Int4" - }, - { - "ordinal": 27, - "name": "state_hash", - "type_info": "Text" - }, - { - "ordinal": 28, - "name": "height", - "type_info": "Int8" - }, - { - "ordinal": 29, - "name": "failure_reasons", - "type_info": "TextArray" - }, - { - "ordinal": 30, - "name": "total_count", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8", - "Text", - "Text", - "Text", - { - "Custom": { - "name": "transaction_status", - "kind": { - "Enum": [ - "applied", - "failed" - ] - } - } - }, - { - "Custom": { - "name": "transaction_status", - "kind": { - "Enum": [ - "applied", - "failed" - ] - } - } - }, - "Text", - "Int8", - "Int8" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - true, - false, - null, - null, - null, - null - ] - }, - "hash": "56485f1d902b775a7d9702dfe3da13b35f3ec2f47bdccd481116f663d3a5c3bc" -} diff --git a/.sqlx/query-de3ae438ab25d585ae49ed2bf4b0761b3fbb32f2ff125cfc557e41106bb7debd.json b/.sqlx/query-de3ae438ab25d585ae49ed2bf4b0761b3fbb32f2ff125cfc557e41106bb7debd.json deleted file mode 100644 index cd3e427..0000000 --- a/.sqlx/query-de3ae438ab25d585ae49ed2bf4b0761b3fbb32f2ff125cfc557e41106bb7debd.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT\n zc.id,\n zc.memo,\n zc.hash,\n pk_fee_payer.value AS fee_payer,\n zfpb.fee,\n zfpb.valid_until,\n zfpb.nonce,\n bzc.sequence_no,\n bzc.status AS \"status: TransactionStatus\",\n ARRAY(\n SELECT\n unnest(zauf.failures)\n FROM\n zkapp_account_update_failures AS zauf\n WHERE\n zauf.id=ANY (bzc.failure_reasons_ids)\n ) AS failure_reasons\nFROM\n blocks_zkapp_commands AS bzc\n INNER JOIN zkapp_commands AS zc ON bzc.zkapp_command_id=zc.id\n INNER JOIN zkapp_fee_payer_body AS zfpb ON zc.zkapp_fee_payer_body_id=zfpb.id\n INNER JOIN public_keys AS pk_fee_payer ON zfpb.public_key_id=pk_fee_payer.id\n INNER JOIN blocks AS b ON bzc.block_id=b.id\n LEFT JOIN zkapp_account_update AS zau ON zau.id=ANY (zc.zkapp_account_updates_ids)\n LEFT JOIN zkapp_account_update_body AS zaub ON zau.body_id=zaub.id\n LEFT JOIN account_identifiers AS ai_update_body ON zaub.account_identifier_id=ai_update_body.id\n LEFT JOIN public_keys AS pk_update_body ON ai_update_body.public_key_id=pk_update_body.id\n LEFT JOIN tokens AS token_update_body ON ai_update_body.token_id=token_update_body.id\nWHERE\n bzc.block_id=$1\n AND (\n token_update_body.value=$2\n OR token_update_body.id IS NULL\n )\nORDER BY\n zc.id,\n bzc.sequence_no\n", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "memo", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "fee_payer", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "fee", - "type_info": "Text" - }, - { - "ordinal": 5, - "name": "valid_until", - "type_info": "Int8" - }, - { - "ordinal": 6, - "name": "nonce", - "type_info": "Int8" - }, - { - "ordinal": 7, - "name": "sequence_no", - "type_info": "Int4" - }, - { - "ordinal": 8, - "name": "status: TransactionStatus", - "type_info": { - "Custom": { - "name": "transaction_status", - "kind": { - "Enum": [ - "applied", - "failed" - ] - } - } - } - }, - { - "ordinal": 9, - "name": "failure_reasons", - "type_info": "TextArray" - } - ], - "parameters": { - "Left": [ - "Int4", - "Text" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - true, - false, - false, - false, - null - ] - }, - "hash": "de3ae438ab25d585ae49ed2bf4b0761b3fbb32f2ff125cfc557e41106bb7debd" -} diff --git a/.vscode/settings.json b/.vscode/settings.json index f7f84cb..e16227c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -23,6 +23,9 @@ "[toml]": { "editor.defaultFormatter": "dprint.dprint" }, + // "[typescript]": { + // "editor.defaultFormatter": "dprint.dprint" + // }, "[yaml]": { "editor.defaultFormatter": "dprint.dprint" }, diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d84cbfa..575c78b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ To develop on your machine, install the following (and please submit issues if e - [Rust](https://www.rust-lang.org/tools/install) - [Docker](https://docs.docker.com/get-docker/) - [dprint](https://dprint.dev/) -- [Just](https://github.com/casey/just) +- [Deno](https://github.com/denoland/deno?tab=readme-ov-file#installation) - [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) - [insta](https://insta.rs/) @@ -84,29 +84,23 @@ changes by contributors where you believe you have something valuable to add or ### Ensure Test DB Accessible -- **Stop PostgreSQL**: To stop the PostgreSQL instance: +If you've already initialized the archive database, ensure it's running (potentially with a +`deno pg:up`). Otherwise, initialize the development archive database. - ```bash - just pg-down - ``` - -- **Restart PostgreSQL**: To restart without reinitializing the database (useful if the database is - already set up): - - ```bash - just pg-up - ``` +```sh +deno task dev:init +``` > You only need to reinitialize the database if you want the latest data dump. ### Run Tests -```bash +```sh cargo test ``` ### Update Snapshots -``` +```sh cargo insta review ``` diff --git a/Cargo.lock b/Cargo.lock index dca5c3c..408c6de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -768,6 +768,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -1553,6 +1559,7 @@ dependencies = [ "indoc", "insta", "paste", + "pretty_assertions", "reqwest", "serde", "serde_json", @@ -1894,6 +1901,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro-crate" version = "3.1.0" diff --git a/Cargo.toml b/Cargo.toml index eab4ae2..cc18fd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ dotenv = "0.15.0" envy = "0.4.2" futures = "0.3.30" paste = "1.0.15" +pretty_assertions = "1.4.1" reqwest = { version = "0.12.5", features = ["json", "blocking"] } serde = { version = "1.0.204", features = ["derive"] } serde_json = { version = "1.0.121" } diff --git a/Justfile b/Justfile deleted file mode 100644 index 784511e..0000000 --- a/Justfile +++ /dev/null @@ -1,25 +0,0 @@ -pg: - docker run -d --name mina-archive-db -p 5432:5432 -v $(pwd)/sql_scripts:/docker-entrypoint-initdb.d -e POSTGRES_PASSWORD=whatever -e POSTGRES_USER=mina postgres - -pg-up: - docker start mina-archive-db - -pg-down: - docker kill mina-archive-db - -pg-rm: - docker rm mina-archive-db - -get-mainnet-archive-db: - ./scripts/get_archive_db.sh mainnet - -wait-for-pg: - ./scripts/wait_for_pg.sh - -test: - SNAP_CHECK=1 cargo test - -setup-archive-db: - just get-mainnet-archive-db - just pg - just wait-for-pg \ No newline at end of file diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..c94c259 --- /dev/null +++ b/deno.json @@ -0,0 +1,53 @@ +{ + "exclude": ["target"], + "lock": false, + "tasks": { + "dl:devnet": "deno run -A tasks/dl.ts", + "dl:mainnet": "deno task dl:devnet --network mainnet", + "pg:init": "docker run -d --name mina-archive-db -p 5432:5432 -v $(pwd)/sql_scripts:/docker-entrypoint-initdb.d -e POSTGRES_PASSWORD=whatever -e POSTGRES_USER=mina postgres", + "pg:wait": "deno run -A ./tasks/pg_wait.ts", + "pg:enable_logging": "deno run -A ./tasks/enable_logging.ts", + "pg:up": "docker start mina-archive-db", + "pg:down": "docker kill mina-archive-db", + "pg:rm": "docker rm mina-archive-db", + "dev:init": "deno task dl:devnet && deno task pg:enable_logging && deno task pg:init && deno task pg:wait", + "dev": "cargo run serve --playground" + }, + "imports": { + "@qnighy/dedent": "jsr:@qnighy/dedent@^0.1.2", + "@std/assert": "jsr:@std/assert@1", + "@std/async": "jsr:@std/async@^1.0.6", + "@std/cache": "jsr:@std/cache@^0.1.3", + "@std/cli": "jsr:@std/cli@^1.0.6", + "@std/datetime": "jsr:@std/datetime@^0.225.2", + "@std/dotenv": "jsr:@std/dotenv@^0.225.2", + "@std/encoding": "jsr:@std/encoding@^1.0.5", + "@std/fs": "jsr:@std/fs@^1.0.4", + "@std/http": "jsr:@std/http@1", + "@std/path": "jsr:@std/path@^1.0.6", + "@std/tar": "jsr:@std/tar@^0.1.2", + "@std/text": "jsr:@std/text@^1.0.7", + "@types/json-schema": "npm:@types/json-schema@^7.0.15", + "@types/pg": "npm:@types/pg@^8.11.10", + "pg": "npm:pg@^8.13.0" + }, + "lint": { + "rules": { + "include": ["ban-untagged-todo", "guard-for-in"], + "exclude": [ + "ban-types", + "ban-untagged-todo", + "no-empty", + "no-explicit-any", + "no-inner-declarations", + "no-namespace" + ] + } + }, + "compilerOptions": { + "lib": ["deno.window"], + "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": false, + "noUncheckedIndexedAccess": true + } +} diff --git a/dprint.json b/dprint.jsonc similarity index 59% rename from dprint.json rename to dprint.jsonc index 7100330..101c1ec 100644 --- a/dprint.json +++ b/dprint.jsonc @@ -6,20 +6,26 @@ "commands": [ { "command": "sql-formatter -c sql_fmt.json -l postgresql", - "exts": ["sql"] - } - ] + "exts": ["sql"], + }, + ], }, "markdown": { - "textWrap": "always" + "textWrap": "always", }, - "excludes": [".sqlx", "src/graphql/generated.rs"], + // "typescript": { + // "arrowFunction.useParentheses": "force", + // "quoteProps": "asNeeded", + // "semiColons": "asi", + // }, + "excludes": [".sqlx", "src/graphql/generated.rs", "target"], "plugins": [ "https://plugins.dprint.dev/dockerfile-0.3.2.wasm", "https://plugins.dprint.dev/exec-0.5.0.json@8d9972eee71fa1590e04873540421f3eda7674d0f1aae3d7c788615e7b7413d0", "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.0.wasm", "https://plugins.dprint.dev/json-0.19.3.wasm", "https://plugins.dprint.dev/markdown-0.17.8.wasm", - "https://plugins.dprint.dev/toml-0.6.3.wasm" - ] + "https://plugins.dprint.dev/toml-0.6.3.wasm", + // "https://plugins.dprint.dev/typescript-0.93.0.wasm" + ], } diff --git a/scripts/get_archive_db.sh b/scripts/get_archive_db.sh deleted file mode 100755 index 2cba484..0000000 --- a/scripts/get_archive_db.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# This script is used to download the archive dump from the mina-archive-dumps bucket -# and extract the archive dump to the sql_scripts directory -# The script will download the archive dump for the last 5 days and extract the first available archive dump -# Usage: ./scripts/get_archive_db.sh -# Example: ./scripts/get_archive_db.sh mainnet - -MINA_NETWORK=${1} -MINA_ARCHIVE_DUMP_URL=${MINA_ARCHIVE_DUMP_URL:=https://storage.googleapis.com/mina-archive-dumps} -DUMP_TIME=0000 -SQL_SCRIPT_PATH=$(pwd)/sql_scripts -TAR_FILE_PATH=${SQL_SCRIPT_PATH}/o1labs-archive-dump.tar.gz - -mkdir -p ${SQL_SCRIPT_PATH} - -MAX_DAYS_LOOKBACK=5 -i=0 -while [ $i -lt $MAX_DAYS_LOOKBACK ]; do - DATE=$(date -d "$i days ago" +%G-%m-%d)_${DUMP_TIME} - STATUS_CODE=$(curl -s -o /dev/null --head -w "%{http_code}" "${MINA_ARCHIVE_DUMP_URL}/${MINA_NETWORK}-archive-dump-${DATE}.sql.tar.gz") - if [[ ! $STATUS_CODE =~ 2[0-9]{2} ]]; then - i=$((i + 1)) - else - echo "Download ${MINA_NETWORK}-archive-dump-${DATE}.sql.tar.gz" - curl "${MINA_ARCHIVE_DUMP_URL}/${MINA_NETWORK}-archive-dump-${DATE}.sql.tar.gz" -o ${TAR_FILE_PATH} - break - fi -done - -[[ $STATUS_CODE =~ 2[0-9]{2} ]] || echo "[WARN] Unable to find archive dump for ${MINA_NETWORK}" - -tar -xvf ${SQL_SCRIPT_PATH}/o1labs-archive-dump.tar.gz -C ${SQL_SCRIPT_PATH} -rm -f ${TAR_FILE_PATH} - -echo "Extracted ${MINA_NETWORK}-archive-dump-${DATE}.sql.tar.gz to ${SQL_SCRIPT_PATH}/${MINA_NETWORK}-archive-dump-${DATE}.sql" diff --git a/scripts/wait_for_pg.sh b/scripts/wait_for_pg.sh deleted file mode 100755 index 8930d15..0000000 --- a/scripts/wait_for_pg.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# This script is used to check if PostgreSQL is available -# Usage: ./scripts/pg_ready.sh -# Example: ./scripts/pg_ready.sh localhost 5432 - -# Parameters -PG_HOST="${1:-localhost}" -PG_PORT="${2:-5432}" - -# Wait for PostgreSQL to become available -until pg_isready -h "$PG_HOST" -p "$PG_PORT"; do - echo "Waiting for PostgreSQL to become available at ${PG_HOST}:${PG_PORT}..." - sleep 1 -done - -echo "PostgreSQL is available at ${PG_HOST}:${PG_PORT}" diff --git a/sql/indexer_zkapp_commands.sql b/sql/indexer_zkapp_commands.sql index 9fd3d9e..05f89e8 100644 --- a/sql/indexer_zkapp_commands.sql +++ b/sql/indexer_zkapp_commands.sql @@ -46,25 +46,11 @@ WITH zfpb.nonce, bzc.sequence_no, bzc.status AS "status: TransactionStatus", - zaub.account_identifier_id, - zaub.update_id, zaub.balance_change, - zaub.increment_nonce, - zaub.events_id, - zaub.actions_id, - zaub.call_data_id, - zaub.call_depth, - zaub.zkapp_network_precondition_id, - zaub.zkapp_account_precondition_id, - zaub.zkapp_valid_while_precondition_id, - zaub.use_full_commitment, - zaub.implicit_account_creation_fee, - zaub.may_use_token AS "may_use_token: MayUseToken", - zaub.authorization_kind AS "authorization_kind: AuthorizationKindType", - zaub.verification_key_hash_id, bzc.block_id, b.state_hash, b.height, + token_update_body.value AS token, ARRAY( SELECT unnest(zauf.failures) diff --git a/sql/zkapp_commands.sql b/sql/zkapp_commands.sql index 8c6d497..dc8d359 100644 --- a/sql/zkapp_commands.sql +++ b/sql/zkapp_commands.sql @@ -8,6 +8,10 @@ SELECT zfpb.nonce, bzc.sequence_no, bzc.status AS "status: TransactionStatus", + b.state_hash, + b.height, + bzc.block_id, + cast(0 AS BIGINT) AS total_count, ARRAY( SELECT unnest(zauf.failures) @@ -15,7 +19,10 @@ SELECT zkapp_account_update_failures AS zauf WHERE zauf.id=ANY (bzc.failure_reasons_ids) - ) AS failure_reasons + ) AS failure_reasons, + zaub.balance_change, + pk_update_body.value AS pk_update_body, + token_update_body.value AS token FROM blocks_zkapp_commands AS bzc INNER JOIN zkapp_commands AS zc ON bzc.zkapp_command_id=zc.id diff --git a/src/api/block.rs b/src/api/block.rs index 9f7cd49..fa0cba1 100644 --- a/src/api/block.rs +++ b/src/api/block.rs @@ -7,8 +7,8 @@ use serde::Serialize; use sqlx::FromRow; use crate::{ - operation, util::DEFAULT_TOKEN_ID, ChainStatus, InternalCommandType, MinaMesh, MinaMeshError, OperationType, - TransactionStatus, UserCommandType, + operation, sql_to_mesh::zkapp_commands_to_transactions, util::DEFAULT_TOKEN_ID, ChainStatus, InternalCommandType, + MinaMesh, MinaMeshError, OperationType, TransactionStatus, UserCommandType, ZkAppCommand, }; /// https://github.com/MinaProtocol/mina/blob/985eda49bdfabc046ef9001d3c406e688bc7ec45/src/app/rosetta/lib/block.ml#L7 @@ -78,16 +78,10 @@ impl MinaMesh { } pub async fn zkapp_commands(&self, metadata: &BlockMetadata) -> Result, MinaMeshError> { - let metadata = sqlx::query_file_as!(ZkappCommandMetadata, "sql/zkapp_commands.sql", metadata.id, DEFAULT_TOKEN_ID) + let metadata = sqlx::query_file_as!(ZkAppCommand, "sql/zkapp_commands.sql", metadata.id, DEFAULT_TOKEN_ID) .fetch_all(&self.pg_pool) .await?; - let transactions = metadata - .into_iter() - .map(|item| { - zkapp_command_metadata_to_operation(&item) - .map(|operation| Transaction::new(TransactionIdentifier::new(item.hash.clone()), operation)) - }) - .collect::, MinaMeshError>>()?; + let transactions = zkapp_commands_to_transactions(metadata); Ok(transactions) } @@ -182,6 +176,9 @@ pub struct ZkappCommandMetadata { sequence_no: i64, status: TransactionStatus, failure_reasons: Option>, + balance_change: String, + account: String, + token: String, } #[derive(Debug, PartialEq, Eq, FromRow, Serialize)] @@ -338,8 +335,3 @@ fn internal_command_metadata_to_operation(metadata: &InternalCommandMetadata) -> } Ok(operations) } - -// TODO: implement -fn zkapp_command_metadata_to_operation(_metadata: &ZkappCommandMetadata) -> Result, MinaMeshError> { - Ok(Vec::new()) -} diff --git a/src/api/search_transactions.rs b/src/api/search_transactions.rs index 8babf40..71d5d40 100644 --- a/src/api/search_transactions.rs +++ b/src/api/search_transactions.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use coinbase_mesh::models::{ AccountIdentifier, BlockIdentifier, BlockTransaction, Operation, SearchTransactionsRequest, @@ -9,8 +9,8 @@ use serde_json::{json, Map, Value}; use sqlx::FromRow; use crate::{ - operation, util::DEFAULT_TOKEN_ID, AuthorizationKindType, ChainStatus, InternalCommandType, MayUseToken, MinaMesh, - MinaMeshError, OperationType, TransactionStatus, UserCommandType, + operation, util::DEFAULT_TOKEN_ID, ChainStatus, InternalCommandType, MinaMesh, MinaMeshError, OperationType, + TransactionStatus, UserCommandType, ZkAppCommand, }; impl MinaMesh { @@ -159,44 +159,8 @@ impl MinaMesh { } } -#[allow(dead_code)] -#[derive(FromRow)] -pub struct ZkAppCommand { - pub id: Option, - pub memo: Option, - pub hash: String, - pub fee_payer: String, - pub pk_update_body: String, - pub fee: Option, - pub valid_until: Option, - pub nonce: Option, - pub sequence_no: i32, - pub status: TransactionStatus, - pub account_identifier_id: Option, - pub update_id: Option, - pub balance_change: Option, - pub increment_nonce: bool, - pub events_id: Option, - pub actions_id: Option, - pub call_data_id: Option, - pub call_depth: Option, - pub zkapp_network_precondition_id: Option, - pub zkapp_account_precondition_id: Option, - pub zkapp_valid_while_precondition_id: Option, - pub use_full_commitment: bool, - pub implicit_account_creation_fee: bool, - pub may_use_token: MayUseToken, - pub authorization_kind: AuthorizationKindType, - pub verification_key_hash_id: Option, - pub block_id: Option, - pub state_hash: Option, - pub height: Option, - pub failure_reasons: Option>, - pub total_count: Option, -} - pub fn zkapp_commands_to_block_transactions(commands: Vec) -> Vec { - let mut block_map: HashMap<(i64, String), HashMap>> = HashMap::new(); + let mut block_map: HashMap<(i64, String), BTreeMap>> = HashMap::new(); for command in commands { // Group by block identifier (block index and block hash) @@ -210,7 +174,7 @@ pub fn zkapp_commands_to_block_transactions(commands: Vec) -> Vec< if operations.is_empty() { operations.push(operation( 0, - Some(&format!("-{}", command.fee.unwrap_or("0".to_string()))), + Some(&format!("-{}", command.fee)), &AccountIdentifier { address: command.fee_payer.clone(), metadata: Some(json!({ "token_id": DEFAULT_TOKEN_ID })), @@ -226,7 +190,7 @@ pub fn zkapp_commands_to_block_transactions(commands: Vec) -> Vec< // Add zkapp balance update operation operations.push(operation( 0, - command.balance_change.as_ref(), + Some(&command.balance_change), &AccountIdentifier { address: command.pk_update_body.clone(), metadata: Some(json!({ "token_id": DEFAULT_TOKEN_ID })), diff --git a/src/lib.rs b/src/lib.rs index 017323c..dee15bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ mod error; mod graphql; mod operation; mod playground; +mod sql_to_mesh; mod types; mod util; diff --git a/src/sql_to_mesh.rs b/src/sql_to_mesh.rs new file mode 100644 index 0000000..38c412f --- /dev/null +++ b/src/sql_to_mesh.rs @@ -0,0 +1,67 @@ +use std::collections::BTreeMap; + +use coinbase_mesh::models::{AccountIdentifier, Operation, Transaction, TransactionIdentifier}; +use serde_json::json; + +use crate::{operation, util::DEFAULT_TOKEN_ID, OperationType, TransactionStatus, ZkAppCommand}; + +pub fn zkapp_commands_to_transactions(commands: Vec) -> Vec { + let mut tx_map = BTreeMap::>::new(); + + for command in commands { + let tx_hash = command.hash.clone(); + + // Initialize or update the operation list for this transaction + let operations = tx_map.entry(tx_hash.clone()).or_default(); + + // Add fee operation (zkapp_fee_payer_dec) + if operations.is_empty() { + operations.push(operation( + 0, + Some(&format!("-{}", command.fee)), + &AccountIdentifier { + address: command.fee_payer.clone(), + metadata: Some(json!({ "token_id": DEFAULT_TOKEN_ID })), + sub_account: None, + }, + OperationType::ZkappFeePayerDec, + Some(&TransactionStatus::Applied), + None, + None, + )); + } + + // Add zkapp balance update operation + operations.push(operation( + 0, + Some(&command.balance_change), + &AccountIdentifier { + address: command.pk_update_body.clone(), + metadata: Some(json!({ "token_id": DEFAULT_TOKEN_ID })), + sub_account: None, + }, + OperationType::ZkappBalanceUpdate, + Some(&command.status), + None, + None, + )); + } + + let mut result = Vec::new(); + for (tx_hash, mut operations) in tx_map { + // Ensure the operations are correctly indexed + for (i, operation) in operations.iter_mut().enumerate() { + operation.operation_identifier.index = i as i64; + } + + let transaction = Transaction { + transaction_identifier: Box::new(TransactionIdentifier { hash: tx_hash.clone() }), + operations, + metadata: None, + related_transactions: None, + }; + result.push(transaction); + } + + result +} diff --git a/src/types.rs b/src/types.rs index 14a1d96..c9558fb 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,6 @@ use derive_more::derive::Display; use serde::Serialize; -use sqlx::Type; +use sqlx::{FromRow, Type}; #[derive(Type, Debug, PartialEq, Eq, Serialize)] #[sqlx(type_name = "chain_status_type", rename_all = "lowercase")] @@ -83,3 +83,25 @@ pub enum AuthorizationKindType { #[sqlx(rename = "Proof")] Proof, } + +#[allow(dead_code)] +#[derive(FromRow)] +pub struct ZkAppCommand { + pub id: Option, + pub memo: Option, + pub hash: String, + pub fee_payer: String, + pub pk_update_body: String, + pub fee: String, + pub valid_until: Option, + pub nonce: Option, + pub sequence_no: i32, + pub status: TransactionStatus, + pub balance_change: String, + pub state_hash: Option, + pub failure_reasons: Option>, + pub token: Option, + pub height: Option, + pub total_count: Option, + pub block_id: Option, +} diff --git a/tasks/dl.ts b/tasks/dl.ts new file mode 100644 index 0000000..54cc534 --- /dev/null +++ b/tasks/dl.ts @@ -0,0 +1,57 @@ +import { dedent } from "@qnighy/dedent" +import { assert, assertExists } from "@std/assert" +import { parseArgs } from "@std/cli" +import { format } from "@std/datetime" +import * as fs from "@std/fs" +import * as path from "@std/path" + +const MINA_ARCHIVE_DUMP_URL = "https://storage.googleapis.com/mina-archive-dumps" + +const { network, "dump-time": dumpTime } = parseArgs(Deno.args, { + string: ["network", "dump-time"], + default: { + network: "devnet", + "dump-time": "0000", + }, +}) + +assert( + ({ + devnet: true, + mainnet: true, + } as Record)[network], +) + +const date = format( + (() => { // 3d ago + const d = new Date() + d.setDate(d.getDate() - 3) + return d + })(), + "yyyy-MM-dd", +) +const dumpUrl = `${MINA_ARCHIVE_DUMP_URL}/${network}-archive-dump-${date}_${dumpTime}.sql.tar.gz` +const destDir = path.join(Deno.cwd(), "sql_scripts") +const dest = path.join(destDir, "archive.tar") + +console.log(`Downloading ${dumpUrl} to ${dest}`) + +await fs.emptyDir(destDir) + +const dumpTarStream = await fetch(dumpUrl).then((v) => v.body) +assertExists(dumpTarStream) + +const file = await Deno.open(dest, { + createNew: true, + append: true, +}) +await dumpTarStream.pipeThrough(new DecompressionStream("gzip")).pipeTo(file.writable) + +// TODO: utilize `UntarStream` from `@std/tar` +await new Deno.Command("tar", { + args: ["-xf", "archive.tar"], + stdout: "inherit", + stderr: "inherit", + cwd: destDir, +}).output() + diff --git a/scripts/enable_logging.sh b/tasks/enable_logging.sh similarity index 81% rename from scripts/enable_logging.sh rename to tasks/enable_logging.sh index f37439a..6c9056f 100755 --- a/scripts/enable_logging.sh +++ b/tasks/enable_logging.sh @@ -1,8 +1,8 @@ #!/bin/bash # This script enables logging of sql statements in the PostgreSQL database -# Put this script in the `../sql_scripts` directory and once you use `just pg` it will be executed automatically -# In order to follow the logs, you can use `docker mina-archive-db logs -f` +# Put this script in the `../sql_scripts` directory and once you use `deno task pg:init` or `deno task dev:init` it will be executed automatically +# In order to follow the logs, you can use `docker mina-archive-db logs -f` echo "Enabling logging settings..." diff --git a/tasks/enable_logging.ts b/tasks/enable_logging.ts new file mode 100644 index 0000000..c22db3f --- /dev/null +++ b/tasks/enable_logging.ts @@ -0,0 +1,12 @@ + +import * as path from "@std/path" + +const destDir = path.join(Deno.cwd(), "sql_scripts") + +await Deno.copyFile( + path.join(path.dirname(path.fromFileUrl(import.meta.url)), "enable_logging.sh"), + path.join(destDir, "enable_logging.sh"), +) + +console.log("Copied enable_logging.sh to", destDir) +console.log("In order to apply the changes, restart the Postgres server. (deno task pg:init)") \ No newline at end of file diff --git a/tasks/pg_wait.ts b/tasks/pg_wait.ts new file mode 100644 index 0000000..42d450f --- /dev/null +++ b/tasks/pg_wait.ts @@ -0,0 +1,43 @@ +// TODO: would we rather use a TypeScript equivalent? + +import pg from "pg" +import "@std/dotenv/load" +import { assertExists } from "@std/assert" + +const connectionString = Deno.env.get("DATABASE_URL") +assertExists(connectionString) + +const MAX_RETRIES = 200 +const RETRY_INTERVAL_MS = 10_000 + +let connected = false +let attempts = 0 + +while (!connected && attempts < MAX_RETRIES) { + try { + const client = new pg.Client({ connectionString }) + await client.connect() + connected = true + await client.end() + } catch (err: unknown) { + if (err instanceof Error && err.message.startsWith("Client has already been connected.")) { + connected = true + break + } + + attempts++ + console.log(`Attempt ${attempts} failed. Waiting for database to be ready...`) + + if (attempts >= MAX_RETRIES) { + console.error("Max retries reached. Could not connect to the database.") + } + + await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL_MS)) + } +} + +if (connected) { + console.log("Database ready at", connectionString) +} else { + Deno.exit(1) +} diff --git a/tests/block.rs b/tests/block.rs index a64737f..1b8e39e 100644 --- a/tests/block.rs +++ b/tests/block.rs @@ -7,6 +7,7 @@ use mina_mesh::{ models::{BlockRequest, BlockResponse, NetworkIdentifier, PartialBlockIdentifier}, MinaMeshConfig, MinaMeshError, }; +use pretty_assertions::assert_eq; #[tokio::test] async fn specified() -> Result<()> { diff --git a/tests/snapshots/block__specified.snap b/tests/snapshots/block__specified.snap index 9e4ed08..bb11316 100644 --- a/tests/snapshots/block__specified.snap +++ b/tests/snapshots/block__specified.snap @@ -558,15 +558,227 @@ Some( transaction_identifier: TransactionIdentifier { hash: "5JtpLNQBmjphWGnyntyqsF8DVX8TUxaYCdzHR4D3ZQGzAx2oJ1Ax", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qrT8ycgyUiAEXA6chy2NaMthRhchbGueX3FrrdbnekjwUN4Bqq5C", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qrT8ycgyUiAEXA6chy2NaMthRhchbGueX3FrrdbnekjwUN4Bqq5C", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qj78UaPdrHwUBTJwFc3tz8GzTLBgijU6MadCdFkY58Lg9gMpPRK8", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JtpLNQBmjphWGnyntyqsF8DVX8TUxaYCdzHR4D3ZQGzAx2oJ1Ax", + hash: "5Ju64BwGA8tYN9F9NMcNKkNUtiAdbdvWWdsriDXCtS28kjwXJJwk", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpfgnUm7zVqi8MJHNB2m37rtgMNDbFNhC2DpMmmVpQt8x6gKv9Ww", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-100000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpfgnUm7zVqi8MJHNB2m37rtgMNDbFNhC2DpMmmVpQt8x6gKv9Ww", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-2000000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpYCQrD9qxKcQF2Ja2bPTtfJ2Zj3SsVsgaivT515NknHsimg63CX", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "2000000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, @@ -574,39 +786,227 @@ Some( transaction_identifier: TransactionIdentifier { hash: "5Ju6Z6aAiKvxNc5Tou87cedCj4tsdv83GzHtu1Jc2FrfwoMqZAwN", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qioSuSzmajyqQK9uXHEfUtQ89aqe7BxGSmaUP6kCCkvSDC4LtuKA", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qioSuSzmajyqQK9uXHEfUtQ89aqe7BxGSmaUP6kCCkvSDC4LtuKA", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpbH52xLKoDASdm37v6V7fLrM4oyaQG3M3tibsPm1aQLagAfAS9r", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5Ju6Z6aAiKvxNc5Tou87cedCj4tsdv83GzHtu1Jc2FrfwoMqZAwN", + hash: "5JuJsuLr6BpWyVQh436qUq4VBnChLDawS8VAX29w8CpZiVSF6VzE", }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JuJsuLr6BpWyVQh436qUq4VBnChLDawS8VAX29w8CpZiVSF6VzE", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JuJsuLr6BpWyVQh436qUq4VBnChLDawS8VAX29w8CpZiVSF6VzE", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JuVUZairQhcerYaTFT2oDyY2vaXYnKaXAxAQ24SGp1oEP4XqPFX", - }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qinuoio4g2CsE6t9YMZZ1r36PttDFDVjs6heZie7Yu1foSBrTbdP", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qinuoio4g2CsE6t9YMZZ1r36PttDFDVjs6heZie7Yu1foSBrTbdP", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qjR4EMKydFpQFzN9uGWHpir8nMXS75dDRkFfDeWpLpZhTecnZCHq", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, @@ -614,183 +1014,1253 @@ Some( transaction_identifier: TransactionIdentifier { hash: "5JuVUZairQhcerYaTFT2oDyY2vaXYnKaXAxAQ24SGp1oEP4XqPFX", }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JuvrqLZ3EwXGPqyHUdP1R7rv3yknzihAGaGgWdMh9iUuTyekLWh", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JuvrqLZ3EwXGPqyHUdP1R7rv3yknzihAGaGgWdMh9iUuTyekLWh", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5Juy3zMDwCBAsaR1rVRFyydkD1WyGt7xPbB3kYSXmAizcsGRE7vJ", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5Juy3zMDwCBAsaR1rVRFyydkD1WyGt7xPbB3kYSXmAizcsGRE7vJ", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5Jv3nsCJYRbw2m7rUmN4tqrf4w35o9Xe38MM1PX7UV7marJuCfoD", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5Jv3nsCJYRbw2m7rUmN4tqrf4w35o9Xe38MM1PX7UV7marJuCfoD", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5Jv43b5zzb8ZJD36K8Qj1n2W56hABvCDHVbjBTnrRa5XSAfYoNJJ", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5Jv43b5zzb8ZJD36K8Qj1n2W56hABvCDHVbjBTnrRa5XSAfYoNJJ", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JvAJNhQLnqEjkWdVEAoKWhS72ZPZGTBP1wecQNZe2mkwBq5uY67", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JvAJNhQLnqEjkWdVEAoKWhS72ZPZGTBP1wecQNZe2mkwBq5uY67", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JvFr3amqo38C5UTScdTrWX2Uh9zEBJMfJ46VkPEBikcy1BzK2uq", - }, - operations: [], - related_transactions: None, - metadata: None, - }, - Transaction { - transaction_identifier: TransactionIdentifier { - hash: "5JvFr3amqo38C5UTScdTrWX2Uh9zEBJMfJ46VkPEBikcy1BzK2uq", - }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qmgdWmgLod7Hr1WAUMLts9vKJ54m9CeWWmgucYTKJHc8Mqt3Wc3k", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qmgdWmgLod7Hr1WAUMLts9vKJ54m9CeWWmgucYTKJHc8Mqt3Wc3k", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qp6GUuQF1V1gftAX77McarE8fyEfQscJDHj77DALNS2b681z6GYL", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JvHyQmPVJUyF4puURRu92hJLVmNy6qpLjjKa6bbHcLeuao6WZ4u", + hash: "5JufsTkU6MYo2QsQh4WiU8F3ssM7TQtx3bdjncLuvxGCPSLZ5mTe", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpfgnUm7zVqi8MJHNB2m37rtgMNDbFNhC2DpMmmVpQt8x6gKv9Ww", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-100000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpfgnUm7zVqi8MJHNB2m37rtgMNDbFNhC2DpMmmVpQt8x6gKv9Ww", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-2000000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpYCQrD9qxKcQF2Ja2bPTtfJ2Zj3SsVsgaivT515NknHsimg63CX", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "2000000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JvHyQmPVJUyF4puURRu92hJLVmNy6qpLjjKa6bbHcLeuao6WZ4u", + hash: "5JuoQgsBxJSrwaRNBnDL8eiz5EbT5kEehepDL5KTamKc2i5v1kaB", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpfgnUm7zVqi8MJHNB2m37rtgMNDbFNhC2DpMmmVpQt8x6gKv9Ww", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-100000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpfgnUm7zVqi8MJHNB2m37rtgMNDbFNhC2DpMmmVpQt8x6gKv9Ww", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-2000000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qrsaLKgMey9Y6aZjdL5FVFa1dkYC4u4qr69Mw1vp54QRt5KVk98o", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "2000000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JvPGvbjz6Kdf9Uiif7RSDFbJRnCfN4mrwK4YuJjQWBUyZKvG6KA", + hash: "5JuvrqLZ3EwXGPqyHUdP1R7rv3yknzihAGaGgWdMh9iUuTyekLWh", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qiU1dVcW2Yw4F4ik82Wjy8W32a8gP3GYzTW6HJEdb2UCmhim8kDu", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qiU1dVcW2Yw4F4ik82Wjy8W32a8gP3GYzTW6HJEdb2UCmhim8kDu", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qphnorEVHZffvCb7BwaP4o6HfumksHyKpf5on9VqbJVPkSBw3ruw", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JvPGvbjz6Kdf9Uiif7RSDFbJRnCfN4mrwK4YuJjQWBUyZKvG6KA", + hash: "5Juy3zMDwCBAsaR1rVRFyydkD1WyGt7xPbB3kYSXmAizcsGRE7vJ", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qo5zQdnJkbjCn8Uu64ukbuSB24PgeaqZSPtErFKnugiT3gygcZop", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qo5zQdnJkbjCn8Uu64ukbuSB24PgeaqZSPtErFKnugiT3gygcZop", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qma6ZCiVp6w4fpMJ5XNKkN9viMvup3HdvxQ1sSfPWuinujVByMzP", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JufsTkU6MYo2QsQh4WiU8F3ssM7TQtx3bdjncLuvxGCPSLZ5mTe", + hash: "5Jv3nsCJYRbw2m7rUmN4tqrf4w35o9Xe38MM1PX7UV7marJuCfoD", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qoVjmoZuWykm6yVTJ7e9zA8q7kVvboK4Jyh4X7KcMjK3hDqYCxbK", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qoVjmoZuWykm6yVTJ7e9zA8q7kVvboK4Jyh4X7KcMjK3hDqYCxbK", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qmLqa3gYiioRho7AaBUQhT1m1yCnaKF8S3sCSXPbJmG98puUHSmp", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JufsTkU6MYo2QsQh4WiU8F3ssM7TQtx3bdjncLuvxGCPSLZ5mTe", + hash: "5Jv43b5zzb8ZJD36K8Qj1n2W56hABvCDHVbjBTnrRa5XSAfYoNJJ", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qnihwg6W1XQhgKqhgkPdQCrvgUguvWE5vBmSAU2Y53nzgJjhk4Bs", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qnihwg6W1XQhgKqhgkPdQCrvgUguvWE5vBmSAU2Y53nzgJjhk4Bs", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qkW4KGRBWn3tDU1PYWqXHbrdf7LWPN3FrZWztEYpGm6e8wUyBjp9", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5Ju64BwGA8tYN9F9NMcNKkNUtiAdbdvWWdsriDXCtS28kjwXJJwk", + hash: "5JvAJNhQLnqEjkWdVEAoKWhS72ZPZGTBP1wecQNZe2mkwBq5uY67", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qnSNPFStU7kdA3gKiHCYouKkYmrzU5NFvu18hbTpUFmZzVjZp6he", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qnSNPFStU7kdA3gKiHCYouKkYmrzU5NFvu18hbTpUFmZzVjZp6he", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qieq72y5Negna1XUQTBSX726LLJ5oAhsFUNZaWAqJJJdamGhGFhv", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5Ju64BwGA8tYN9F9NMcNKkNUtiAdbdvWWdsriDXCtS28kjwXJJwk", + hash: "5JvFr3amqo38C5UTScdTrWX2Uh9zEBJMfJ46VkPEBikcy1BzK2uq", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qjCLySG219LysX9j6U8gpTfLS6JScd2nuMfWPtzQzFZQnemxb1MQ", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qjCLySG219LysX9j6U8gpTfLS6JScd2nuMfWPtzQzFZQnemxb1MQ", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qqRKxgG1cA5hkVs8cYUDoHdsvpW1M8AMgSURwtNpNqXa21Cd9dpQ", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JuoQgsBxJSrwaRNBnDL8eiz5EbT5kEehepDL5KTamKc2i5v1kaB", + hash: "5JvHyQmPVJUyF4puURRu92hJLVmNy6qpLjjKa6bbHcLeuao6WZ4u", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qn8f9eE2ux3LoXvXrpiREF3X9nyHBXajGLeTPyJhq2MPnieV3tbg", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qn8f9eE2ux3LoXvXrpiREF3X9nyHBXajGLeTPyJhq2MPnieV3tbg", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qp4LJX3bwWdxmVJE8csx6CkzjSEZRNQGUiV7S39mcRngsjtygXbg", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, Transaction { transaction_identifier: TransactionIdentifier { - hash: "5JuoQgsBxJSrwaRNBnDL8eiz5EbT5kEehepDL5KTamKc2i5v1kaB", + hash: "5JvPGvbjz6Kdf9Uiif7RSDFbJRnCfN4mrwK4YuJjQWBUyZKvG6KA", }, - operations: [], + operations: [ + Operation { + operation_identifier: OperationIdentifier { + index: 0, + network_index: None, + }, + related_operations: None, + type: "zkapp_fee_payer_dec", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qkZjTMxUwTTumLd5E35DHCos75hjo3jVZdMpo9D73x6vgvY2hoxs", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-200000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 1, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qkZjTMxUwTTumLd5E35DHCos75hjo3jVZdMpo9D73x6vgvY2hoxs", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "-298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + Operation { + operation_identifier: OperationIdentifier { + index: 2, + network_index: None, + }, + related_operations: None, + type: "zkapp_balance_update", + status: Some( + "Success", + ), + account: Some( + AccountIdentifier { + address: "B62qpuN14M3vKvrfecc5k5Skqns4STnq54E2nvDnjvaWYduMPkT2xzs", + sub_account: None, + metadata: Some( + Object { + "token_id": String("wSHV2S4qX9jFsLjQo8r1BsMLH2ZRKsZx6EJd1sbozGPieEC4Jf"), + }, + ), + }, + ), + amount: Some( + Amount { + value: "298800000000", + currency: Currency { + symbol: "MINA", + decimals: 9, + metadata: None, + }, + metadata: None, + }, + ), + coin_change: None, + metadata: None, + }, + ], related_transactions: None, metadata: None, }, diff --git a/words.txt b/words.txt index ff84354..4e41c6e 100644 --- a/words.txt +++ b/words.txt @@ -1,9 +1,9 @@ -MINAMESH -RUSTFLAGS codegen coinbases darklight +datetime deamon +deno devnet dotenv dprint @@ -17,6 +17,7 @@ harrysolovay indoc initdb insta +iohk isready joaosreis johnmarcou @@ -26,13 +27,17 @@ lookback microschemas mina minafoundation +MINAMESH navroot nocapture openapi +piotr preprocess +qnighy querygen reqwest retriable +RUSTFLAGS rustfmt schnorr secp @@ -40,6 +45,8 @@ snarked sqltools sqlx thiserror +untar +untarring urlencode utxo walkdir