initial implementation of multi input support

This commit is contained in:
Rodolphe Marques 2016-03-22 19:30:53 +01:00
parent 4dcd25e8ac
commit 194bf8c6bd
4 changed files with 42 additions and 25 deletions

View File

@ -119,7 +119,7 @@ class BaseConsensusRules(AbstractConsensusRules):
# If the operation is CREATE the transaction should have no inputs and
# should be signed by a federation node
if transaction['transaction']['operation'] == 'CREATE':
if transaction['transaction']['input']:
if transaction['transaction']['inputs']:
raise ValueError('A CREATE operation has no inputs')
if transaction['transaction']['current_owner'] not in (
bigchain.federation_nodes + [bigchain.me]):
@ -128,32 +128,32 @@ class BaseConsensusRules(AbstractConsensusRules):
else:
# check if the input exists, is owned by the current_owner
if not transaction['transaction']['input']:
if not transaction['transaction']['inputs']:
raise ValueError(
'Only `CREATE` transactions can have null inputs')
tx_input = bigchain.get_transaction(
transaction['transaction']['input'])
# check inputs
for inp in transaction['transaction']['inputs']:
tx_input = bigchain.get_transaction(inp)
if not tx_input:
raise exceptions.TransactionDoesNotExist(
'input `{}` does not exist in the bigchain'.format(
transaction['transaction']['input']))
if not tx_input:
raise exceptions.TransactionDoesNotExist(
'input `{}` does not exist in the bigchain'.format(
transaction['transaction']['input']))
if (tx_input['transaction']['new_owner'] !=
transaction['transaction']['current_owner']):
raise exceptions.TransactionOwnerError(
'current_owner `{}` does not own the input `{}`'.format(
transaction['transaction']['current_owner'],
transaction['transaction']['input']))
if (tx_input['transaction']['new_owner'] !=
transaction['transaction']['current_owner']):
raise exceptions.TransactionOwnerError(
'current_owner `{}` does not own the input `{}`'.format(
transaction['transaction']['current_owner'],
transaction['transaction']['input']))
# check if the input was already spent by a transaction other than
# this one.
spent = bigchain.get_spent(tx_input['id'])
if spent and spent['id'] != transaction['id']:
raise exceptions.DoubleSpend(
'input `{}` was already spent'.format(
transaction['transaction']['input']))
# check if the input was already spent by a transaction other than
# this one.
spent = bigchain.get_spent(tx_input['id'])
if spent and spent['id'] != transaction['id']:
raise exceptions.DoubleSpend(
'input `{}` was already spent'.format(inp))
# Check hash of the transaction
calculated_hash = hash_data(util.serialize(

View File

@ -203,7 +203,7 @@ class Bigchain(object):
# checks if an input was already spent
# checks if the bigchain has any transaction with input `transaction_id`
response = r.table('bigchain').concat_map(lambda doc: doc['block']['transactions'])\
.filter(lambda transaction: transaction['transaction']['input'] == txid).run(self.conn)
.filter(lambda transaction: transaction['transaction']['inputs'].contains(txid)).run(self.conn)
# a transaction_id should have been spent at most one time
transactions = list(response)

View File

@ -76,7 +76,7 @@ def timestamp():
return "{0:.6f}".format(time.mktime(dt.timetuple()) + dt.microsecond / 1e6)
def create_tx(current_owner, new_owner, tx_input, operation, payload=None):
def create_tx(current_owner, new_owner, inputs, operation, payload=None):
"""Create a new transaction
A transaction in the bigchain is a transfer of a digital asset between two entities represented
@ -94,7 +94,7 @@ def create_tx(current_owner, new_owner, tx_input, operation, payload=None):
Args:
current_owner (str): base58 encoded public key of the current owner of the asset.
new_owner (str): base58 encoded public key of the new owner of the digital asset.
tx_input (str): id of the transaction to use as input.
inputs (list): id of the transaction to use as input.
operation (str): Either `CREATE` or `TRANSFER` operation.
payload (Optional[dict]): dictionary with information about asset.
@ -106,6 +106,7 @@ def create_tx(current_owner, new_owner, tx_input, operation, payload=None):
TypeError: if the optional ``payload`` argument is not a ``dict``.
"""
# handle payload
data = None
if payload is not None:
if isinstance(payload, dict):
@ -123,10 +124,13 @@ def create_tx(current_owner, new_owner, tx_input, operation, payload=None):
'payload': payload
}
if inputs == []:
inputs = None
tx = {
'current_owner': current_owner,
'new_owner': new_owner,
'input': tx_input,
'inputs': inputs,
'operation': operation,
'timestamp': timestamp(),
'data': data

View File

@ -756,3 +756,16 @@ class TestBigchainBlock(object):
def test_duplicated_transactions(self):
pytest.skip('We may have duplicates in the initial_results and changefeed')
class TestMultipleInputs(object):
def test_transfer_transaction_multiple(self, b):
pass
def test_transfer_single_input_from_multi_input(self, b):
pass
def test_get_spent(self, b):
pass