def governanceblock(): sb = GovernanceBlock( event_block_height=62500, payment_addresses= 'yYe8KwyaUu5YswSYmB3q3ryx8XTUu9y7Ui|yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV', payment_amounts='5|3', proposal_hashes= 'e8a0057914a2e1964ae8a945c4723491caae2077a90a00a2aabee22b40081a87|d1ce73527d7cd6f2218f8ca893990bc7d5c6b9334791ce7973bfa22f155f826e', ) return sb
def test_serialisable_fields(): s1 = [ 'event_block_height', 'payment_addresses', 'payment_amounts', 'proposal_hashes' ] s2 = GovernanceBlock.serialisable_fields() s1.sort() s2.sort() assert s2 == s1
def test_deterministic_governanceblock_selection(go_list_governanceblocks): from genesisd import GenesisDaemon genesisd = GenesisDaemon.from_genesis_conf(config.genesis_conf) for item in go_list_governanceblocks: (go, subobj) = GovernanceObject.import_gobject_from_genesisd( genesisd, item) # highest hash wins if same -- so just order by hash sb = GovernanceBlock.find_highest_deterministic( '542f4433e438bdd64697b8381fda1a7a9b7a111c3a4e32fad524d1821d820394') assert sb.object_hash == 'bc2834f357da7504138566727c838e6ada74d079e63b6104701f4f8eb05dae36'
def create_governanceblock(proposals, event_block_height, budget_max, sb_epoch_time, maxgovobjdatasize): from models import GovernanceBlock, GovernanceObject, Proposal from constants import GOVERNANCEBLOCK_FUDGE_WINDOW # don't create an empty governanceblock if (len(proposals) == 0): printdbg("No proposals, cannot create an empty governanceblock.") return None budget_allocated = Decimal(0) fudge = GOVERNANCEBLOCK_FUDGE_WINDOW # fudge-factor to allow for slightly incorrect estimates payments = [] for proposal in proposals: fmt_string = "name: %s, rank: %4d, hash: %s, amount: %s <= %s" # skip proposals that are too expensive... if (budget_allocated + proposal.payment_amount) > budget_max: printdbg(fmt_string % ( proposal.name, proposal.rank, proposal.object_hash, proposal.payment_amount, "skipped (blows the budget)", )) continue # skip proposals if the SB isn't within the Proposal time window... window_start = proposal.start_epoch - fudge window_end = proposal.end_epoch + fudge printdbg("\twindow_start: %s" % epoch2str(window_start)) printdbg("\twindow_end: %s" % epoch2str(window_end)) printdbg("\tsb_epoch_time: %s" % epoch2str(sb_epoch_time)) if (sb_epoch_time < window_start or sb_epoch_time > window_end): printdbg(fmt_string % ( proposal.name, proposal.rank, proposal.object_hash, proposal.payment_amount, "skipped (SB time is outside of Proposal window)", )) continue printdbg(fmt_string % ( proposal.name, proposal.rank, proposal.object_hash, proposal.payment_amount, "adding", )) payment = { 'address': proposal.payment_address, 'amount': "{0:.8f}".format(proposal.payment_amount), 'proposal': "{}".format(proposal.object_hash) } # calculate current sb data size sb_temp = GovernanceBlock( event_block_height=event_block_height, payment_addresses='|'.join([pd['address'] for pd in payments]), payment_amounts='|'.join([pd['amount'] for pd in payments]), proposal_hashes='|'.join([pd['proposal'] for pd in payments])) data_size = len(sb_temp.genesisd_serialise()) if data_size > maxgovobjdatasize: printdbg("MAX_GOVERNANCE_OBJECT_DATA_SIZE limit reached!") break # else add proposal and keep track of total budget allocation budget_allocated += proposal.payment_amount payments.append(payment) # don't create an empty governanceblock if not payments: printdbg("No proposals made the cut!") return None # 'payments' now contains all the proposals for inclusion in the # GovernanceBlock, but needs to be sorted by proposal hash descending payments.sort(key=lambda k: k['proposal'], reverse=True) sb = GovernanceBlock( event_block_height=event_block_height, payment_addresses='|'.join([pd['address'] for pd in payments]), payment_amounts='|'.join([pd['amount'] for pd in payments]), proposal_hashes='|'.join([pd['proposal'] for pd in payments]), ) printdbg("generated governanceblock: %s" % sb.__dict__) return sb
def setup(): # clear tables first... Vote.delete().execute() Proposal.delete().execute() GovernanceBlock.delete().execute() GovernanceObject.delete().execute()
def test_governanceblock_is_valid(governanceblock): from genesisd import GenesisDaemon genesisd = GenesisDaemon.from_genesis_conf(config.genesis_conf) orig = GovernanceBlock(**governanceblock.get_dict()) # make a copy # original as-is should be valid assert orig.is_valid() is True # mess with payment amounts governanceblock.payment_amounts = '7|yyzx' assert governanceblock.is_valid() is False governanceblock.payment_amounts = '7,|yzx' assert governanceblock.is_valid() is False governanceblock.payment_amounts = '7|8' assert governanceblock.is_valid() is True governanceblock.payment_amounts = ' 7|8' assert governanceblock.is_valid() is False governanceblock.payment_amounts = '7|8 ' assert governanceblock.is_valid() is False governanceblock.payment_amounts = ' 7|8 ' assert governanceblock.is_valid() is False # reset governanceblock = GovernanceBlock(**orig.get_dict()) assert governanceblock.is_valid() is True # mess with payment addresses governanceblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV|1234 Anywhere ST, Chicago, USA' assert governanceblock.is_valid() is False # leading spaces in payment addresses governanceblock.payment_addresses = ' yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV' governanceblock.payment_amounts = '5.00' assert governanceblock.is_valid() is False # trailing spaces in payment addresses governanceblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV ' governanceblock.payment_amounts = '5.00' assert governanceblock.is_valid() is False # leading & trailing spaces in payment addresses governanceblock.payment_addresses = ' yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV ' governanceblock.payment_amounts = '5.00' assert governanceblock.is_valid() is False # single payment addr/amt is ok governanceblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV' governanceblock.payment_amounts = '5.00' assert governanceblock.is_valid() is True # ensure number of payment addresses matches number of payments governanceblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV' governanceblock.payment_amounts = '37.00|23.24' assert governanceblock.is_valid() is False governanceblock.payment_addresses = 'yYe8KwyaUu5YswSYmB3q3ryx8XTUu9y7Ui|yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV' governanceblock.payment_amounts = '37.00' assert governanceblock.is_valid() is False # ensure amounts greater than zero governanceblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV' governanceblock.payment_amounts = '-37.00' assert governanceblock.is_valid() is False # reset governanceblock = GovernanceBlock(**orig.get_dict()) assert governanceblock.is_valid() is True # mess with proposal hashes governanceblock.proposal_hashes = '7|yyzx' assert governanceblock.is_valid() is False governanceblock.proposal_hashes = '7,|yyzx' assert governanceblock.is_valid() is False governanceblock.proposal_hashes = '0|1' assert governanceblock.is_valid() is False governanceblock.proposal_hashes = '0000000000000000000000000000000000000000000000000000000000000000|1111111111111111111111111111111111111111111111111111111111111111' assert governanceblock.is_valid() is True # reset governanceblock = GovernanceBlock(**orig.get_dict()) assert governanceblock.is_valid() is True
def attempt_governanceblock_creation(genesisd): import genesislib if not genesisd.is_masternode(): print("We are not a Masternode... can't submit governanceblocks!") return # query votes for this specific ebh... if we have voted for this specific # ebh, then it's voted on. since we track votes this is all done using joins # against the votes table # # has this masternode voted on *any* governanceblocks at the given event_block_height? # have we voted FUNDING=YES for a governanceblock for this specific event_block_height? event_block_height = genesisd.next_governanceblock_height() if GovernanceBlock.is_voted_funding(event_block_height): # printdbg("ALREADY VOTED! 'til next time!") # vote down any new SBs because we've already chosen a winner for sb in GovernanceBlock.at_height(event_block_height): if not sb.voted_on(signal=VoteSignals.funding): sb.vote(genesisd, VoteSignals.funding, VoteOutcomes.no) # now return, we're done return if not genesisd.is_govobj_maturity_phase(): printdbg( "Not in maturity phase yet -- will not attempt GovernanceBlock") return proposals = Proposal.approved_and_ranked( proposal_quorum=genesisd.governance_quorum(), next_governanceblock_max_budget=genesisd. next_governanceblock_max_budget()) budget_max = genesisd.get_governanceblock_budget_allocation( event_block_height) sb_epoch_time = genesisd.block_height_to_epoch(event_block_height) maxgovobjdatasize = genesisd.govinfo['maxgovobjdatasize'] sb = genesislib.create_governanceblock(proposals, event_block_height, budget_max, sb_epoch_time, maxgovobjdatasize) if not sb: printdbg("No governanceblock created, sorry. Returning.") return # find the deterministic SB w/highest object_hash in the DB dbrec = GovernanceBlock.find_highest_deterministic(sb.hex_hash()) if dbrec: dbrec.vote(genesisd, VoteSignals.funding, VoteOutcomes.yes) # any other blocks which match the sb_hash are duplicates, delete them for sb in GovernanceBlock.select().where( GovernanceBlock.sb_hash == sb.hex_hash()): if not sb.voted_on(signal=VoteSignals.funding): sb.vote(genesisd, VoteSignals.delete, VoteOutcomes.yes) printdbg( "VOTED FUNDING FOR SB! We're done here 'til next governanceblock cycle." ) return else: printdbg("The correct governanceblock wasn't found on the network...") # if we are the elected masternode... if (genesisd.we_are_the_winner()): printdbg("we are the winner! Submit SB to network") sb.submit(genesisd)