def test_good_sbc_returns_true(self): tx_1 = { 'something': 'who_cares' } tx_2 = { 'something_else': 'who_cares' } txs = [encode(tx).encode() for tx in [tx_1, tx_2]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something' signature = w.sign(expected_tree[0]) sbc = { 'subblock': 1, 'transactions': [tx_1, tx_2], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } s = contender.SBCInbox() self.assertTrue(s.sbc_is_valid(sbc, 1))
def test_merkle_leaf_complex_objects_works(self): tx_1_raw = b'{"hash": "503fa157e4d990f78f2b032731dffb398f6ff642b6bbc305817e24dd42b33402", "result": "None", "stamps_used": 198, "state": [{"key": "rewards.S:current_votes:masternodes", "value": 20}, {"key": "rewards.S:current_votes:delegates", "value": 20}, {"key": "rewards.S:current_votes:blackhole", "value": 5}, {"key": "rewards.S:current_votes:foundation", "value": 5}, {"key": "rewards.S:current_votes:developer", "value": 450}, {"key": "rewards.S:has_voted:b0fc27299da14bc08834df9c70d73074f3e511a5a91321d4fa413f3401144918", "value": true}, {"key": "rewards.S:vote_count", "value": 5}, {"key": "rewards.S:value", "value": [{"__fixed__": "0.04"}, {"__fixed__": "0.04"}, {"__fixed__": "0.01"}, {"__fixed__": "0.01"}, {"__fixed__": "0.9"}]}, {"key": "rewards.S:election_start", "value": null}, {"key": "currency.balances:b0fc27299da14bc08834df9c70d73074f3e511a5a91321d4fa413f3401144918", "value": {"__fixed__": "535.30200000"}}], "status": 0, "transaction": {"metadata": {"signature": "ceb4630c8be71f2c0c1e059790609fafa6ed948b7fceb4bb44c36dca46848fac8d55fe27f539036fee5bda6d772fff852b622393eab593aa6dce67f93f7d8f08", "timestamp": 1601411941}, "payload": {"contract": "election_house", "function": "vote", "kwargs": {"policy": "rewards", "value": [4, 4, 1, 1, 90]}, "nonce": 3, "processor": "5b09493df6c18d17cc883ebce54fcb1f5afbd507533417fe32c006009a9c3c4a", "sender": "b0fc27299da14bc08834df9c70d73074f3e511a5a91321d4fa413f3401144918", "stamps_supplied": 999}}}' tx_1 = decode(tx_1_raw) txs = [encode(tx).encode() for tx in [tx_1]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something' signature = w.sign(expected_tree[0]) sbc = { 'subblock': 1, 'transactions': [tx_1], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } s = contender.SBCInbox() self.assertTrue(s.sbc_is_valid(sbc, 1))
def execute_work(self, driver, work, wallet, previous_block_hash, current_height=0, stamp_cost=20000, parallelism=4): # Assume single threaded, single process for now. subblocks = [] i = 0 for tx_batch in work: results = self.execute_tx_batch(driver=driver, batch=tx_batch, timestamp=tx_batch['timestamp'], input_hash=tx_batch['input_hash'], stamp_cost=stamp_cost, bhash=previous_block_hash, num=current_height) if len(results) > 0: merkle = merklize([encode(r).encode() for r in results]) proof = wallet.sign(merkle[0]) else: merkle = merklize([bytes.fromhex(tx_batch['input_hash'])]) proof = wallet.sign(tx_batch['input_hash']) merkle_tree = {'leaves': merkle, 'signature': proof} sbc = { 'input_hash': tx_batch['input_hash'], 'transactions': results, 'merkle_tree': merkle_tree, 'signer': wallet.verifying_key, 'subblock': i % parallelism, 'previous': previous_block_hash } sbc = format_dictionary(sbc) subblocks.append(sbc) i += 1 return subblocks
def sbc_is_valid(self, sbc, sb_idx=0): if sbc['subblock'] != sb_idx: self.log.error(f'Subblock Contender[{sb_idx}] is out order.') return False # Make sure signer is in the delegates if len(sbc['transactions']) == 0: message = sbc['input_hash'] else: message = sbc['merkle_tree']['leaves'][0] valid_sig = verify(vk=sbc['signer'], msg=message, signature=sbc['merkle_tree']['signature']) if not valid_sig: self.log.error( f'Subblock Contender[{sb_idx}] from {sbc["signer"][:8]} has an invalid signature.' ) return False if len(sbc['merkle_tree']['leaves']) > 0: txs = [encode(tx).encode() for tx in sbc['transactions']] expected_tree = merklize(txs) # Missing leaves, etc if len(sbc['merkle_tree']['leaves']) != len(expected_tree) and len( sbc['transactions']) > 0: self.log.error('Merkle Tree Len mismatch') return False for i in range(len(expected_tree)): if expected_tree[i] != sbc['merkle_tree']['leaves'][i]: self.log.error( f'Subblock Contender[{sbc["subblock"]}] from {sbc["signer"][:8]} has an Merkle tree proof.' ) self.log.error(expected_tree[i]) self.log.error(txs[i]) return False self.log.info( f'Subblock[{sbc["subblock"]}] from {sbc["signer"][:8]} is valid.') return True
def test_process_message_good_and_bad_sbc_doesnt_pass_to_q(self): ### GOOD SBC tx_1_1 = { 'something': 'who_cares' } tx_1_2 = { 'something_else': 'who_cares' } txs = [encode(tx).encode() for tx in [tx_1_1, tx_1_2]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something' signature = w.sign(expected_tree[0]) sbc_1 = { 'subblock': 0, 'transactions': [tx_1_1, tx_1_2], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } ### BAD SBC tx_2_1 = { 'something': 'who_cares2' } tx_2_2 = { 'something_else': 'who_cares2' } txs = [encode(tx).encode() for tx in [tx_2_1, tx_2_2]] expected_tree = merklize(txs) w = Wallet() input_hash = 'something2' signature = w.sign(expected_tree[0]) expected_tree[1] = 'crap' sbc_2 = { 'subblock': 1, 'transactions': [tx_2_1, tx_2_2], 'input_hash': input_hash, 'signer': w.verifying_key, 'merkle_tree': { 'signature': signature, 'leaves': expected_tree } } s = contender.SBCInbox() loop = asyncio.get_event_loop() if loop.is_closed(): loop = asyncio.new_event_loop() loop.run_until_complete(s.process_message([sbc_1, sbc_2])) self.assertEqual(s.q, [])