class Blockchain: def __init__(self): self.proxy = Proxy('http://*****:*****@blockchain.infnote.com:8962') @staticmethod def deserialize_transaction(raw_tx): return CTransaction.deserialize(unhexlify(raw_tx.encode('utf8'))) def decode_transaction(self, tx): contents = [] for out in tx.vout: if out.nValue > 0: continue data = self.get_data_from_vout(out) if data: contents.append(data) return contents def send_transaction(self, raw_tx): transaction = self.deserialize_transaction(raw_tx) txid = self.proxy.sendrawtransaction(transaction) return txid @staticmethod def get_data_from_vout(vout): i = iter(vout.scriptPubKey) flag = next(i) # TODO: 需要区分类型,以填充至不同的模型 if flag == script.OP_RETURN or flag == script.OP_NOP8: data = next(i).decode('utf8') return json.loads(data) return None def get_transaction(self, txid): return self.proxy.getrawtransaction(txid) def get_block_count(self): return self.proxy.getblockcount() def get_block_by_height(self, height: int): return self.proxy.getblock(self.proxy.getblockhash(height)) def server_unspent(self): return self.proxy.listunspent() @staticmethod def freeze_coins_in_tx(tx: CTransaction): for vin in tx.vin: coin = Coin.objects.get(txid=b2lx(vin.prevout.hash), vout=vin.prevout.n) coin.frozen = True coin.save() def send_coin_to(self, address, coin: Coin): txin = CMutableTxIn(COutPoint(lx(coin.txid), coin.vout)) txout = CMutableTxOut(coin.value - 1e5, CBitcoinAddress(address).to_scriptPubKey()) tx = CMutableTransaction([txin], [txout]) tx = self.proxy.signrawtransaction(tx)['tx'] # sig_hash = SignatureHash(txin_script_pubkey, tx, 0, SIGHASH_ALL) # sig = seckey.sign(sig_hash) + bytes([SIGHASH_ALL]) # txin.scriptSig = CScript([sig, seckey.pub]) # VerifyScript(txin.scriptSig, txin_script_pubkey, tx, 0, (SCRIPT_VERIFY_P2SH,)) # print(b2x(tx.serialize())) self.proxy.sendrawtransaction(tx) coin.frozen = True coin.save()
# Calculate the signature hash for the transaction. This is then signed by the # private key that controls the UTXO being spent here at this txin_index. sighash = SignatureHash(redeem_script, tx, txin_index, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) signature = seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Construct a witness for this transaction input. The public key is given in # the witness so that the appropriate redeem_script can be calculated by # anyone. The original scriptPubKey had only the Hash160 hash of the public # key, not the public key itself, and the redeem script can be entirely # re-constructed (from implicit template) if given just the public key. So the # public key is added to the witness. This is P2WPKH in bip141. witness = [signature, public_key] # Aggregate all of the witnesses together, and then assign them to the # transaction object. ctxinwitnesses = [CTxInWitness(CScriptWitness(witness))] tx.wit = CTxWitness(ctxinwitnesses) # Broadcast the transaction to the regtest network. spend_txid = connection.sendrawtransaction(tx) # Done! Print the transaction to standard output. Show the transaction # serialization in hex (instead of bytes), and render the txid. print("serialized transaction: {}".format(b2x(tx.serialize()))) print("txid: {}".format(b2lx(spend_txid)))
def issue_op_return(conf, op_return_bstring): print('\nConfigured values are:\n') print('working_directory:\t{}'.format(conf.working_directory)) print('issuing_address:\t{}'.format(conf.issuing_address)) print('full_node_url:\t\t{}'.format(conf.full_node_url)) print('full_node_rpc_user:\t{}'.format(conf.full_node_rpc_user)) print('testnet:\t\t{}'.format(conf.testnet)) print('tx_fee_per_byte:\t{}'.format(conf.tx_fee_per_byte)) print('Bytes for OP_RETURN:\n{}'.format(op_return_bstring)) print('Hex for OP_RETURN:\n{}'.format(binascii.hexlify(op_return_bstring))) op_return_cert_protocol = op_return_bstring consent = input('Do you want to continue? [y/N]: ').lower() in ('y', 'yes') if not consent: sys.exit() full_node_rpc_password = getpass.getpass( '\nPlease enter the password for the node\'s RPC user: '******'testnet') else: SelectParams('mainnet') proxy = Proxy("http://{0}:{1}@{2}".format(conf.full_node_rpc_user, full_node_rpc_password, conf.full_node_url)) # create transaction tx_outputs = [] unspent = sorted(proxy.listunspent(1, 9999999, [conf.issuing_address]), key=lambda x: hash(x['amount']), reverse=True) issuing_pubkey = proxy.validateaddress(conf.issuing_address)['pubkey'] tx_inputs = [CMutableTxIn(unspent[0]['outpoint'])] input_amount = unspent[0]['amount'] change_script_out = CBitcoinAddress(conf.issuing_address).to_scriptPubKey() change_output = CMutableTxOut(input_amount, change_script_out) op_return_output = CMutableTxOut( 0, CScript([OP_RETURN, op_return_cert_protocol])) tx_outputs = [change_output, op_return_output] tx = CMutableTransaction(tx_inputs, tx_outputs) # sign transaction to get its size r = proxy.signrawtransaction(tx) assert r['complete'] signed_tx = r['tx'] signed_tx_size = len(signed_tx.serialize()) # calculate fees and change tx_fee = signed_tx_size * conf.tx_fee_per_byte change_amount = input_amount - tx_fee if (change_amount < 0): sys.exit( "Specified address cannot cover the transaction fee of: {} satoshis" .format(tx_fee)) # update tx out for change and re-sign tx.vout[0].nValue = change_amount r = proxy.signrawtransaction(tx) assert r['complete'] signed_tx = r['tx'] # send transaction print('The fee will be {} satoshis.\n'.format(tx_fee)) consent = input( 'Do you want to issue on the blockchain? [y/N]: ').lower() in ('y', 'yes') if not consent: sys.exit() tx_id = b2lx(proxy.sendrawtransaction(signed_tx)) return tx_id