def test_trans_ins_outs(): ins = [TransactionInput('0', 10), TransactionInput('1', 10)] outs = [] tx = Transaction('123', '321', 15, ins, outs, 'mytrans') return tx, ins, outs
def test_transaction(node_setup, test_client): response = test_client.post('/transactions/create', data=json.dumps( dict(sender_address=node.wallet.address, recipient_address='0', amount=15)), content_type='application/json') assert response.content_type == 'application/json' assert response.status_code == 200 data = response.get_json() return Transaction.from_dict(data)
def test_transaction_dictification(test_trans_ins_outs): tx, ins, outs = test_trans_ins_outs tx_dict = tx.to_dict() assert tx_dict['transaction_inputs'] == [t.to_dict() for t in ins] assert tx_dict['transaction_outputs'] == [t.to_dict() for t in outs] tx_ressurection = Transaction.from_dict(tx_dict) assert tx_ressurection == tx assert tx_ressurection.transaction_outputs == outs assert tx_ressurection.transaction_inputs == ins
def test_transaction(nodes, network): response = req.post(nodes[0] + '/transactions/create', json=dict(sender_address=network[0]['public_key'], recipient_address=network[1]['public_key'], amount=10)) tx_dict = response.json() response = req.post(nodes[0] + '/transactions/sign', json=tx_dict) data = response.json() signature = data['signature'] response = req.post(nodes[0] + '/transactions/submit?broadcast=1', json=dict(transaction=tx_dict, signature=signature)) return Transaction.from_dict(tx_dict)
def sign_transaction(): """ Sign provided transaction document using host private key. """ data = request.get_json() try: tx = Transaction.from_dict(data) except TypeError: response = dict(message='Improper transaction json provided.') status_code = 400 return jsonify(response), status_code signature = tx.sign(node.wallet.private_key_rsa) response = dict(signature=signature) return jsonify(response), 200
def test_create_transaction(nodes, network): # Create document response = req.post( nodes[0] + '/transactions/create', json=dict( sender_address=network[0]['public_key'], recipient_address=network[1]['public_key'], amount=10 ) ) assert response.status_code == 200 tx_dict = response.json() tx = Transaction.from_dict(tx_dict) assert any(to.amount == 10 for to in tx.transaction_outputs) assert any(to.amount == 290 for to in tx.transaction_outputs) # Sign document response = req.post( nodes[0] + '/transactions/sign', json=tx_dict ) assert response.status_code == 200 data = response.json() signature = data['signature'] # Submit to blockchain response = req.post( nodes[0] + '/transactions/submit?broadcast=1', json=dict( transaction=tx_dict, signature=signature ) ) assert response.status_code == 200 # Test if it reached the others for i in range(0, 2): response = req.get(nodes[i] + '/blockchain/get_chain') assert response.status_code == 200 bc_dict = response.json() bc = Blockchain.from_dict(bc_dict) assert tx in bc.unconfirmed_transactions for to in tx.transaction_outputs: assert to in bc.utxos[to.recipient_address]
def setup_bootstrap(): data = request.get_json() node.node_id = 0 node.wallet = Wallet() init_tx = Transaction('0', node.wallet.public_key, data['initial_amount']) init_out = TransactionOutput(init_tx.transaction_id, node.wallet.public_key, data['initial_amount']) node.blkchain = Blockchain( create_genesis=True, initial_transaction=init_tx ) node.blkchain.utxos[node.wallet.public_key] = [init_out] # print(node.blkchain.utxos) node.network = [dict( id=node.node_id, ip=request.host_url[:-1], public_key=node.wallet.public_key )] response, status = dict(message='Bootstrap node setup complete.'), 200 return make_response(jsonify(response)), 200
def test_create_transaction(test_client, node_setup): response = test_client.post( '/transactions/create', json=dict( sender_address=node.wallet.address, recipient_address='0', amount=15 ) ) assert_json_200(response) data = response.get_json() tx = Transaction.from_dict(data) assert tx.amount == 15 assert tx.sender_address == node.wallet.address assert tx.recipient_address == '0' assert len(tx.transaction_inputs) == 2 assert len(tx.transaction_outputs) == 2 assert sum(ti.amount for ti in tx.transaction_inputs) == 20 assert sum(to.amount for to in tx.transaction_outputs) == 20 assert tx.transaction_outputs[0].recipient_address == '0' assert tx.transaction_outputs[1].recipient_address == node.wallet.address
def submit_transaction(): """ Parse a signed transaction document, check its validity, verify signature and add to local blockchain. Broadcast to the same endpoint for network if required. """ data = request.get_json() # Create candidate transaction object try: tx = Transaction.from_dict(data['transaction']) except (KeyError, TypeError): response = dict(message='Improper transaction json provided.') status_code = 400 return jsonify(response), status_code statuses = [] # Broadcast if needed and turn off broadcasting for other nodes if request.args.get('broadcast', type=int, default=0): for node_ in node.network: if not node_['id'] == node.node_id: response = requests.post( node_['ip'] + '/transactions/submit?broadcast=0', json=dict( transaction=data['transaction'], signature=data['signature'] ) ) statuses.append(response.status_code) if not response.status_code == 200: response = dict(message='Transaction rejected by the network.') return jsonify(response), 202 # Validate transaction as-is val_result = validate_transaction_document(tx) if isinstance(val_result, str): response = dict(message=val_result) status_code = 400 return jsonify(response), status_code # Verify signature # defined in backend/utils sign_result = verify_signature(tx, data['signature']) if isinstance(sign_result, str): response = dict(message=sign_result) status_code = 400 return jsonify(response), status_code # Add transaction to local blockchain node.blkchain.add_transaction(tx) myurl = node.network[node.node_id]['ip'] url = myurl + '/blockchain/mine_block' mine_resp = requests.get(url=url) if mine_resp.status_code == 200: block_dict = mine_resp.json() add_resp = requests.post(url=myurl + '/blockchain/add_block?\ broadcast=1', json=block_dict) # run consensus requests.get(url=myurl+'/blockchain/consensus') response = dict(message='Transaction added.') return jsonify(response), 200
def create_transaction(): """ Create a valid transaction document using any UTXOs available and return it. """ data = request.get_json() response = None status_code = None # Proposed transaction document validity checks if balance() < (data['amount']): response = dict(message='Your balance is not enough to complete transaction') status_code = 400 elif not ( any(node_['public_key'] == data['sender_address'] for node_ in node.network) and any(node_['public_key'] == data['recipient_address'] for node_ in node.network) and isinstance((data['amount']), (int, float)) ): response = dict(message='Please make sure the proposed transaction is valid.') status_code = 400 if response and status_code: return jsonify(response), status_code transaction_id = str(uuid4()) # Use as many utxos as necessary to create the new transaction inputs sender_address = data['sender_address'] sum_ = 0 tx_inputs = [] for utxo in node.blkchain.utxos[sender_address]: if sum_ >= (data['amount']): break elif not node.blkchain.transaction_unconfirmed(utxo): sum_ += utxo.amount tx_inputs.append(TransactionInput.from_output(utxo)) # Create 2 transaction outputs, one for the transfer and one for the sender's change tx_outputs = [ TransactionOutput( transaction_id=transaction_id, recipient_address=data['recipient_address'], amount=(data['amount']) ), TransactionOutput( transaction_id=transaction_id, recipient_address=data['sender_address'], amount=sum_ - (data['amount']) ) ] # Actual transaction object: tx = Transaction( sender_address=data['sender_address'], recipient_address=data['recipient_address'], amount=(data['amount']), transaction_inputs=tx_inputs, transaction_outputs=tx_outputs, transaction_id=transaction_id ) response = tx.to_dict() return jsonify(response), 200
def test_verify_signature(): w = Wallet() tx = Transaction(w.address, '0', 0) signature = tx.sign(w.private_key_rsa) assert verify_signature(tx, signature)