import pytest import sys import os import time os.environ['SENTINEL_ENV'] = 'test' os.environ['SENTINEL_CONFIG'] = os.path.normpath(os.path.join(os.path.dirname(__file__), '../../test_sentinel.conf')) sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '../../../lib'))) import misc import config from models import GovernanceObject, Proposal, Superblock, Vote # clear DB tables before each execution def setup(): # clear tables first... Vote.delete().execute() Proposal.delete().execute() Superblock.delete().execute() GovernanceObject.delete().execute() def teardown(): pass # list of proposal govobjs to import for testing @pytest.fixture def go_list_proposals(): items = [ {u'AbsoluteYesCount': 1000, u'AbstainCount': 7, u'CollateralHash': u'acb67ec3f3566c9b94a26b70b36c1f74a010a37c0950c22d683cc50da324fdca', u'DataHex': u'5b5b2270726f706f73616c222c207b22656e645f65706f6368223a20323132323532303430302c20226e616d65223a20227465737470726f706f73616c2d35343933222c20227061796d656e745f61646472657373223a20227365564e704835726b617538644b68756d694c46314259737070327666374c6b7962222c20227061796d656e745f616d6f756e74223a2032352e37352c202273746172745f65706f6368223a20313437343236313038362c202274797065223a20312c202275726c223a2022687474703a2f2f736962636f6e74726f6c2e6f72672f70726f706f73616c732f7465737470726f706f73616c2d35343933227d5d5d', u'DataString': u'[["proposal", {"end_epoch": 2122520400, "name": "testproposal-5493", "payment_address": "seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb", "payment_amount": 25.75, "start_epoch": 1474261086, "type": 1, "url": "http://sibcontrol.org/proposals/testproposal-5493"}]]', u'Hash': u'dfd7d63979c0b62456b63d5fc5306dbec451180adee85876cbf5b28c69d1a86c', u'IsValidReason': u'', u'NoCount': 25, u'YesCount': 1025, u'fBlockchainValidity': True, u'fCachedDelete': False, u'fCachedEndorsed': False, u'fCachedFunding': False, u'fCachedValid': True}, {u'AbsoluteYesCount': 1000, u'AbstainCount': 29, u'CollateralHash': u'3efd23283aa98c2c33f80e4d9ed6f277d195b72547b6491f43280380f6aac810', u'DataHex': u'5b5b2270726f706f73616c222c207b22656e645f65706f6368223a20323132323532303430302c20226e616d65223a20226665726e616e64657a2d37363235222c20227061796d656e745f61646472657373223a2022736674734a6564686d4c71594257506b627670716b7371737653397041624c614c53222c20227061796d656e745f616d6f756e74223a2033322e30312c202273746172745f65706f6368223a20313437343236313038362c202274797065223a20312c202275726c223a2022687474703a2f2f736962636f6e74726f6c2e6f72672f70726f706f73616c732f6665726e616e64657a2d37363235227d5d5d', u'DataString': u'[["proposal", {"end_epoch": 2122520400, "name": "fernandez-7625", "payment_address": "sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS", "payment_amount": 32.01, "start_epoch": 1474261086, "type": 1, "url": "http://sibcontrol.org/proposals/fernandez-7625"}]]', u'Hash': u'0523445762025b2e01a2cd34f1d10f4816cf26ee1796167e5b029901e5873630', u'IsValidReason': u'', u'NoCount': 56, u'YesCount': 1056, u'fBlockchainValidity': True, u'fCachedDelete': False, u'fCachedEndorsed': False, u'fCachedFunding': False, u'fCachedValid': True}, ] return items # list of superblock govobjs to import for testing @pytest.fixture def go_list_superblocks(): items = [ {u'AbsoluteYesCount': 1, u'AbstainCount': 0, u'CollateralHash': u'0000000000000000000000000000000000000000000000000000000000000000', u'DataHex': u'5b5b2274726967676572222c207b226576656e745f626c6f636b5f686569676874223a2037323639362c20227061796d656e745f616464726573736573223a20227365564e704835726b617538644b68756d694c46314259737070327666374c6b79627c736674734a6564686d4c71594257506b627670716b7371737653397041624c614c53222c20227061796d656e745f616d6f756e7473223a202232352e37353030303030307c32352e3735303030303030222c202274797065223a20327d5d5d', u'DataString': u'[["trigger", {"event_block_height": 72696, "payment_addresses": "seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb|sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS", "payment_amounts": "25.75000000|25.7575000000", "type": 2}]]', u'Hash': u'667c4a53eb81ba14d02860fdb4779e830eb8e98306f9145f3789d347cbeb0721', u'IsValidReason': u'', u'NoCount': 0, u'YesCount': 1, u'fBlockchainValidity': True, u'fCachedDelete': False, u'fCachedEndorsed': False, u'fCachedFunding': False, u'fCachedValid': True}, {u'AbsoluteYesCount': 1, u'AbstainCount': 0, u'CollateralHash': u'0000000000000000000000000000000000000000000000000000000000000000', u'DataHex': u'5b5b2274726967676572222c207b226576656e745f626c6f636b5f686569676874223a2037323639362c20227061796d656e745f616464726573736573223a20227365564e704835726b617538644b68756d694c46314259737070327666374c6b79627c736674734a6564686d4c71594257506b627670716b7371737653397041624c614c53222c20227061796d656e745f616d6f756e7473223a202232352e37353030303030307c32352e3735303030303030222c202274797065223a20327d5d5d', u'DataString': u'[["trigger", {"event_block_height": 72696, "payment_addresses": "seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb|sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS", "payment_amounts": "25.75000000|25.75000000", "type": 2}]]', u'Hash': u'8f91ffb105739ec7d5b6c0b12000210fcfcc0837d3bb8ca6333ba93ab5fc0bdf', u'IsValidReason': u'', u'NoCount': 0, u'YesCount': 1, u'fBlockchainValidity': True, u'fCachedDelete': False, u'fCachedEndorsed': False, u'fCachedFunding': False, u'fCachedValid': True}, {u'AbsoluteYesCount': 1, u'AbstainCount': 0, u'CollateralHash': u'0000000000000000000000000000000000000000000000000000000000000000', u'DataHex': u'5b5b2274726967676572222c207b226576656e745f626c6f636b5f686569676874223a2037323639362c20227061796d656e745f616464726573736573223a20227365564e704835726b617538644b68756d694c46314259737070327666374c6b79627c736674734a6564686d4c71594257506b627670716b7371737653397041624c614c53222c20227061796d656e745f616d6f756e7473223a202232352e37353030303030307c32352e3735303030303030222c202274797065223a20327d5d5d', u'DataString': u'[["trigger", {"event_block_height": 72696, "payment_addresses": "seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb|sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS", "payment_amounts": "25.75000000|25.75000000", "type": 2}]]', u'Hash': u'bc2834f357da7504138566727c838e6ada74d079e63b6104701f4f8eb05dae36', u'IsValidReason': u'', u'NoCount': 0, u'YesCount': 1, u'fBlockchainValidity': True, u'fCachedDelete': False, u'fCachedEndorsed': False, u'fCachedFunding': False, u'fCachedValid': True}, ] return items @pytest.fixture def superblock(): sb = Superblock( event_block_height=62500, payment_addresses='seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb|sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS', payment_amounts='5|3', proposal_hashes='e8a0057914a2e1964ae8a945c4723491caae2077a90a00a2aabee22b40081a87|d1ce73527d7cd6f2218f8ca893990bc7d5c6b9334791ce7973bfa22f155f826e', ) return sb def test_superblock_is_valid(superblock): from sibcoind import SibcoinDaemon sibcoind = SibcoinDaemon.from_sibcoin_conf(config.sibcoin_conf) orig = Superblock(**superblock.get_dict()) # make a copy # original as-is should be valid assert orig.is_valid() is True # mess with payment amounts superblock.payment_amounts = '7|yyzx' assert superblock.is_valid() is False superblock.payment_amounts = '7,|yzx' assert superblock.is_valid() is False superblock.payment_amounts = '7|8' assert superblock.is_valid() is True superblock.payment_amounts = ' 7|8' assert superblock.is_valid() is False superblock.payment_amounts = '7|8 ' assert superblock.is_valid() is False superblock.payment_amounts = ' 7|8 ' assert superblock.is_valid() is False # reset superblock = Superblock(**orig.get_dict()) assert superblock.is_valid() is True # mess with payment addresses superblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV|1234 Anywhere ST, Chicago, USA' assert superblock.is_valid() is False # leading spaces in payment addresses superblock.payment_addresses = ' yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV' superblock.payment_amounts = '5.00' assert superblock.is_valid() is False # trailing spaces in payment addresses superblock.payment_addresses = 'yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV ' superblock.payment_amounts = '5.00' assert superblock.is_valid() is False # leading & trailing spaces in payment addresses superblock.payment_addresses = ' yTC62huR4YQEPn9AJHjnQxxreHSbgAoatV ' superblock.payment_amounts = '5.00' assert superblock.is_valid() is False # single payment addr/amt is ok superblock.payment_addresses = 'sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS' superblock.payment_amounts = '5.00' assert superblock.is_valid() is True # ensure number of payment addresses matches number of payments superblock.payment_addresses = 'sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS' superblock.payment_amounts = '37.00|23.24' assert superblock.is_valid() is False superblock.payment_addresses = 'seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb|sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS' superblock.payment_amounts = '37.00' assert superblock.is_valid() is False # ensure amounts greater than zero superblock.payment_addresses = 'sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS' superblock.payment_amounts = '-37.00' assert superblock.is_valid() is False # reset superblock = Superblock(**orig.get_dict()) assert superblock.is_valid() is True # mess with proposal hashes superblock.proposal_hashes = '7|yyzx' assert superblock.is_valid() is False superblock.proposal_hashes = '7,|yyzx' assert superblock.is_valid() is False superblock.proposal_hashes = '0|1' assert superblock.is_valid() is False superblock.proposal_hashes = '0000000000000000000000000000000000000000000000000000000000000000|1111111111111111111111111111111111111111111111111111111111111111' assert superblock.is_valid() is True # reset superblock = Superblock(**orig.get_dict()) assert superblock.is_valid() is True def test_serialisable_fields(): s1 = ['event_block_height', 'payment_addresses', 'payment_amounts', 'proposal_hashes'] s2 = Superblock.serialisable_fields() s1.sort() s2.sort() assert s2 == s1 def test_deterministic_superblock_creation(go_list_proposals): import dashlib import misc from sibcoind import SibcoinDaemon sibcoind = SibcoinDaemon.from_sibcoin_conf(config.sibcoin_conf) for item in go_list_proposals: (go, subobj) = GovernanceObject.import_gobject_from_dashd(sibcoind, item) max_budget = 60 prop_list = Proposal.approved_and_ranked(proposal_quorum=1, next_superblock_max_budget=max_budget) sb = dashlib.create_superblock(prop_list, 72000, max_budget, misc.now()) assert sb.event_block_height == 72000 assert sb.payment_addresses == 'seVNpH5rkau8dKhumiLF1BYspp2vf7Lkyb|sftsJedhmLqYBWPkbvpqksqsvS9pAbLaLS' assert sb.payment_amounts == '25.75000000|32.01000000' assert sb.proposal_hashes == 'dfd7d63979c0b62456b63d5fc5306dbec451180adee85876cbf5b28c69d1a86c|0523445762025b2e01a2cd34f1d10f4816cf26ee1796167e5b029901e5873630' assert sb.hex_hash() == 'f8cabf11ddc5479a9440868064b85bc7c726d267fc942b324e940e02949618c7' def test_deterministic_superblock_selection(go_list_superblocks): from sibcoind import SibcoinDaemon sibcoind = SibcoinDaemon.from_sibcoin_conf(config.sibcoin_conf) for item in go_list_superblocks: (go, subobj) = GovernanceObject.import_gobject_from_dashd(sibcoind, item) # highest hash wins if same -- so just order by hash sb = Superblock.find_highest_deterministic('366d15f2075cf8dc29301ec862d0343f79976a804ef76ef61adf50f818228413') assert sb.object_hash == 'bc2834f357da7504138566727c838e6ada74d079e63b6104701f4f8eb05dae36'