From 8d4677f456720cdac699ce4d92e6a938150a7b45 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Wed, 23 Nov 2016 10:01:44 +0100 Subject: [PATCH 1/4] flatten transaction - code changes --- bigchaindb/common/schema/transaction.yaml | 75 +++--- bigchaindb/common/transaction.py | 14 +- bigchaindb/core.py | 4 +- bigchaindb/db/backends/rethinkdb.py | 11 +- bigchaindb/db/utils.py | 2 +- bigchaindb/util.py | 2 +- docs/server/generate_schema_documentation.py | 11 +- tests/common/test_transaction.py | 251 +++++++++---------- tests/db/test_bigchain_api.py | 4 +- tests/web/test_transactions.py | 10 +- 10 files changed, 173 insertions(+), 211 deletions(-) diff --git a/bigchaindb/common/schema/transaction.yaml b/bigchaindb/common/schema/transaction.yaml index 03f93ac7..b64ceed4 100644 --- a/bigchaindb/common/schema/transaction.yaml +++ b/bigchaindb/common/schema/transaction.yaml @@ -5,10 +5,14 @@ type: object additionalProperties: false title: Transaction Schema description: | - This is the outer transaction wrapper. It contains the ID, version and the body of the transaction, which is also called ``transaction``. + TODO - What should go here? required: - id -- transaction +- fulfillments +- conditions +- operation +- metadata +- asset - version properties: id: @@ -18,51 +22,38 @@ properties: derived hashes and signatures from the transaction, serializing it to JSON with keys in sorted order and then hashing the resulting string with sha3. - transaction: - type: object - title: transaction + operation: + "$ref": "#/definitions/operation" + asset: + "$ref": "#/definitions/asset" description: | - See: `Transaction Body`_. - additionalProperties: false - required: - - fulfillments - - conditions - - operation - - metadata - - asset - properties: - operation: - "$ref": "#/definitions/operation" - asset: - "$ref": "#/definitions/asset" - description: | - Description of the asset being transacted. + Description of the asset being transacted. - See: `Asset`_. - fulfillments: - type: array - title: "Fulfillments list" - description: | - Array of the fulfillments (inputs) of a transaction. + See: `Asset`_. + fulfillments: + type: array + title: "Fulfillments list" + description: | + Array of the fulfillments (inputs) of a transaction. - See: Fulfillment_. - items: - "$ref": "#/definitions/fulfillment" - conditions: - type: array - description: | - Array of conditions (outputs) provided by this transaction. + See: Fulfillment_. + items: + "$ref": "#/definitions/fulfillment" + conditions: + type: array + description: | + Array of conditions (outputs) provided by this transaction. - See: Condition_. - items: - "$ref": "#/definitions/condition" - metadata: - "$ref": "#/definitions/metadata" - description: | - User provided transaction metadata. This field may be ``null`` or may - contain an object with freeform metadata. + See: Condition_. + items: + "$ref": "#/definitions/condition" + metadata: + "$ref": "#/definitions/metadata" + description: | + User provided transaction metadata. This field may be ``null`` or may + contain an id and an object with freeform metadata. - See: `Metadata`_. + See: `Metadata`_. version: type: integer minimum: 1 diff --git a/bigchaindb/common/transaction.py b/bigchaindb/common/transaction.py index 6fa1aa2b..2a9591c2 100644 --- a/bigchaindb/common/transaction.py +++ b/bigchaindb/common/transaction.py @@ -1110,7 +1110,7 @@ class Transaction(object): # NOTE: An `asset` in a `TRANSFER` only contains the asset's id asset = {'id': self.asset.data_id} - tx_body = { + tx = { 'fulfillments': [fulfillment.to_dict(fid) for fid, fulfillment in enumerate(self.fulfillments)], 'conditions': [condition.to_dict(cid) for cid, condition @@ -1118,10 +1118,7 @@ class Transaction(object): 'operation': str(self.operation), 'metadata': self.metadata, 'asset': asset, - } - tx = { 'version': self.version, - 'transaction': tx_body, } tx_no_signatures = Transaction._remove_signatures(tx) @@ -1146,7 +1143,7 @@ class Transaction(object): # NOTE: We remove the reference since we need `tx_dict` only for the # transaction's hash tx_dict = deepcopy(tx_dict) - for fulfillment in tx_dict['transaction']['fulfillments']: + for fulfillment in tx_dict['fulfillments']: # NOTE: Not all Cryptoconditions return a `signature` key (e.g. # ThresholdSha256Fulfillment), so setting it to `None` in any # case could yield incorrect signatures. This is why we only @@ -1196,7 +1193,7 @@ class Transaction(object): raise InvalidHash() @classmethod - def from_dict(cls, tx_body): + def from_dict(cls, tx): """Transforms a Python dictionary to a Transaction object. Args: @@ -1205,8 +1202,7 @@ class Transaction(object): Returns: :class:`~bigchaindb.common.transaction.Transaction` """ - cls.validate_structure(tx_body) - tx = tx_body['transaction'] + cls.validate_structure(tx) fulfillments = [Fulfillment.from_dict(fulfillment) for fulfillment in tx['fulfillments']] conditions = [Condition.from_dict(condition) for condition @@ -1217,4 +1213,4 @@ class Transaction(object): asset = AssetLink.from_dict(tx['asset']) return cls(tx['operation'], asset, fulfillments, conditions, - tx['metadata'], tx_body['version']) + tx['metadata'], tx['version']) diff --git a/bigchaindb/core.py b/bigchaindb/core.py index 6fd892e7..8fec1c89 100644 --- a/bigchaindb/core.py +++ b/bigchaindb/core.py @@ -367,7 +367,7 @@ class Bigchain(object): cursor = self.backend.get_asset_by_id(asset_id) cursor = list(cursor) if cursor: - return Asset.from_dict(cursor[0]['transaction']['asset']) + return Asset.from_dict(cursor[0]['asset']) def get_spent(self, txid, cid): """Check if a `txid` was already used as an input. @@ -436,7 +436,7 @@ class Bigchain(object): # use it after the execution of this function. # a transaction can contain multiple outputs (conditions) so we need to iterate over all of them # to get a list of outputs available to spend - for index, cond in enumerate(tx['transaction']['conditions']): + for index, cond in enumerate(tx['conditions']): # for simple signature conditions there are no subfulfillments # check if the owner is in the condition `owners_after` if len(cond['owners_after']) == 1: diff --git a/bigchaindb/db/backends/rethinkdb.py b/bigchaindb/db/backends/rethinkdb.py index 87b09dd2..9d81f595 100644 --- a/bigchaindb/db/backends/rethinkdb.py +++ b/bigchaindb/db/backends/rethinkdb.py @@ -159,7 +159,7 @@ class RethinkDBBackend: r.table('bigchain', read_mode=self.read_mode) .get_all(asset_id, index='asset_id') .concat_map(lambda block: block['block']['transactions']) - .filter(lambda transaction: transaction['transaction']['asset']['id'] == asset_id) + .filter(lambda transaction: transaction['asset']['id'] == asset_id) .get_field('id')) def get_asset_by_id(self, asset_id): @@ -176,10 +176,9 @@ class RethinkDBBackend: .get_all(asset_id, index='asset_id') .concat_map(lambda block: block['block']['transactions']) .filter(lambda transaction: - transaction['transaction']['asset']['id'] == asset_id) + transaction['asset']['id'] == asset_id) .filter(lambda transaction: - transaction['transaction']['operation'] == 'CREATE') - .pluck({'transaction': 'asset'})) + transaction['operation'] == 'CREATE')) def get_spent(self, transaction_id, condition_id): """Check if a `txid` was already used as an input. @@ -199,7 +198,7 @@ class RethinkDBBackend: return self.connection.run( r.table('bigchain', read_mode=self.read_mode) .concat_map(lambda doc: doc['block']['transactions']) - .filter(lambda transaction: transaction['transaction']['fulfillments'].contains( + .filter(lambda transaction: transaction['fulfillments'].contains( lambda fulfillment: fulfillment['input'] == {'txid': transaction_id, 'cid': condition_id}))) def get_owned_ids(self, owner): @@ -216,7 +215,7 @@ class RethinkDBBackend: return self.connection.run( r.table('bigchain', read_mode=self.read_mode) .concat_map(lambda doc: doc['block']['transactions']) - .filter(lambda tx: tx['transaction']['conditions'].contains( + .filter(lambda tx: tx['conditions'].contains( lambda c: c['owners_after'].contains(owner)))) def get_votes_by_block_id(self, block_id): diff --git a/bigchaindb/db/utils.py b/bigchaindb/db/utils.py index cbcebc85..2b3c2d0d 100644 --- a/bigchaindb/db/utils.py +++ b/bigchaindb/db/utils.py @@ -119,7 +119,7 @@ def create_bigchain_secondary_index(conn, dbname): # secondary index for asset uuid r.db(dbname).table('bigchain')\ .index_create('asset_id', - r.row['block']['transactions']['transaction']['asset']['id'], multi=True)\ + r.row['block']['transactions']['asset']['id'], multi=True)\ .run(conn) # wait for rethinkdb to finish creating secondary indexes diff --git a/bigchaindb/util.py b/bigchaindb/util.py index 27b7fc00..3b0526d7 100644 --- a/bigchaindb/util.py +++ b/bigchaindb/util.py @@ -156,4 +156,4 @@ def is_genesis_block(block): try: return block.transactions[0].operation == 'GENESIS' except AttributeError: - return block['block']['transactions'][0]['transaction']['operation'] == 'GENESIS' + return block['block']['transactions'][0]['operation'] == 'GENESIS' diff --git a/docs/server/generate_schema_documentation.py b/docs/server/generate_schema_documentation.py index 8767cabf..1d1b751b 100644 --- a/docs/server/generate_schema_documentation.py +++ b/docs/server/generate_schema_documentation.py @@ -27,8 +27,6 @@ Transaction Schema * `Transaction`_ -* `Transaction Body`_ - * Condition_ * Fulfillment_ @@ -58,11 +56,6 @@ Transaction Schema Transaction ----------- -%(wrapper)s - -Transaction Body ----------------- - %(transaction)s Condition @@ -158,9 +151,7 @@ def main(): """ Main function """ defs = TX_SCHEMA['definitions'] doc = TPL_DOC % { - 'wrapper': render_section('Transaction', TX_SCHEMA), - 'transaction': render_section('Transaction', - TX_SCHEMA['properties']['transaction']), + 'transaction': render_section('Transaction', TX_SCHEMA), 'condition': render_section('Condition', defs['condition']), 'fulfillment': render_section('Fulfillment', defs['fulfillment']), 'asset': render_section('Asset', defs['asset']), diff --git a/tests/common/test_transaction.py b/tests/common/test_transaction.py index 335fd0a2..b55b4cb7 100644 --- a/tests/common/test_transaction.py +++ b/tests/common/test_transaction.py @@ -301,20 +301,18 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id): expected = { 'id': tx_id, 'version': Transaction.VERSION, - 'transaction': { - # NOTE: This test assumes that Fulfillments and Conditions can - # successfully be serialized - 'fulfillments': [user_ffill.to_dict(0)], - 'conditions': [user_cond.to_dict(0)], - 'operation': Transaction.CREATE, - 'metadata': None, - 'asset': { - 'id': data_id, - 'divisible': False, - 'updatable': False, - 'refillable': False, - 'data': data, - } + # NOTE: This test assumes that Fulfillments and Conditions can + # successfully be serialized + 'fulfillments': [user_ffill.to_dict(0)], + 'conditions': [user_cond.to_dict(0)], + 'operation': Transaction.CREATE, + 'metadata': None, + 'asset': { + 'id': data_id, + 'divisible': False, + 'updatable': False, + 'refillable': False, + 'data': data, } } @@ -322,7 +320,7 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id): [user_cond]) tx_dict = tx.to_dict() tx_dict['id'] = tx_id - tx_dict['transaction']['asset']['id'] = data_id + tx_dict['asset']['id'] = data_id assert tx_dict == expected @@ -342,20 +340,18 @@ def test_transaction_deserialization(user_ffill, user_cond, data, uuid4): tx = { 'version': Transaction.VERSION, - 'transaction': { - # NOTE: This test assumes that Fulfillments and Conditions can - # successfully be serialized - 'fulfillments': [user_ffill.to_dict()], - 'conditions': [user_cond.to_dict()], - 'operation': Transaction.CREATE, - 'metadata': None, - 'asset': { - 'id': uuid4, - 'divisible': False, - 'updatable': False, - 'refillable': False, - 'data': data, - } + # NOTE: This test assumes that Fulfillments and Conditions can + # successfully be serialized + 'fulfillments': [user_ffill.to_dict()], + 'conditions': [user_cond.to_dict()], + 'operation': Transaction.CREATE, + 'metadata': None, + 'asset': { + 'id': uuid4, + 'divisible': False, + 'updatable': False, + 'refillable': False, + 'data': data, } } tx_no_signatures = Transaction._remove_signatures(tx) @@ -732,35 +728,33 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4): from .util import validate_transaction_model expected = { - 'transaction': { - 'conditions': [user_cond.to_dict(0)], - 'metadata': data, - 'asset': { - 'id': uuid4, - 'divisible': False, - 'updatable': False, - 'refillable': False, - 'data': data, - }, - 'fulfillments': [ - { - 'owners_before': [ - user_pub - ], - 'fid': 0, - 'fulfillment': None, - 'input': None - } - ], - 'operation': 'CREATE', + 'conditions': [user_cond.to_dict(0)], + 'metadata': data, + 'asset': { + 'id': uuid4, + 'divisible': False, + 'updatable': False, + 'refillable': False, + 'data': data, }, + 'fulfillments': [ + { + 'owners_before': [ + user_pub + ], + 'fid': 0, + 'fulfillment': None, + 'input': None + } + ], + 'operation': 'CREATE', 'version': 1, } asset = Asset(data, uuid4) tx = Transaction.create([user_pub], [([user_pub], 1)], data, asset) tx_dict = tx.to_dict() - tx_dict['transaction']['fulfillments'][0]['fulfillment'] = None + tx_dict['fulfillments'][0]['fulfillment'] = None tx_dict.pop('id') assert tx_dict == expected @@ -786,14 +780,12 @@ def test_create_create_transaction_multiple_io(user_cond, user2_cond, user_pub, ffill = Fulfillment.generate([user_pub, user2_pub]).to_dict() ffill.update({'fid': 0}) expected = { - 'transaction': { - 'conditions': [user_cond.to_dict(0), user2_cond.to_dict(1)], - 'metadata': { - 'message': 'hello' - }, - 'fulfillments': [ffill], - 'operation': 'CREATE', + 'conditions': [user_cond.to_dict(0), user2_cond.to_dict(1)], + 'metadata': { + 'message': 'hello' }, + 'fulfillments': [ffill], + 'operation': 'CREATE', 'version': 1 } asset = Asset(divisible=True) @@ -802,7 +794,7 @@ def test_create_create_transaction_multiple_io(user_cond, user2_cond, user_pub, asset=asset, metadata={'message': 'hello'}).to_dict() tx.pop('id') - tx['transaction'].pop('asset') + tx.pop('asset') assert tx == expected @@ -829,28 +821,26 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, from bigchaindb.common.transaction import Transaction, Asset expected = { - 'transaction': { - 'conditions': [user_user2_threshold_cond.to_dict(0)], - 'metadata': data, - 'asset': { - 'id': uuid4, - 'divisible': False, - 'updatable': False, - 'refillable': False, - 'data': data, - }, - 'fulfillments': [ - { - 'owners_before': [ - user_pub, - ], - 'fid': 0, - 'fulfillment': None, - 'input': None - }, - ], - 'operation': 'CREATE', + 'conditions': [user_user2_threshold_cond.to_dict(0)], + 'metadata': data, + 'asset': { + 'id': uuid4, + 'divisible': False, + 'updatable': False, + 'refillable': False, + 'data': data, }, + 'fulfillments': [ + { + 'owners_before': [ + user_pub, + ], + 'fid': 0, + 'fulfillment': None, + 'input': None + }, + ], + 'operation': 'CREATE', 'version': 1 } asset = Asset(data, uuid4) @@ -858,7 +848,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub, data, asset) tx_dict = tx.to_dict() tx_dict.pop('id') - tx_dict['transaction']['fulfillments'][0]['fulfillment'] = None + tx_dict['fulfillments'][0]['fulfillment'] = None assert tx_dict == expected @@ -912,27 +902,25 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, from .util import validate_transaction_model expected = { - 'transaction': { - 'conditions': [user2_cond.to_dict(0)], - 'metadata': None, - 'asset': { - 'id': uuid4, - }, - 'fulfillments': [ - { - 'owners_before': [ - user_pub - ], - 'fid': 0, - 'fulfillment': None, - 'input': { - 'txid': tx.id, - 'cid': 0 - } - } - ], - 'operation': 'TRANSFER', + 'conditions': [user2_cond.to_dict(0)], + 'metadata': None, + 'asset': { + 'id': uuid4, }, + 'fulfillments': [ + { + 'owners_before': [ + user_pub + ], + 'fid': 0, + 'fulfillment': None, + 'input': { + 'txid': tx.id, + 'cid': 0 + } + } + ], + 'operation': 'TRANSFER', 'version': 1 } inputs = tx.to_inputs([0]) @@ -940,14 +928,13 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub, transfer_tx = Transaction.transfer(inputs, [([user2_pub], 1)], asset=asset) transfer_tx = transfer_tx.sign([user_priv]) transfer_tx = transfer_tx.to_dict() - transfer_tx_body = transfer_tx['transaction'] expected_input = deepcopy(inputs[0]) expected['id'] = transfer_tx['id'] expected_input.fulfillment.sign(serialize(expected).encode(), PrivateKey(user_priv)) expected_ffill = expected_input.fulfillment.serialize_uri() - transfer_ffill = transfer_tx_body['fulfillments'][0]['fulfillment'] + transfer_ffill = transfer_tx['fulfillments'][0]['fulfillment'] assert transfer_ffill == expected_ffill @@ -968,34 +955,32 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, tx = tx.sign([user_priv]) expected = { - 'transaction': { - 'conditions': [user2_cond.to_dict(0), user2_cond.to_dict(1)], - 'metadata': None, - 'fulfillments': [ - { - 'owners_before': [ - user_pub - ], - 'fid': 0, - 'fulfillment': None, - 'input': { - 'txid': tx.id, - 'cid': 0 - } - }, { - 'owners_before': [ - user2_pub - ], - 'fid': 1, - 'fulfillment': None, - 'input': { - 'txid': tx.id, - 'cid': 1 - } + 'conditions': [user2_cond.to_dict(0), user2_cond.to_dict(1)], + 'metadata': None, + 'fulfillments': [ + { + 'owners_before': [ + user_pub + ], + 'fid': 0, + 'fulfillment': None, + 'input': { + 'txid': tx.id, + 'cid': 0 } - ], - 'operation': 'TRANSFER', - }, + }, { + 'owners_before': [ + user2_pub + ], + 'fid': 1, + 'fulfillment': None, + 'input': { + 'txid': tx.id, + 'cid': 1 + } + } + ], + 'operation': 'TRANSFER', 'version': 1 } @@ -1010,10 +995,10 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv, assert transfer_tx.fulfillments_valid(tx.conditions) is True transfer_tx = transfer_tx.to_dict() - transfer_tx['transaction']['fulfillments'][0]['fulfillment'] = None - transfer_tx['transaction']['fulfillments'][1]['fulfillment'] = None + transfer_tx['fulfillments'][0]['fulfillment'] = None + transfer_tx['fulfillments'][1]['fulfillment'] = None + transfer_tx.pop('asset') transfer_tx.pop('id') - transfer_tx['transaction'].pop('asset') assert expected == transfer_tx diff --git a/tests/db/test_bigchain_api.py b/tests/db/test_bigchain_api.py index cd030249..afe2bbd6 100644 --- a/tests/db/test_bigchain_api.py +++ b/tests/db/test_bigchain_api.py @@ -273,8 +273,8 @@ class TestBigchainApi(object): block = b.backend.get_genesis_block() assert len(block['block']['transactions']) == 1 - assert block['block']['transactions'][0]['transaction']['operation'] == 'GENESIS' - assert block['block']['transactions'][0]['transaction']['fulfillments'][0]['input'] is None + assert block['block']['transactions'][0]['operation'] == 'GENESIS' + assert block['block']['transactions'][0]['fulfillments'][0]['input'] is None def test_create_genesis_block_fails_if_table_not_empty(self, b): from bigchaindb.common.exceptions import GenesisBlockAlreadyExistsError diff --git a/tests/web/test_transactions.py b/tests/web/test_transactions.py index dd034c10..94c3f22f 100644 --- a/tests/web/test_transactions.py +++ b/tests/web/test_transactions.py @@ -33,8 +33,8 @@ def test_post_create_transaction_endpoint(b, client): tx = tx.sign([user_priv]) res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict())) - assert res.json['transaction']['fulfillments'][0]['owners_before'][0] == user_pub - assert res.json['transaction']['conditions'][0]['owners_after'][0] == user_pub + assert res.json['fulfillments'][0]['owners_before'][0] == user_pub + assert res.json['conditions'][0]['owners_after'][0] == user_pub def test_post_create_transaction_with_invalid_id(b, client): @@ -55,7 +55,7 @@ def test_post_create_transaction_with_invalid_signature(b, client): tx = Transaction.create([user_pub], [([user_pub], 1)]) tx = tx.sign([user_priv]).to_dict() - tx['transaction']['fulfillments'][0]['fulfillment'] = 'cf:0:0' + tx['fulfillments'][0]['fulfillment'] = 'cf:0:0' res = client.post(TX_ENDPOINT, data=json.dumps(tx)) assert res.status_code == 400 @@ -81,8 +81,8 @@ def test_post_transfer_transaction_endpoint(b, client, user_pk, user_sk): res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx.to_dict())) - assert res.json['transaction']['fulfillments'][0]['owners_before'][0] == user_pk - assert res.json['transaction']['conditions'][0]['owners_after'][0] == user_pub + assert res.json['fulfillments'][0]['owners_before'][0] == user_pk + assert res.json['conditions'][0]['owners_after'][0] == user_pub @pytest.mark.usefixtures('inputs') From 21af588f7c09309645ddb60c50b73b049f95af8a Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 24 Nov 2016 17:20:01 +0100 Subject: [PATCH 2/4] docs update for flat transaction --- .../source/data-models/transaction-model.rst | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/docs/server/source/data-models/transaction-model.rst b/docs/server/source/data-models/transaction-model.rst index 2bee661f..0d3cd136 100644 --- a/docs/server/source/data-models/transaction-model.rst +++ b/docs/server/source/data-models/transaction-model.rst @@ -22,38 +22,35 @@ A transaction has the following structure: { "id": "", "version": "", - "transaction": { - "fulfillments": [""], - "conditions": [""], - "operation": "", - "asset": "", - "metadata": { - "id": "", - "data": "" - } + "fulfillments": [""], + "conditions": [""], + "operation": "", + "asset": "", + "metadata": { + "id": "", + "data": "" } } Here's some explanation of the contents of a :ref:`transaction `: -- :ref:`id `: The id of the transaction, and also the database primary key. -- :ref:`version `: Version number of the transaction model, so that software can support different transaction models. -- :ref:`transaction `: - - **fulfillments**: List of fulfillments. Each :ref:`fulfillment ` contains a pointer to an unspent asset - and a *crypto fulfillment* that satisfies a spending condition set on the unspent asset. A *fulfillment* - is usually a signature proving the ownership of the asset. - See :doc:`./crypto-conditions`. +- id: The :ref:`id ` of the transaction, and also the database primary key. +- version: :ref:`Version ` number of the transaction model, so that software can support different transaction models. +- **fulfillments**: List of fulfillments. Each :ref:`fulfillment ` contains a pointer to an unspent asset + and a *crypto fulfillment* that satisfies a spending condition set on the unspent asset. A *fulfillment* + is usually a signature proving the ownership of the asset. + See :doc:`./crypto-conditions`. - - **conditions**: List of conditions. Each :ref:`condition ` is a *crypto-condition* that needs to be fulfilled by a transfer transaction in order to transfer ownership to new owners. - See :doc:`./crypto-conditions`. +- **conditions**: List of conditions. Each :ref:`condition ` is a *crypto-condition* that needs to be fulfilled by a transfer transaction in order to transfer ownership to new owners. + See :doc:`./crypto-conditions`. - - **operation**: String representation of the :ref:`operation ` being performed (currently either "CREATE", "TRANSFER" or "GENESIS"). It determines how the transaction should be validated. +- **operation**: String representation of the :ref:`operation ` being performed (currently either "CREATE", "TRANSFER" or "GENESIS"). It determines how the transaction should be validated. - - **asset**: Definition of the digital :ref:`asset `. See next section. +- **asset**: Definition of the digital :ref:`asset `. See next section. - - **metadata**: - - :ref:`id `: UUID version 4 (random) converted to a string of hex digits in standard form. - - :ref:`data `: Can be any JSON document. It may be empty in the case of a transfer transaction. +- **metadata**: + - :ref:`id `: UUID version 4 (random) converted to a string of hex digits in standard form. + - :ref:`data `: Can be any JSON document. It may be empty in the case of a transfer transaction. Later, when we get to the models for the block and the vote, we'll see that both include a signature (from the node which created it). You may wonder why transactions don't have signatures... The answer is that they do! They're just hidden inside the ``fulfillment`` string of each fulfillment. A creation transaction is signed by whoever created it. A transfer transaction is signed by whoever currently controls or owns it. From e699536a643c1da7871029584f5869db00bfc3a8 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 24 Nov 2016 17:47:22 +0100 Subject: [PATCH 3/4] Fix transaction description in transaction.yaml --- bigchaindb/common/schema/transaction.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigchaindb/common/schema/transaction.yaml b/bigchaindb/common/schema/transaction.yaml index b64ceed4..03dbe8ad 100644 --- a/bigchaindb/common/schema/transaction.yaml +++ b/bigchaindb/common/schema/transaction.yaml @@ -5,7 +5,7 @@ type: object additionalProperties: false title: Transaction Schema description: | - TODO - What should go here? + A transaction represents the creation or transfer of assets in BigchainDB. required: - id - fulfillments From 8f513fc81d3ca31851c093e53c5714964cbc8b52 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 1 Dec 2016 14:49:05 +0100 Subject: [PATCH 4/4] put back a pluck() that was removed by accident --- bigchaindb/db/backends/rethinkdb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bigchaindb/db/backends/rethinkdb.py b/bigchaindb/db/backends/rethinkdb.py index 9d81f595..39d2aff9 100644 --- a/bigchaindb/db/backends/rethinkdb.py +++ b/bigchaindb/db/backends/rethinkdb.py @@ -178,7 +178,8 @@ class RethinkDBBackend: .filter(lambda transaction: transaction['asset']['id'] == asset_id) .filter(lambda transaction: - transaction['operation'] == 'CREATE')) + transaction['operation'] == 'CREATE') + .pluck('asset')) def get_spent(self, transaction_id, condition_id): """Check if a `txid` was already used as an input.