Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 4
0
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)
Esempio n. 5
0
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]
Esempio n. 7
0
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
Esempio n. 9
0
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
Esempio n. 10
0
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)