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

Add OCG voting scenarios tests #1706

Merged
merged 2 commits into from
Jan 27, 2023
Merged
Changes from all 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
171 changes: 171 additions & 0 deletions test/functional/feature_on_chain_government_voting_scenarios.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2019 The Bitcoin Core developers
# Copyright (c) DeFi Blockchain Developers
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
"""Test OCG voting scenarios"""

from test_framework.test_framework import DefiTestFramework
from test_framework.util import (
assert_equal,
)

APPROVAL_THRESHOLD=50
QUORUM=50
VOTING_PERIOD=10

class OCGVotingScenarionTest(DefiTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [
['-jellyfish_regtest=1', '-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-grandcentralheight=101', '-simulatemainnet=1'],
]

def setup_masternodes(self, nMasternodes = 19):
self.nodes[0].mns = []
operatorAddresses = []

for _ in range(nMasternodes):
address = self.nodes[0].getnewaddress('', 'legacy')
self.nodes[0].mns.append(self.nodes[0].createmasternode(address))
operatorAddresses.append(address)
self.nodes[0].generate(1)

self.nodes[0].generate(20) # Enables all MNs
self.sync_blocks(timeout=120)

# restart node with masternode_operator addresses to be able to mint with every MNs
self.restart_node(0, self.nodes[0].extra_args + ['-masternode_operator={}'.format(address) for address in operatorAddresses])

# Mint with every MNs to meet voting eligibility criteria
for address in operatorAddresses:
self.nodes[0].generatetoaddress(1, address)

def setup(self):
# Generate chain
self.nodes[0].generate(100)
self.sync_blocks(timeout=120)

self.setup_masternodes()

# activate on-chain governance
self.nodes[0].setgov({"ATTRIBUTES":{
'v0/params/feature/gov':'true',
'v0/gov/proposals/voting_period': '{}'.format(VOTING_PERIOD),
}})
self.nodes[0].generate(1)

def test_vote_on_cfp(self, yesVote, noVote, neutralVote, expectedStatus):
height = self.nodes[0].getblockcount()

# Create address for CFP
address = self.nodes[0].getnewaddress()
context = "<Git issue url>"
title = "Create test community fund proposal"
amount = 100

# Create CFP
propId = self.nodes[0].creategovcfp({"title": title, "context": context, "amount": amount, "cycles": 1, "payoutAddress": address})
self.nodes[0].generate(1)

mnIterator = iter(self.nodes[0].mns)

for _ in range(yesVote):
mnId = next(mnIterator)
self.nodes[0].votegov(propId, mnId, 'yes')

for _ in range(noVote):
mnId = next(mnIterator)
self.nodes[0].votegov(propId, mnId, 'no')

for _ in range(neutralVote):
mnId = next(mnIterator)
self.nodes[0].votegov(propId, mnId, 'neutral')

self.nodes[0].generate(1)

self.nodes[0].generate(VOTING_PERIOD * 2)
proposal = self.nodes[0].getgovproposal(propId)

assert_equal(proposal['status'], expectedStatus)

self.rollback_to(height)

def test_scenario_below_approval_threshold(self, expectedStatus):
self.test_vote_on_cfp(yesVote=4, noVote=6, neutralVote=2, expectedStatus=expectedStatus)

def test_scenario_at_approval_threshold(self, expectedStatus):
self.test_vote_on_cfp(yesVote=8, noVote=8, neutralVote=0, expectedStatus=expectedStatus)

def test_scenario_above_approval_threshold(self, expectedStatus):
self.test_vote_on_cfp(yesVote=10, noVote=6, neutralVote=2, expectedStatus=expectedStatus)

def test_scenario_below_quorum(self, expectedStatus):
self.test_vote_on_cfp(yesVote=6, noVote=2, neutralVote=1, expectedStatus=expectedStatus)

def test_scenario_at_quorum(self, expectedStatus):
self.test_vote_on_cfp(yesVote=6, noVote=2, neutralVote=2, expectedStatus=expectedStatus)

def test_scenario_above_quorum(self, expectedStatus):
self.test_vote_on_cfp(yesVote=6, noVote=3, neutralVote=2, expectedStatus=expectedStatus)

def test_scenario_high_neutral_vote(self, expectedStatus):
self.test_vote_on_cfp(yesVote=8, noVote=3, neutralVote=5, expectedStatus=expectedStatus)

def test_scenario_only_yes_and_neutral(self, expectedStatus):
self.test_vote_on_cfp(yesVote=8, noVote=0, neutralVote=8, expectedStatus=expectedStatus)

def test_scenario_66_6_percent_approval_full_yes_votes(self, expectedStatus):
self.test_vote_on_cfp(yesVote=len(self.nodes[0].mns), noVote=0, neutralVote=0, expectedStatus=expectedStatus)

def test_scenario_66_6_percent_approval_full_no_votes(self, expectedStatus):
self.test_vote_on_cfp(yesVote=0, noVote=len(self.nodes[0].mns), neutralVote=0, expectedStatus=expectedStatus)

def test_scenario_66_6_percent_approval_full_neutral_votes(self, expectedStatus):
self.test_vote_on_cfp(yesVote=0, noVote=0, neutralVote=len(self.nodes[0].mns), expectedStatus=expectedStatus)

def scenarios_test(self):
self.nodes[0].setgov({"ATTRIBUTES":{
'v0/gov/proposals/cfp_approval_threshold':'{}%'.format(APPROVAL_THRESHOLD),
}})
self.nodes[0].generate(1)

self.test_scenario_below_approval_threshold(expectedStatus='Rejected')
self.test_scenario_at_approval_threshold(expectedStatus='Rejected')
self.test_scenario_above_approval_threshold(expectedStatus='Completed')

self.nodes[0].setgov({"ATTRIBUTES":{
'v0/gov/proposals/quorum':'{}%'.format(QUORUM),
}})
self.nodes[0].generate(1)

self.test_scenario_below_quorum(expectedStatus='Rejected')
self.test_scenario_at_quorum(expectedStatus='Rejected')
self.test_scenario_above_quorum(expectedStatus='Completed')

# Currently marked as Rejected as neutral votes are incorrectly counted as no
# Should assert that it's Completed once https://github.com/DeFiCh/ain/issues/1704 is fixed
self.test_scenario_high_neutral_vote(expectedStatus='Rejected')

# Currently marked as Rejected as neutral votes are incorrectly counted as no
# Should assert that it's Completed once https://github.com/DeFiCh/ain/issues/1704 is fixed
self.test_scenario_only_yes_and_neutral(expectedStatus='Rejected')

self.nodes[0].setgov({"ATTRIBUTES":{
'v0/gov/proposals/cfp_approval_threshold':'{}%'.format(66.6),
}})
self.nodes[0].generate(1)

self.test_scenario_66_6_percent_approval_full_yes_votes(expectedStatus="Completed")
self.test_scenario_66_6_percent_approval_full_no_votes(expectedStatus="Rejected")
self.test_scenario_66_6_percent_approval_full_neutral_votes(expectedStatus="Rejected")

def run_test(self):

self.setup()

self.scenarios_test()

if __name__ == '__main__':
OCGVotingScenarionTest().main ()
1 change: 1 addition & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
@@ -303,6 +303,7 @@
'feature_on_chain_government.py',
'feature_on_chain_government_voting_period_alignment.py',
'feature_on_chain_government_fee_distribution.py',
'feature_on_chain_government_voting_scenarios.py',
'rpc_listgovproposals.py',
'rpc_help.py',
'feature_help.py',