mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Merge pull request #855 from bigchaindb/flat-transaction
Flat transaction
This commit is contained in:
commit
97ff0efd8b
@ -5,10 +5,14 @@ type: object
|
|||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
title: Transaction Schema
|
title: Transaction Schema
|
||||||
description: |
|
description: |
|
||||||
This is the outer transaction wrapper. It contains the ID, version and the body of the transaction, which is also called ``transaction``.
|
A transaction represents the creation or transfer of assets in BigchainDB.
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- transaction
|
- fulfillments
|
||||||
|
- conditions
|
||||||
|
- operation
|
||||||
|
- metadata
|
||||||
|
- asset
|
||||||
- version
|
- version
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@ -18,19 +22,6 @@ properties:
|
|||||||
derived hashes and signatures from the transaction, serializing it to
|
derived hashes and signatures from the transaction, serializing it to
|
||||||
JSON with keys in sorted order and then hashing the resulting string
|
JSON with keys in sorted order and then hashing the resulting string
|
||||||
with sha3.
|
with sha3.
|
||||||
transaction:
|
|
||||||
type: object
|
|
||||||
title: transaction
|
|
||||||
description: |
|
|
||||||
See: `Transaction Body`_.
|
|
||||||
additionalProperties: false
|
|
||||||
required:
|
|
||||||
- fulfillments
|
|
||||||
- conditions
|
|
||||||
- operation
|
|
||||||
- metadata
|
|
||||||
- asset
|
|
||||||
properties:
|
|
||||||
operation:
|
operation:
|
||||||
"$ref": "#/definitions/operation"
|
"$ref": "#/definitions/operation"
|
||||||
asset:
|
asset:
|
||||||
@ -60,7 +51,7 @@ properties:
|
|||||||
"$ref": "#/definitions/metadata"
|
"$ref": "#/definitions/metadata"
|
||||||
description: |
|
description: |
|
||||||
User provided transaction metadata. This field may be ``null`` or may
|
User provided transaction metadata. This field may be ``null`` or may
|
||||||
contain an object with freeform metadata.
|
contain an id and an object with freeform metadata.
|
||||||
|
|
||||||
See: `Metadata`_.
|
See: `Metadata`_.
|
||||||
version:
|
version:
|
||||||
|
@ -1110,7 +1110,7 @@ class Transaction(object):
|
|||||||
# NOTE: An `asset` in a `TRANSFER` only contains the asset's id
|
# NOTE: An `asset` in a `TRANSFER` only contains the asset's id
|
||||||
asset = {'id': self.asset.data_id}
|
asset = {'id': self.asset.data_id}
|
||||||
|
|
||||||
tx_body = {
|
tx = {
|
||||||
'fulfillments': [fulfillment.to_dict(fid) for fid, fulfillment
|
'fulfillments': [fulfillment.to_dict(fid) for fid, fulfillment
|
||||||
in enumerate(self.fulfillments)],
|
in enumerate(self.fulfillments)],
|
||||||
'conditions': [condition.to_dict(cid) for cid, condition
|
'conditions': [condition.to_dict(cid) for cid, condition
|
||||||
@ -1118,10 +1118,7 @@ class Transaction(object):
|
|||||||
'operation': str(self.operation),
|
'operation': str(self.operation),
|
||||||
'metadata': self.metadata,
|
'metadata': self.metadata,
|
||||||
'asset': asset,
|
'asset': asset,
|
||||||
}
|
|
||||||
tx = {
|
|
||||||
'version': self.version,
|
'version': self.version,
|
||||||
'transaction': tx_body,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_no_signatures = Transaction._remove_signatures(tx)
|
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
|
# NOTE: We remove the reference since we need `tx_dict` only for the
|
||||||
# transaction's hash
|
# transaction's hash
|
||||||
tx_dict = deepcopy(tx_dict)
|
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.
|
# NOTE: Not all Cryptoconditions return a `signature` key (e.g.
|
||||||
# ThresholdSha256Fulfillment), so setting it to `None` in any
|
# ThresholdSha256Fulfillment), so setting it to `None` in any
|
||||||
# case could yield incorrect signatures. This is why we only
|
# case could yield incorrect signatures. This is why we only
|
||||||
@ -1196,7 +1193,7 @@ class Transaction(object):
|
|||||||
raise InvalidHash()
|
raise InvalidHash()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, tx_body):
|
def from_dict(cls, tx):
|
||||||
"""Transforms a Python dictionary to a Transaction object.
|
"""Transforms a Python dictionary to a Transaction object.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -1205,8 +1202,7 @@ class Transaction(object):
|
|||||||
Returns:
|
Returns:
|
||||||
:class:`~bigchaindb.common.transaction.Transaction`
|
:class:`~bigchaindb.common.transaction.Transaction`
|
||||||
"""
|
"""
|
||||||
cls.validate_structure(tx_body)
|
cls.validate_structure(tx)
|
||||||
tx = tx_body['transaction']
|
|
||||||
fulfillments = [Fulfillment.from_dict(fulfillment) for fulfillment
|
fulfillments = [Fulfillment.from_dict(fulfillment) for fulfillment
|
||||||
in tx['fulfillments']]
|
in tx['fulfillments']]
|
||||||
conditions = [Condition.from_dict(condition) for condition
|
conditions = [Condition.from_dict(condition) for condition
|
||||||
@ -1217,4 +1213,4 @@ class Transaction(object):
|
|||||||
asset = AssetLink.from_dict(tx['asset'])
|
asset = AssetLink.from_dict(tx['asset'])
|
||||||
|
|
||||||
return cls(tx['operation'], asset, fulfillments, conditions,
|
return cls(tx['operation'], asset, fulfillments, conditions,
|
||||||
tx['metadata'], tx_body['version'])
|
tx['metadata'], tx['version'])
|
||||||
|
@ -367,7 +367,7 @@ class Bigchain(object):
|
|||||||
cursor = self.backend.get_asset_by_id(asset_id)
|
cursor = self.backend.get_asset_by_id(asset_id)
|
||||||
cursor = list(cursor)
|
cursor = list(cursor)
|
||||||
if cursor:
|
if cursor:
|
||||||
return Asset.from_dict(cursor[0]['transaction']['asset'])
|
return Asset.from_dict(cursor[0]['asset'])
|
||||||
|
|
||||||
def get_spent(self, txid, cid):
|
def get_spent(self, txid, cid):
|
||||||
"""Check if a `txid` was already used as an input.
|
"""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.
|
# use it after the execution of this function.
|
||||||
# a transaction can contain multiple outputs (conditions) so we need to iterate over all of them
|
# 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
|
# 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
|
# for simple signature conditions there are no subfulfillments
|
||||||
# check if the owner is in the condition `owners_after`
|
# check if the owner is in the condition `owners_after`
|
||||||
if len(cond['owners_after']) == 1:
|
if len(cond['owners_after']) == 1:
|
||||||
|
@ -159,7 +159,7 @@ class RethinkDBBackend:
|
|||||||
r.table('bigchain', read_mode=self.read_mode)
|
r.table('bigchain', read_mode=self.read_mode)
|
||||||
.get_all(asset_id, index='asset_id')
|
.get_all(asset_id, index='asset_id')
|
||||||
.concat_map(lambda block: block['block']['transactions'])
|
.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'))
|
.get_field('id'))
|
||||||
|
|
||||||
def get_asset_by_id(self, asset_id):
|
def get_asset_by_id(self, asset_id):
|
||||||
@ -176,10 +176,10 @@ class RethinkDBBackend:
|
|||||||
.get_all(asset_id, index='asset_id')
|
.get_all(asset_id, index='asset_id')
|
||||||
.concat_map(lambda block: block['block']['transactions'])
|
.concat_map(lambda block: block['block']['transactions'])
|
||||||
.filter(lambda transaction:
|
.filter(lambda transaction:
|
||||||
transaction['transaction']['asset']['id'] == asset_id)
|
transaction['asset']['id'] == asset_id)
|
||||||
.filter(lambda transaction:
|
.filter(lambda transaction:
|
||||||
transaction['transaction']['operation'] == 'CREATE')
|
transaction['operation'] == 'CREATE')
|
||||||
.pluck({'transaction': 'asset'}))
|
.pluck('asset'))
|
||||||
|
|
||||||
def get_spent(self, transaction_id, condition_id):
|
def get_spent(self, transaction_id, condition_id):
|
||||||
"""Check if a `txid` was already used as an input.
|
"""Check if a `txid` was already used as an input.
|
||||||
@ -199,7 +199,7 @@ class RethinkDBBackend:
|
|||||||
return self.connection.run(
|
return self.connection.run(
|
||||||
r.table('bigchain', read_mode=self.read_mode)
|
r.table('bigchain', read_mode=self.read_mode)
|
||||||
.concat_map(lambda doc: doc['block']['transactions'])
|
.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})))
|
lambda fulfillment: fulfillment['input'] == {'txid': transaction_id, 'cid': condition_id})))
|
||||||
|
|
||||||
def get_owned_ids(self, owner):
|
def get_owned_ids(self, owner):
|
||||||
@ -216,7 +216,7 @@ class RethinkDBBackend:
|
|||||||
return self.connection.run(
|
return self.connection.run(
|
||||||
r.table('bigchain', read_mode=self.read_mode)
|
r.table('bigchain', read_mode=self.read_mode)
|
||||||
.concat_map(lambda doc: doc['block']['transactions'])
|
.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))))
|
lambda c: c['owners_after'].contains(owner))))
|
||||||
|
|
||||||
def get_votes_by_block_id(self, block_id):
|
def get_votes_by_block_id(self, block_id):
|
||||||
|
@ -119,7 +119,7 @@ def create_bigchain_secondary_index(conn, dbname):
|
|||||||
# secondary index for asset uuid
|
# secondary index for asset uuid
|
||||||
r.db(dbname).table('bigchain')\
|
r.db(dbname).table('bigchain')\
|
||||||
.index_create('asset_id',
|
.index_create('asset_id',
|
||||||
r.row['block']['transactions']['transaction']['asset']['id'], multi=True)\
|
r.row['block']['transactions']['asset']['id'], multi=True)\
|
||||||
.run(conn)
|
.run(conn)
|
||||||
|
|
||||||
# wait for rethinkdb to finish creating secondary indexes
|
# wait for rethinkdb to finish creating secondary indexes
|
||||||
|
@ -156,4 +156,4 @@ def is_genesis_block(block):
|
|||||||
try:
|
try:
|
||||||
return block.transactions[0].operation == 'GENESIS'
|
return block.transactions[0].operation == 'GENESIS'
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return block['block']['transactions'][0]['transaction']['operation'] == 'GENESIS'
|
return block['block']['transactions'][0]['operation'] == 'GENESIS'
|
||||||
|
@ -27,8 +27,6 @@ Transaction Schema
|
|||||||
|
|
||||||
* `Transaction`_
|
* `Transaction`_
|
||||||
|
|
||||||
* `Transaction Body`_
|
|
||||||
|
|
||||||
* Condition_
|
* Condition_
|
||||||
|
|
||||||
* Fulfillment_
|
* Fulfillment_
|
||||||
@ -58,11 +56,6 @@ Transaction Schema
|
|||||||
Transaction
|
Transaction
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
%(wrapper)s
|
|
||||||
|
|
||||||
Transaction Body
|
|
||||||
----------------
|
|
||||||
|
|
||||||
%(transaction)s
|
%(transaction)s
|
||||||
|
|
||||||
Condition
|
Condition
|
||||||
@ -158,9 +151,7 @@ def main():
|
|||||||
""" Main function """
|
""" Main function """
|
||||||
defs = TX_SCHEMA['definitions']
|
defs = TX_SCHEMA['definitions']
|
||||||
doc = TPL_DOC % {
|
doc = TPL_DOC % {
|
||||||
'wrapper': render_section('Transaction', TX_SCHEMA),
|
'transaction': render_section('Transaction', TX_SCHEMA),
|
||||||
'transaction': render_section('Transaction',
|
|
||||||
TX_SCHEMA['properties']['transaction']),
|
|
||||||
'condition': render_section('Condition', defs['condition']),
|
'condition': render_section('Condition', defs['condition']),
|
||||||
'fulfillment': render_section('Fulfillment', defs['fulfillment']),
|
'fulfillment': render_section('Fulfillment', defs['fulfillment']),
|
||||||
'asset': render_section('Asset', defs['asset']),
|
'asset': render_section('Asset', defs['asset']),
|
||||||
|
@ -22,7 +22,6 @@ A transaction has the following structure:
|
|||||||
{
|
{
|
||||||
"id": "<hash of transaction, excluding signatures (see explanation)>",
|
"id": "<hash of transaction, excluding signatures (see explanation)>",
|
||||||
"version": "<version number of the transaction model>",
|
"version": "<version number of the transaction model>",
|
||||||
"transaction": {
|
|
||||||
"fulfillments": ["<list of fulfillments>"],
|
"fulfillments": ["<list of fulfillments>"],
|
||||||
"conditions": ["<list of conditions>"],
|
"conditions": ["<list of conditions>"],
|
||||||
"operation": "<string>",
|
"operation": "<string>",
|
||||||
@ -32,26 +31,24 @@ A transaction has the following structure:
|
|||||||
"data": "<any JSON document>"
|
"data": "<any JSON document>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Here's some explanation of the contents of a :ref:`transaction <transaction>`:
|
Here's some explanation of the contents of a :ref:`transaction <transaction>`:
|
||||||
|
|
||||||
- :ref:`id <transaction.id>`: The id of the transaction, and also the database primary key.
|
- id: The :ref:`id <transaction.id>` of the transaction, and also the database primary key.
|
||||||
- :ref:`version <transaction.version>`: Version number of the transaction model, so that software can support different transaction models.
|
- version: :ref:`Version <transaction.version>` number of the transaction model, so that software can support different transaction models.
|
||||||
- :ref:`transaction <Transaction Body>`:
|
- **fulfillments**: List of fulfillments. Each :ref:`fulfillment <Fulfillment>` contains a pointer to an unspent asset
|
||||||
- **fulfillments**: List of fulfillments. Each :ref:`fulfillment <Fulfillment>` contains a pointer to an unspent asset
|
|
||||||
and a *crypto fulfillment* that satisfies a spending condition set on the unspent asset. A *fulfillment*
|
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.
|
is usually a signature proving the ownership of the asset.
|
||||||
See :doc:`./crypto-conditions`.
|
See :doc:`./crypto-conditions`.
|
||||||
|
|
||||||
- **conditions**: List of conditions. Each :ref:`condition <Condition>` is a *crypto-condition* that needs to be fulfilled by a transfer transaction in order to transfer ownership to new owners.
|
- **conditions**: List of conditions. Each :ref:`condition <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`.
|
See :doc:`./crypto-conditions`.
|
||||||
|
|
||||||
- **operation**: String representation of the :ref:`operation <transaction.operation>` being performed (currently either "CREATE", "TRANSFER" or "GENESIS"). It determines how the transaction should be validated.
|
- **operation**: String representation of the :ref:`operation <transaction.operation>` being performed (currently either "CREATE", "TRANSFER" or "GENESIS"). It determines how the transaction should be validated.
|
||||||
|
|
||||||
- **asset**: Definition of the digital :ref:`asset <Asset>`. See next section.
|
- **asset**: Definition of the digital :ref:`asset <Asset>`. See next section.
|
||||||
|
|
||||||
- **metadata**:
|
- **metadata**:
|
||||||
- :ref:`id <metadata.id>`: UUID version 4 (random) converted to a string of hex digits in standard form.
|
- :ref:`id <metadata.id>`: UUID version 4 (random) converted to a string of hex digits in standard form.
|
||||||
- :ref:`data <metadata.data>`: Can be any JSON document. It may be empty in the case of a transfer transaction.
|
- :ref:`data <metadata.data>`: Can be any JSON document. It may be empty in the case of a transfer transaction.
|
||||||
|
|
||||||
|
@ -301,7 +301,6 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id):
|
|||||||
expected = {
|
expected = {
|
||||||
'id': tx_id,
|
'id': tx_id,
|
||||||
'version': Transaction.VERSION,
|
'version': Transaction.VERSION,
|
||||||
'transaction': {
|
|
||||||
# NOTE: This test assumes that Fulfillments and Conditions can
|
# NOTE: This test assumes that Fulfillments and Conditions can
|
||||||
# successfully be serialized
|
# successfully be serialized
|
||||||
'fulfillments': [user_ffill.to_dict(0)],
|
'fulfillments': [user_ffill.to_dict(0)],
|
||||||
@ -316,13 +315,12 @@ def test_transaction_serialization(user_ffill, user_cond, data, data_id):
|
|||||||
'data': data,
|
'data': data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tx = Transaction(Transaction.CREATE, Asset(data, data_id), [user_ffill],
|
tx = Transaction(Transaction.CREATE, Asset(data, data_id), [user_ffill],
|
||||||
[user_cond])
|
[user_cond])
|
||||||
tx_dict = tx.to_dict()
|
tx_dict = tx.to_dict()
|
||||||
tx_dict['id'] = tx_id
|
tx_dict['id'] = tx_id
|
||||||
tx_dict['transaction']['asset']['id'] = data_id
|
tx_dict['asset']['id'] = data_id
|
||||||
|
|
||||||
assert tx_dict == expected
|
assert tx_dict == expected
|
||||||
|
|
||||||
@ -342,7 +340,6 @@ def test_transaction_deserialization(user_ffill, user_cond, data, uuid4):
|
|||||||
|
|
||||||
tx = {
|
tx = {
|
||||||
'version': Transaction.VERSION,
|
'version': Transaction.VERSION,
|
||||||
'transaction': {
|
|
||||||
# NOTE: This test assumes that Fulfillments and Conditions can
|
# NOTE: This test assumes that Fulfillments and Conditions can
|
||||||
# successfully be serialized
|
# successfully be serialized
|
||||||
'fulfillments': [user_ffill.to_dict()],
|
'fulfillments': [user_ffill.to_dict()],
|
||||||
@ -357,7 +354,6 @@ def test_transaction_deserialization(user_ffill, user_cond, data, uuid4):
|
|||||||
'data': data,
|
'data': data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
tx_no_signatures = Transaction._remove_signatures(tx)
|
tx_no_signatures = Transaction._remove_signatures(tx)
|
||||||
tx['id'] = Transaction._to_hash(Transaction._to_str(tx_no_signatures))
|
tx['id'] = Transaction._to_hash(Transaction._to_str(tx_no_signatures))
|
||||||
tx = Transaction.from_dict(tx)
|
tx = Transaction.from_dict(tx)
|
||||||
@ -732,7 +728,6 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
|
|||||||
from .util import validate_transaction_model
|
from .util import validate_transaction_model
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
'transaction': {
|
|
||||||
'conditions': [user_cond.to_dict(0)],
|
'conditions': [user_cond.to_dict(0)],
|
||||||
'metadata': data,
|
'metadata': data,
|
||||||
'asset': {
|
'asset': {
|
||||||
@ -753,14 +748,13 @@ def test_create_create_transaction_single_io(user_cond, user_pub, data, uuid4):
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
'operation': 'CREATE',
|
'operation': 'CREATE',
|
||||||
},
|
|
||||||
'version': 1,
|
'version': 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
asset = Asset(data, uuid4)
|
asset = Asset(data, uuid4)
|
||||||
tx = Transaction.create([user_pub], [([user_pub], 1)], data, asset)
|
tx = Transaction.create([user_pub], [([user_pub], 1)], data, asset)
|
||||||
tx_dict = tx.to_dict()
|
tx_dict = tx.to_dict()
|
||||||
tx_dict['transaction']['fulfillments'][0]['fulfillment'] = None
|
tx_dict['fulfillments'][0]['fulfillment'] = None
|
||||||
tx_dict.pop('id')
|
tx_dict.pop('id')
|
||||||
|
|
||||||
assert tx_dict == expected
|
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 = Fulfillment.generate([user_pub, user2_pub]).to_dict()
|
||||||
ffill.update({'fid': 0})
|
ffill.update({'fid': 0})
|
||||||
expected = {
|
expected = {
|
||||||
'transaction': {
|
|
||||||
'conditions': [user_cond.to_dict(0), user2_cond.to_dict(1)],
|
'conditions': [user_cond.to_dict(0), user2_cond.to_dict(1)],
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'message': 'hello'
|
'message': 'hello'
|
||||||
},
|
},
|
||||||
'fulfillments': [ffill],
|
'fulfillments': [ffill],
|
||||||
'operation': 'CREATE',
|
'operation': 'CREATE',
|
||||||
},
|
|
||||||
'version': 1
|
'version': 1
|
||||||
}
|
}
|
||||||
asset = Asset(divisible=True)
|
asset = Asset(divisible=True)
|
||||||
@ -802,7 +794,7 @@ def test_create_create_transaction_multiple_io(user_cond, user2_cond, user_pub,
|
|||||||
asset=asset,
|
asset=asset,
|
||||||
metadata={'message': 'hello'}).to_dict()
|
metadata={'message': 'hello'}).to_dict()
|
||||||
tx.pop('id')
|
tx.pop('id')
|
||||||
tx['transaction'].pop('asset')
|
tx.pop('asset')
|
||||||
|
|
||||||
assert tx == expected
|
assert tx == expected
|
||||||
|
|
||||||
@ -829,7 +821,6 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
|
|||||||
from bigchaindb.common.transaction import Transaction, Asset
|
from bigchaindb.common.transaction import Transaction, Asset
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
'transaction': {
|
|
||||||
'conditions': [user_user2_threshold_cond.to_dict(0)],
|
'conditions': [user_user2_threshold_cond.to_dict(0)],
|
||||||
'metadata': data,
|
'metadata': data,
|
||||||
'asset': {
|
'asset': {
|
||||||
@ -850,7 +841,6 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
'operation': 'CREATE',
|
'operation': 'CREATE',
|
||||||
},
|
|
||||||
'version': 1
|
'version': 1
|
||||||
}
|
}
|
||||||
asset = Asset(data, uuid4)
|
asset = Asset(data, uuid4)
|
||||||
@ -858,7 +848,7 @@ def test_create_create_transaction_threshold(user_pub, user2_pub, user3_pub,
|
|||||||
data, asset)
|
data, asset)
|
||||||
tx_dict = tx.to_dict()
|
tx_dict = tx.to_dict()
|
||||||
tx_dict.pop('id')
|
tx_dict.pop('id')
|
||||||
tx_dict['transaction']['fulfillments'][0]['fulfillment'] = None
|
tx_dict['fulfillments'][0]['fulfillment'] = None
|
||||||
|
|
||||||
assert tx_dict == expected
|
assert tx_dict == expected
|
||||||
|
|
||||||
@ -912,7 +902,6 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub,
|
|||||||
from .util import validate_transaction_model
|
from .util import validate_transaction_model
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
'transaction': {
|
|
||||||
'conditions': [user2_cond.to_dict(0)],
|
'conditions': [user2_cond.to_dict(0)],
|
||||||
'metadata': None,
|
'metadata': None,
|
||||||
'asset': {
|
'asset': {
|
||||||
@ -932,7 +921,6 @@ def test_create_transfer_transaction_single_io(tx, user_pub, user2_pub,
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
'operation': 'TRANSFER',
|
'operation': 'TRANSFER',
|
||||||
},
|
|
||||||
'version': 1
|
'version': 1
|
||||||
}
|
}
|
||||||
inputs = tx.to_inputs([0])
|
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 = Transaction.transfer(inputs, [([user2_pub], 1)], asset=asset)
|
||||||
transfer_tx = transfer_tx.sign([user_priv])
|
transfer_tx = transfer_tx.sign([user_priv])
|
||||||
transfer_tx = transfer_tx.to_dict()
|
transfer_tx = transfer_tx.to_dict()
|
||||||
transfer_tx_body = transfer_tx['transaction']
|
|
||||||
|
|
||||||
expected_input = deepcopy(inputs[0])
|
expected_input = deepcopy(inputs[0])
|
||||||
expected['id'] = transfer_tx['id']
|
expected['id'] = transfer_tx['id']
|
||||||
expected_input.fulfillment.sign(serialize(expected).encode(),
|
expected_input.fulfillment.sign(serialize(expected).encode(),
|
||||||
PrivateKey(user_priv))
|
PrivateKey(user_priv))
|
||||||
expected_ffill = expected_input.fulfillment.serialize_uri()
|
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
|
assert transfer_ffill == expected_ffill
|
||||||
|
|
||||||
@ -968,7 +955,6 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
|
|||||||
tx = tx.sign([user_priv])
|
tx = tx.sign([user_priv])
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
'transaction': {
|
|
||||||
'conditions': [user2_cond.to_dict(0), user2_cond.to_dict(1)],
|
'conditions': [user2_cond.to_dict(0), user2_cond.to_dict(1)],
|
||||||
'metadata': None,
|
'metadata': None,
|
||||||
'fulfillments': [
|
'fulfillments': [
|
||||||
@ -995,7 +981,6 @@ def test_create_transfer_transaction_multiple_io(user_pub, user_priv,
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
'operation': 'TRANSFER',
|
'operation': 'TRANSFER',
|
||||||
},
|
|
||||||
'version': 1
|
'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
|
assert transfer_tx.fulfillments_valid(tx.conditions) is True
|
||||||
|
|
||||||
transfer_tx = transfer_tx.to_dict()
|
transfer_tx = transfer_tx.to_dict()
|
||||||
transfer_tx['transaction']['fulfillments'][0]['fulfillment'] = None
|
transfer_tx['fulfillments'][0]['fulfillment'] = None
|
||||||
transfer_tx['transaction']['fulfillments'][1]['fulfillment'] = None
|
transfer_tx['fulfillments'][1]['fulfillment'] = None
|
||||||
|
transfer_tx.pop('asset')
|
||||||
transfer_tx.pop('id')
|
transfer_tx.pop('id')
|
||||||
transfer_tx['transaction'].pop('asset')
|
|
||||||
|
|
||||||
assert expected == transfer_tx
|
assert expected == transfer_tx
|
||||||
|
|
||||||
|
@ -273,8 +273,8 @@ class TestBigchainApi(object):
|
|||||||
block = b.backend.get_genesis_block()
|
block = b.backend.get_genesis_block()
|
||||||
|
|
||||||
assert len(block['block']['transactions']) == 1
|
assert len(block['block']['transactions']) == 1
|
||||||
assert block['block']['transactions'][0]['transaction']['operation'] == 'GENESIS'
|
assert block['block']['transactions'][0]['operation'] == 'GENESIS'
|
||||||
assert block['block']['transactions'][0]['transaction']['fulfillments'][0]['input'] is None
|
assert block['block']['transactions'][0]['fulfillments'][0]['input'] is None
|
||||||
|
|
||||||
def test_create_genesis_block_fails_if_table_not_empty(self, b):
|
def test_create_genesis_block_fails_if_table_not_empty(self, b):
|
||||||
from bigchaindb.common.exceptions import GenesisBlockAlreadyExistsError
|
from bigchaindb.common.exceptions import GenesisBlockAlreadyExistsError
|
||||||
|
@ -33,8 +33,8 @@ def test_post_create_transaction_endpoint(b, client):
|
|||||||
tx = tx.sign([user_priv])
|
tx = tx.sign([user_priv])
|
||||||
|
|
||||||
res = client.post(TX_ENDPOINT, data=json.dumps(tx.to_dict()))
|
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['fulfillments'][0]['owners_before'][0] == user_pub
|
||||||
assert res.json['transaction']['conditions'][0]['owners_after'][0] == user_pub
|
assert res.json['conditions'][0]['owners_after'][0] == user_pub
|
||||||
|
|
||||||
|
|
||||||
def test_post_create_transaction_with_invalid_id(b, client):
|
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 = Transaction.create([user_pub], [([user_pub], 1)])
|
||||||
tx = tx.sign([user_priv]).to_dict()
|
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))
|
res = client.post(TX_ENDPOINT, data=json.dumps(tx))
|
||||||
assert res.status_code == 400
|
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()))
|
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['fulfillments'][0]['owners_before'][0] == user_pk
|
||||||
assert res.json['transaction']['conditions'][0]['owners_after'][0] == user_pub
|
assert res.json['conditions'][0]['owners_after'][0] == user_pub
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures('inputs')
|
@pytest.mark.usefixtures('inputs')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user