def register(self, from_address, to_address, hash, password, edition_num, min_confirmations=6, sync=False, ownership=True): """ Register an edition or master edition of a piece :param from_address: Federation address. All register transactions originate from the the Federation wallet :param to_address: Address registering the edition :param hash: Hash of the piece. Tuple (file_hash, file_hash_metadata) :param password: Federation wallet password. For signing the transaction :param edition_num: The number of the edition to register. User edition_num=0 to register the master edition :param min_confirmations: Override the number of confirmations when chosing the inputs of the transaction. Defaults to 6 :param sync: Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False :param ownership: Check ownsership in the blockchain before pushing the transaction. Defaults to True :return: transaction id """ file_hash, file_hash_metadata = hash path, from_address = from_address verb = Spoolverb(edition_num=edition_num) unsigned_tx = self.simple_spool_transaction(from_address, [file_hash, file_hash_metadata, to_address], op_return=verb.register, min_confirmations=min_confirmations) signed_tx = self._t.sign_transaction(unsigned_tx, password) txid = self._t.push(signed_tx) return txid
def refill(self, from_address, to_address, nfees, ntokens, password, min_confirmations=6, sync=False): """ Refill wallets with the necessary fuel to perform spool transactions :param from_address: Federation wallet address. Fuels the wallets with tokens and fees. All transactions to wallets holding a particular piece should come from the Federation wallet :param to_address: Wallet address that needs to perform a spool transaction :param nfees: Number of fees to transfer. Each fee is 10000 satoshi. Used to pay for the transactions :param ntokens: Number of tokens to transfer. Each token is 600 satoshi. Used to register hashes in the blockchain :param password: Password for the Federation wallet. Used to sign the transaction :param min_confirmations: Number of confirmations when chosing the inputs of the transaction. Defaults to 6 :param sync: Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False :return: transaction id """ path, from_address = from_address verb = Spoolverb() # nfees + 1: nfees to refill plus one fee for the refill transaction itself inputs = self.select_inputs(from_address, nfees + 1, ntokens, min_confirmations=min_confirmations) outputs = [{'address': to_address, 'value': self.TOKEN}] * ntokens outputs += [{'address': to_address, 'value': self.FEE}] * nfees outputs += [{'script': self._t._op_return_hex(verb.fuel), 'value': 0}] unsigned_tx = self._t.build_transaction(inputs, outputs) signed_tx = self._t.sign_transaction(unsigned_tx, password, path=path) txid = self._t.push(signed_tx) return txid
def loan(self, from_address, to_address, hash, password, edition_num, loan_start, loan_end, min_confirmations=6, sync=False, ownership=True): """ Loan the edition :param from_address: Address currently holding the edition :param to_address: Address to loan the edition to :param hash: Hash of the piece. Tuple (file_hash, file_hash_metadata) :param password: Password for the wallet currently holding the edition. For signing the transaction :param edition_num: the number of the edition to unconsign :param loan_start: Start date for the loan. In the form YYMMDD :param loan_end: End date for the loan. In the form YYMMDD :param min_confirmations: Number of confirmations when chosing the inputs of the transaction. Defaults to 6 :param sync: Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False :param ownership: Check ownsership in the blockchain before pushing the transaction. Defaults to True :return: transaction id """ path, from_address = from_address file_hash, file_hash_metadata = hash verb = Spoolverb(edition_num=edition_num, loan_start=loan_start, loan_end=loan_end) unsigned_tx = self.simple_spool_transaction(from_address, [file_hash, to_address], op_return=verb.loan, min_confirmations=min_confirmations) signed_tx = self._t.sign_transaction(unsigned_tx, password, path=path) txid = self._t.push(signed_tx) return txid
def unconsign(self, from_address, to_address, hash, password, edition_num, min_confirmations=6, sync=False, ownership=True): """ Unconsign the edition :param from_address: Address where the edition is currently consigned :param to_address: Address that consigned the piece to from_address :param hash: Hash of the piece. Tuple (file_hash, file_hash_metadata) :param password: Password for the wallet currently holding the edition. For signing the transaction :param edition_num: the number of the edition to unconsign :param min_confirmations: Number of confirmations when chosing the inputs of the transaction. Defaults to 6 :param sync: Perform the transaction in synchronous mode, the call to the function will block until there is at least on confirmation on the blockchain. Defaults to False :param ownership: Check ownsership in the blockchain before pushing the transaction. Defaults to True :return: transaction id """ # In an unconsignment the to_address needs to be the address that created the consign transaction path, from_address = from_address file_hash, file_hash_metadata = hash verb = Spoolverb(edition_num=edition_num) unsigned_tx = self.simple_spool_transaction(from_address, [file_hash, to_address], op_return=verb.unconsign, min_confirmations=min_confirmations) signed_tx = self._t.sign_transaction(unsigned_tx, password, path=path) txid = self._t.push(signed_tx) return txid
def check_script(vouts): """ Looks into the vouts list of a transaction and returns the op_return if one exists :param vouts: lists of outputs of a transaction :return: string representation of the op_return """ for vout in [v for v in vouts[::-1] if v['hex'].startswith('6a')]: verb = BlockchainSpider.decode_op_return(vout['hex']) action = Spoolverb.from_verb(verb).action if action in Spoolverb.supported_actions: return verb raise Exception("Invalid ascribe transaction")
def history(self, hash): """ Retrieve the ownership tree of all editions of a piece given the hash. Args: hash (str): Hash of the file to check. Can be created with the :class:`File` class Returns: ownsership tree of all editions of a piece .. note:: For now we only support searching the blockchain by the piece hash. """ txs = self._t.get(hash, max_transactions=10000)['transactions'] tree = defaultdict(list) number_editions = 0 for tx in txs: _tx = self._t.get(tx['txid']) txid = _tx['txid'] verb_str = BlockchainSpider.check_script(_tx['vouts']) verb = Spoolverb.from_verb(verb_str) from_address, to_address, piece_address = BlockchainSpider._get_addresses(_tx) timestamp_utc = _tx['time'] action = verb.action edition_number = 0 if action != 'EDITIONS': edition_number = verb.edition_number else: number_editions = verb.num_editions tree[edition_number].append({'txid': txid, 'verb': verb_str, 'from_address': from_address, 'to_address': to_address, 'piece_address': piece_address, 'timestamp_utc': timestamp_utc, 'action': action, 'number_editions': number_editions, 'edition_number': edition_number}) # lets update the records with the number of editions of the piece since we do not know # this information before the EDITIONS transaction for edition, chain in tree.iteritems(): [d.update({'number_editions': number_editions}) for d in chain] return dict(tree)
def history(self, hash): """ Retrieve the ownership tree of all editions of a piece given the hash :param hash: Hash of the file to check. Can be created with the File class :return: ownsership tree of all editions of a piece """ # For now we only support searching the blockchain by the piece hash txs = self._t.get(hash, max_transactions=10000)['transactions'] tree = defaultdict(list) number_editions = 0 for tx in txs: _tx = self._t.get(tx['txid']) txid = _tx['txid'] verb_str = BlockchainSpider.check_script(_tx['vouts']) verb = Spoolverb.from_verb(verb_str) from_address, to_address, piece_address = BlockchainSpider._get_addresses( _tx) timestamp_utc = _tx['time'] action = verb.action edition_number = 0 if action != 'EDITIONS': edition_number = verb.edition_number else: number_editions = verb.num_editions tree[edition_number].append({ 'txid': txid, 'verb': verb_str, 'from_address': from_address, 'to_address': to_address, 'piece_address': piece_address, 'timestamp_utc': timestamp_utc, 'action': action, 'number_editions': number_editions, 'edition_number': edition_number }) # lets update the records with the number of editions of the piece since we do not know # this information before the EDITIONS transaction for edition, chain in tree.iteritems(): [d.update({'number_editions': number_editions}) for d in chain] return dict(tree)