mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Merge pull request #574 from bigchaindb/core/557/improve-get-transaction
return block status
This commit is contained in:
commit
6b583cd791
@ -16,9 +16,14 @@ class Bigchain(object):
|
||||
Create, read, sign, write transactions to the database
|
||||
"""
|
||||
|
||||
# return if a block has been voted invalid
|
||||
BLOCK_INVALID = 'invalid'
|
||||
BLOCK_VALID = 'valid'
|
||||
BLOCK_UNDECIDED = 'undecided'
|
||||
# return if a block is valid, or tx is in valid block
|
||||
BLOCK_VALID = TX_VALID = 'valid'
|
||||
# return if block is undecided, or tx is in undecided block
|
||||
BLOCK_UNDECIDED = TX_UNDECIDED = 'undecided'
|
||||
# return if transaction is in backlog
|
||||
TX_IN_BACKLOG = 'backlog'
|
||||
|
||||
def __init__(self, host=None, port=None, dbname=None,
|
||||
public_key=None, private_key=None, keyring=[],
|
||||
@ -132,46 +137,57 @@ class Bigchain(object):
|
||||
response = r.table('backlog').insert(signed_transaction, durability=durability).run(self.conn)
|
||||
return response
|
||||
|
||||
def get_transaction(self, txid):
|
||||
def get_transaction(self, txid, include_status=False):
|
||||
"""Retrieve a transaction with `txid` from bigchain.
|
||||
|
||||
Queries the bigchain for a transaction that was already included in a block.
|
||||
Queries the bigchain for a transaction, if it's in a valid or invalid
|
||||
block.
|
||||
|
||||
Args:
|
||||
txid (str): transaction id of the transaction to query
|
||||
include_status (bool): also return the status of the transaction
|
||||
the return value is then a tuple: (tx, status)
|
||||
|
||||
Returns:
|
||||
A dict with the transaction details if the transaction was found.
|
||||
|
||||
If no transaction with that `txid` was found it returns `None`
|
||||
Will add the transaction status to payload ('valid', 'undecided',
|
||||
or 'backlog'). If no transaction with that `txid` was found it
|
||||
returns `None`
|
||||
"""
|
||||
|
||||
response, tx_status = None, None
|
||||
|
||||
validity = self.get_blocks_status_containing_tx(txid)
|
||||
|
||||
if validity:
|
||||
# Disregard invalid blocks, and return if there are no valid or undecided blocks
|
||||
validity = {_id: status for _id, status in validity.items()
|
||||
if status != Bigchain.BLOCK_INVALID}
|
||||
if not validity:
|
||||
return None
|
||||
if validity:
|
||||
|
||||
# If the transaction is in a valid or any undecided block, return it. Does not check
|
||||
# if transactions in undecided blocks are consistent, but selects the valid block before
|
||||
# undecided ones
|
||||
for _id in validity:
|
||||
target_block_id = _id
|
||||
if validity[_id] == Bigchain.BLOCK_VALID:
|
||||
break
|
||||
tx_status = self.TX_UNDECIDED
|
||||
# If the transaction is in a valid or any undecided block, return it. Does not check
|
||||
# if transactions in undecided blocks are consistent, but selects the valid block before
|
||||
# undecided ones
|
||||
for target_block_id in validity:
|
||||
if validity[target_block_id] == Bigchain.BLOCK_VALID:
|
||||
tx_status = self.TX_VALID
|
||||
break
|
||||
|
||||
# Query the transaction in the target block and return
|
||||
response = r.table('bigchain', read_mode=self.read_mode).get(target_block_id)\
|
||||
.get_field('block').get_field('transactions')\
|
||||
.filter(lambda tx: tx['id'] == txid).run(self.conn)
|
||||
|
||||
return response[0]
|
||||
# Query the transaction in the target block and return
|
||||
response = r.table('bigchain', read_mode=self.read_mode).get(target_block_id)\
|
||||
.get_field('block').get_field('transactions')\
|
||||
.filter(lambda tx: tx['id'] == txid).run(self.conn)[0]
|
||||
|
||||
else:
|
||||
return None
|
||||
# Otherwise, check the backlog
|
||||
response = r.table('backlog').get(txid).run(self.conn)
|
||||
if response:
|
||||
tx_status = self.TX_IN_BACKLOG
|
||||
if include_status:
|
||||
return response, tx_status
|
||||
else:
|
||||
return response
|
||||
|
||||
def search_block_election_on_index(self, value, index):
|
||||
"""Retrieve block election information given a secondary index and value
|
||||
|
||||
@ -110,25 +110,37 @@ class TestBigchainApi(object):
|
||||
assert response['inserted'] == 1
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_read_transaction(self, b, user_vk, user_sk):
|
||||
def test_read_transaction_undecided_block(self, b, user_vk, user_sk):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
tx = b.create_transaction(user_vk, user_vk, input_tx, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
b.write_transaction(tx_signed)
|
||||
|
||||
# create block and write it to the bighcain before retrieving the transaction
|
||||
block = b.create_block([tx_signed])
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
response = b.get_transaction(tx_signed["id"])
|
||||
response, status = b.get_transaction(tx_signed["id"], include_status=True)
|
||||
# add validity information, which will be returned
|
||||
assert util.serialize(tx_signed) == util.serialize(response)
|
||||
assert status == b.TX_UNDECIDED
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_read_transaction_backlog(self, b, user_vk, user_sk):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
tx = b.create_transaction(user_vk, user_vk, input_tx, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
b.write_transaction(tx_signed)
|
||||
|
||||
response, status = b.get_transaction(tx_signed["id"], include_status=True)
|
||||
# add validity information, which will be returned
|
||||
assert util.serialize(tx_signed) == util.serialize(response)
|
||||
assert status == b.TX_IN_BACKLOG
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_read_transaction_invalid_block(self, b, user_vk, user_sk):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
tx = b.create_transaction(user_vk, user_vk, input_tx, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
b.write_transaction(tx_signed)
|
||||
|
||||
# create block
|
||||
block = b.create_block([tx_signed])
|
||||
@ -142,6 +154,26 @@ class TestBigchainApi(object):
|
||||
# should be None, because invalid blocks are ignored
|
||||
assert response is None
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_read_transaction_valid_block(self, b, user_vk, user_sk):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
tx = b.create_transaction(user_vk, user_vk, input_tx, 'TRANSFER')
|
||||
tx_signed = b.sign_transaction(tx, user_sk)
|
||||
b.write_transaction(tx_signed)
|
||||
|
||||
# create block
|
||||
block = b.create_block([tx_signed])
|
||||
b.write_block(block, durability='hard')
|
||||
|
||||
# vote the block invalid
|
||||
vote = b.vote(block['id'], b.get_last_voted_block()['id'], True)
|
||||
b.write_vote(vote)
|
||||
|
||||
response, status = b.get_transaction(tx_signed["id"], include_status=True)
|
||||
# add validity information, which will be returned
|
||||
assert util.serialize(tx_signed) == util.serialize(response)
|
||||
assert status == b.TX_VALID
|
||||
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_assign_transaction_one_node(self, b, user_vk, user_sk):
|
||||
input_tx = b.get_owned_ids(user_vk).pop()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user