Skip to content

Commit

Permalink
Problem: validating create+transfer might crash the system (#2487)
Browse files Browse the repository at this point in the history
Solution: if a TRANSFER transaction is validated after a CREATE
transaction, the system crashes with `AttributeError: 'NoneType' object
has no attribute 'txid'`.

This happens because querying `get_spent` checks the attributes `txid`
and `output` of `input.fulfills` for every transaction in the current
buffer (`current_transactions`). For a CREATE, `input.fulfills` is None,
so the check would fail.

The solution is to check if `input.fulfills` is defined. If not, then
the current transaction cannot spend any output, so we can safely skip
it.
  • Loading branch information
vrde authored and kansi committed Aug 29, 2018
1 parent 8e97c75 commit 407b771
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
3 changes: 2 additions & 1 deletion bigchaindb/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ def get_spent(self, txid, output, current_transactions=[]):
current_spent_transactions = []
for ctxn in current_transactions:
for ctxn_input in ctxn.inputs:
if ctxn_input.fulfills.txid == txid and\
if ctxn_input.fulfills and\
ctxn_input.fulfills.txid == txid and\
ctxn_input.fulfills.output == output:
current_spent_transactions.append(ctxn)

Expand Down
22 changes: 22 additions & 0 deletions tests/tendermint/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,25 @@ def test_get_spent_transaction_critical_double_spend(b, alice, bob, carol):

with pytest.raises(CriticalDoubleSpend):
b.get_spent(tx.id, tx_transfer.inputs[0].fulfills.output)


def test_validation_with_transaction_buffer(b):
from bigchaindb.common.crypto import generate_key_pair
from bigchaindb.models import Transaction

priv_key, pub_key = generate_key_pair()

create_tx = Transaction.create([pub_key], [([pub_key], 10)]).sign([priv_key])
transfer_tx = Transaction.transfer(create_tx.to_inputs(),
[([pub_key], 10)],
asset_id=create_tx.id).sign([priv_key])
double_spend = Transaction.transfer(create_tx.to_inputs(),
[([pub_key], 10)],
asset_id=create_tx.id).sign([priv_key])

assert b.is_valid_transaction(create_tx)
assert b.is_valid_transaction(transfer_tx, [create_tx])

assert not b.is_valid_transaction(create_tx, [create_tx])
assert not b.is_valid_transaction(transfer_tx, [create_tx, transfer_tx])
assert not b.is_valid_transaction(double_spend, [create_tx, transfer_tx])

0 comments on commit 407b771

Please sign in to comment.