def test_superblock_size_limit(go_list_proposals): import chaincoinlib import misc from chaincoind import ChaincoinDaemon chaincoind = ChaincoinDaemon.from_chaincoin_conf(config.chaincoin_conf) for item in go_list_proposals: (go, subobj) = GovernanceObject.import_gobject_from_chaincoind(chaincoind, item) max_budget = 60 prop_list = Proposal.approved_and_ranked(proposal_quorum=1, next_superblock_max_budget=max_budget) # mock maxgovobjdatasize by setting equal to the size of a trigger # (serialized) if only the first proposal had been included... anything # larger should break the limit single_proposal_sb = Superblock( event_block_height=72000, payment_addresses=prop_list[0].payment_address, payment_amounts="{0:.8f}".format(prop_list[0].payment_amount), proposal_hashes=prop_list[0].object_hash, ) maxgovobjdatasize = len(single_proposal_sb.serialise()) # now try and create a Superblock with the entire proposal list sb = chaincoinlib.create_superblock(prop_list, 72000, max_budget, misc.now(), maxgovobjdatasize) # two proposals in the list, but... assert len(prop_list) == 2 # only one should have been included in the SB, because the 2nd one is over the size limit assert sb.event_block_height == 72000 assert sb.payment_addresses == 'ZHJV7jhBWgaB1uxazbVsnQU5HUDAqX14Bz|ZH6bt95skGVco2t3gRuHggcSUrtRZ5BUsr' assert sb.payment_amounts == '315.75000000|21.05000000' assert sb.proposal_hashes == '7fa2798fee8ea74c3a369db72ae872096bd4e4714f1f5027c730ccfbf58aac02|d1ce73527d7cd6f2218f8ca893990bc7d5c6b9334791ce7973bfa22f155f826e' assert sb.hex_hash() == 'bb3f33ccf95415c396bd09d35325dbcbc7b067010d51c7ccf772a9e839c1e414'
def test_superblock_size_limit(go_list_proposals): import exiliumlib import misc from exiliumd import ExiliumDaemon exiliumd = ExiliumDaemon.from_exilium_conf(config.exilium_conf) for item in go_list_proposals: (go, subobj) = GovernanceObject.import_gobject_from_exiliumd( exiliumd, item) max_budget = 60 prop_list = Proposal.approved_and_ranked( proposal_quorum=1, next_superblock_max_budget=max_budget) # mock maxgovobjdatasize by setting equal to the size of a trigger # (serialized) if only the first proposal had been included... anything # larger should break the limit single_proposal_sb = Superblock( event_block_height=72000, payment_addresses=prop_list[0].payment_address, payment_amounts="{0:.8f}".format(prop_list[0].payment_amount), proposal_hashes=prop_list[0].object_hash, ) maxgovobjdatasize = len(single_proposal_sb.serialise()) # now try and create a Superblock with the entire proposal list sb = exiliumlib.create_superblock(prop_list, 72000, max_budget, misc.now(), maxgovobjdatasize) # two proposals in the list, but... assert len(prop_list) == 2 # only one should have been included in the SB, because the 2nd one is over the size limit assert sb.event_block_height == 72000 assert sb.payment_addresses == 'yYe8KwyaUu5YswSYmB3q3ryx8XTUu9y7Ui' assert sb.payment_amounts == '25.75000000' assert sb.proposal_hashes == 'dfd7d63979c0b62456b63d5fc5306dbec451180adee85876cbf5b28c69d1a86c' assert sb.hex_hash( ) == '6b8cababf797644f1d62003e4cc68c1c40a8c1873c8a68ed0fc88772ea77cc44'
def create_superblock(proposals, event_block_height, budget_max, sb_epoch_time): from models import Superblock, GovernanceObject, Proposal from constants import SUPERBLOCK_FUDGE_WINDOW import copy # don't create an empty superblock if (len(proposals) == 0): printdbg("No proposals, cannot create an empty superblock.") return None budget_allocated = Decimal(0) fudge = SUPERBLOCK_FUDGE_WINDOW # fudge-factor to allow for slightly incorrect estimates payments_list = [] 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) } temp_payments_list = copy.deepcopy(payments_list) temp_payments_list.append(payment) # calculate size of proposed Superblock sb_temp = Superblock(event_block_height=event_block_height, payment_addresses='|'.join( [pd['address'] for pd in temp_payments_list]), payment_amounts='|'.join( [pd['amount'] for pd in temp_payments_list]), proposal_hashes='|'.join([ pd['proposal'] for pd in temp_payments_list ])) proposed_sb_size = len(sb_temp.serialise()) # add proposal and keep track of total budget allocation budget_allocated += proposal.payment_amount payments_list.append(payment) # don't create an empty superblock if not payments_list: printdbg("No proposals made the cut!") return None # 'payments' now contains all the proposals for inclusion in the # Superblock, but needs to be sorted by proposal hash descending payments_list.sort(key=lambda k: k['proposal'], reverse=True) sb = Superblock( event_block_height=event_block_height, payment_addresses='|'.join([pd['address'] for pd in payments_list]), payment_amounts='|'.join([pd['amount'] for pd in payments_list]), proposal_hashes='|'.join([pd['proposal'] for pd in payments_list]), ) printdbg("generated superblock: %s" % sb.__dict__) return sb