Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: tx pagination #3530

Merged
merged 8 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions bats/core/api/onchain-receive.bats
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ setup_file() {
[[ "${on_chain_address_created_1}" != "null" ]] || exit 1

bitcoin_cli sendtoaddress "$on_chain_address_created_1" "$amount"
retry 15 1 check_for_broadcast 'alice' "$on_chain_address_created_1" 1
retry 15 1 check_for_broadcast 'alice' "$on_chain_address_created_1"

# Create address and broadcast transaction 2
exec_graphql 'alice' 'on-chain-address-create' "$variables"
on_chain_address_created_2="$(graphql_output '.data.onChainAddressCreate.address')"
[[ "${on_chain_address_created_2}" != "null" ]] || exit 1

bitcoin_cli sendtoaddress "$on_chain_address_created_2" "$amount"
retry 15 1 check_for_broadcast 'alice' "$on_chain_address_created_2" 1
retry 15 1 check_for_broadcast 'alice' "$on_chain_address_created_2"

# Check pending transactions for address 1
address_1_pending_txns_variables=$(
Expand Down Expand Up @@ -224,7 +224,7 @@ setup_file() {

# Execute onchain send and check for transaction
bitcoin_cli sendtoaddress "$on_chain_address_created" "$amount"
retry 15 1 check_for_broadcast 'alice' "$on_chain_address_created" 1
retry 15 1 check_for_broadcast 'alice' "$on_chain_address_created"

# Check pending transactions for address
address_pending_txns_variables=$(
Expand Down Expand Up @@ -315,9 +315,9 @@ setup_file() {
tx_hex=$(bitcoin_cli finalizepsbt "$signed_psbt" | jq -r '.hex')
txid=$(bitcoin_cli sendrawtransaction "$tx_hex")

retry 15 1 check_for_broadcast 'alice' "$alice_address_1" 2
retry 3 1 check_for_broadcast 'alice' "$alice_address_2" 2
retry 3 1 check_for_broadcast 'bob' "$bob_address_1" 1
retry 15 1 check_for_broadcast 'alice' "$alice_address_1"
retry 3 1 check_for_broadcast 'alice' "$alice_address_2"
retry 3 1 check_for_broadcast 'bob' "$bob_address_1"

# Check 'pendingIncomingBalance' query
exec_graphql 'alice' 'wallets-for-account'
Expand Down Expand Up @@ -406,9 +406,9 @@ setup_file() {
tx_hex=$(bitcoin_cli finalizepsbt "$signed_psbt" | jq -r '.hex')
txid=$(bitcoin_cli sendrawtransaction "$tx_hex")

retry 45 1 check_for_broadcast 'alice' "$alice_btc_address" 10
retry 3 1 check_for_broadcast 'alice' "$alice_usd_address" 10
retry 3 1 check_for_broadcast 'bob' "$bob_btc_address" 10
retry 45 1 check_for_broadcast 'alice' "$alice_btc_address"
retry 3 1 check_for_broadcast 'alice' "$alice_usd_address"
retry 3 1 check_for_broadcast 'bob' "$bob_btc_address"

# Mine transactions
# Note: subscription event operates in a delayed way from lnd1 state
Expand Down
8 changes: 4 additions & 4 deletions bats/core/api/onchain-send.bats
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,10 @@ grep_in_trigger_logs() {
# ----------

# Check for broadcast of last send
retry 15 1 check_for_broadcast 'alice' "$on_chain_payment_send_all_address" 4
retry 3 1 check_for_broadcast 'alice' "$on_chain_usd_payment_send_as_btc_denominated_address" 4
retry 3 1 check_for_broadcast 'alice' "$on_chain_usd_payment_send_address" 4
retry 3 1 check_for_broadcast 'alice' "$on_chain_payment_send_address" 4
retry 15 1 check_for_outgoing_broadcast 'alice' "$on_chain_payment_send_all_address" 4
retry 3 1 check_for_outgoing_broadcast 'alice' "$on_chain_usd_payment_send_as_btc_denominated_address" 4
retry 3 1 check_for_outgoing_broadcast 'alice' "$on_chain_usd_payment_send_address" 4
retry 3 1 check_for_outgoing_broadcast 'alice' "$on_chain_payment_send_address" 4

# Mine all
bitcoin_cli -generate 2
Expand Down
25 changes: 25 additions & 0 deletions bats/helpers/onchain.bash
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,34 @@ get_from_transaction_by_address() {
| jq -r "$property_query"
}

get_from_pending_transaction_by_address() {
property_query=$2

jq_query='.data.me.defaultAccount.pendingIncomingTransactions[] | select(.initiationVia.address == $address)'
echo $output \
| jq -r --arg address "$1" "$jq_query" \
| jq -r "$property_query"
}

check_for_broadcast() {
UncleSamtoshi marked this conversation as resolved.
Show resolved Hide resolved
local token_name=$1
local address=$2

exec_graphql "$token_name" 'pending-incoming-transactions'

tx="$(get_from_pending_transaction_by_address "$address" '.')"
[[ -n "${tx}" && "${tx}" != "null" ]] || exit 1
txid="$(echo $tx | jq -r '.settlementVia.transactionHash')"
[[ "${txid}" != "null" ]] || exit 1
status="$(echo $tx | jq -r '.status')"
[[ "${status}" == "PENDING" ]] || exit 1

bitcoin_cli gettransaction "$txid" || exit 1
}

check_for_outgoing_broadcast() {
local token_name=$1
local address=$2
local first=${3:-"1"}

variables=$(
Expand Down
44 changes: 33 additions & 11 deletions core/api/src/app/accounts/get-account-transactions-for-contact.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { memoSharingConfig } from "@/config"
import { MAX_PAGINATION_PAGE_SIZE, memoSharingConfig } from "@/config"
import { LedgerError } from "@/domain/ledger"
import { checkedToPaginatedQueryArgs } from "@/domain/primitives"
import { WalletTransactionHistory } from "@/domain/wallets"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"
Expand All @@ -8,29 +9,50 @@ import { WalletsRepository } from "@/services/mongoose"
export const getAccountTransactionsForContact = async ({
account,
contactUsername,
paginationArgs,
rawPaginationArgs,
}: {
account: Account
contactUsername: Username
paginationArgs?: PaginationArgs
}): Promise<PaginatedArray<WalletTransaction> | ApplicationError> => {
rawPaginationArgs: {
first?: number
last?: number
before?: string
after?: string
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
const paginationArgs = checkedToPaginatedQueryArgs({
paginationArgs: rawPaginationArgs,
maxPageSize: MAX_PAGINATION_PAGE_SIZE,
})

if (paginationArgs instanceof Error) return paginationArgs

const ledger = LedgerService()

const wallets = await WalletsRepository().listByAccountId(account.id)
if (wallets instanceof Error) return wallets

const resp = await ledger.getTransactionsByWalletIdAndContactUsername({
const ledgerTxs = await ledger.getTransactionsByWalletIdAndContactUsername({
walletIds: wallets.map((wallet) => wallet.id),
contactUsername,
paginationArgs,
})
if (resp instanceof LedgerError) return resp
if (ledgerTxs instanceof LedgerError) return ledgerTxs

const nonEndUserWalletIds = Object.values(await getNonEndUserWalletIds())

const txEdges = ledgerTxs.edges.map((edge) => {
const { transactions } = WalletTransactionHistory.fromLedger({
ledgerTransactions: [edge.node],
nonEndUserWalletIds,
memoSharingConfig,
})

const confirmedHistory = WalletTransactionHistory.fromLedger({
ledgerTransactions: resp.slice,
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
return {
cursor: edge.cursor,
node: transactions[0],
}
UncleSamtoshi marked this conversation as resolved.
Show resolved Hide resolved
})

return { slice: confirmedHistory.transactions, total: resp.total }
return { ...ledgerTxs, edges: txEdges }
}
8 changes: 4 additions & 4 deletions core/api/src/app/accounts/get-invoices-for-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export const getInvoicesForAccountByWalletIds = async ({
account: Account
walletIds?: WalletId[]
rawPaginationArgs: {
first?: number | null
last?: number | null
before?: string | null
after?: string | null
first?: number
last?: number
before?: string
after?: string
}
}): Promise<PaginatedQueryResult<WalletInvoice> | ApplicationError> => {
const walletsRepo = WalletsRepository()
Expand Down
40 changes: 25 additions & 15 deletions core/api/src/app/accounts/get-transactions-for-account.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
import { getTransactionsForWallets } from "../wallets"

import { PartialResult } from "../partial-result"

import { AccountValidator } from "@/domain/accounts"
import { RepositoryError } from "@/domain/errors"
import { WalletsRepository } from "@/services/mongoose"

export const getTransactionsForAccountByWalletIds = async ({
account,
walletIds,
paginationArgs,
rawPaginationArgs,
}: {
account: Account
walletIds: WalletId[]
paginationArgs?: PaginationArgs
}): Promise<PartialResult<PaginatedArray<WalletTransaction>>> => {
walletIds?: WalletId[]
rawPaginationArgs: {
first?: number
last?: number
before?: string
after?: string
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
const walletsRepo = WalletsRepository()

const wallets: Wallet[] = []
for (const walletId of walletIds) {
const wallet = await walletsRepo.findById(walletId)
if (wallet instanceof RepositoryError) return PartialResult.err(wallet)

const accountValidator = AccountValidator(account)
if (accountValidator instanceof Error) return PartialResult.err(accountValidator)
const validateWallet = accountValidator.validateWalletForAccount(wallet)
if (validateWallet instanceof Error) return PartialResult.err(validateWallet)
if (walletIds) {
for (const walletId of walletIds) {
const wallet = await walletsRepo.findById(walletId)
if (wallet instanceof RepositoryError) return wallet

const accountValidator = AccountValidator(account)
if (accountValidator instanceof Error) return accountValidator
const validateWallet = accountValidator.validateWalletForAccount(wallet)
if (validateWallet instanceof Error) return validateWallet

wallets.push(wallet)
wallets.push(wallet)
}
} else {
const accountWallets = await walletsRepo.listByAccountId(account.id)
if (accountWallets instanceof RepositoryError) return accountWallets
wallets.push(...accountWallets)
}

return getTransactionsForWallets({ wallets, paginationArgs })
return getTransactionsForWallets({ wallets, rawPaginationArgs })
}
8 changes: 4 additions & 4 deletions core/api/src/app/wallets/get-invoices-for-wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export const getInvoicesForWallets = async ({
}: {
wallets: Wallet[]
rawPaginationArgs: {
first?: number | null
last?: number | null
before?: string | null
after?: string | null
first?: number
last?: number
before?: string
after?: string
}
}): Promise<PaginatedQueryResult<WalletInvoice> | ApplicationError> => {
const walletIds = wallets.map((wallet) => wallet.id)
Expand Down
75 changes: 37 additions & 38 deletions core/api/src/app/wallets/get-transactions-by-addresses.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,60 @@
import { memoSharingConfig } from "@/config"
import { PartialResult } from "@/app/partial-result"
import { MAX_PAGINATION_PAGE_SIZE, memoSharingConfig } from "@/config"

import { LedgerError } from "@/domain/ledger"
import { WalletTransactionHistory } from "@/domain/wallets"
import { CouldNotFindError } from "@/domain/errors"

import { getNonEndUserWalletIds, LedgerService } from "@/services/ledger"
import { WalletOnChainPendingReceiveRepository } from "@/services/mongoose"
import { checkedToPaginatedQueryArgs } from "@/domain/primitives"

export const getTransactionsForWalletsByAddresses = async ({
wallets,
addresses,
paginationArgs,
rawPaginationArgs,
}: {
wallets: Wallet[]
addresses: OnChainAddress[]
paginationArgs?: PaginationArgs
}): Promise<PartialResult<PaginatedArray<WalletTransaction>>> => {
const walletIds = wallets.map((wallet) => wallet.id)
rawPaginationArgs: {
first?: number
last?: number
before?: string
after?: string
}
}): Promise<PaginatedQueryResult<WalletTransaction> | ApplicationError> => {
UncleSamtoshi marked this conversation as resolved.
Show resolved Hide resolved
const paginationArgs = checkedToPaginatedQueryArgs({
paginationArgs: rawPaginationArgs,
maxPageSize: MAX_PAGINATION_PAGE_SIZE,
})

let pendingHistory =
await WalletOnChainPendingReceiveRepository().listByWalletIdsAndAddresses({
walletIds,
addresses,
})
if (pendingHistory instanceof Error) {
if (pendingHistory instanceof CouldNotFindError) {
pendingHistory = []
} else {
return PartialResult.err(pendingHistory)
}
if (paginationArgs instanceof Error) {
return paginationArgs
}

const confirmedLedgerTxns = await LedgerService().getTransactionsByWalletIds({
const walletIds = wallets.map((wallet) => wallet.id)

const ledgerTxs = await LedgerService().getTransactionsByWalletIdsAndAddresses({
walletIds,
paginationArgs,
addresses,
})
if (confirmedLedgerTxns instanceof LedgerError) {
return PartialResult.partial(
{ slice: pendingHistory, total: pendingHistory.length },
confirmedLedgerTxns,
)

if (ledgerTxs instanceof LedgerError) {
return ledgerTxs
}
const ledgerTransactions = confirmedLedgerTxns.slice.filter(
(tx) => tx.address && addresses.includes(tx.address),
)

const confirmedHistory = WalletTransactionHistory.fromLedger({
ledgerTransactions,
nonEndUserWalletIds: Object.values(await getNonEndUserWalletIds()),
memoSharingConfig,
})

const transactions = [...pendingHistory, ...confirmedHistory.transactions]
const nonEndUserWalletIds = Object.values(await getNonEndUserWalletIds())

const txEdges = ledgerTxs.edges.map((edge) => {
const { transactions } = WalletTransactionHistory.fromLedger({
ledgerTransactions: [edge.node],
nonEndUserWalletIds,
memoSharingConfig,
})

return PartialResult.ok({
slice: transactions,
total: transactions.length,
return {
cursor: edge.cursor,
node: transactions[0],
}
UncleSamtoshi marked this conversation as resolved.
Show resolved Hide resolved
})

return { ...ledgerTxs, edges: txEdges }
}
Loading
Loading