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

feat(jellyfish-api-core): add blockchain getMempoolDescendants RPC #1796

Merged
Show file tree
Hide file tree
Changes from 4 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
43 changes: 43 additions & 0 deletions docs/node/CATEGORIES/01-blockchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,49 @@ interface MempoolTx {
}
```

## getMempoolDescendants

Get all in-mempool descendants if a transaction id is in mempool as string[] if verbose is false else as json object

```ts title="client.blockchain.getMempoolDescendants()"
interface blockchain {
getMempoolDescendants (txId: string, verbose?: false): Promise<string[]>
getMempoolDescendants (txId: string, verbose?: true): Promise<MempoolTx>
getMempoolDescendants (txId: string, verbose?: boolean: Promise<string[] | MempoolTx>
}

interface MempoolTx {
[key: string]: {
vsize: BigNumber
/**
* @deprecated same as vsize. Only returned if defid is started with -deprecatedrpc=size
*/
size: BigNumber
weight: BigNumber
fee: BigNumber
modifiedfee: BigNumber
time: BigNumber
height: BigNumber
descendantcount: BigNumber
descendantsize: BigNumber
descendantfees: BigNumber
ancestorcount: BigNumber
ancestorsize: BigNumber
ancestorfees: BigNumber
wtxid: string
fees: {
base: BigNumber
modified: BigNumber
ancestor: BigNumber
descendant: BigNumber
}
depends: string[]
spentby: string[]
'bip125-replaceable': boolean
}
}
```

## getMempoolEntry

Get transaction details in the memory pool using a transaction ID.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { MasterNodeRegTestContainer } from '@defichain/testcontainers'
import { Testing } from '@defichain/jellyfish-testing'
import BigNumber from 'bignumber.js'

describe('Transactions without descendants', () => {
const container = new MasterNodeRegTestContainer()
const testing = Testing.create(container)

beforeAll(async () => {
await testing.container.start()
await testing.container.waitForWalletCoinbaseMaturity()
})

afterAll(async () => {
await testing.container.stop()
})

it('should return empty array for transaction id without descendants', async () => {
const txId = await testing.rpc.wallet.sendToAddress('mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU', 0.003)
const mempoolDescendants = await testing.rpc.blockchain.getMempoolDescendants(txId)

expect(mempoolDescendants.length).toStrictEqual(0)
})

it('should return error if transaction is not in mempool', async () => {
const nonExistingTxId = 'a'.repeat(64)
const promise = testing.rpc.blockchain.getMempoolDescendants(nonExistingTxId)

await expect(promise)
.rejects
.toThrowError('RpcApiError: \'Transaction not in mempool\', code: -5, method: getmempooldescendants')
})

it('should return error if transaction id has an invalid length', async () => {
const invalidLengthTxid = 'a'.repeat(5)
const promise = testing.rpc.blockchain.getMempoolDescendants(invalidLengthTxid)

await expect(promise)
.rejects
.toThrow(`RpcApiError: 'parameter 1 must be of length 64 (not ${invalidLengthTxid.length}, for '${invalidLengthTxid}')', code: -8, method: getmempooldescendants`)
})
})

describe('Transactions with descendants', () => {
const container = new MasterNodeRegTestContainer()
const testing = Testing.create(container)

beforeAll(async () => {
await testing.container.start()
await testing.container.waitForWalletCoinbaseMaturity()
})

async function getTxIdWithDescendants (): Promise<string> {
const txId = await testing.rpc.wallet.sendToAddress('mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU', 0.003)
for (let i = 0; i < 10; i++) {
await testing.rpc.wallet.sendToAddress('mwsZw8nF7pKxWH8eoKL9tPxTpaFkz7QeLU', 0.003)
}
return txId
}

afterAll(async () => {
await testing.container.stop()
})

it('should return JSON object if verbose is true', async () => {
const txIdWithDescendants = await getTxIdWithDescendants()
const mempoolDescendants = await testing.rpc.blockchain.getMempoolDescendants(txIdWithDescendants, true)

const keys = Object.keys(mempoolDescendants)
expect(keys.length).toBeGreaterThan(0)
for (const key of keys) {
expect(mempoolDescendants[key]).toStrictEqual({
fees: expect.any(Object),
vsize: expect.any(BigNumber),
weight: expect.any(BigNumber),
fee: expect.any(BigNumber),
modifiedfee: expect.any(BigNumber),
time: expect.any(BigNumber),
height: expect.any(BigNumber),
descendantcount: expect.any(BigNumber),
descendantsize: expect.any(BigNumber),
descendantfees: expect.any(BigNumber),
ancestorcount: expect.any(BigNumber),
ancestorsize: expect.any(BigNumber),
ancestorfees: expect.any(BigNumber),
wtxid: expect.any(String),
depends: expect.any(Array),
spentby: expect.any(Array),
'bip125-replaceable': expect.any(Boolean)
})
}
})

it('should return array of transaction ids if verbose is false', async () => {
const txIdWithDescendants = await getTxIdWithDescendants()
const mempoolDescendants = await testing.rpc.blockchain.getMempoolDescendants(txIdWithDescendants, false)
expect(mempoolDescendants.length).toBeGreaterThan(0)
infinia-yzl marked this conversation as resolved.
Show resolved Hide resolved
for (const descendantId of mempoolDescendants) {
expect(descendantId).toStrictEqual(expect.stringMatching(/^[0-9a-f]{64}$/))
}
})

it('should return array of transaction ids if verbose is undefined', async () => {
const txIdWithDescendants = await getTxIdWithDescendants()
const mempoolDescendants = await testing.rpc.blockchain.getMempoolDescendants(txIdWithDescendants)
expect(mempoolDescendants.length).toBeGreaterThan(0)
for (const descendantId of mempoolDescendants) {
expect(descendantId).toStrictEqual(expect.stringMatching(/^[0-9a-f]{64}$/))
}
})
})
30 changes: 30 additions & 0 deletions packages/jellyfish-api-core/src/category/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,36 @@ export class Blockchain {
return await this.client.call('getmempoolancestors', [txId, verbose], 'bignumber')
}

/**
* Get all in-mempool descendants for a given transaction as string[]
*
* @param {string} txId the transaction id
* @param {boolean} verbose false
* @return {Promise<string[]>}
*/
getMempoolDescendants (txId: string, verbose?: false): Promise<string[]>

/**
* Get all in-mempool descendants for a given transaction as json object
*
* @param {string} txId the transaction id
* @param {boolean} verbose true
* @return {Promise<MempoolTx>}
*/
getMempoolDescendants (txId: string, verbose?: true): Promise<MempoolTx>

/**
* Get all in-mempool descendants if txId is in mempool as string[] if verbose is false
* else as json object
*
* @param {string} txId the transaction id
* @param {boolean} verbose default = false, true for json object, false for array of transaction ids
* @return {Promise<string[] | MempoolTx>}
*/
async getMempoolDescendants (txId: string, verbose: boolean = false): Promise<string[] | MempoolTx> {
return await this.client.call('getmempooldescendants', [txId, verbose], 'bignumber')
}

/**
* Get mempool data for the given transaction
* @param {string} txId the transaction id
Expand Down