mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: Stateful validation doesn't raise double spend exception (#2422)
* Problem: Stateful validation doesn't raise double spend exception Solution: Transaction.validate should raise exception DoubleSpend if the given transaction is already a part of the database * Problem: Double spend exception message not accurate Solution: The exception message should state that the double spend is because of spending the same input more than once in the transaction
This commit is contained in:
parent
4795a78d49
commit
f13c9a9d57
@ -59,7 +59,7 @@ class Transaction(Transaction):
|
|||||||
|
|
||||||
spent = bigchain.get_spent(input_txid, input_.fulfills.output,
|
spent = bigchain.get_spent(input_txid, input_.fulfills.output,
|
||||||
current_transactions)
|
current_transactions)
|
||||||
if spent and spent.id != self.id:
|
if spent:
|
||||||
raise DoubleSpend('input `{}` was already spent'
|
raise DoubleSpend('input `{}` was already spent'
|
||||||
.format(input_txid))
|
.format(input_txid))
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ class Transaction(Transaction):
|
|||||||
# Validate that all inputs are distinct
|
# Validate that all inputs are distinct
|
||||||
links = [i.fulfills.to_uri() for i in self.inputs]
|
links = [i.fulfills.to_uri() for i in self.inputs]
|
||||||
if len(links) != len(set(links)):
|
if len(links) != len(set(links)):
|
||||||
raise DoubleSpend('tx "{}" spends inputs twice'.format(self.id))
|
raise DoubleSpend('tx "{}" spends the same output more than once'.format(self.id))
|
||||||
|
|
||||||
# validate asset id
|
# validate asset id
|
||||||
asset_id = Transaction.get_asset_id(input_txs)
|
asset_id = Transaction.get_asset_id(input_txs)
|
||||||
|
@ -12,7 +12,7 @@ def test_asset_transfer(b, signed_create_tx, user_pk, user_sk):
|
|||||||
signed_create_tx.id)
|
signed_create_tx.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([signed_create_tx, tx_transfer])
|
b.store_bulk_transactions([signed_create_tx])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert tx_transfer_signed.asset['id'] == signed_create_tx.id
|
assert tx_transfer_signed.asset['id'] == signed_create_tx.id
|
||||||
@ -27,7 +27,7 @@ def test_validate_transfer_asset_id_mismatch(b, signed_create_tx, user_pk, user_
|
|||||||
tx_transfer.asset['id'] = 'a' * 64
|
tx_transfer.asset['id'] = 'a' * 64
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([signed_create_tx, tx_transfer_signed])
|
b.store_bulk_transactions([signed_create_tx])
|
||||||
|
|
||||||
with pytest.raises(AssetIdMismatch):
|
with pytest.raises(AssetIdMismatch):
|
||||||
tx_transfer_signed.validate(b)
|
tx_transfer_signed.validate(b)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
from bigchaindb.common.exceptions import DoubleSpend
|
||||||
|
|
||||||
|
|
||||||
pytestmark = pytest.mark.tendermint
|
pytestmark = pytest.mark.tendermint
|
||||||
|
|
||||||
@ -127,7 +129,7 @@ def test_single_in_single_own_single_out_single_own_transfer(alice, b, user_pk,
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b)
|
assert tx_transfer_signed.validate(b)
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
@ -154,7 +156,7 @@ def test_single_in_single_own_multiple_out_single_own_transfer(alice, b, user_pk
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 2
|
assert len(tx_transfer_signed.outputs) == 2
|
||||||
@ -182,7 +184,7 @@ def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
@ -194,6 +196,10 @@ def test_single_in_single_own_single_out_multiple_own_transfer(alice, b, user_pk
|
|||||||
|
|
||||||
assert len(tx_transfer_signed.inputs) == 1
|
assert len(tx_transfer_signed.inputs) == 1
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Single input
|
# Single input
|
||||||
@ -215,7 +221,7 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk,
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 2
|
assert len(tx_transfer_signed.outputs) == 2
|
||||||
@ -228,6 +234,10 @@ def test_single_in_single_own_multiple_out_mix_own_transfer(alice, b, user_pk,
|
|||||||
|
|
||||||
assert len(tx_transfer_signed.inputs) == 1
|
assert len(tx_transfer_signed.inputs) == 1
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Single input
|
# Single input
|
||||||
@ -249,7 +259,7 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
@ -260,6 +270,10 @@ def test_single_in_multiple_own_single_out_single_own_transfer(alice, b, user_pk
|
|||||||
assert 'subconditions' in ffill
|
assert 'subconditions' in ffill
|
||||||
assert len(ffill['subconditions']) == 2
|
assert len(ffill['subconditions']) == 2
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Multiple inputs
|
# Multiple inputs
|
||||||
@ -280,13 +294,17 @@ def test_multiple_in_single_own_single_out_single_own_transfer(alice, b, user_pk
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b)
|
assert tx_transfer_signed.validate(b)
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
assert tx_transfer_signed.outputs[0].amount == 100
|
assert tx_transfer_signed.outputs[0].amount == 100
|
||||||
assert len(tx_transfer_signed.inputs) == 2
|
assert len(tx_transfer_signed.inputs) == 2
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Multiple inputs
|
# Multiple inputs
|
||||||
@ -309,9 +327,9 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b)
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
assert tx_transfer_signed.outputs[0].amount == 100
|
assert tx_transfer_signed.outputs[0].amount == 100
|
||||||
assert len(tx_transfer_signed.inputs) == 2
|
assert len(tx_transfer_signed.inputs) == 2
|
||||||
@ -323,6 +341,10 @@ def test_multiple_in_multiple_own_single_out_single_own_transfer(alice, b, user_
|
|||||||
assert len(ffill_fid0['subconditions']) == 2
|
assert len(ffill_fid0['subconditions']) == 2
|
||||||
assert len(ffill_fid1['subconditions']) == 2
|
assert len(ffill_fid1['subconditions']) == 2
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Multiple inputs
|
# Multiple inputs
|
||||||
@ -345,7 +367,7 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
@ -358,6 +380,10 @@ def test_muiltiple_in_mix_own_multiple_out_single_own_transfer(alice, b, user_pk
|
|||||||
assert 'subconditions' in ffill_fid1
|
assert 'subconditions' in ffill_fid1
|
||||||
assert len(ffill_fid1['subconditions']) == 2
|
assert len(ffill_fid1['subconditions']) == 2
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Multiple inputs
|
# Multiple inputs
|
||||||
@ -382,7 +408,7 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk,
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
tx_transfer_signed = tx_transfer.sign([alice.private_key, user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 2
|
assert len(tx_transfer_signed.outputs) == 2
|
||||||
@ -402,6 +428,10 @@ def test_muiltiple_in_mix_own_multiple_out_mix_own_transfer(alice, b, user_pk,
|
|||||||
assert 'subconditions' in ffill_fid1
|
assert 'subconditions' in ffill_fid1
|
||||||
assert len(ffill_fid1['subconditions']) == 2
|
assert len(ffill_fid1['subconditions']) == 2
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
# TRANSFER divisible asset
|
# TRANSFER divisible asset
|
||||||
# Multiple inputs from different transactions
|
# Multiple inputs from different transactions
|
||||||
@ -436,7 +466,7 @@ def test_multiple_in_different_transactions(alice, b, user_pk, user_sk):
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer2_signed = tx_transfer2.sign([user_sk])
|
tx_transfer2_signed = tx_transfer2.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer1_signed, tx_transfer2_signed])
|
b.store_bulk_transactions([tx_create_signed, tx_transfer1_signed])
|
||||||
|
|
||||||
assert tx_transfer2_signed.validate(b) == tx_transfer2_signed
|
assert tx_transfer2_signed.validate(b) == tx_transfer2_signed
|
||||||
assert len(tx_transfer2_signed.outputs) == 1
|
assert len(tx_transfer2_signed.outputs) == 1
|
||||||
@ -501,10 +531,14 @@ def test_threshold_same_public_key(alice, b, user_pk, user_sk):
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk, user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk, user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
def test_sum_amount(alice, b, user_pk, user_sk):
|
def test_sum_amount(alice, b, user_pk, user_sk):
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
@ -520,12 +554,16 @@ def test_sum_amount(alice, b, user_pk, user_sk):
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 1
|
assert len(tx_transfer_signed.outputs) == 1
|
||||||
assert tx_transfer_signed.outputs[0].amount == 3
|
assert tx_transfer_signed.outputs[0].amount == 3
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
|
||||||
|
|
||||||
def test_divide(alice, b, user_pk, user_sk):
|
def test_divide(alice, b, user_pk, user_sk):
|
||||||
from bigchaindb.models import Transaction
|
from bigchaindb.models import Transaction
|
||||||
@ -541,9 +579,13 @@ def test_divide(alice, b, user_pk, user_sk):
|
|||||||
asset_id=tx_create.id)
|
asset_id=tx_create.id)
|
||||||
tx_transfer_signed = tx_transfer.sign([user_sk])
|
tx_transfer_signed = tx_transfer.sign([user_sk])
|
||||||
|
|
||||||
b.store_bulk_transactions([tx_create_signed, tx_transfer_signed])
|
b.store_bulk_transactions([tx_create_signed])
|
||||||
|
|
||||||
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
assert tx_transfer_signed.validate(b) == tx_transfer_signed
|
||||||
assert len(tx_transfer_signed.outputs) == 3
|
assert len(tx_transfer_signed.outputs) == 3
|
||||||
for output in tx_transfer_signed.outputs:
|
for output in tx_transfer_signed.outputs:
|
||||||
assert output.amount == 1
|
assert output.amount == 1
|
||||||
|
|
||||||
|
b.store_bulk_transactions([tx_transfer_signed])
|
||||||
|
with pytest.raises(DoubleSpend):
|
||||||
|
tx_transfer_signed.validate(b)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user