from bigchaindb_driver import ( BigchainDB, ) from bigchaindb_driver.crypto import generate_keypair from constants.application_constants import BDB_SERVER_URL from utils.bigchaindb_utils import (poll_status_and_fetch_transaction, prepare_transfer_ed25519_simple, sign_ed25519) # see simple_transaction.py untill next comment bdb = BigchainDB(BDB_SERVER_URL) print(bdb.info()) alice = generate_keypair() bob = generate_keypair() carly = generate_keypair() tx_create_alice_simple = bdb.transactions.prepare( operation='CREATE', signers=alice.public_key, asset={ 'data': { 'asset_message': 'I will stick to every future transfer transaction' } }, metadata={'metadata_message': 'I only stick to the create transaction'}) tx_create_alice_simple_signed = bdb.transactions.fulfill( tx_create_alice_simple, private_keys=alice.private_key) asset_id = tx_create_alice_simple_signed['id']
class BigchaindbConnector(BlockchainConnector): # Bigchaindb requires list of endpoints given as full urls and # optional dictionary of parameters called headers (e.g., app_id) def __init__(self, endpoints=['http://localhost:9984'], params=None): BlockchainConnector.__init__(self, 'Bigchaindb', endpoints) self.headers = params self.conn = BigchainDB(*self.endpoints, headers=self.headers) self.conn.info() #if this fails exception generated def getConnectorConfig(self): config = dict() config['backend'] = self.backend config['endpoints'] = self.endpoints config['params'] = self.headers return config def createParticipant(self, participant=None, participant_type=None): #for bigchain a participant is just a set of private/public keys k = generate_keypair() keys = dict() keys['private_key'] = k.private_key keys['public_key'] = k.public_key return keys def updateParticipant(self, participant=None, participant_type=None): return self.createParticipant() def submitAssetCreateTransaction(self, casset, asset_type, ass_data, owner): asset = dict() # In asset there must be a 'data' property with the data in it. asset['data'] = casset # prepare asset creation for blockchain transaction prepared_create_tx = self.conn.transactions.prepare( operation='CREATE', signers=owner['public_key'], asset=asset, metadata=ass_data) # The transaction now needs to be fulfilled by signing it with the private key: fulfilled_create_tx = self.conn.transactions.fulfill( prepared_create_tx, private_keys=owner['private_key']) print( 'BigChainConnector>> Asset prepared, signed and verified for submission' ) # Send transaction over to a BigchainDB node # Commit (opposed to async) waits until the transaction is committed to a block or a timeout is reached. self.conn.transactions.send_commit(fulfilled_create_tx) txid = fulfilled_create_tx['id'] print( 'BigChainConnector>> Asset committed to blockchain ledger with transaction id: ' + txid) resp = { 'asset_id': txid, #CREATE ops have same asset and trans id 'trans_id': txid, 'status_code': 200 } return resp def submitAssetAppendTransaction(self, asset_id, asset_type, ass_data, prev_trans_id, prev_owner, new_owner): prev_trans = self.conn.transactions.retrieve(prev_trans_id) if not prev_trans: return transfer_asset = {'id': asset_id} output_index = 0 output = prev_trans['outputs'][output_index] transfer_input = { 'fulfillment': output['condition']['details'], 'fulfills': { 'output_index': output_index, 'transaction_id': prev_trans['id'], }, 'owners_before': output['public_keys'], } prepared_transfer_tx = self.conn.transactions.prepare( operation='TRANSFER', asset=transfer_asset, inputs=transfer_input, recipients=new_owner['public_key'], metadata=ass_data) fulfilled_transfer_tx = self.conn.transactions.fulfill( prepared_transfer_tx, private_keys=prev_owner['private_key'], ) print( 'BigChainConnector>> Asset prepared, signed and verified for submission' ) self.conn.transactions.send_commit(fulfilled_transfer_tx) txid = fulfilled_transfer_tx['id'] print( 'BigChainConnector>> Asset transfer committed to blockchain ledger with transaction id: ' + txid) resp = {'asset_id': asset_id, 'trans_id': txid, 'status_code': 200} return resp def getAssetBlockInLedger(self, trans_id, trans_type=None): # if block_height is None then either trans does not exist, # invalid or simply queued - so not processed yet. block_height = self.conn.blocks.get(txid=trans_id) if block_height: return self.conn.blocks.retrieve(str(block_height)) return None def getAssetTransactions(self, asset_id, asset_type=None, trans_type=None): #TODO use query data return self.conn.transactions.get(asset_id=asset_id) def getAsset(self, asset_id, asset_type=None): data = self.conn.transactions.get(asset_id=asset_id, operation='CREATE') return data[0]['asset']['data'] def getAssetMutableData(self, asset_id, asset_type=None): #limit not supported data = self.conn.transactions.get(asset_id=asset_id) ml = [] for m in data: ml.append(m['metadata']) return ml def getAssetOwnership(self, asset_id, asset_type=None): #limit not supported data = self.conn.transactions.get(asset_id=asset_id) ml = [] for m in data: obj = dict() obj['trans_id'] = m['id'] obj['operation'] = m['operation'] obj['owners_before'] = m['inputs'][0]['owners_before'] obj['current_owners'] = m['outputs'][0]['public_keys'] ml.append(obj) return ml