From aeede798460d3a892e38d39f3e4f5d9161927d17 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 24 Feb 2016 02:38:30 +0100 Subject: [PATCH] Add asset create and transfer --- bigchaindb/core.py | 4 ++-- bigchaindb/util.py | 17 ++++++++++++++++- bigchaindb/web/views.py | 23 +++++++++++++++++++++-- tests/conftest.py | 7 +++++++ tests/db/conftest.py | 4 ---- tests/db/test_utils.py | 1 + tests/test_util.py | 12 ++++++++++++ tests/web/test_basic_views.py | 34 +++++++++++++++++++++++++++++++++- 8 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 tests/test_util.py diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 030d831c..61c2ad2f 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -96,7 +96,7 @@ class Bigchain(object): public_key = crypto.PublicKey(public_key_base58) return public_key.verify(util.serialize(data), signature) - def write_transaction(self, signed_transaction): + def write_transaction(self, signed_transaction, durability='soft'): """Write the transaction to bigchain. When first writing a transaction to the bigchain the transaction will be kept in a backlog until @@ -122,7 +122,7 @@ class Bigchain(object): signed_transaction.update({'assignee': assignee}) # write to the backlog - response = r.table('backlog').insert(signed_transaction, durability='soft').run(self.conn) + response = r.table('backlog').insert(signed_transaction, durability=durability).run(self.conn) return response # TODO: the same `txid` can be in two different blocks diff --git a/bigchaindb/util.py b/bigchaindb/util.py index e501ed96..b8c32b74 100644 --- a/bigchaindb/util.py +++ b/bigchaindb/util.py @@ -5,6 +5,7 @@ import time import multiprocessing as mp from datetime import datetime +import bigchaindb from bigchaindb import exceptions from bigchaindb.crypto import PrivateKey, PublicKey @@ -154,7 +155,7 @@ def sign_tx(transaction, private_key): def create_and_sign_tx(private_key, current_owner, new_owner, tx_input, operation='TRANSFER', payload=None): tx = create_tx(current_owner, new_owner, tx_input, operation, payload) - return sign_tx(private_key, tx) + return sign_tx(tx, private_key) def hash_data(data): @@ -195,3 +196,17 @@ def verify_signature(signed_transaction): public_key = PublicKey(public_key_base58) return public_key.verify(serialize(data), signature) + +def transform_create(tx): + """Change the owner and signature for a ``CREATE`` transaction created by a node""" + + # XXX: the next instruction opens a new connection to the DB, consider using a singleton or a global + # if you need a Bigchain instance. + b = bigchaindb.Bigchain() + transaction = tx['transaction'] + payload = None + if transaction['data'] and 'payload' in transaction['data']: + payload = transaction['data']['payload'] + new_tx = create_tx(b.me, transaction['current_owner'], None, 'CREATE', payload=payload) + return new_tx + diff --git a/bigchaindb/web/views.py b/bigchaindb/web/views.py index b106658d..9d5afbe7 100644 --- a/bigchaindb/web/views.py +++ b/bigchaindb/web/views.py @@ -1,13 +1,32 @@ import flask -from flask import Blueprint +from flask import request, Blueprint +from bigchaindb import util from bigchaindb import Bigchain basic_views = Blueprint('basic_views', __name__) b = Bigchain() + @basic_views.route('/tx/') -def show(tx_id): +def get_transaction(tx_id): tx = b.get_transaction(tx_id) return flask.jsonify(**tx) + +@basic_views.route('/tx/', methods=['POST']) +def create_transaction(): + val = {} + tx = request.get_json(force=True) + + if tx['operation'] == 'CREATE': + tx = util.transform_create(tx) + tx = util.sign_tx(tx, b.me_private) + + if not util.verify_signature(tx): + val['error'] = 'Invalid transaction signature' + + val = b.write_transaction(tx) + + return flask.jsonify(**tx) + diff --git a/tests/conftest.py b/tests/conftest.py index 2191f73b..96be00f6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -47,3 +47,10 @@ def user_private_key(): @pytest.fixture def user_public_key(): return USER_PUBLIC_KEY + + +@pytest.fixture +def b(): + from bigchaindb import Bigchain + return Bigchain() + diff --git a/tests/db/conftest.py b/tests/db/conftest.py index ae4abfd7..d79ee846 100644 --- a/tests/db/conftest.py +++ b/tests/db/conftest.py @@ -80,10 +80,6 @@ def cleanup_tables(request, node_config): request.addfinalizer(fin) -@pytest.fixture -def b(): - return Bigchain() - @pytest.fixture def inputs(user_public_key, amount=1, b=None): # 1. create the genesis block diff --git a/tests/db/test_utils.py b/tests/db/test_utils.py index 287fdfcf..9e032b25 100644 --- a/tests/db/test_utils.py +++ b/tests/db/test_utils.py @@ -4,6 +4,7 @@ import pytest import rethinkdb as r import bigchaindb +from bigchaindb import util from bigchaindb.db import utils from .conftest import setup_database as _setup_database diff --git a/tests/test_util.py b/tests/test_util.py new file mode 100644 index 00000000..f4708b59 --- /dev/null +++ b/tests/test_util.py @@ -0,0 +1,12 @@ +from bigchaindb import util + + +def test_transform_create(b, user_private_key, user_public_key): + tx = util.create_tx(user_public_key, user_public_key, None, 'CREATE') + tx = util.transform_create(tx) + tx = util.sign_tx(tx, b.me_private) + + assert tx['transaction']['current_owner'] == b.me + assert tx['transaction']['new_owner'] == user_public_key + assert util.verify_signature(tx) + diff --git a/tests/web/test_basic_views.py b/tests/web/test_basic_views.py index bb629cca..eaa72e85 100644 --- a/tests/web/test_basic_views.py +++ b/tests/web/test_basic_views.py @@ -1,10 +1,42 @@ +import json + import pytest +from bigchaindb import crypto +from bigchaindb import util @pytest.mark.usefixtures('inputs') -def test_tx_endpoint(b, client, user_public_key): +def test_get_transaction_endpoint(b, client, user_public_key): input_tx = b.get_owned_ids(user_public_key).pop() tx = b.get_transaction(input_tx) res = client.get('/tx/{}'.format(input_tx)) assert tx == res.json + + +def test_post_create_transaction_endpoint(b, client): + keypair = crypto.generate_key_pair() + + tx = util.create_and_sign_tx(keypair[0], keypair[1], keypair[1], None, 'CREATE') + + res = client.post('/tx/', data=json.dumps(tx)) + from pprint import pprint as pp + pp(res.body) + assert res.json['transaction']['current_owner'] == b.me + assert res.json['transaction']['new_owner'] == keypair[1] + + +def test_post_transfer_transaction_endpoint(b, client): + from_keypair = crypto.generate_key_pair() + to_keypair = crypto.generate_key_pair() + + tx = util.create_and_sign_tx(from_keypair[0], from_keypair[1], from_keypair[1], None, 'CREATE') + res = client.post('/tx/', data=json.dumps(tx)) + tx_id = res.json['id'] + + transfer = util.create_and_sign_tx(from_keypair[0], from_keypair[1], to_keypair[1], tx_id) + res = client.post('/tx/', data=json.dumps(transfer)) + + assert res.json['transaction']['current_owner'] == from_keypair[1] + assert res.json['transaction']['new_owner'] == to_keypair[1] +