mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Initial implementation of the fix
This commit is contained in:
parent
6614f7a102
commit
024817a4ac
@ -272,20 +272,25 @@ class Bigchain(object):
|
||||
The transaction that used the `txid` as an input if it exists else it returns `None`
|
||||
|
||||
"""
|
||||
|
||||
# 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'])\
|
||||
response = r.table('bigchain').group('block_number')\
|
||||
.concat_map(lambda doc: doc['block']['transactions'])\
|
||||
.filter(lambda transaction: transaction['transaction']['input'] == txid).run(self.conn)
|
||||
|
||||
# the query returns a dictionary in which keys are block numbers and values are list of transactions
|
||||
# with that using that input inside the block. For it to be correct:
|
||||
# - There should be at most one block with transactions using that input
|
||||
# - There should be at most one transaction with that input
|
||||
|
||||
# a transaction_id should have been spent at most one time
|
||||
transactions = list(response)
|
||||
if transactions:
|
||||
if len(transactions) != 1:
|
||||
if response:
|
||||
if len(response) > 1 or len(*response.values()) > 1:
|
||||
raise Exception('`{}` was spent more then once. There is a problem with the chain'.format(
|
||||
txid))
|
||||
else:
|
||||
return transactions[0]
|
||||
response = list(response.items())
|
||||
return (response[0][0], response[0][1][0])
|
||||
else:
|
||||
return None
|
||||
|
||||
@ -466,7 +471,8 @@ class Bigchain(object):
|
||||
try:
|
||||
self.validate_block(block)
|
||||
return True
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
def write_block(self, block, durability='soft'):
|
||||
|
@ -47,6 +47,122 @@ class TestBigchainVoter(object):
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_valid_block_voting_with_create_transaction(self, b):
|
||||
q_new_block = mp.Queue()
|
||||
|
||||
genesis = b.create_genesis_block()
|
||||
|
||||
# create a `CREATE` transaction
|
||||
test_user_priv, test_user_pub = b.generate_keys()
|
||||
tx = b.create_transaction(b.me, test_user_pub, None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
assert b.is_valid_transaction(tx_signed)
|
||||
|
||||
# create valid block
|
||||
block = b.create_block([tx_signed])
|
||||
# assert block is valid
|
||||
assert b.is_valid_block(block)
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# create queue and voter
|
||||
voter = Voter(q_new_block)
|
||||
|
||||
# vote
|
||||
voter.start()
|
||||
# wait for vote to be written
|
||||
time.sleep(1)
|
||||
voter.kill()
|
||||
|
||||
# retrive block from bigchain
|
||||
blocks = list(r.table('bigchain')
|
||||
.order_by(r.asc((r.row['block']['timestamp'])))
|
||||
.run(b.conn))
|
||||
|
||||
|
||||
# validate vote
|
||||
assert len(blocks[1]['votes']) == 1
|
||||
vote = blocks[1]['votes'][0]
|
||||
|
||||
assert vote['vote']['voting_for_block'] == block['id']
|
||||
assert vote['vote']['previous_block'] == genesis['id']
|
||||
assert vote['vote']['is_block_valid'] is True
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_valid_block_voting_with_transfer_transactions(self, b):
|
||||
q_new_block = mp.Queue()
|
||||
|
||||
genesis = b.create_genesis_block()
|
||||
|
||||
# create a `CREATE` transaction
|
||||
test_user_priv, test_user_pub = b.generate_keys()
|
||||
tx = b.create_transaction(b.me, test_user_pub, None, 'CREATE')
|
||||
tx_signed = b.sign_transaction(tx, b.me_private)
|
||||
assert b.is_valid_transaction(tx_signed)
|
||||
|
||||
# create valid block
|
||||
block = b.create_block([tx_signed])
|
||||
# assert block is valid
|
||||
assert b.is_valid_block(block)
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# create queue and voter
|
||||
voter = Voter(q_new_block)
|
||||
|
||||
# vote
|
||||
voter.start()
|
||||
# wait for vote to be written
|
||||
time.sleep(1)
|
||||
voter.kill()
|
||||
|
||||
# retrive block from bigchain
|
||||
blocks = list(r.table('bigchain')
|
||||
.order_by(r.asc((r.row['block']['timestamp'])))
|
||||
.run(b.conn))
|
||||
|
||||
|
||||
# validate vote
|
||||
assert len(blocks[1]['votes']) == 1
|
||||
|
||||
|
||||
# create a `TRANSFER` transaction
|
||||
test_user2_priv, test_user2_pub = b.generate_keys()
|
||||
tx2 = b.create_transaction(test_user_pub, test_user2_pub, tx['id'], 'TRANSFER')
|
||||
tx2_signed = b.sign_transaction(tx2, test_user_priv)
|
||||
assert b.is_valid_transaction(tx2_signed)
|
||||
|
||||
# create valid block
|
||||
block = b.create_block([tx2_signed])
|
||||
# assert block is valid
|
||||
assert b.is_valid_block(block)
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# create queue and voter
|
||||
voter = Voter(q_new_block)
|
||||
|
||||
# vote
|
||||
voter.start()
|
||||
# wait for vote to be written
|
||||
time.sleep(1)
|
||||
voter.kill()
|
||||
|
||||
# retrive block from bigchain
|
||||
blocks = list(r.table('bigchain')
|
||||
.order_by(r.asc((r.row['block']['timestamp'])))
|
||||
.run(b.conn))
|
||||
|
||||
|
||||
# validate vote
|
||||
assert len(blocks[2]['votes']) == 1
|
||||
|
||||
vote = blocks[2]['votes'][0]
|
||||
|
||||
assert vote['vote']['voting_for_block'] == block['id']
|
||||
assert vote['vote']['is_block_valid'] is True
|
||||
assert vote['vote']['invalid_reason'] is None
|
||||
assert vote['node_pubkey'] == b.me
|
||||
assert PublicKey(b.me).verify(b.serialize(vote['vote']), vote['signature']) is True
|
||||
|
||||
def test_invalid_block_voting(self, b, user_public_key):
|
||||
# create queue and voter
|
||||
|
Loading…
x
Reference in New Issue
Block a user