async def handle_msg(self, _id, msg): # Try to deserialize the message and run it through the rpc service try: json_command = decode(msg.decode()) self.log.info('Received command: {}'.format(json_command)) result = self.interface.process_json_rpc_command(json_command) # If this fails, just set the result to None except Exception as e: self.log.info('EXCEPTION!! -> ', str(e)) result = None # Try to send the message now. This persists if the socket fails. sent = False while not sent: try: msg = encode(result).encode() self.log.info('result sent: {}, {}'.format(msg, result)) await self.socket.send_multipart([_id, msg]) sent = True except zmq.error.ZMQError: self.log.info('zmq error: {}'.format(zmq.error.ZMQError)) self.socket.close() self.setup_socket()
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 test_sign_works_properly(self): w = Wallet() tx = build_transaction( wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' } ) decoded = decode(tx) res = verify( w.verifying_key, encode(decoded['payload']), decoded['metadata']['signature'] ) self.assertTrue(res)
def test_serialize_works_properly(self): w = Wallet() expected = { 'sender': w.verifying_key, 'processor': 'b' * 64, 'stamps_supplied': 123, 'nonce': 0, 'contract': 'currency', 'function': 'transfer', 'kwargs': { 'amount': 123, 'to': 'jeff' } } tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) self.assertDictEqual(decoded['payload'], expected)
def get(self, item: str): v = self.db.find_one({'_id': item}) if v is None: return None return decode(v['v'])
def test_transaction_is_valid_complete_test_passes(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) client = ContractingClient() client.flush() client.set_var(contract='currency', variable='balances', arguments=[w.verifying_key], value=1_000_000) client.set_var(contract='stamp_cost', variable='S', arguments=['value'], value=20_000) transaction.transaction_is_valid(transaction=decoded, expected_processor='b' * 64, client=client, nonces=self.driver)
def get_transaction_by_hash(self, h: str): self.cursor.execute('select * from transaction_inputs where hash=?', (h,)) tx_input = self.cursor.fetchone() self.cursor.execute('select * from transaction_outputs where hash=?', (h,)) tx_output = self.cursor.fetchone() tx_hash, _, idx, sender, sig, contract, func, args = tx_input args_unpacked = json.loads(args) _, _, _, status, updates, result = tx_output updates_unpacked = json.loads(updates) # Build the dict tx = { 'hash': tx_hash, 'input': { 'index': idx, 'sender': sender, 'signature': sig, 'payload': { 'contract': contract, 'function': func, 'arguments': args_unpacked } }, 'output': { 'status': status, 'updates': updates_unpacked, 'result': decode(result) } } return tx
def build_transaction(wallet, contract: str, function: str, kwargs: dict, nonce: int, processor: str, stamps: int): payload = { 'contract': contract, 'function': function, 'kwargs': kwargs, 'nonce': nonce, 'processor': processor, 'sender': wallet.verifying_key, 'stamps_supplied': stamps, } payload = format_dictionary( payload) # Sort payload in case kwargs unsorted assert check_format( payload, rules.TRANSACTION_PAYLOAD_RULES), 'Invalid payload provided!' true_payload = encode(decode(encode(payload))) signature = wallet.sign(true_payload) metadata = {'signature': signature, 'timestamp': int(time.time())} tx = {'payload': payload, 'metadata': metadata} return encode(format_dictionary(tx))
async def submit_transaction(self, request): log.debug(f'New request: {request}') # Reject TX if the queue is too large if len(self.queue) >= self.max_queue_len: return response.json({'error': "Queue full. Resubmit shortly."}, status=503, headers={'Access-Control-Allow-Origin': '*'}) tx_raw = _json.loads(request.body) log.error(tx_raw) # Check that the payload is valid JSON tx = decode(request.body) if tx is None: return response.json({'error': 'Malformed request body.'}, headers={'Access-Control-Allow-Origin': '*'}) # Check that the TX is correctly formatted try: transaction.check_tx_formatting(tx, self.wallet.verifying_key) transaction.transaction_is_valid( transaction=tx, expected_processor=self.wallet.verifying_key, client=self.client, nonces=self.nonces) nonce, pending_nonce = transaction.get_nonces( sender=tx['payload']['sender'], processor=tx['payload']['processor'], driver=self.nonces) pending_nonce = transaction.get_new_pending_nonce( tx_nonce=tx['payload']['nonce'], nonce=nonce, pending_nonce=pending_nonce) self.nonces.set_pending_nonce(sender=tx['payload']['sender'], processor=tx['payload']['processor'], value=pending_nonce) except TransactionException as e: log.error(f'Tx has error: {type(e)}') log.error(tx) return response.json(transaction.EXCEPTION_MAP[type(e)], headers={'Access-Control-Allow-Origin': '*'}) # Add TX to the processing queue self.queue.append(request.body) log.error('Added to q') # Return the TX hash to the user so they can track it tx_hash = tx_hash_from_tx(tx) return response.json( { 'success': 'Transaction successfully submitted to the network.', 'hash': tx_hash }, headers={'Access-Control-Allow-Origin': '*'})
def get(self, item: str): with self.db_reader.begin() as tx: v = tx.get(item.encode()) if v is None: return None return decode(v)
def pop(self, idx): items = sorted(self.root.iterdir(), key=os.path.getmtime) item = items.pop(idx) with open(item) as f: i = decode(f.read()) os.remove(item) return i
def get(self, item: str): try: filename = self._key_to_file(item) with open(filename, 'r') as f: v = f.read() except FileNotFoundError: return None return decode(v)
def get(self, item: str): # supports item strings like contract.variable:key1:key2 contract, args = item.split('.') args = args.split(':') variable = args.pop(0) keys = ','.join(args) r = requests.get(f'{self.masternode}/contracts/{contract}/{variable}?key={keys}') return decode(r.json()['value'])
async def request(msg): msg = encode(msg).encode() socket = self.ctx.socket(zmq.DEALER) socket.connect('ipc:///tmp/router') await socket.send(msg) resp = await socket.recv() resp = decode(resp) return resp
def test_transaction_is_not_expired_true_if_within_timeout(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) transaction.transaction_is_not_expired(decoded)
def test_future_transactions_fine_if_in_expiry(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) decoded['metadata']['timestamp'] += 4 transaction.transaction_is_not_expired(decoded)
def test_check_tx_formatting_incorrect_processor_fails(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123.0, 'to': 'jeff' }) decoded = decode(tx) with self.assertRaises(transaction.TransactionProcessorInvalid): transaction.check_tx_formatting(decoded, 'c' * 64)
async def secure_request(msg: dict, service: str, wallet: Wallet, vk: str, ip: str, ctx: zmq.asyncio.Context, linger=500, timeout=1000, cert_dir=DEFAULT_DIR): #if wallet.verifying_key == vk: # return socket = ctx.socket(zmq.DEALER) socket.setsockopt(zmq.LINGER, linger) socket.setsockopt(zmq.TCP_KEEPALIVE, 1) socket.curve_secretkey = wallet.curve_sk socket.curve_publickey = wallet.curve_vk filename = str(cert_dir / f'{vk}.key') if not os.path.exists(filename): return None server_pub, _ = load_certificate(filename) socket.curve_serverkey = server_pub try: socket.connect(ip) except ZMQBaseError: logger.debug(f'Could not connect to {ip}') socket.close() return None message = build_message(service=service, message=msg) payload = encode(message).encode() await socket.send(payload) event = await socket.poll(timeout=timeout, flags=zmq.POLLIN) msg = None if event: #logger.debug(f'Message received on {ip}') response = await socket.recv() msg = decode(response) socket.close() return msg
def _build_block(block, tx_inputs, tx_outputs): block_dict = { 'hash': block[0], 'index': block[1], 'transactions': [] } # Iterate through all transactions fetched for i in range(len(tx_inputs)): # Unpack the arguments in a concise way tx_hash, _, idx, sender, sig, contract, func, args = tx_inputs[i] args_unpacked = json.loads(args) _, _, _, status, updates, result = tx_outputs[i] updates_unpacked = json.loads(updates) # Build the dict tx = { 'hash': tx_hash, 'input': { 'index': idx, 'sender': sender, 'signature': sig, 'payload': { 'contract': contract, 'function': func, 'arguments': args_unpacked } }, 'output': { 'status': status, 'updates': updates_unpacked, 'result': decode(result) } } # Add the dict to the transactions list block_dict['transactions'].append(tx) # Sort transactions by index sorted(block_dict['transactions'], key=lambda t: t['input']['index']) return block_dict
def test_check_tx_formatting_signature_fails(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) decoded['payload']['sender'] = 'a' * 64 with self.assertRaises(transaction.TransactionSignatureInvalid): transaction.check_tx_formatting(decoded, 'b' * 64)
def test_transaction_is_expired_false_if_outside_timeout(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) decoded['metadata']['timestamp'] -= 1000 with self.assertRaises(transaction.TransactionStaleError): transaction.transaction_is_not_expired(decoded)
def test_future_transactions_raise_error_if_beyond_expiry(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) decoded['metadata']['timestamp'] += 6 with self.assertRaises(transaction.TransactionInvalidTimestampError): transaction.transaction_is_not_expired(decoded)
def test_check_tx_formatting_succeeds(self): w = Wallet() tx = build_transaction( wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': decimal.Decimal('123.872345873452873459873459870'), 'to': 'jeff' }) decoded = decode(tx) error = transaction.check_tx_formatting(decoded, 'b' * 64) self.assertIsNone(error)
def test_check_tx_formatting_not_formatted_fails(self): w = Wallet() tx = build_transaction(wallet=w, processor='b' * 64, stamps=123, nonce=0, contract='currency', function='transfer', kwargs={ 'amount': 123, 'to': 'jeff' }) decoded = decode(tx) decoded['payload']['nonce'] = -123 with self.assertRaises(transaction.TransactionFormattingError): transaction.check_tx_formatting(decoded, 'b' * 64)
def execute_tx(executor: Executor, transaction, stamp_cost, environment: dict = {}, debug=True): # Deserialize Kwargs. Kwargs should be serialized JSON moving into the future for DX. kwargs = decode(transaction.payload.kwargs) output = executor.execute(sender=transaction.payload.sender.hex(), contract_name=transaction.payload.contractName, function_name=transaction.payload.functionName, stamps=transaction.payload.stampsSupplied, stamp_cost=stamp_cost, kwargs=kwargs, environment=environment, auto_commit=False) if debug: log.error(output) deltas = [] for k, v in output['writes'].items(): key, value = encode_kv(k, v) d = transaction_capnp.Delta.new_message(key=key, value=value) deltas.append(d) tx_hash = tx_hash_from_tx(transaction) # Encode deltas into a Capnp struct tx_output = transaction_capnp.TransactionData.new_message( hash=tx_hash, transaction=transaction, status=output['status_code'], state=deltas, stampsUsed=output['stamps_used']) executor.driver.pending_writes.clear() # add return tx_output
def test_bigint_decode(self): _bi = '{"__big_int__":' + str(MONGO_MAX_INT + 1) + '}' self.assertEqual(decode(_bi), MONGO_MAX_INT + 1)
def test_int_decode(self): i = '10' self.assertEqual(10, decode(i))
def test_timedelta_decode(self): _t = '{"__delta__": [8, 0]}' t = decode(_t) self.assertEqual(t, Timedelta(weeks=1, days=1))
def test_date_decode(self): _d = '{"__time__": [2019, 1, 1, 0, 0, 0, 0]}' d = decode(_d) self.assertEqual(Datetime(2019, 1, 1), d)
def test_decode_failure(self): b = b'xwow' self.assertIsNone(decode(b))