diff --git a/packages/jellyfish-api-core/__tests__/category/blockchain.test.ts b/packages/jellyfish-api-core/__tests__/category/blockchain.test.ts index 892509e92d..8830480be0 100644 --- a/packages/jellyfish-api-core/__tests__/category/blockchain.test.ts +++ b/packages/jellyfish-api-core/__tests__/category/blockchain.test.ts @@ -1,6 +1,7 @@ import { RegTestContainer, MasterNodeRegTestContainer } from '@defichain/testcontainers' import { ContainerAdapterClient } from '../container_adapter_client' import waitForExpect from 'wait-for-expect' +import { Block, Transaction } from '../../src' describe('non masternode', () => { const container = new RegTestContainer() @@ -55,26 +56,128 @@ describe('masternode', () => { await container.stop() }) - it('should getBlockchainInfo', async () => { - await waitForExpect(async () => { + describe('getBlockchainInfo', () => { + it('should getBlockchainInfo', async () => { + await waitForExpect(async () => { + const info = await client.blockchain.getBlockchainInfo() + await expect(info.blocks).toBeGreaterThan(1) + }) + const info = await client.blockchain.getBlockchainInfo() - await expect(info.blocks).toBeGreaterThan(1) + + expect(info.chain).toBe('regtest') + expect(info.blocks).toBeGreaterThan(0) + expect(info.headers).toBeGreaterThan(0) + + expect(info.bestblockhash.length).toBe(64) + expect(info.difficulty).toBeGreaterThan(0) + expect(info.mediantime).toBeGreaterThan(1550000000) + + expect(info.verificationprogress).toBe(1) + expect(info.initialblockdownload).toBe(false) + expect(info.chainwork.length).toBe(64) + expect(info.size_on_disk).toBeGreaterThan(0) + expect(info.pruned).toBe(false) }) + }) - const info = await client.blockchain.getBlockchainInfo() + describe('getBlock', () => { + /** + * Wait for block hash to reach a certain height + */ + async function waitForBlockHash (height: number): Promise { + await waitForExpect(async () => { + const info = await client.blockchain.getBlockchainInfo() + await expect(info.blocks).toBeGreaterThan(height) + }) - expect(info.chain).toBe('regtest') - expect(info.blocks).toBeGreaterThan(0) - expect(info.headers).toBeGreaterThan(0) + return await client.blockchain.getBlockHash(height) + } - expect(info.bestblockhash.length).toBe(64) - expect(info.difficulty).toBeGreaterThan(0) - expect(info.mediantime).toBeGreaterThan(1550000000) + it('should getBlock with verbosity 0 and return just a string that is serialized, hex-encoded data for block', async () => { + const blockHash = await waitForBlockHash(1) + const hash: string = await client.blockchain.getBlock(blockHash, 0) - expect(info.verificationprogress).toBe(1) - expect(info.initialblockdownload).toBe(false) - expect(info.chainwork.length).toBe(64) - expect(info.size_on_disk).toBeGreaterThan(0) - expect(info.pruned).toBe(false) + expect(hash).not.toBeNull() + }) + + it('should getBlock with verbosity 1 and return block with tx as hex', async () => { + const blockHash = await waitForBlockHash(1) + const block: Block = await client.blockchain.getBlock(blockHash, 1) + + expect(block.hash.length).toBe(64) + + expect(block.confirmations).toBeGreaterThanOrEqual(2) + expect(block.strippedsize).toBeGreaterThanOrEqual(360) + + expect(block.size).toBeGreaterThanOrEqual(396) + expect(block.weight).toBeGreaterThanOrEqual(1476) + expect(block.height).toBeGreaterThanOrEqual(1) + + expect(block.masternode.length).toBe(64) + expect(block.minter.length).toBe(34) // legacy address length + + expect(block.mintedBlocks).toBeGreaterThanOrEqual(1) + expect(block.stakeModifier.length).toBe(64) + expect(block.version).toBeGreaterThanOrEqual(536870912) + expect(block.versionHex).toStrictEqual('20000000') + expect(block.merkleroot.length).toBe(64) + + expect(block.tx.length).toBeGreaterThanOrEqual(1) + expect(block.tx[0].length).toBe(64) + + expect(block.time).toBeGreaterThan(1) + expect(block.mediantime).toBeGreaterThan(1) + + expect(block.bits).toStrictEqual('207fffff') + expect(block.difficulty).toBeGreaterThan(0) + + expect(block.chainwork.length).toBe(64) + expect(block.nTx).toBeGreaterThanOrEqual(1) + expect(block.previousblockhash.length).toBe(64) + }) + + it('should getBlock with verbosity 2 and return block with tx as RawText', async () => { + const blockHash = await waitForBlockHash(1) + const block: Block = await client.blockchain.getBlock(blockHash, 2) + + expect(block.tx.length).toBeGreaterThanOrEqual(1) + expect(block.tx[0].vin[0].coinbase).toStrictEqual('5100') + expect(block.tx[0].vin[0].sequence).toBeGreaterThanOrEqual(4294967295) + + expect(block.tx[0].vout[0].value).toBeGreaterThanOrEqual(38) + expect(block.tx[0].vout[0].n).toBeGreaterThanOrEqual(0) + + expect(block.tx[0].vout[0].scriptPubKey.asm).toStrictEqual('OP_DUP OP_HASH160 b36814fd26190b321aa985809293a41273cfe15e OP_EQUALVERIFY OP_CHECKSIG') + expect(block.tx[0].vout[0].scriptPubKey).toHaveProperty('hex') + expect(block.tx[0].vout[0].scriptPubKey.reqSigs).toBeGreaterThanOrEqual(1) + expect(block.tx[0].vout[0].scriptPubKey.type).toStrictEqual('pubkeyhash') + expect(block.tx[0].vout[0].scriptPubKey.addresses[0].length).toBe(34) + }) + }) + + describe('getBlockHash', () => { + it('should getBlockHash', async () => { + await waitForExpect(async () => { + const info = await client.blockchain.getBlockchainInfo() + await expect(info.blocks).toBeGreaterThan(1) + }) + + const blockHash: string = await client.blockchain.getBlockHash(1) + expect(blockHash).not.toBeNull() + expect(blockHash.length).toBe(64) + }) + }) + + describe('getBlockCount', () => { + it('should getBlockCount', async () => { + await waitForExpect(async () => { + const info = await client.blockchain.getBlockchainInfo() + await expect(info.blocks).toBeGreaterThan(1) + }) + + const blockCount: number = await client.blockchain.getBlockCount() + expect(blockCount).toBeGreaterThanOrEqual(2) + }) }) }) diff --git a/packages/jellyfish-api-core/src/category/blockchain.ts b/packages/jellyfish-api-core/src/category/blockchain.ts index e59494c65f..762052fff9 100644 --- a/packages/jellyfish-api-core/src/category/blockchain.ts +++ b/packages/jellyfish-api-core/src/category/blockchain.ts @@ -17,6 +17,57 @@ export class Blockchain { async getBlockchainInfo (): Promise { return await this.client.call('getblockchaininfo', [], 'number') } + + /** + * Get a hash of block in best-block-chain at height provided. + * @param height + * @return Promise + */ + async getBlockHash (height: number): Promise { + return await this.client.call('getblockhash', [height], 'number') + } + + /** + * Get the height of the most-work fully-validated chain. + * @return Promise + */ + async getBlockCount (): Promise { + return await this.client.call('getblockcount', [], 'number') + } + + /** + * Get block data with particular header hash. + * Returns a string that is serialized, hex-encoded data for block 'hash' + * + * @param hash of the block + * @param verbosity 0 + * @return Promise + */ + getBlock (hash: string, verbosity: 0): Promise + + /** + * Get block data with particular header hash. + * Returns an Object with information about the block 'hash'. + * + * @param hash of the block + * @param verbosity 1 + * @return Promise> + */ + getBlock (hash: string, verbosity: 1): Promise> + + /** + * Get block data with particular header hash. + * Returns an Object with information about block 'hash' and information about each transaction. + * + * @param hash of the block + * @param verbosity 2 + * @return Promise> + */ + getBlock (hash: string, verbosity: 2): Promise> + + async getBlock (hash: string, verbosity: 0 | 1 | 2): Promise> { + return await this.client.call('getblock', [hash, verbosity], 'number') + } } /** @@ -43,3 +94,66 @@ export interface BlockchainInfo { } warnings: string } + +export interface Block { + hash: string + confirmations: number + strippedsize: number + size: number + weight: number + height: number + masternode: string + minter: string + mintedBlocks: number + stakeModifier: string + version: number + versionHex: string + merkleroot: string + time: number + mediantime: number + bits: string + difficulty: number + chainwork: string + tx: T[] + nTx: number + previousblockhash: string + nextblockhash: string +} + +export interface Transaction { + txid: string + hash: string + version: number + size: number + vsize: number + weight: number + locktime: number + vin: Vin[] + vout: Vout[] + hex: string +} + +export interface Vin { + coinbase: string + txid: string + vout: number + scriptSig: { + asm: string + hex: string + } + txinwitness: string[] + sequence: string +} + +export interface Vout { + value: number + n: number + scriptPubKey: { + asm: string + hex: string + type: string + reqSigs: number + addresses: string[] + tokenId: string + } +} diff --git a/website/docs/jellyfish/api/blockchain.md b/website/docs/jellyfish/api/blockchain.md index 4b75b4f70a..08e614713e 100644 --- a/website/docs/jellyfish/api/blockchain.md +++ b/website/docs/jellyfish/api/blockchain.md @@ -44,3 +44,100 @@ interface BlockchainInfo { warnings: string } ``` + +## getBlock + +Get block data with particular header hash. + +```ts title="client.blockchain.getBlock()" +interface blockchain { + getBlock (hash: string, verbosity: 0): Promise + getBlock (hash: string, verbosity: 1): Promise> + getBlock (hash: string, verbosity: 2): Promise> + getBlock (hash: string, verbosity: 0 | 1 | 2): Promise> +} + +export interface Block { + hash: string + confirmations: number + strippedsize: number + size: number + weight: number + height: number + masternode: string + minter: string + mintedBlocks: number + stakeModifier: string + version: number + versionHex: string + merkleroot: string + time: number + mediantime: number + bits: string + difficulty: number + chainwork: string + tx: T[] + nTx: number + previousblockhash: string + nextblockhash: string +} + +export interface Transaction { + txid: string + hash: string + version: number + size: number + vsize: number + weight: number + locktime: number + vin: Vin[] + vout: Vout[] + hex: string +} + +export interface Vin { + coinbase: string + txid: string + vout: number + scriptSig: { + asm: string + hex: string + } + txinwitness: string[] + sequence: string +} + +export interface Vout { + value: number + n: number + scriptPubKey: { + asm: string + hex: string + type: string + reqSigs: number + addresses: string[] + tokenId: string + } +} +``` + +## getBlockHash + +Get a hash of block in best-block-chain at height provided. + +```ts title="client.blockchain.getBlockHash()" +interface blockchain { + getBlockHash(height: number): Promise +} +``` + +## getBlockCount + +Get the height of the most-work fully-validated chain. + +```ts title="client.blockchain.getBlockCount()" +interface blockchain { + getBlockCount (): Promise +} +``` +