def segwit_signature_form(tx, i, script, amount, hashcode=SIGHASH_ALL, fork_id=None): d = deserialize(tx) def parse_vout(o): return b''.join([struct.pack('<Q', o['value']), struct.pack('B', len(o['script']) // 2), binascii.unhexlify(o['script'])]) def parse_vin(inp): return b''.join([binascii.unhexlify(inp['outpoint']['hash'])[::-1], struct.pack('<I', (inp['outpoint']['index']))]) vin_outpoint = [binascii.unhexlify(d['ins'][i]['outpoint']['hash'])[::-1], struct.pack('<I', (d['ins'][i]['outpoint']['index']))] hashcode_strategy = get_hashcode_strategy(hashcode) outpoints = [parse_vin(inp) for inp in hashcode_strategy.get_inputs_for_sequences(d, i)] sequences = hashcode_strategy.get_sequences(d, i) outputs_to_sign = hashcode_strategy.get_outputs(d, i) outputs = [parse_vout(out) for out in outputs_to_sign] hash_outputs = hashlib.sha256(hashlib.sha256(b''.join(outputs)).digest()).digest() if outputs_to_sign else b'\x00'*32 hash_sequences = hashlib.sha256(hashlib.sha256(b''.join(sequences)).digest()).digest() if sequences else b'\x00'*32 hash_outpoints = hashlib.sha256(hashlib.sha256(b''.join(outpoints)).digest()).digest() if outpoints else b'\x00'*32 hashcode = fork_id != None and (int(fork_id) | hashcode) or hashcode preimage = [struct.pack('<I', d['version']), hash_outpoints, hash_sequences, b''.join(vin_outpoint), struct.pack('B', len(script) // 2), binascii.unhexlify(script), struct.pack('<Q', amount), struct.pack('<I', d['ins'][i]['sequence']), hash_outputs, struct.pack('<I', d['locktime']), struct.pack('<I', hashcode)] return binascii.hexlify(b''.join(preimage)).decode('ascii')
def payto(self, destination, amount, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False, broadcast=False): """Create a transaction. """ domain = [from_addr] if from_addr else None tx = self._mktx([(destination, amount)], tx_fee, change_addr, domain, nocheck, unsigned) if broadcast: r, h = self.wallet.sendtx(tx) return h else: return deserialize(tx) if deserialized else tx
def gettransaction(self, txid, deserialized=False): """Retrieve a transaction. """ tx = self.wallet.transactions.get(txid) if self.wallet else None if tx is None and self.network: raw = self.network.synchronous_get([('blockchain.transaction.get', [txid])])[0] if raw: tx = Transaction.deserialize(raw) else: raise BaseException("Unknown transaction") return deserialize(tx) if deserialized else tx
def paytomany(self, csv_file, tx_fee=None, from_addr=None, change_addr=None, nocheck=False, unsigned=False, deserialized=False, broadcast=False): """Create a multi-output transaction. """ domain = [from_addr] if from_addr else None outputs = self._read_csv(csv_file) tx = self._mktx(outputs, tx_fee, change_addr, domain, nocheck, unsigned) if broadcast: r, h = self.wallet.sendtx(tx) return h else: return deserialize(tx) if deserialized else tx
def apply_segwit_multisignatures(tx, i, witness_program, signatures, dummy=True, nested=False): o = [""] + signatures + [witness_program] if dummy else signatures + [witness_program] txobj = deserialize(tx) txobj['ins'][i]['txinwitness'] = o if nested: redeem_script = hashlib.sha256(binascii.unhexlify( witness_program )).hexdigest() length = len(redeem_script) // 2 redeem_script = serialize_script( [length + 2, None, redeem_script]) txobj["ins"][i]["script"] = redeem_script return serialize(txobj)
def apply_multisignatures(*args): # tx,i,script,sigs OR tx,i,script,sig1,sig2...,sig[n] tx, i, script = args[0], int(args[1]), args[2] sigs = args[3] if isinstance(args[3], list) else list(args[3:]) if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): script = binascii.unhexlify(script) sigs = [binascii.unhexlify(x) if x[:2] == '30' else x for x in sigs] if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): signed_tx = apply_multisignatures(binascii.unhexlify(tx), i, script, sigs) return binascii.hexlify(signed_tx).decode() # Not pushing empty elements on the top of the stack if passing no # script (in case of bare multisig inputs there is no script) script_blob = [] if script.__len__() == 0 else [script] txobj = deserialize(tx) txobj["ins"][i]["script"] = serialize_script([None]+sigs+script_blob) return serialize(txobj)
def segwit_sign(tx, i, priv, amount, hashcode=SIGHASH_ALL, script=None, separator_index=None): i = int(i) txobj = tx if isinstance(tx, dict) else deserialize(tx) if not isinstance(tx, dict) and ((not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx)): return binascii.unhexlify(sign(binascii.hexlify(tx), i, priv)) if len(priv) <= 33: priv = binascii.hexlify(priv) pub = privkey_to_pubkey(priv) address = pubkey_to_address(pub) wscript = mk_pubkey_script(address) if not script else script stripped_script = segwit_strip_script_separator(wscript, separator_index) signing_tx = segwit_signature_form(tx, i, stripped_script, amount, hashcode=hashcode) rawsig = ecdsa_raw_sign(hashlib.sha256(hashlib.sha256(binascii.unhexlify(signing_tx)).digest()).hexdigest(), priv) sig = der_encode_sig(*rawsig)+encode(hashcode, 16, 2) if (hashcode & SIGHASH_FORKID): txobj['ins'][i]['script'] = serialize_script([sig, pub if not script else script]) else: txobj['ins'][i]['txinwitness'] = [sig, pub if not script else script] return serialize(txobj)
def strip_witness_data(tx): tx = deserialize(tx) tx.pop('segwit', '') for inp in tx['ins']: inp.pop('txinwitness', '') return serialize(tx)
def deserialize(self, tx): """Deserialize a serialized transaction.""" return deserialize(tx)