diff --git a/indexer/src/kadena-server/repository/infra/repository/block-db-repository.ts b/indexer/src/kadena-server/repository/infra/repository/block-db-repository.ts index 82a12d28..b5d8f517 100644 --- a/indexer/src/kadena-server/repository/infra/repository/block-db-repository.ts +++ b/indexer/src/kadena-server/repository/infra/repository/block-db-repository.ts @@ -697,7 +697,7 @@ export default class BlockDbRepository implements BlockRepository { `SELECT COUNT(*) as "totalCount" FROM "Blocks" b JOIN "Transactions" t ON t."blockId" = b.id - WHERE b.hash = $1`, + WHERE b.hash = $1 AND t.sender != 'coinbase'`, [blockHash], ); diff --git a/indexer/src/kadena-server/repository/infra/repository/transfer-db-repository.ts b/indexer/src/kadena-server/repository/infra/repository/transfer-db-repository.ts index 7da57831..5e5dbabc 100644 --- a/indexer/src/kadena-server/repository/infra/repository/transfer-db-repository.ts +++ b/indexer/src/kadena-server/repository/infra/repository/transfer-db-repository.ts @@ -133,6 +133,10 @@ export default class TransferDbRepository implements TransferRepository { let query = ''; if (blockHash) { + if (requestKey) { + queryParams.push(requestKey); + conditions += `\nAND t.requestkey = $${queryParams.length}`; + } queryParams.push(blockHash); query = ` WITH filtered_block AS ( @@ -163,6 +167,11 @@ export default class TransferDbRepository implements TransferRepository { LIMIT $1 `; } else if (requestKey) { + if (blockHash) { + queryParams.push(blockHash); + conditions += `\nAND b.hash = $${queryParams.length}`; + } + queryParams.push(requestKey); query = ` WITH filtered_transaction AS ( diff --git a/indexer/src/kadena-server/resolvers/fields/block/transactions-block-resolver.ts b/indexer/src/kadena-server/resolvers/fields/block/transactions-block-resolver.ts index a28b4cb4..78a3fa7a 100644 --- a/indexer/src/kadena-server/resolvers/fields/block/transactions-block-resolver.ts +++ b/indexer/src/kadena-server/resolvers/fields/block/transactions-block-resolver.ts @@ -24,6 +24,7 @@ export const transactionsBlockResolver: BlockResolvers['transac const { first, last, before, after } = args; const output = await context.transactionRepository.getTransactions({ blockHash: hash, + isCoinbase: false, first, last, before, diff --git a/indexer/tests/integration/api-parity/blocks-from-depth.builder.ts b/indexer/tests/integration/api-parity/blocks-from-depth.builder.ts new file mode 100644 index 00000000..98940aec --- /dev/null +++ b/indexer/tests/integration/api-parity/blocks-from-depth.builder.ts @@ -0,0 +1,80 @@ +import { gql } from 'graphql-request'; + +export const blocksFromDepthQueryGql = gql` + query blocksFromDepth($minimumDepth: Int!, $chainIds: [String!]!) { + blocksFromDepth(minimumDepth: $minimumDepth, chainIds: $chainIds, first: 20) { + edges { + node { + chainId + creationTime + difficulty + hash + epoch + events { + totalCount + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + chainId + height + id + moduleName + name + orderIndex + parameters + parameterText + qualifiedName + requestKey + } + } + } + flags + hash + height + id + minerAccount { + accountName + balance + chainId + fungibleName + guard { + ... on KeysetGuard { + keys + predicate + raw + } + } + id + } + neighbors { + chainId + hash + } + nonce + parent { + chainId + } + payloadHash + powHash + target + transactions { + totalCount + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + id + } + } + } + weight + } + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/blocks-from-height.builder.ts b/indexer/tests/integration/api-parity/blocks-from-height.builder.ts new file mode 100644 index 00000000..53701af5 --- /dev/null +++ b/indexer/tests/integration/api-parity/blocks-from-height.builder.ts @@ -0,0 +1,79 @@ +import { gql } from 'graphql-request'; + +export const blocksFromHeightQueryGql = gql` + query blocksFromHeight($startHeight: Int!, $endHeight: Int) { + blocksFromHeight(startHeight: $startHeight, endHeight: $endHeight, first: 20) { + edges { + node { + chainId + creationTime + difficulty + epoch + events { + totalCount + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + chainId + height + id + moduleName + name + orderIndex + parameters + parameterText + qualifiedName + requestKey + } + } + } + flags + hash + height + id + minerAccount { + accountName + balance + chainId + fungibleName + guard { + ... on KeysetGuard { + keys + predicate + raw + } + } + id + } + neighbors { + chainId + hash + } + nonce + parent { + chainId + } + payloadHash + powHash + target + transactions { + totalCount + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + id + } + } + } + weight + } + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/completed-block-heights.builder.ts b/indexer/tests/integration/api-parity/completed-block-heights.builder.ts new file mode 100644 index 00000000..2410fb00 --- /dev/null +++ b/indexer/tests/integration/api-parity/completed-block-heights.builder.ts @@ -0,0 +1,80 @@ +import { gql } from 'graphql-request'; + +export const completedBlockHeightsQueryGql = gql` + query completedBlockHeights($completedHeights: Boolean) { + completedBlockHeights(completedHeights: $completedHeights, first: 20) { + edges { + node { + chainId + creationTime + difficulty + hash + epoch + events { + totalCount + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + chainId + height + id + moduleName + name + orderIndex + parameters + parameterText + qualifiedName + requestKey + } + } + } + flags + hash + height + id + minerAccount { + accountName + balance + chainId + fungibleName + guard { + ... on KeysetGuard { + keys + predicate + raw + } + } + id + } + neighbors { + chainId + hash + } + nonce + parent { + chainId + } + payloadHash + powHash + target + transactions { + totalCount + pageInfo { + hasNextPage + hasPreviousPage + } + edges { + node { + id + } + } + } + weight + } + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/fungible-accounts-by-public-key.builder.ts b/indexer/tests/integration/api-parity/fungible-accounts-by-public-key.builder.ts new file mode 100644 index 00000000..36006cfd --- /dev/null +++ b/indexer/tests/integration/api-parity/fungible-accounts-by-public-key.builder.ts @@ -0,0 +1,25 @@ +import { gql } from 'graphql-request'; + +export const fungibleAccountsByPublicKeyQueryGql = gql` + query fungibleAccountsByPublicKey($publicKey: String!) { + fungibleAccountsByPublicKey(publicKey: $publicKey) { + fungibleName + accountName + totalBalance + chainAccounts { + id + accountName + balance + chainId + fungibleName + guard { + ... on KeysetGuard { + keys + predicate + raw + } + } + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/fungible-chain-account.builder.ts b/indexer/tests/integration/api-parity/fungible-chain-account.builder.ts new file mode 100644 index 00000000..34aacc5b --- /dev/null +++ b/indexer/tests/integration/api-parity/fungible-chain-account.builder.ts @@ -0,0 +1,23 @@ +import { gql } from 'graphql-request'; + +export const fungibleChainAccountQueryGql = gql` + query { + fungibleChainAccount( + accountName: "k:1dc186034e79417a93f5cf05a99874c0a3681936faaf3d5963f77b262218fe82" + chainId: "0" + ) { + id + accountName + balance + chainId + fungibleName + guard { + ... on KeysetGuard { + keys + predicate + raw + } + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/fungible-chain-accounts-by-public-key.builder.ts b/indexer/tests/integration/api-parity/fungible-chain-accounts-by-public-key.builder.ts new file mode 100644 index 00000000..8e35f3b7 --- /dev/null +++ b/indexer/tests/integration/api-parity/fungible-chain-accounts-by-public-key.builder.ts @@ -0,0 +1,20 @@ +import { gql } from 'graphql-request'; + +export const fungibleChainAccountsByPublicKeyQueryGql = gql` + query fungibleChainAccountsByPublicKey($publicKey: String!, $chainId: String!) { + fungibleChainAccountsByPublicKey(publicKey: $publicKey, chainId: $chainId) { + id + accountName + balance + chainId + fungibleName + guard { + ... on KeysetGuard { + keys + predicate + raw + } + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/graph-configuration.builder.ts b/indexer/tests/integration/api-parity/graph-configuration.builder.ts new file mode 100644 index 00000000..552d87e8 --- /dev/null +++ b/indexer/tests/integration/api-parity/graph-configuration.builder.ts @@ -0,0 +1,10 @@ +import { gql } from 'graphql-request'; + +export const graphConfigurationQueryGql = gql` + query { + graphConfiguration { + minimumBlockHeight + version + } + } +`; diff --git a/indexer/tests/integration/api-parity/kadena-vs-hackachain.test.ts b/indexer/tests/integration/api-parity/kadena-vs-hackachain.test.ts index 16992daf..4dae3fba 100644 --- a/indexer/tests/integration/api-parity/kadena-vs-hackachain.test.ts +++ b/indexer/tests/integration/api-parity/kadena-vs-hackachain.test.ts @@ -7,8 +7,21 @@ import { transactionsQueryGql } from './transactions.builder'; import { lastBlockHeightQueryGql } from './last-block-height.builder'; import { fungibleAccountQueryGql } from './fungible-account.builder'; import { nonFungibleAccountQueryGql } from './non-fungible-account.builder'; +import { pactQueryGql } from './pact-query.builder'; +import { transactionByPublicKeyQueryGql } from './transaction-by-public-key.builder'; import { generateHashes } from './hash-generator'; import { logoutError } from './test-error-logger'; +import { fungibleChainAccountQueryGql } from './fungible-chain-account.builder'; +import { nonFungibleChainAccountQueryGql } from './non-fungible-chain-account.builder'; +import { getNodeQuery } from '../builders/node.builder'; +import { getNodesQuery } from '../builders/nodes.builder'; +import { networkInfoQueryGql } from './network-info.builder'; +import { graphConfigurationQueryGql } from './graph-configuration.builder'; +import { fungibleAccountsByPublicKeyQueryGql } from './fungible-accounts-by-public-key.builder'; +import { getFungibleChainAccountsByPublicKeyQuery } from '../builders/fungible-chain-accounts-by-public-key.builder'; +import { blocksFromHeightQueryGql } from './blocks-from-height.builder'; +import { blocksFromDepthQueryGql } from './blocks-from-depth.builder'; +import { completedBlockHeightsQueryGql } from './completed-block-heights.builder'; if (!process.env.HACKACHAIN_API_URL || !process.env.KADENA_API_URL) { throw new Error('Missing HACKACHAIN_API_URL or KADENA_API_URL environment variables.'); @@ -177,4 +190,297 @@ describe('Transactions', () => { expect(hackachainData).toMatchObject(kadenaData); }); + + it('#009 - pact query', async () => { + const pactQueries = [ + { + chainId: '1', + code: '(describe-module "coin")', + }, + { + chainId: '1', + code: '(coin.details "test")', + }, + { + chainId: '1', + code: "(coin.details (read-msg 'account))", + data: [{ key: 'account', value: 'test' }], + }, + ]; + const hackachainData = await hackachainClient.request(pactQueryGql, { + pactQueries, + }); + + const kadenaData = await kadenaClient.request(pactQueryGql, { + pactQueries, + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#010 - transactionsByPublicKey', async () => { + const hackachainData = await hackachainClient.request(transactionByPublicKeyQueryGql, { + publicKey: '1001e8d69988110ca08122cf6d4e0258cac3b3a3de1978c47080a1cf9f0bcadf', + }); + hackachainData.transactionsByPublicKey.edges.sort((a: any, b: any) => + a.node.id.localeCompare(b.node.id), + ); + + const kadenaData = await kadenaClient.request(transactionByPublicKeyQueryGql, { + publicKey: '1001e8d69988110ca08122cf6d4e0258cac3b3a3de1978c47080a1cf9f0bcadf', + }); + kadenaData.transactionsByPublicKey.edges.sort((a: any, b: any) => + a.node.id.localeCompare(b.node.id), + ); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#011 - fungibleChainAccount', async () => { + const hackachainData = await hackachainClient.request(fungibleChainAccountQueryGql, { + accountName: 'k:1dc186034e79417a93f5cf05a99874c0a3681936faaf3d5963f77b262218fe82', + chainId: '0', + }); + + const kadenaData = await kadenaClient.request(fungibleChainAccountQueryGql, { + accountName: 'k:1dc186034e79417a93f5cf05a99874c0a3681936faaf3d5963f77b262218fe82', + chainId: '0', + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + // kadena returns a timeout on this query, skipping for now + it.skip('#012 - fungibleAccountsByPublicKey', async () => { + const hackachainData = await hackachainClient.request(fungibleAccountsByPublicKeyQueryGql, { + publicKey: '1dc186034e79417a93f5cf05a99874c0a3681936faaf3d5963f77b262218fe82', + }); + + const kadenaData = await kadenaClient.request(fungibleAccountsByPublicKeyQueryGql, { + publicKey: '1dc186034e79417a93f5cf05a99874c0a3681936faaf3d5963f77b262218fe82', + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#013 - nonFungibleChainAccount', async () => { + const hackachainData = await hackachainClient.request(nonFungibleChainAccountQueryGql, { + accountName: 'k:7b80749bd0c0f8dc793ffe6a0a4c75f8c74ef25008c45ca02bcc154ef00c7c31', + chainId: '8', + }); + + hackachainData.nonFungibleChainAccount.nonFungibleTokenBalances.sort((a: any, b: any) => + a.id.localeCompare(b.id), + ); + + const kadenaData = await kadenaClient.request(nonFungibleChainAccountQueryGql, { + accountName: 'k:7b80749bd0c0f8dc793ffe6a0a4c75f8c74ef25008c45ca02bcc154ef00c7c31', + chainId: '8', + }); + + kadenaData.nonFungibleChainAccount.nonFungibleTokenBalances.sort((a: any, b: any) => + a.id.localeCompare(b.id), + ); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#014 - node (block)', async () => { + const nodeQuery = getNodeQuery('Block', { + id: 'QmxvY2s6T0txV3psalZXZll6SkdVaEtIMlBBUUo1M2VIMjRNdUd0TC13Sl82bGxWbw==', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery, { + id: 'QmxvY2s6T0txV3psalZXZll6SkdVaEtIMlBBUUo1M2VIMjRNdUd0TC13Sl82bGxWbw==', + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#015 - node (event)', async () => { + const nodeQuery = getNodeQuery('Event', { + id: 'RXZlbnQ6WyIyZU9LNTBhZnppZjRIN2pNQmdLNjlVNURERnRLemJYQjlLbnd2RWVXQ2swIiwiMyIsIlR5Z3VGOVZVbG5rVkYtSmRTVXdSeXpya2FGOTl2OUNONWk3UUpiQ01HZVkiXQ==', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery, { + id: 'RXZlbnQ6WyIyZU9LNTBhZnppZjRIN2pNQmdLNjlVNURERnRLemJYQjlLbnd2RWVXQ2swIiwiMyIsIlR5Z3VGOVZVbG5rVkYtSmRTVXdSeXpya2FGOTl2OUNONWk3UUpiQ01HZVkiXQ==', + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#016 - node (fungible account)', async () => { + const nodeQuery = getNodeQuery('FungibleAccount', { + id: 'RnVuZ2libGVBY2NvdW50OlsiY29pbiIsIms6ZWY3Y2I2NmMzMDZiMjhiMzI3MzRhNTQ0YmJiMDVhYmQxNDMwZDYzNzgyN2MwOWZkMGY4OThhODliNzc5YmFjYyJd', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery, { + id: 'RnVuZ2libGVBY2NvdW50OlsiY29pbiIsIms6ZWY3Y2I2NmMzMDZiMjhiMzI3MzRhNTQ0YmJiMDVhYmQxNDMwZDYzNzgyN2MwOWZkMGY4OThhODliNzc5YmFjYyJd', + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#017 - node (fungible chain account)', async () => { + const nodeQuery = getNodeQuery('FungibleChainAccount', { + id: 'RnVuZ2libGVDaGFpbkFjY291bnQ6WyIwIiwiY29pbiIsIms6ODRhY2FjMGI3MmU4MWU2MTdlZTQxN2E1NWIxNmNkYWE5Y2JjZDNmZjhmZmZkMTI5NmNiMDkzNzZhNzkxNmQ0MCJd', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery, { + id: 'RnVuZ2libGVDaGFpbkFjY291bnQ6WyIwIiwiY29pbiIsIms6ODRhY2FjMGI3MmU4MWU2MTdlZTQxN2E1NWIxNmNkYWE5Y2JjZDNmZjhmZmZkMTI5NmNiMDkzNzZhNzkxNmQ0MCJd', + }); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#018 - node (non fungible account)', async () => { + const nodeQuery = getNodeQuery('NonFungibleAccount', { + id: 'Tm9uRnVuZ2libGVBY2NvdW50Oms6MGM2ODZkZjVkNTE0OWY2NjJiY2JkZGIzNWZjYmVkZGM2M2YxM2IyMmZlNmE5ZTI0NWFkNzgxOTgzNGQ2NjNjMw==', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + hackachainData.node.nonFungibleTokenBalances.sort((a: any, b: any) => a.id.localeCompare(b.id)); + + const kadenaData = await kadenaClient.request(nodeQuery); + + kadenaData.node.nonFungibleTokenBalances.sort((a: any, b: any) => a.id.localeCompare(b.id)); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#019 - node (non fungible chain account)', async () => { + const nodeQuery = getNodeQuery('NonFungibleChainAccount', { + id: 'Tm9uRnVuZ2libGVDaGFpbkFjY291bnQ6WyI4IiwiazowY2JlMmI4ZTIwNWIzZTIyNTExMzM0NTc4ZjhlY2Q5MjY3Yzc1MjdkMjBjZjZhMWFhN2IxMzRkODI4Mjc2NzhkIl0=', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + hackachainData.node.nonFungibleTokenBalances.sort((a: any, b: any) => a.id.localeCompare(b.id)); + + const kadenaData = await kadenaClient.request(nodeQuery); + + kadenaData.node.nonFungibleTokenBalances.sort((a: any, b: any) => a.id.localeCompare(b.id)); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#020 - node (non fungible token balance)', async () => { + const nodeQuery = getNodeQuery('NonFungibleTokenBalance', { + id: 'Tm9uRnVuZ2libGVUb2tlbkJhbGFuY2U6WyJ0OjdyTHhnY2ptNFZienJVcGRGVENlOUVZSFBSOU5rNlR1YkVKTVd6Ny03MTQiLCJrOjQ4ZjNjOGVlM2YxNDk0M2UyMGFkYmIzMDJjZDdlNzQwMzBhZTRlZDFjZmNiYjYzMTNiOGFjNTM2N2MxYTNkZjQiLCI4Il0=', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#021 - node (signer)', async () => { + const nodeQuery = getNodeQuery('Signer', { + id: 'U2lnbmVyOlsiTzNYRHYzX2NZaHFUUGwyWXItMFVKREZHdUMwNHBlZHd0c0gzVEYxbW1JcyIsIjAiXQ==', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#022 - node (transaction)', async () => { + const nodeQuery = getNodeQuery('Transaction', { + id: 'VHJhbnNhY3Rpb246WyIyUkprUUpkZ1hRSjZQTkI5MG44WmwwdVZZQklOcV90TGt5STNoVjlpeDEwIiwiWm1jVTNKb0xkU0h2TDQ2MzQzVkJEMTM5ZnM3cFkwczRDOU1YNDJKQnVlZyJd', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#023 - node (transfer)', async () => { + const nodeQuery = getNodeQuery('Transfer', { + id: 'VHJhbnNmZXI6WyJzNUp3ckxJeUVkQ00tdUJRTFN6RGxJeG9RSld4RkV3UDVOcHN4ekdESEVzIiwiMCIsIjQiLCJCNURsTnQ4T2E1VG53UUhneEszQlowbFdGM0pvdW94WmhWOWN5ZHNmQlRBIiwiT1ZzRFJzQkN0MzZkME1fWjA1ZG5fQ2UxcGVDUUYwY3JnOTloYkI5X1FYVSJd', + }); + const hackachainData = await hackachainClient.request(nodeQuery); + + const kadenaData = await kadenaClient.request(nodeQuery); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#024 - nodes (block and transfer)', async () => { + const query = getNodesQuery({ + ids: [ + 'QmxvY2s6T0txV3psalZXZll6SkdVaEtIMlBBUUo1M2VIMjRNdUd0TC13Sl82bGxWbw==', + 'VHJhbnNmZXI6WyJzNUp3ckxJeUVkQ00tdUJRTFN6RGxJeG9RSld4RkV3UDVOcHN4ekdESEVzIiwiMCIsIjQiLCJCNURsTnQ4T2E1VG53UUhneEszQlowbFdGM0pvdW94WmhWOWN5ZHNmQlRBIiwiT1ZzRFJzQkN0MzZkME1fWjA1ZG5fQ2UxcGVDUUYwY3JnOTloYkI5X1FYVSJd', + ], + }); + const hackachainData = await hackachainClient.request(query); + + const kadenaData = await kadenaClient.request(query); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#025 - networkInfo', async () => { + const hackachainData = await hackachainClient.request(networkInfoQueryGql); + const kadenaData = await kadenaClient.request(networkInfoQueryGql); + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#026 - graphConfiguration', async () => { + const hackachainData = await hackachainClient.request(graphConfigurationQueryGql); + const kadenaData = await kadenaClient.request(graphConfigurationQueryGql); + expect(hackachainData).toMatchObject(kadenaData); + }); + + // kadena api returns a timeout on this query, skipping while there's not fix on it + it.skip('#027 - fungibleChainAccountsByPublicKey', async () => { + const query = getFungibleChainAccountsByPublicKeyQuery({ + publicKey: '20d27f46670fba5aba26a6291a350fc72b46729af1d9776661479c4860c215da', + chainId: '0', + }); + const hackachainData = await hackachainClient.request(query); + const kadenaData = await kadenaClient.request(query); + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#028 - blocksFromHeight', async () => { + const hackachainData = await hackachainClient.request(blocksFromHeightQueryGql, { + startHeight: 4000000, + endHeight: 4500000, + }); + + hackachainData.blocksFromHeight.edges.sort((a: any, b: any) => a.node.chainId - b.node.chainId); + + const kadenaData = await kadenaClient.request(blocksFromHeightQueryGql, { + startHeight: 4000000, + endHeight: 4000000, + }); + + kadenaData.blocksFromHeight.edges.sort((a: any, b: any) => a.node.chainId - b.node.chainId); + + expect(hackachainData).toMatchObject(kadenaData); + }); + + it('#029 - blocksFromDepth', async () => { + const hackachainData = await hackachainClient.request(blocksFromDepthQueryGql, { + minimumDepth: 1, + chainIds: ['9'], + }); + + hackachainData.blocksFromDepth.edges.sort((a: any, b: any) => a.node.height - b.node.height); + + const kadenaData = await kadenaClient.request(blocksFromDepthQueryGql, { + minimumDepth: 1, + chainIds: ['9'], + }); + + kadenaData.blocksFromDepth.edges.sort((a: any, b: any) => a.node.height - b.node.height); + + expect(hackachainData).toMatchObject(kadenaData); + }); }); diff --git a/indexer/tests/integration/api-parity/network-info.builder.ts b/indexer/tests/integration/api-parity/network-info.builder.ts new file mode 100644 index 00000000..5f976dbe --- /dev/null +++ b/indexer/tests/integration/api-parity/network-info.builder.ts @@ -0,0 +1,15 @@ +import { gql } from 'graphql-request'; + +export const networkInfoQueryGql = gql` + query { + networkInfo { + apiVersion + coinsInCirculation + networkHashRate + networkHost + networkId + totalDifficulty + transactionCount + } + } +`; diff --git a/indexer/tests/integration/api-parity/node.builder.ts b/indexer/tests/integration/api-parity/node.builder.ts new file mode 100644 index 00000000..9bb22897 --- /dev/null +++ b/indexer/tests/integration/api-parity/node.builder.ts @@ -0,0 +1,286 @@ +import { gql } from 'graphql-request'; + +export const blockFragment = ` +... on Block { + chainId + creationTime + difficulty + epoch + events { + edges { + node { + id + } + } + } + flags + hash + height + id + minerAccount { + accountName + balance + } + neighbors { + chainId + hash + } + nonce + parent { + id + } + payloadHash + powHash + target + transactions { + edges { + node { + id + } + } + } + weight +} +`; + +const eventFragment = ` +... on Event { + block { + id + } + chainId + height + id + moduleName + name + orderIndex + parameters + parameterText + qualifiedName + requestKey + transaction { + id + } +} +`; + +const fungibleAccountFragment = ` +... on FungibleAccount { + accountName + chainAccounts { + accountName + chainId + fungibleName + guard { + raw + } + id + } + fungibleName + id +} +`; + +const fungibleChainAccountFragment = ` +... on FungibleChainAccount { + accountName + chainId + fungibleName + guard { + raw + } + id +} +`; + +const nonFungibleAccountFragment = ` +... on NonFungibleAccount { + id + accountName + nonFungibleTokenBalances { + id + accountName + chainId + guard { + raw + } + info { + precision + supply + uri + } + tokenId + version + } +} +`; + +const nonFungibleChainAccountFragment = ` +... on NonFungibleChainAccount { + accountName + chainId + id + nonFungibleTokenBalances { + accountName + chainId + guard { + raw + } + id + info { + precision + supply + uri + } + tokenId + version + } +} +`; + +const nonFungibleTokenBalanceFragment = ` +... on NonFungibleTokenBalance { + accountName + balance + chainId + guard { + raw + } + id + info { + precision + supply + uri + } + tokenId + version +} +`; + +const signerFragment = ` +... on Signer { + address + clist { + args + name + } + id + orderIndex + pubkey + scheme +} +`; + +export const transactionFragment = ` +... on Transaction { + cmd { + meta { + chainId + creationTime + gasLimit + gasPrice + sender + ttl + } + networkId + nonce + payload { + ... on ExecutionPayload { + code + data + } + } + signers { + id + } + } + hash + id + orphanedTransactions { + id + } + result { + ... on TransactionResult { + badResult + block { + id + } + continuation + eventCount + events { + edges { + node { + id + } + } + } + gas + goodResult + logs + transactionId + transfers { + edges { + node { + id + } + } + } + } + } + sigs { + sig + } +} +`; + +const transferFragment = ` +... on Transfer { + amount + block { + id + } + creationTime + crossChainTransfer { + id + } + id + moduleHash + moduleName + orderIndex + receiverAccount + requestKey + senderAccount + transaction { + id + } +} +`; + +export const getNodeQuery = (type: string, params: any): string => { + if (Object.keys(params).length === 0) { + throw new Error('No parameters provided to getNodeQuery.'); + } + + const query = Object.entries(params) + .map(([key, value]) => `${key}: ${typeof value === 'string' ? `"${value}"` : value}`) + .join(', '); + + const queryGql = gql` + query { + node(${query}) { + ${type === 'Block' ? blockFragment : ''} + ${type === 'Event' ? eventFragment : ''} + ${type === 'FungibleAccount' ? fungibleAccountFragment : ''} + ${type === 'FungibleChainAccount' ? fungibleChainAccountFragment : ''} + ${type === 'NonFungibleAccount' ? nonFungibleAccountFragment : ''} + ${type === 'NonFungibleChainAccount' ? nonFungibleChainAccountFragment : ''} + ${type === 'NonFungibleTokenBalance' ? nonFungibleTokenBalanceFragment : ''} + ${type === 'Signer' ? signerFragment : ''} + ${type === 'Transaction' ? transactionFragment : ''} + ${type === 'Transfer' ? transferFragment : ''} + } + } + `; + + return queryGql; +}; diff --git a/indexer/tests/integration/api-parity/non-fungible-chain-account.builder.ts b/indexer/tests/integration/api-parity/non-fungible-chain-account.builder.ts new file mode 100644 index 00000000..22a8669a --- /dev/null +++ b/indexer/tests/integration/api-parity/non-fungible-chain-account.builder.ts @@ -0,0 +1,28 @@ +import { gql } from 'graphql-request'; + +export const nonFungibleChainAccountQueryGql = gql` + query nonFungibleChainAccount($accountName: String!, $chainId: String!) { + nonFungibleChainAccount(accountName: $accountName, chainId: $chainId) { + id + accountName + nonFungibleTokenBalances { + id + accountName + chainId + guard { + ... on KeysetGuard { + keys + predicate + } + } + info { + precision + supply + uri + } + tokenId + version + } + } + } +`; diff --git a/indexer/tests/integration/api-parity/pact-query.builder.ts b/indexer/tests/integration/api-parity/pact-query.builder.ts new file mode 100644 index 00000000..688b0004 --- /dev/null +++ b/indexer/tests/integration/api-parity/pact-query.builder.ts @@ -0,0 +1,13 @@ +import { gql } from 'graphql-request'; + +export const pactQueryGql = gql` + query pactQuery($pactQueries: [PactQuery!]!) { + pactQuery(pactQuery: $pactQueries) { + chainId + code + error + result + status + } + } +`; diff --git a/indexer/tests/integration/api-parity/transaction-by-public-key.builder.ts b/indexer/tests/integration/api-parity/transaction-by-public-key.builder.ts new file mode 100644 index 00000000..1746dfcb --- /dev/null +++ b/indexer/tests/integration/api-parity/transaction-by-public-key.builder.ts @@ -0,0 +1,80 @@ +import { gql } from 'graphql-request'; + +export const transactionByPublicKeyQueryGql = gql` + query transactionByPublicKey($publicKey: String!) { + transactionsByPublicKey(publicKey: $publicKey, first: 50) { + edges { + node { + cmd { + meta { + chainId + creationTime + gasLimit + gasPrice + sender + ttl + } + networkId + nonce + payload { + ... on ExecutionPayload { + code + data + } + } + signers { + address + clist { + args + name + } + id + orderIndex + pubkey + scheme + } + } + hash + id + result { + ... on TransactionResult { + badResult + block { + id + } + continuation + eventCount + # events { + # pageInfo { + # endCursor + # hasNextPage + # hasPreviousPage + # startCursor + # } + # edges { + # node { + # id + # } + # } + # } + gas + goodResult + logs + transactionId + transfers { + edges { + node { + id + } + } + } + } + } + sigs { + sig + } + } + } + } + } +`; diff --git a/indexer/tests/integration/builders/node.builder.ts b/indexer/tests/integration/builders/node.builder.ts index 9bb22897..13c29d99 100644 --- a/indexer/tests/integration/builders/node.builder.ts +++ b/indexer/tests/integration/builders/node.builder.ts @@ -102,7 +102,10 @@ const nonFungibleAccountFragment = ` accountName chainId guard { - raw + ... on KeysetGuard { + keys + predicate + } } info { precision @@ -124,7 +127,10 @@ const nonFungibleChainAccountFragment = ` accountName chainId guard { - raw + ... on KeysetGuard { + keys + predicate + } } id info { @@ -144,7 +150,10 @@ const nonFungibleTokenBalanceFragment = ` balance chainId guard { - raw + ... on KeysetGuard { + keys + predicate + } } id info { @@ -196,9 +205,6 @@ export const transactionFragment = ` } hash id - orphanedTransactions { - id - } result { ... on TransactionResult { badResult