Skip to content

Commit

Permalink
fix(jellyfish-api-core): Update listGovProposalVotes arguments (#1908)
Browse files Browse the repository at this point in the history
<!--  Thanks for sending a pull request! -->

#### What this PR does / why we need it:

- Update listGovProposalVotes arguments as per
DeFiCh/ain#1635. This is required to keep
compatibility with the next release.

Signed-off-by: Shoham Chakraborty <shhmchk@gmail.com>
  • Loading branch information
shohamc1 authored Jan 11, 2023
1 parent 71fd2cd commit 5abb393
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 23 deletions.
19 changes: 16 additions & 3 deletions docs/node/CATEGORIES/12-governance.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ Returns list of proposals.

```ts title="client.governance.listGovProposals()"
interface governance {
async listGovProposals ({
listGovProposals ({
type = ListProposalsType.ALL,
status = ListProposalsStatus.ALL
} = {}): Promise<ProposalInfo[]>
Expand Down Expand Up @@ -175,7 +175,7 @@ Vote on a community proposal.

```ts title="client.governance.voteGov()"
interface governance {
async voteGov (data: VoteData, utxos: UTXO[] = []): Promise<string>
voteGov (data: VoteData, utxos: UTXO[] = []): Promise<string>
}

enum VoteDecision {
Expand All @@ -202,14 +202,27 @@ Returns information about proposal votes.

```ts title="client.governance.listGovProposalVotes()"
interface governance {
async listGovProposalVotes (proposalId: string, masternode: MasternodeType | string = MasternodeType.MINE, cycle: number = 0): Promise<ListVotesResult[]>
listGovProposalVotes (options: ListGovProposalVotesOptions): Promise<ListVotesResult[]>
}

enum MasternodeType {
MINE = 'mine',
ALL = 'all'
}

interface ListGovProposalVotesPagination {
start?: number
including_start?: boolean
limit?: number
}

interface ListGovProposalVotesOptions {
proposalId: string
masternode?: MasternodeType | string
cycle?: number
pagination?: ListGovProposalVotesPagination
}

interface ListVotesResult {
proposalId: string
masternodeId: string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BigNumber from 'bignumber.js'
import { StartOptions, MasterNodeRegTestContainer } from '@defichain/testcontainers'
import { MasterNodeRegTestContainer, StartOptions } from '@defichain/testcontainers'
import { MasternodeType, VoteDecision } from '../../../src/category/governance'
import { Testing } from '@defichain/jellyfish-testing'
import { masternode } from '@defichain/jellyfish-api-core'
Expand Down Expand Up @@ -53,12 +53,16 @@ describe('Governance', () => {
for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({ proposalId, masternodeId: id, decision: VoteDecision.YES })
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes(proposalId)
const votes = await testing.rpc.governance.listGovProposalVotes({ proposalId: proposalId })
expect(votes.length).toStrictEqual(3) // The three masternodes should have voted on the proposal
expect(typeof votes[0].masternodeId).toStrictEqual('string')
expect(votes[0].masternodeId.length).toStrictEqual(64)
Expand All @@ -67,6 +71,145 @@ describe('Governance', () => {
expect(votes[0].vote).toStrictEqual('YES')
})

it('should listGovProposalVotes - pagination', async () => {
const data = {
title: 'A vote of confidence',
context: '<Git issue url>'
}
const proposalId = await testing.rpc.governance.createGovVoc(data) // Creates a vote of confidence on which to vote
await testing.container.generate(1)

for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes({ proposalId: proposalId })
const votes1 = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
pagination: {
start: 0,
including_start: true,
limit: 2
}
})
const votes2 = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
pagination: {
start: 2,
including_start: true,
limit: 2
}
})

votes1.push(...votes2)
expect(votes.length).toStrictEqual(votes1.length)
expect(votes).toStrictEqual(votes1)
expect(votes[0]).toStrictEqual(votes1[0])
expect(votes[1]).toStrictEqual(votes1[1])
expect(votes[2]).toStrictEqual(votes2[0])
})

it('should listGovProposalVotes - including_start should override default', async () => {
const data = {
title: 'A vote of confidence',
context: '<Git issue url>'
}
const proposalId = await testing.rpc.governance.createGovVoc(data) // Creates a vote of confidence on which to vote
await testing.container.generate(1)

for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes({ proposalId: proposalId })

// including start is false, limit is not set
const votesIncludingStart1 = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
pagination: {
start: 0,
including_start: false
}
})
expect(votesIncludingStart1[0]).toStrictEqual(votes[1])
expect(votesIncludingStart1.length).toStrictEqual(votes.length - 1)
})

it('should listGovProposalVotes - including_start should default to false if start is set', async () => {
const data = {
title: 'A vote of confidence',
context: '<Git issue url>'
}
const proposalId = await testing.rpc.governance.createGovVoc(data) // Creates a vote of confidence on which to vote
await testing.container.generate(1)

for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes({ proposalId: proposalId })
// including_start not set, start is set (should default to false)
const votesIncludingStart2 = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
pagination: {
start: 0
}
})
expect(votesIncludingStart2[0]).toStrictEqual(votes[1])
expect(votesIncludingStart2.length).toStrictEqual(votes.length - 1)
})

it('should listGovProposalVotes - should limit results', async () => {
const data = {
title: 'A vote of confidence',
context: '<Git issue url>'
}
const proposalId = await testing.rpc.governance.createGovVoc(data) // Creates a vote of confidence on which to vote
await testing.container.generate(1)

for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
pagination: { limit: 2 }
})
expect(votes.length).toStrictEqual(2)
})

it('should listGovProposalVotes with filter masternode=MasternodeType.ALL', async () => {
const data = {
title: 'A vote of confidence',
Expand All @@ -78,12 +221,19 @@ describe('Governance', () => {
for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({ proposalId, masternodeId: id, decision: VoteDecision.YES })
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes(proposalId, MasternodeType.ALL)
const votes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: MasternodeType.ALL
})
expect(votes.length).toStrictEqual(3) // The three masternodes should have voted on the proposal
expect(typeof votes[0].masternodeId).toStrictEqual('string')
expect(votes[0].masternodeId.length).toStrictEqual(64)
Expand All @@ -105,13 +255,20 @@ describe('Governance', () => {
for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({ proposalId, masternodeId: id, decision: VoteDecision.YES })
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
masternodeId = id // Uses the last id as masternodeId
}
}
await testing.container.generate(1)

const votes = await testing.rpc.governance.listGovProposalVotes(proposalId, masternodeId)
const votes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: masternodeId
})
expect(votes.length).toStrictEqual(1)
expect(votes[0].masternodeId).toStrictEqual(masternodeId)
expect(votes[0].proposalId).toStrictEqual(proposalId)
Expand Down Expand Up @@ -141,15 +298,22 @@ describe('Governance', () => {
for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({ proposalId, masternodeId: id, decision: VoteDecision.YES })
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: VoteDecision.YES
})
masternodeId = id // Uses the first id as masternodeId
break // only one masternote vote in first cycle
}
}
await testing.container.generate(1)

// check total votes for current cycle
let proposalVotes = await testing.rpc.governance.listGovProposalVotes(proposalId, 'all')
let proposalVotes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: 'all'
})
expect(proposalVotes.length).toStrictEqual(1)
expect(proposalVotes[0].cycle).toStrictEqual(1)
expect(proposalVotes[0].vote).toStrictEqual('YES')
Expand All @@ -163,32 +327,56 @@ describe('Governance', () => {
for (const [id, data] of Object.entries(masternodes)) {
if (data.operatorIsMine) {
await testing.container.generate(1, data.operatorAuthAddress) // Generate a block to operatorAuthAddress to be allowed to vote on proposal
await testing.rpc.governance.voteGov({ proposalId, masternodeId: id, decision: votes[index] })
await testing.rpc.governance.voteGov({
proposalId,
masternodeId: id,
decision: votes[index]
})
index++ // all masternodes vote in second cycle
}
}
await testing.container.generate(1)

// check total votes for current cycle
proposalVotes = await testing.rpc.governance.listGovProposalVotes(proposalId, 'all')
proposalVotes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: 'all',
cycle: 2
})
expect(proposalVotes.length).toStrictEqual(3)
expect(proposalVotes[0].cycle).toStrictEqual(2)

// check total votes for a given cycle
proposalVotes = await testing.rpc.governance.listGovProposalVotes(proposalId, 'all', 1)
proposalVotes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: 'all',
cycle: 1
})
expect(proposalVotes.length).toStrictEqual(1)
expect(proposalVotes[0].cycle).toStrictEqual(1)

// check total votes for all cycles
proposalVotes = await testing.rpc.governance.listGovProposalVotes(proposalId, 'all', -1)
proposalVotes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: 'all',
cycle: -1
})
expect(proposalVotes.length).toStrictEqual(4)

// check total votes for specific masternode for all cycles
proposalVotes = await testing.rpc.governance.listGovProposalVotes(proposalId, masternodeId, -1)
proposalVotes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: masternodeId,
cycle: -1
})
expect(proposalVotes.length).toStrictEqual(2)

// check votes for specific masternode for a given cycle
proposalVotes = await testing.rpc.governance.listGovProposalVotes(proposalId, masternodeId, 2)
proposalVotes = await testing.rpc.governance.listGovProposalVotes({
proposalId: proposalId,
masternode: masternodeId,
cycle: 2
})
expect(proposalVotes.length).toStrictEqual(1)
})
})
30 changes: 25 additions & 5 deletions packages/jellyfish-api-core/src/category/governance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,20 @@ export class Governance {
/**
* Returns information about proposal votes.
*
* @param {string} proposalId Proposal id
* @param {MasternodeType | string} [masternode=MasternodeType.MINE] masternode id or reserved words 'mine' to list votes for all owned accounts or 'all' to list all votes
* @param {number} [cycle=0] cycle: 0 (show current), cycle: N (show cycle N), cycle: -1 (show all)
* @param {ListGovProposalVotesOptions} options
* @param {string} options.proposalId Proposal id
* @param {MasternodeType | string} [options.masternode=MasternodeType.MINE] masternode id or reserved words 'mine' to list votes for all owned accounts or 'all' to list all votes
* @param {number} [options.cycle=0] cycle: 0 (show current), cycle: N (show cycle N), cycle: -1 (show all)
* @param {ListGovProposalVotesPagination} [options.pagination]
* @param {number} [options.pagination.start=0]
* @param {boolean} [options.pagination.including_start=true] defaults to false if options.pagination.start is set, true otherwise
* @param {number} [options.pagination.limit=100] to limit number of records
* @return {Promise<ListVotesResult[]>} Proposal vote information
*/
async listGovProposalVotes (proposalId: string, masternode: MasternodeType | string = MasternodeType.MINE, cycle: number = 0): Promise<ListVotesResult[]> {
return await this.client.call('listgovproposalvotes', [proposalId, masternode, cycle], 'number')
async listGovProposalVotes (
options: ListGovProposalVotesOptions
): Promise<ListVotesResult[]> {
return await this.client.call('listgovproposalvotes', [options], 'number')
}
}

Expand Down Expand Up @@ -201,3 +208,16 @@ export interface ListVotesResult {
cycle: number
vote: string
}

export interface ListGovProposalVotesOptions {
proposalId: string
masternode?: MasternodeType | string
cycle?: number
pagination?: ListGovProposalVotesPagination
}

export interface ListGovProposalVotesPagination {
start?: number
including_start?: boolean
limit?: number
}

0 comments on commit 5abb393

Please sign in to comment.