Skip to content

Commit

Permalink
Merge 5a96f6b into 7d9b142
Browse files Browse the repository at this point in the history
  • Loading branch information
shohamc1 authored Jan 25, 2023
2 parents 7d9b142 + 5a96f6b commit 570fe64
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 1 deletion.
22 changes: 21 additions & 1 deletion docs/node/CATEGORIES/01-blockchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ Get all in-mempool ancestors if a transaction id is in mempool as string[] if ve
interface blockchain {
getMempoolAncestors (txId: string, verbose?: false): Promise<string[]>
getMempoolAncestors (txId: string, verbose?: true): Promise<MempoolTx>
getMempoolAncestors (txId: string, verbose?: boolean: Promise<string[] | MempoolTx>
getMempoolAncestors (txId: string, verbose?: boolean): Promise<string[] | MempoolTx>
}

interface MempoolTx {
Expand Down Expand Up @@ -525,3 +525,23 @@ interface ChainTxStats {
txrate: number
}
```
## invalidateBlock
Permanently marks a block as invalid, as if it violated a consensus rule.
```ts title="client.blockchain.invalidateBlock()"
interface blockchain {
invalidateBlock (blockHash: string): Promise<void>
}
```
## reconsiderBlock
Removes invalidity status of a block, its ancestors and its descendants, reconsider them for activation. This can be used to undo the effects of invalidateBlock.
```ts title="client.blockchain.reconsiderBlock()"
interface blockchain {
reconsiderBlock (blockHash: string): Promise<void>
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { MasterNodeRegTestContainer } from '@defichain/testcontainers'
import { Testing } from '@defichain/jellyfish-testing'
import { RpcApiError } from '@defichain/jellyfish-api-core'

describe('Invalidate block', () => {
const testing = Testing.create(new MasterNodeRegTestContainer())

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

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

it('should throw error if no blockhash provided', async () => {
const promise = testing.rpc.blockchain.invalidateBlock('')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -8,
message: 'blockhash must be of length 64 (not 0, for \'\')',
method: 'invalidateblock'
}
})
})

it('should throw error if invalid blockhash provided - invalid length', async () => {
const promise = testing.rpc.blockchain.invalidateBlock('invalidblockhash')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -8,
message: 'blockhash must be of length 64 (not 16, for \'invalidblockhash\')',
method: 'invalidateblock'
}
})
})

it('should throw error if invalid blockhash provided - invalid hex string', async () => {
const promise = testing.rpc.blockchain.invalidateBlock('d744db74fb70ed42767aj028a129365fb4d7de54ba1b6575fb047490554f8a7b')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -8,
message: 'blockhash must be hexadecimal string (not \'d744db74fb70ed42767aj028a129365fb4d7de54ba1b6575fb047490554f8a7b\')',
method: 'invalidateblock'
}
})
})

it('should throw error if block is not found', async () => {
const promise = testing.rpc.blockchain.reconsiderBlock('a9b5faec3324361a842df4302ce987f5fe1c5ce9ba53650f3a54397a36fea3b2')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -5,
message: 'Block not found',
method: 'reconsiderblock'
}
})
})

it('should invalidate block', async () => {
await testing.generate(1) // generate some blocks to have a chain history
const blockToInvalidate = await testing.rpc.blockchain.getBestBlockHash()

await testing.generate(2) // generate new blocks
await expect(testing.rpc.blockchain.getBestBlockHash()).not.toStrictEqual(blockToInvalidate) // confirm that new blocks were generated
const promise = testing.rpc.blockchain.invalidateBlock(blockToInvalidate)

await expect(promise).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { MasterNodeRegTestContainer } from '@defichain/testcontainers'
import { Testing } from '@defichain/jellyfish-testing'
import { RpcApiError } from '@defichain/jellyfish-api-core'

describe('Reconsider block', () => {
const testing = Testing.create(new MasterNodeRegTestContainer())

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

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

it('should throw error if no blockhash provided', async () => {
const promise = testing.rpc.blockchain.reconsiderBlock('')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -8,
message: 'blockhash must be of length 64 (not 0, for \'\')',
method: 'reconsiderblock'
}
})
})

it('should throw error if invalid blockhash provided - invalid length', async () => {
const promise = testing.rpc.blockchain.reconsiderBlock('invalidblockhash')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -8,
message: 'blockhash must be of length 64 (not 16, for \'invalidblockhash\')',
method: 'reconsiderblock'
}
})
})

it('should throw error if invalid blockhash provided - invalid hex string', async () => {
const promise = testing.rpc.blockchain.reconsiderBlock('d744db74fb70ed42767aj028a129365fb4d7de54ba1b6575fb047490554f8a7b')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -8,
message: 'blockhash must be hexadecimal string (not \'d744db74fb70ed42767aj028a129365fb4d7de54ba1b6575fb047490554f8a7b\')',
method: 'reconsiderblock'
}
})
})

it('should throw error if block is not found', async () => {
const promise = testing.rpc.blockchain.reconsiderBlock('a9b5faec3324361a842df4302ce987f5fe1c5ce9ba53650f3a54397a36fea3b2')

await expect(promise).rejects.toThrow(RpcApiError)
await expect(promise).rejects.toMatchObject({
payload: {
code: -5,
message: 'Block not found',
method: 'reconsiderblock'
}
})
})

it('should reconsider block', async () => {
await testing.generate(1) // generate some blocks to have a chain history
const blockToInvalidate = await testing.rpc.blockchain.getBestBlockHash()

await testing.generate(2) // generate new blocks
const bestBlockHash = await testing.rpc.blockchain.getBestBlockHash()

await expect(bestBlockHash).not.toStrictEqual(blockToInvalidate) // confirm that new blocks were generated
await testing.rpc.blockchain.invalidateBlock(blockToInvalidate)

const promise = testing.rpc.blockchain.reconsiderBlock(blockToInvalidate)
await expect(promise).toBeTruthy()
})
})
21 changes: 21 additions & 0 deletions packages/jellyfish-api-core/src/category/blockchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,27 @@ export class Blockchain {
async getChainTxStats (nBlocks?: number, blockHash?: string): Promise<ChainTxStats> {
return await this.client.call('getchaintxstats', [nBlocks, blockHash], 'number')
}

/**
* Permanently marks a block as invalid, as if it violated a consensus rule.
*
* @param {string} blockHash the hash of the block to invalidate
* @return {Promise<void>}
*/
async invalidateBlock (blockHash: string): Promise<void> {
return await this.client.call('invalidateblock', [blockHash], 'number')
}

/**
* Removes invalidity status of a block, its ancestors and its descendants, reconsider them for activation.
* This can be used to undo the effects of invalidateBlock.
*
* @param {string} blockHash the hash of the block to invalidate
* @return {Promise<void>}
*/
async reconsiderBlock (blockHash: string): Promise<void> {
return await this.client.call('reconsiderblock', [blockHash], 'number')
}
}

/**
Expand Down

0 comments on commit 570fe64

Please sign in to comment.