From 537942e01f8b3b070007891bf2de6b1e3e5efca4 Mon Sep 17 00:00:00 2001 From: cedric ogire Date: Wed, 11 Jan 2023 14:33:30 +0800 Subject: [PATCH 1/8] feat: add decodeRawTransaction function --- .../rawtx/decodeRawTransaction.test.ts | 34 +++++++++++++++++++ .../jellyfish-api-core/src/category/rawtx.ts | 18 ++++++++++ 2 files changed, 52 insertions(+) create mode 100644 packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts new file mode 100644 index 0000000000..af8958a829 --- /dev/null +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -0,0 +1,34 @@ +import { MasterNodeRegTestContainer } from '@defichain/testcontainers/dist/index' +import { ContainerAdapterClient } from '../../container_adapter_client' +import { RpcApiError } from '../../../src' + +describe('poolpair update', () => { + const container = new MasterNodeRegTestContainer() + const client = new ContainerAdapterClient(container) + + beforeAll(async () => { + await container.start() + await container.waitForWalletCoinbaseMaturity() + }) + + afterAll(async () => { + await container.stop() + }) + + it('should decode a witness transaction', async () => { + const encrawtx = '010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000' + const decrawtx = await client.rawtx.decodeRawTransaction(encrawtx, true) + expect(decrawtx.vout[0].value).toStrictEqual(1) + }) + + it('should throw an error when for decode as non-witness a witness transaction', async () => { + const encrawtx = '010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000' + await expect(client.rawtx.decodeRawTransaction(encrawtx, false)).rejects.toThrow(RpcApiError) + }) + + it('should decode a non-witness transaction', async () => { + const encrawtx = '01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000' + const decrawtx = await client.rawtx.decodeRawTransaction(encrawtx, true) + expect(decrawtx.vout[0].value).toStrictEqual(1) + }) +}) diff --git a/packages/jellyfish-api-core/src/category/rawtx.ts b/packages/jellyfish-api-core/src/category/rawtx.ts index b1a40b27d8..3e68d57eba 100644 --- a/packages/jellyfish-api-core/src/category/rawtx.ts +++ b/packages/jellyfish-api-core/src/category/rawtx.ts @@ -44,6 +44,24 @@ export class RawTx { ], 'number') } + /** + * Return a JSON object representing the serialized, hex-encoded transaction. + * If iswitness is not present, heuristic tests will be used in decoding. + * If true, only witness deserialization will be tried. + * If false, only non-witness deserialization will be tried. + * This boolean should reflect whether the transaction has inputs + * (e.g. fully valid, or on-chain transactions), if known by the caller. + * + * @param {string} hexstring The transaction hex string + * @param {boolean} iswitness Whether the transaction hex is a serialized witness transaction. + */ + async decodeRawTransaction ( + hexstring: string, + iswitness: boolean + ): Promise { + return await this.client.call('decoderawtransaction', [hexstring, iswitness], 'number') + } + /** * Sign inputs for raw transaction (serialized, hex-encoded), providing an array of base58-encoded private keys that * will be the keys used to sign the transaction. An optional array of previous transaction outputs that this From fe783d38ff20ce604cc9ef9fffb34ab0753e1360 Mon Sep 17 00:00:00 2001 From: cedric ogire Date: Wed, 11 Jan 2023 16:29:39 +0800 Subject: [PATCH 2/8] chore: check all the properties of of decoded transation in test --- .../rawtx/decodeRawTransaction.test.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts index af8958a829..99c3a7373a 100644 --- a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -18,7 +18,25 @@ describe('poolpair update', () => { it('should decode a witness transaction', async () => { const encrawtx = '010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000' const decrawtx = await client.rawtx.decodeRawTransaction(encrawtx, true) + + expect(decrawtx.txid).toStrictEqual('d006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a') + expect(decrawtx.hash).toStrictEqual('23f0c1f68f0a43bb434494933a5a0f6f9636261f33b036b7700d96e264aceeda') + expect(decrawtx.version).toStrictEqual(1) + expect(decrawtx.size).toStrictEqual(66) + expect(decrawtx.vsize).toStrictEqual(62) + expect(decrawtx.weight).toStrictEqual(246) + expect(decrawtx.locktime).toStrictEqual(0) + expect(decrawtx.vin[0].txid).toStrictEqual('000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000') + expect(decrawtx.vin[0].vout).toStrictEqual(0) + expect(decrawtx.vin[0].scriptSig.asm).toStrictEqual('') + expect(decrawtx.vin[0].scriptSig.hex).toStrictEqual('') + expect(decrawtx.vin[0].txinwitness).toStrictEqual(['6161']) + expect(decrawtx.vin[0].sequence).toStrictEqual(4294967295) expect(decrawtx.vout[0].value).toStrictEqual(1) + expect(decrawtx.vout[0].n).toStrictEqual(0) + expect(decrawtx.vout[0].scriptPubKey.asm).toStrictEqual('') + expect(decrawtx.vout[0].scriptPubKey.hex).toStrictEqual('') + expect(decrawtx.vout[0].scriptPubKey.type).toStrictEqual('nonstandard') }) it('should throw an error when for decode as non-witness a witness transaction', async () => { @@ -29,6 +47,23 @@ describe('poolpair update', () => { it('should decode a non-witness transaction', async () => { const encrawtx = '01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000' const decrawtx = await client.rawtx.decodeRawTransaction(encrawtx, true) + + expect(decrawtx.txid).toStrictEqual('d006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a') + expect(decrawtx.hash).toStrictEqual('d006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a') + expect(decrawtx.version).toStrictEqual(1) + expect(decrawtx.size).toStrictEqual(60) + expect(decrawtx.vsize).toStrictEqual(60) + expect(decrawtx.weight).toStrictEqual(240) + expect(decrawtx.locktime).toStrictEqual(0) + expect(decrawtx.vin[0].txid).toStrictEqual('000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000') + expect(decrawtx.vin[0].vout).toStrictEqual(0) + expect(decrawtx.vin[0].scriptSig.asm).toStrictEqual('') + expect(decrawtx.vin[0].scriptSig.hex).toStrictEqual('') + expect(decrawtx.vin[0].sequence).toStrictEqual(4294967295) expect(decrawtx.vout[0].value).toStrictEqual(1) + expect(decrawtx.vout[0].n).toStrictEqual(0) + expect(decrawtx.vout[0].scriptPubKey.asm).toStrictEqual('') + expect(decrawtx.vout[0].scriptPubKey.hex).toStrictEqual('') + expect(decrawtx.vout[0].scriptPubKey.type).toStrictEqual('nonstandard') }) }) From 8d4e5c18e7fc9595cc1ff74e23428a46cc3bf968 Mon Sep 17 00:00:00 2001 From: cedric ogire Date: Wed, 11 Jan 2023 17:10:15 +0800 Subject: [PATCH 3/8] chore: add doc for decodeRawTransaction --- docs/node/CATEGORIES/04-rawtx.md | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/node/CATEGORIES/04-rawtx.md b/docs/node/CATEGORIES/04-rawtx.md index f7c871bb10..264e51660c 100644 --- a/docs/node/CATEGORIES/04-rawtx.md +++ b/docs/node/CATEGORIES/04-rawtx.md @@ -43,6 +43,41 @@ interface CreateRawTxOut { } ``` +## decodeRawTransaction + +Return a JSON object representing the serialized, hex-encoded transaction. +If iswitness is not present, heuristic tests will be used in decoding. +If true, only witness deserialization will be tried. +If false, only non-witness deserialization will be tried. +This boolean should reflect whether the transaction has inputs +(e.g. fully valid, or on-chain transactions), if known by the caller. + +```ts title="client.rawtx.decodeRawTransaction()" +interface rawtx { + decodeRawTransaction ( + hexstring: string, + iswitness: boolean + ): Promise +} + +interface RawTransaction { + in_active_chain?: boolean + txid: string + hash: string + version: number + size: number + vsize: number + weight: number + locktime: number + vin: Vin[] + vout: Vout[] + hex: string + blockhash: string + confirmations: number + time: number + blocktime: number +} +``` ## signRawTransactionWithKey From 3f70535fe818752716f8ac2678166eb7f9bf4d95 Mon Sep 17 00:00:00 2001 From: cedric ogire Date: Fri, 13 Jan 2023 10:34:25 +0800 Subject: [PATCH 4/8] chore: change individual assertion to object assertion for testing --- .../rawtx/decodeRawTransaction.test.ts | 102 ++++++++++++------ 1 file changed, 67 insertions(+), 35 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts index 99c3a7373a..64f6de5b73 100644 --- a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -19,24 +19,40 @@ describe('poolpair update', () => { const encrawtx = '010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000' const decrawtx = await client.rawtx.decodeRawTransaction(encrawtx, true) - expect(decrawtx.txid).toStrictEqual('d006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a') - expect(decrawtx.hash).toStrictEqual('23f0c1f68f0a43bb434494933a5a0f6f9636261f33b036b7700d96e264aceeda') - expect(decrawtx.version).toStrictEqual(1) - expect(decrawtx.size).toStrictEqual(66) - expect(decrawtx.vsize).toStrictEqual(62) - expect(decrawtx.weight).toStrictEqual(246) - expect(decrawtx.locktime).toStrictEqual(0) - expect(decrawtx.vin[0].txid).toStrictEqual('000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000') - expect(decrawtx.vin[0].vout).toStrictEqual(0) - expect(decrawtx.vin[0].scriptSig.asm).toStrictEqual('') - expect(decrawtx.vin[0].scriptSig.hex).toStrictEqual('') - expect(decrawtx.vin[0].txinwitness).toStrictEqual(['6161']) - expect(decrawtx.vin[0].sequence).toStrictEqual(4294967295) - expect(decrawtx.vout[0].value).toStrictEqual(1) - expect(decrawtx.vout[0].n).toStrictEqual(0) - expect(decrawtx.vout[0].scriptPubKey.asm).toStrictEqual('') - expect(decrawtx.vout[0].scriptPubKey.hex).toStrictEqual('') - expect(decrawtx.vout[0].scriptPubKey.type).toStrictEqual('nonstandard') + expect(decrawtx).toStrictEqual({ + txid: 'd006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a', + hash: '23f0c1f68f0a43bb434494933a5a0f6f9636261f33b036b7700d96e264aceeda', + version: 1, + size: 66, + vsize: 62, + weight: 246, + locktime: 0, + vin: [ + expect.objectContaining({ + txid: '000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000', + vout: 0, + scriptSig: + expect.objectContaining({ + asm: '', + hex: '' + }), + txinwitness: ['6161'], + sequence: 4294967295 + }) + ], + vout: [ + expect.objectContaining({ + value: 1, + n: 0, + scriptPubKey: + expect.objectContaining({ + asm: '', + hex: '', + type: 'nonstandard' + }) + }) + ] + }) }) it('should throw an error when for decode as non-witness a witness transaction', async () => { @@ -48,22 +64,38 @@ describe('poolpair update', () => { const encrawtx = '01000000010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f505000000000000000000' const decrawtx = await client.rawtx.decodeRawTransaction(encrawtx, true) - expect(decrawtx.txid).toStrictEqual('d006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a') - expect(decrawtx.hash).toStrictEqual('d006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a') - expect(decrawtx.version).toStrictEqual(1) - expect(decrawtx.size).toStrictEqual(60) - expect(decrawtx.vsize).toStrictEqual(60) - expect(decrawtx.weight).toStrictEqual(240) - expect(decrawtx.locktime).toStrictEqual(0) - expect(decrawtx.vin[0].txid).toStrictEqual('000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000') - expect(decrawtx.vin[0].vout).toStrictEqual(0) - expect(decrawtx.vin[0].scriptSig.asm).toStrictEqual('') - expect(decrawtx.vin[0].scriptSig.hex).toStrictEqual('') - expect(decrawtx.vin[0].sequence).toStrictEqual(4294967295) - expect(decrawtx.vout[0].value).toStrictEqual(1) - expect(decrawtx.vout[0].n).toStrictEqual(0) - expect(decrawtx.vout[0].scriptPubKey.asm).toStrictEqual('') - expect(decrawtx.vout[0].scriptPubKey.hex).toStrictEqual('') - expect(decrawtx.vout[0].scriptPubKey.type).toStrictEqual('nonstandard') + expect(decrawtx).toStrictEqual({ + txid: 'd006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a', + hash: 'd006b4ece5d4adbd6f46b3a6f65f4a230caf6c44d8510e4340d0f26b7ceeb44a', + version: 1, + size: 60, + vsize: 60, + weight: 240, + locktime: 0, + vin: [ + expect.objectContaining({ + txid: '000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000', + vout: 0, + scriptSig: + expect.objectContaining({ + asm: '', + hex: '' + }), + sequence: 4294967295 + }) + ], + vout: [ + expect.objectContaining({ + value: 1, + n: 0, + scriptPubKey: + expect.objectContaining({ + asm: '', + hex: '', + type: 'nonstandard' + }) + }) + ] + }) }) }) From ca79d06c383c85df31abbafcfae6fc750d5f3ff5 Mon Sep 17 00:00:00 2001 From: DrPing Date: Fri, 13 Jan 2023 17:39:45 +0800 Subject: [PATCH 5/8] chore: Use proper container for decodeRawTransaction test Co-authored-by: Fuxing Loh <4266087+fuxingloh@users.noreply.github.com> Signed-off-by: DrPing --- .../__tests__/category/rawtx/decodeRawTransaction.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts index 64f6de5b73..d7bf31ed48 100644 --- a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -3,7 +3,7 @@ import { ContainerAdapterClient } from '../../container_adapter_client' import { RpcApiError } from '../../../src' describe('poolpair update', () => { - const container = new MasterNodeRegTestContainer() + const container = new RegTestContainer() const client = new ContainerAdapterClient(container) beforeAll(async () => { From 6edd7f0e3a2bb3a5196a50aa510d8b07cf8a1b3d Mon Sep 17 00:00:00 2001 From: DrPing Date: Fri, 13 Jan 2023 17:40:31 +0800 Subject: [PATCH 6/8] chore: remove useless waitForWalletMaturity in decodeRawTransaction test Co-authored-by: Fuxing Loh <4266087+fuxingloh@users.noreply.github.com> Signed-off-by: DrPing --- .../__tests__/category/rawtx/decodeRawTransaction.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts index d7bf31ed48..169cf5afd7 100644 --- a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -8,7 +8,6 @@ describe('poolpair update', () => { beforeAll(async () => { await container.start() - await container.waitForWalletCoinbaseMaturity() }) afterAll(async () => { From 6308818a7592532d4507e33d7cbd216a0ddd5dff Mon Sep 17 00:00:00 2001 From: cedric ogire Date: Fri, 13 Jan 2023 17:45:40 +0800 Subject: [PATCH 7/8] chore: fix test name for decoderawtransaction --- .../__tests__/category/rawtx/decodeRawTransaction.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts index 169cf5afd7..4f9d833669 100644 --- a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -2,8 +2,8 @@ import { MasterNodeRegTestContainer } from '@defichain/testcontainers/dist/index import { ContainerAdapterClient } from '../../container_adapter_client' import { RpcApiError } from '../../../src' -describe('poolpair update', () => { - const container = new RegTestContainer() +describe('decode raw transaction', () => { + const container = new MasterNodeRegTestContainer() const client = new ContainerAdapterClient(container) beforeAll(async () => { From 50c1e3f8c09289b0d387f9e1cfd1d8f7ce50bf03 Mon Sep 17 00:00:00 2001 From: cedric ogire Date: Fri, 13 Jan 2023 17:49:32 +0800 Subject: [PATCH 8/8] chore: remove useless objectContaining for decoderawtransaction test --- .../rawtx/decodeRawTransaction.test.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts index 4f9d833669..679486c323 100644 --- a/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/rawtx/decodeRawTransaction.test.ts @@ -27,29 +27,29 @@ describe('decode raw transaction', () => { weight: 246, locktime: 0, vin: [ - expect.objectContaining({ + { txid: '000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000', vout: 0, scriptSig: - expect.objectContaining({ + { asm: '', hex: '' - }), + }, txinwitness: ['6161'], sequence: 4294967295 - }) + } ], vout: [ - expect.objectContaining({ + { value: 1, n: 0, scriptPubKey: - expect.objectContaining({ + { asm: '', hex: '', type: 'nonstandard' - }) - }) + } + } ] }) }) @@ -72,28 +72,28 @@ describe('decode raw transaction', () => { weight: 240, locktime: 0, vin: [ - expect.objectContaining({ + { txid: '000000000019d6689c085ae165831e934ff763ae46a2a6c17200000000000000', vout: 0, scriptSig: - expect.objectContaining({ + { asm: '', hex: '' - }), + }, sequence: 4294967295 - }) + } ], vout: [ - expect.objectContaining({ + { value: 1, n: 0, scriptPubKey: - expect.objectContaining({ + { asm: '', hex: '', type: 'nonstandard' - }) - }) + } + } ] }) })