def add_signature(self, sigb64): sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False txhex = btc.serialize(self.latest_tx) #batch retrieval of utxo data utxo = {} ctr = 0 for index, ins in enumerate(self.latest_tx['ins']): utxo_for_checking = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if ins['script'] != '' or utxo_for_checking in self.input_utxos.keys(): continue utxo[ctr] = [index, utxo_for_checking] ctr += 1 utxo_data = common.bc_interface.query_utxo_set([x[1] for x in utxo.values()]) #insert signatures for i,u in utxo.iteritems(): if utxo_data[i] == None: continue sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (u[0])) self.latest_tx['ins'][u[0]]['script'] = sig inserted_sig = True break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return debug('the entire tx is signed, ready to pushtx()') txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) #TODO send to a random maker or push myself #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) self.txid = common.bc_interface.pushtx(txhex) debug('pushed tx ' + str(self.txid)) if self.txid == None: debug('unable to pushtx') if self.finishcallback != None: self.finishcallback(self)
def normalize_transaction(tx): _tx = deserialize(tx) _tx['segwit'] = True for i, vin in enumerate(_tx['ins']): if vin.get('txinwitness', '0' * 64) == '0' * 64: _tx['ins'][i]['txinwitness'] = '' return serialize(_tx)
def to_rawtx(tx): """ Take a tx object in the moneywagon format and convert it to the format that pybitcointools's `serialize` funcion takes, then return in raw hex format. """ if tx.get('hex'): return tx['hex'] new_tx = {} locktime = tx.get('locktime', 0) new_tx['locktime'] = locktime new_tx['version'] = tx.get('version', 1) new_tx['ins'] = [ { 'outpoint': {'hash': str(x['txid']), 'index': x['n']}, 'script': str(x['scriptSig'].replace(' ', '')), 'sequence': x.get('sequence', 0xFFFFFFFF if locktime == 0 else None) } for x in tx['inputs'] ] new_tx['outs'] = [ { 'script': str(x['scriptPubKey']), 'value': x['amount'] } for x in tx['outputs'] ] return serialize(new_tx)
def test_native_P2WSH_SIGHASH_SINGLE_ANYONECANPAY(self): tx = TEST_CASES[2] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][1]['privkey']) partially_signed = segwit_sign(generated_tx, 0, priv0, int(0.16777215 * 10**8), hashcode=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, script=tx['ins'][0]['txinwitness'][1]) signed = segwit_sign(partially_signed, 1, priv0, int(0.16777215 * 10**8), hashcode=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, script=tx['ins'][1]['txinwitness'][1], separator_index=tx['ins'][1]['separator']) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
def push(self): tx = btc.serialize(self.latest_tx) log.debug('\n' + tx) self.txid = btc.txhash(tx) log.debug('txid = ' + self.txid) tx_broadcast = jm_single().config.get('POLICY', 'tx_broadcast') if tx_broadcast == 'self': pushed = jm_single().bc_interface.pushtx(tx) elif tx_broadcast in ['random-peer', 'not-self']: n = len(self.active_orders) if tx_broadcast == 'random-peer': i = random.randrange(n + 1) else: i = random.randrange(n) if i == n: pushed = jm_single().bc_interface.pushtx(tx) else: self.msgchan.push_tx(self.active_orders.keys()[i], tx) pushed = True elif tx_broadcast == 'random-maker': crow = self.db.execute( 'SELECT DISTINCT counterparty FROM orderbook ORDER BY ' + 'RANDOM() LIMIT 1;' ).fetchone() counterparty = crow['counterparty'] log.debug('pushing tx to ' + counterparty) self.msgchan.push_tx(counterparty, tx) pushed = True if not pushed: log.debug('unable to pushtx') return pushed
def sign_donation_tx(tx, i, priv): from bitcoin.main import fast_multiply, decode_privkey, G, inv, N from bitcoin.transaction import der_encode_sig k = sign_k hashcode = btc.SIGHASH_ALL i = int(i) if len(priv) <= 33: priv = btc.safe_hexlify(priv) pub = btc.privkey_to_pubkey(priv) address = btc.pubkey_to_address(pub) signing_tx = btc.signature_form(tx, i, btc.mk_pubkey_script(address), hashcode) msghash = btc.bin_txhash(signing_tx, hashcode) z = btc.hash_to_int(msghash) # k = deterministic_generate_k(msghash, priv) r, y = fast_multiply(G, k) s = inv(k, N) * (z + r * decode_privkey(priv)) % N rawsig = 27 + (y % 2), r, s sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = btc.deserialize(tx) txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) return btc.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) txobj['ins'][i]['txinwitness'] = [sig, pub if not script else script] return serialize(txobj)
def push(self): tx = btc.serialize(self.latest_tx) log.debug('\n' + tx) self.txid = btc.txhash(tx) log.debug('txid = ' + self.txid) tx_broadcast = jm_single().config.get('POLICY', 'tx_broadcast') if tx_broadcast == 'self': pushed = jm_single().bc_interface.pushtx(tx) elif tx_broadcast in ['random-peer', 'not-self']: n = len(self.active_orders) if tx_broadcast == 'random-peer': i = random.randrange(n + 1) else: i = random.randrange(n) if i == n: pushed = jm_single().bc_interface.pushtx(tx) else: self.msgchan.push_tx(self.active_orders.keys()[i], tx) pushed = True elif tx_broadcast == 'random-maker': crow = self.db.execute( 'SELECT DISTINCT counterparty FROM orderbook ORDER BY ' + 'RANDOM() LIMIT 1;').fetchone() counterparty = crow['counterparty'] log.debug('pushing tx to ' + counterparty) self.msgchan.push_tx(counterparty, tx) pushed = True if not pushed: log.debug('unable to pushtx') return pushed
def sign_donation_tx(tx, i, priv): from bitcoin.main import fast_multiply, decode_privkey, G, inv, N from bitcoin.transaction import der_encode_sig k = sign_k hashcode = btc.SIGHASH_ALL i = int(i) if len(priv) <= 33: priv = btc.safe_hexlify(priv) pub = btc.privkey_to_pubkey(priv) address = btc.pubkey_to_address(pub) signing_tx = btc.signature_form( tx, i, btc.mk_pubkey_script(address), hashcode) msghash = btc.bin_txhash(signing_tx, hashcode) z = btc.hash_to_int(msghash) # k = deterministic_generate_k(msghash, priv) r, y = fast_multiply(G, k) s = inv(k, N) * (z + r * decode_privkey(priv)) % N rawsig = 27 + (y % 2), r, s sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = btc.deserialize(tx) txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) return btc.serialize(txobj)
def sign(tx, i, priv, t="default", script="", hashcode=SIGHASH_ALL): i = int(i) #if (not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx): if not re.match('^[0-9a-fA-F]*$', tx): return binascii.unhexlify( custom_sign(safe_hexlify(tx), i, priv, hashcode)) if len(priv) <= 33: priv = b.safe_hexlify(priv) pub = b.privkey_to_pubkey(priv) address = b.pubkey_to_address(pub) if t not in ["atomic_1", "atomic_2"]: script = b.mk_pubkey_script(address) if script == "": error() signing_tx = b.signature_form( tx, i, script, hashcode) #mk_pubkey_scrip needs to be our custom scriptn sig = b.ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = b.deserialize(tx) if t == "atomic_1": txobj["ins"][i]["script"] = b.serialize_script([sig]) if t == "atomic_2": old_sig = txobj["ins"][i]["script"] txobj["ins"][i]["script"] = b.serialize_script([old_sig, sig, 1]) else: txobj["ins"][i]["script"] = b.serialize_script([sig, pub]) return b.serialize(txobj)
def test_native_P2WSH_SIGHASH_SINGLE_ANYONECANPAY(self): tx = TEST_CASES[2] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][1]['privkey']) partially_signed = segwit_sign(generated_tx, 0, priv0, int(0.16777215 * 10**8), hashcode=SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, script=tx['ins'][0]['txinwitness'][1]) signed = segwit_sign(partially_signed, 1, priv0, int(0.16777215 * 10 ** 8), hashcode=SIGHASH_SINGLE|SIGHASH_ANYONECANPAY, script=tx['ins'][1]['txinwitness'][1], separator_index=tx['ins'][1]['separator']) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
def main(): locktime = args.locktime privkey = args.privkey address = args.address script = getRedeemScript(locktime, privkey) ins, balance = getBalance(scriptaddr(script, 50)) len_inputs = len(ins) tx = '' if balance > 0 and check_addr(address) and is_privkey(privkey): # Fee fee = round(base_fee + fee_per_input * len_inputs, 8) # Outputs out_value = int((balance - fee) * COIN) outs = [{'address' : address, 'value' : out_value}] # Make unsigned transaction tx = mktx(ins, outs) # Append nLockTime and reset nSequence unpacked = deserialize(tx) unpacked['locktime'] = locktime for i in range(len_inputs): unpacked['ins'][i]['sequence'] = 0 tx = serialize(unpacked) # get all signatures sigs = [] for i in range(len_inputs): sigs.append(multisign(tx, i, script, privkey)) # sign inputs unpacked = deserialize(tx) for i in range(len_inputs): unpacked['ins'][i]['script'] = getLen(sigs[i]) + sigs[i] unpacked['ins'][i]['script'] += getLen(script) + script tx = serialize(unpacked) print('> BALANCE (%s): %f' % (scriptaddr(script, 50), balance)) if len(tx) > 0: txid = broadcast(tx) print('> RESPONSE: %s' % txid.text)
def tx_serialize( tx ): """ Convert a bitcoin-given transaction into its hex string. tx format is {'vin': [...], 'vout': [...], 'locktime': ..., 'version': ...}, with the same formatting rules as getrawtransaction. (in particular, each value in vout is a Decimal, in BTC) """ tx_ins = [] tx_outs = [] try: for inp in tx['vin']: next_inp = { "outpoint": { "index": int(inp['vout']), "hash": str(inp['txid']) } } if 'sequence' in inp: next_inp['sequence'] = int(inp['sequence']) else: next_inp['sequence'] = pybitcoin.UINT_MAX if 'scriptSig' in inp: next_inp['script'] = str(inp['scriptSig']['hex']) else: next_inp['script'] = "" tx_ins.append(next_inp) for out in tx['vout']: assert out['value'] < 1000, "High transaction value\n%s" % simplejson.dumps(tx, indent=4, sort_keys=True) next_out = { 'value': int(Decimal(out['value']) * Decimal(10**8)), 'script': str(out['scriptPubKey']['hex']) } tx_outs.append(next_out) tx_fields = { "locktime": int(tx['locktime']), "version": int(tx['version']), "ins": tx_ins, "outs": tx_outs } tx_serialized = bitcoin.serialize( tx_fields ) return str(tx_serialized) except KeyError, ke: if tx_is_coinbase(tx) and 'hex' in tx.keys(): tx_serialized = tx['hex'] return str(tx_serialized) import simplejson log.error("Key error in :\n%s" % simplejson.dumps(tx, indent=4, sort_keys=True)) traceback.print_exc() raise ke
def on_peer_announce(tx): txhash = bitcoin.txhash(bitcoin.serialize(tx["tx"])) if txhash in self.subscriptions[address][0] and self.subscriptions[address][0][txhash][0] != "complete": self.subscriptions[address][0][txhash][0] += 1 if self.subscriptions[address][0][txhash][0] >= self.subscriptions[address][0][txhash][1]: self.subscriptions[address][0][txhash][0] = "complete" self.subscriptions[address][1](tx["tx"]) elif txhash not in self.subscriptions[address][0]: self.subscriptions[address][0][txhash] = [1, len(self.peers)/2]
def self_sign_and_push(self): #now sign it ourselves tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if utxo not in self.input_utxos.keys(): continue addr = self.input_utxos[utxo]['address'] tx = btc.sign(tx, index, self.wallet.get_key_from_addr(addr)) txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) debug('txid = ' + btc.txhash(tx)) #TODO send to a random maker or push myself #TODO need to check whether the other party sent it #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) self.txid = common.bc_interface.pushtx(tx) if self.txid == None: debug('unable to pushtx')
def add_signature(self, nick, sigb64): if nick not in self.nonrespondants: debug('add_signature => nick=' + nick + ' not in nonrespondants ' + str(self.nonrespondants)) return sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False txhex = btc.serialize(self.latest_tx) #batch retrieval of utxo data utxo = {} ctr = 0 for index, ins in enumerate(self.latest_tx['ins']): utxo_for_checking = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if ins['script'] != '' or utxo_for_checking in self.input_utxos.keys(): continue utxo[ctr] = [index, utxo_for_checking] ctr += 1 utxo_data = common.bc_interface.query_utxo_set([x[1] for x in utxo.values()]) #insert signatures for i,u in utxo.iteritems(): if utxo_data[i] == None: continue sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (u[0])) self.latest_tx['ins'][u[0]]['script'] = sig inserted_sig = True #check if maker has sent everything possible self.utxos[nick].remove(u[1]) if len(self.utxos[nick]) == 0: debug('nick = ' + nick + ' sent all sigs, removing from nonrespondant list') self.nonrespondants.remove(nick) break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return self.end_timeout_thread = True self.all_responded = True with self.timeout_lock: self.timeout_lock.notify() debug('all makers have sent their signatures') for index, ins in enumerate(self.latest_tx['ins']): #remove placeholders if ins['script'] == 'deadbeef': ins['script'] = '' if self.finishcallback != None: self.finishcallback(self)
def push(self, txd): tx = btc.serialize(txd) debug('\n' + tx) debug('txid = ' + btc.txhash(tx)) #TODO send to a random maker or push myself #TODO need to check whether the other party sent it #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) self.txid = common.bc_interface.pushtx(tx) if self.txid == None: debug('unable to pushtx')
def reorder_sigs( self, sigs ): reorderedSigs = [] stx = bitcoin.serialize( self.tx ) for pub in self.pubs: for sig in sigs: if bitcoin.verify_tx_input( stx, 0, self.redeemScript, sig, pub ): reorderedSigs.append( sig ) break return reorderedSigs
def self_sign(self): #now sign it ourselves tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if utxo not in self.input_utxos.keys(): continue addr = self.input_utxos[utxo]['address'] tx = self.sign_tx(tx, index, self.wallet.get_key_from_addr(addr)) self.latest_tx = btc.deserialize(tx)
def finishcallback(self, coinjointx): if coinjointx.all_responded: tx = btc.serialize(coinjointx.latest_tx) print 'unsigned tx = \n\n' + tx + '\n' log.debug('created unsigned tx, ending') self.taker.msgchan.shutdown() return self.ignored_makers += coinjointx.nonrespondants log.debug('recreating the tx, ignored_makers=' + str( self.ignored_makers)) self.create_tx()
def tx_serialize( inputs, outputs, locktime, version ): """ Given (possibly signed) inputs and outputs, convert them into a hex string. Each input must have: * transaction_hash: string * output_index: int * [optional] sequence: int * [optional] script_sig: str Each output must have: * value: int * script_hex: string """ tmp_inputs = [] tmp_outputs = [] # convert to a format bitcoin understands for inp in inputs: tmp_inp = { "outpoint": { "index": inp["output_index"], "hash": inp["transaction_hash"] } } if "sequence" in inp: tmp_inp["sequence"] = inp["sequence"] else: tmp_inp["sequence"] = pybitcoin.UINT_MAX if "script_sig" in inp: tmp_inp["script"] = inp["script_sig"] else: tmp_inp["script"] = "" tmp_inputs.append( tmp_inp ) for out in outputs: tmp_out = { "value": out["value"], "script": out["script_hex"] } tmp_outputs.append( tmp_out ) txobj = { "locktime": locktime, "version": version, "ins": tmp_inputs, "outs": tmp_outputs } return bitcoin.serialize( txobj )
def finishcallback(self, coinjointx): if coinjointx.all_responded: tx = btc.serialize(coinjointx.latest_tx) print 'unsigned tx = \n\n' + tx + '\n' log.debug('created unsigned tx, ending') self.taker.msgchan.shutdown() return self.ignored_makers += coinjointx.nonrespondants log.debug('recreating the tx, ignored_makers=' + str(self.ignored_makers)) self.create_tx()
def self_sign(self): #now sign it ourselves tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) if utxo not in self.input_utxos.keys(): continue addr = self.input_utxos[utxo]['address'] tx = self.sign_tx(tx, index, self.wallet.get_key_from_addr(addr)) self.latest_tx = btc.deserialize(tx)
def add_signature(self, sigb64): sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): if ins['script'] != '': continue utxo = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) utxo_data = common.bc_interface.query_utxo_set(utxo) if utxo_data[0] == None: continue sig_good = btc.verify_tx_input(tx, index, utxo_data[0]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (index)) ins['script'] = sig inserted_sig = True break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return debug('the entire tx is signed, ready to pushtx()') txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) #TODO send to a random maker or push myself #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) txid = common.bc_interface.pushtx(txhex) debug('pushed tx ' + str(txid)) if self.finishcallback != None: self.finishcallback(self)
def atomic(peer_pub, wallet, to, send, receive, secret_hash): tx1=mk_spend(wallet, to, send)#puts your money into the channel. tx=b.deserialize(tx1) script="6352"+serialize(peer_pub)+serialize(wallet["pub"])+"52af67aa"+serialize(secret_hash)+"87"+serialize(peer_pub)+"ad68" print("script: " +str(script)) tx['outs'][0]['script']=script tx=b.serialize(tx) txd=txid(tx) txd={'output':(txd+':1'), 'block_height':None, 'value':send, 'address':wallet['address']} refund_tx=mk_spend_txids(wallet, wallet["address"], send-fee, [txd]) return {"refund": refund_tx, "channel": tx, "script":script}
def test_native_P2WSH_SIGHASH_SINGLE(self): tx = TEST_CASES[1] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) partially_signed = p2pk_sign(stripped_tx, 0, self.append_compressed_flag_to_privkey( tx['ins'][0]['privkey']), hashcode=SIGHASH_ALL) priv0 = self.append_compressed_flag_to_privkey( tx['ins'][1]['privkeys'][0]) priv1 = self.append_compressed_flag_to_privkey( tx['ins'][1]['privkeys'][1]) pub0 = privtopub(priv0) pub1 = privtopub(priv1) REDEEM_SCRIPT_STRUCTURE = { 'keys': [pub0, pub1], 'schema': [{ 'reqs': 1, 'keys': [0], }, { 'reqs': 1, 'keys': [1], }] } witness_script = mk_OPCS_multisig_script(REDEEM_SCRIPT_STRUCTURE) sign1 = segwit_multisign(partially_signed, 1, witness_script, priv0, 49 * 10**8, hashcode=SIGHASH_SINGLE) sign2 = segwit_multisign(partially_signed, 1, witness_script, priv1, 49 * 10**8, hashcode=SIGHASH_SINGLE, separator_index=1) signed = apply_segwit_multisignatures(partially_signed, 1, witness_script, [sign2, sign1], dummy=False) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
def test_native_P2WSH_SIGHASH_SINGLE(self): tx = TEST_CASES[1] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) partially_signed = p2pk_sign(stripped_tx, 0, self.append_compressed_flag_to_privkey(tx['ins'][0]['privkey']), hashcode=SIGHASH_ALL) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][1]['privkeys'][0]) priv1 = self.append_compressed_flag_to_privkey(tx['ins'][1]['privkeys'][1]) pub0 = privtopub(priv0) pub1 = privtopub(priv1) REDEEM_SCRIPT_STRUCTURE = { 'keys': [ pub0, pub1 ], 'schema': [ { 'reqs': 1, 'keys': [0], }, { 'reqs': 1, 'keys': [1], } ] } witness_script = mk_OPCS_multisig_script(REDEEM_SCRIPT_STRUCTURE) sign1 = segwit_multisign(partially_signed, 1, witness_script, priv0, 49 * 10**8, hashcode=SIGHASH_SINGLE) sign2 = segwit_multisign(partially_signed, 1, witness_script, priv1, 49 * 10 ** 8, hashcode=SIGHASH_SINGLE, separator_index=1) signed = apply_segwit_multisignatures(partially_signed, 1, witness_script, [sign2, sign1], dummy=False) self.assertEqual(signed, tx['signed']) print('[Native P2WSH] SIGHASH_SINGLE OK')
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 push(self, txd): tx = btc.serialize(txd) log.debug('\n' + tx) log.debug('txid = ' + btc.txhash(tx)) # TODO send to a random maker or push myself # TODO need to check whether the other party sent it # self.msgchan.push_tx(self.active_orders.keys()[0], txhex) pushed = jm_single().bc_interface.pushtx(tx) if pushed[0]: self.txid = btc.txhash(tx) else: log.debug('unable to pushtx, reason: '+str(pushed[1])) return pushed[0]
def add_signature(self, sigb64): sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): if ins['script'] != '': continue utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) utxo_data = common.bc_interface.query_utxo_set(utxo) if utxo_data[0] == None: continue sig_good = btc.verify_tx_input(tx, index, utxo_data[0]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (index)) ins['script'] = sig inserted_sig = True break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return debug('the entire tx is signed, ready to pushtx()') txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) #TODO send to a random maker or push myself #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) txid = common.bc_interface.pushtx(txhex) debug('pushed tx ' + str(txid)) if self.finishcallback != None: self.finishcallback(self)
def on_peer_announce(tx): txhash = bitcoin.txhash(bitcoin.serialize(tx["tx"])) if txhash in self.subscriptions[address][0] and self.subscriptions[ address][0][txhash][0] != "complete": self.subscriptions[address][0][txhash][0] += 1 if self.subscriptions[address][0][txhash][ 0] >= self.subscriptions[address][0][txhash][1]: self.subscriptions[address][0][txhash][0] = "complete" self.subscriptions[address][1](tx["tx"]) elif txhash not in self.subscriptions[address][0]: self.subscriptions[address][0][txhash] = [ 1, len(self.peers) / 2 ]
def push(self, txd): tx = btc.serialize(txd) log.debug('\n' + tx) log.debug('txid = ' + btc.txhash(tx)) # TODO send to a random maker or push myself # TODO need to check whether the other party sent it # self.msgchan.push_tx(self.active_orders.keys()[0], txhex) pushed = jm_single().bc_interface.pushtx(tx) if pushed[0]: self.txid = pushed[1] else: log.debug('unable to pushtx, reason: ' + str(pushed[1])) return pushed[0]
def apply_segwit_multisignatures(tx, i, witness_program, signatures, dummy=True, nested=False): txobj = deserialize(tx) signed = apply_segwit_multisignatures_deserialized_data(txobj, i, witness_program, signatures, dummy=dummy, nested=nested) return serialize(signed)
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) txobj['ins'][i]['txinwitness'] = [sig, pub if not script else script] return serialize(txobj)
def finishcallback(self, coinjointx): if coinjointx.all_responded: #now sign it ourselves tx = btc.serialize(coinjointx.latest_tx) for index, ins in enumerate(coinjointx.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if utxo != self.taker.auth_utxo: continue addr = coinjointx.input_utxos[utxo]['address'] tx = btc.sign(tx, index, coinjointx.wallet.get_key_from_addr(addr)) print 'unsigned tx = \n\n' + tx + '\n' debug('created unsigned tx, ending') self.taker.msgchan.shutdown() return self.ignored_makers += coinjointx.nonrespondants debug('recreating the tx, ignored_makers=' + str(self.ignored_makers)) self.create_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 test_serialization_roundtrip2(): #Data extracted from: #https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json #These are a variety of rather strange edge case transactions, which are #still valid. #Note that of course this is only a serialization, not validity test, so #only currently of very limited significance with open("test/tx_valid.json", "r") as f: json_data = f.read() valid_txs = json.loads(json_data) for j in valid_txs: #ignore comment entries if len(j) < 2: continue print j deserialized = btc.deserialize(str(j[0])) print deserialized assert j[0] == btc.serialize(deserialized)
def atomic(peer_pub, wallet, to, send, receive, secret_hash): tx1 = mk_spend(wallet, to, send) #puts your money into the channel. tx = b.deserialize(tx1) script = "6352" + serialize(peer_pub) + serialize( wallet["pub"]) + "52af67aa" + serialize( secret_hash) + "87" + serialize(peer_pub) + "ad68" print("script: " + str(script)) tx['outs'][0]['script'] = script tx = b.serialize(tx) txd = txid(tx) txd = { 'output': (txd + ':1'), 'block_height': None, 'value': send, 'address': wallet['address'] } refund_tx = mk_spend_txids(wallet, wallet["address"], send - fee, [txd]) return {"refund": refund_tx, "channel": tx, "script": script}
def finishcallback(self, coinjointx): if coinjointx.all_responded: #now sign it ourselves tx = btc.serialize(coinjointx.latest_tx) for index, ins in enumerate(coinjointx.latest_tx['ins']): utxo = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) if utxo != self.taker.auth_utxo: continue addr = coinjointx.input_utxos[utxo]['address'] tx = btc.sign(tx, index, coinjointx.wallet.get_key_from_addr(addr)) print 'unsigned tx = \n\n' + tx + '\n' debug('created unsigned tx, ending') self.taker.msgchan.shutdown() return self.ignored_makers += coinjointx.nonrespondants debug('recreating the tx, ignored_makers=' + str(self.ignored_makers)) self.create_tx()
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) # 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 tx_to_hex(tx): """ Convert a bitcoin-given transaction into its hex string. Does NOT work on coinbase transactions. """ tx_ins = [] tx_outs = [] for inp in tx['vin']: next_inp = { "outpoint": { "index": int(inp['vout']), "hash": str(inp['txid']) } } if 'sequence' in inp: next_inp['sequence'] = int(inp['sequence']) else: next_inp['sequence'] = pybitcoin.UINT_MAX if 'scriptSig' in inp: next_inp['script'] = str(inp['scriptSig']['hex']) else: next_inp['script'] = "" tx_ins.append(next_inp) for out in tx['vout']: next_out = { 'value': int(round(Decimal(out['value']) * Decimal(10**8))), 'script': str(out['scriptPubKey']['hex']) } tx_outs.append(next_out) tx_fields = { "locktime": int(tx['locktime']), "version": int(tx['version']), "ins": tx_ins, "outs": tx_outs } tx_serialized = bitcoin.serialize(tx_fields) return str(tx_serialized)
def tx_to_hex( tx ): """ Convert a bitcoin-given transaction into its hex string. Does NOT work on coinbase transactions. """ tx_ins = [] tx_outs = [] for inp in tx['vin']: next_inp = { "outpoint": { "index": int(inp['vout']), "hash": str(inp['txid']) } } if 'sequence' in inp: next_inp['sequence'] = int(inp['sequence']) else: next_inp['sequence'] = pybitcoin.UINT_MAX if 'scriptSig' in inp: next_inp['script'] = str(inp['scriptSig']['hex']) else: next_inp['script'] = "" tx_ins.append(next_inp) for out in tx['vout']: next_out = { 'value': int(round(Decimal(out['value']) * Decimal(10**8))), 'script': str(out['scriptPubKey']['hex']) } tx_outs.append(next_out) tx_fields = { "locktime": int(tx['locktime']), "version": int(tx['version']), "ins": tx_ins, "outs": tx_outs } tx_serialized = bitcoin.serialize( tx_fields ) return str(tx_serialized)
def test_native_P2WPKH_SIGHASH_ALL(self): tx = TEST_CASES[0] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs, locktime=tx['locktime']) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) partially_signed = p2pk_sign( stripped_tx, 0, self.append_compressed_flag_to_privkey(tx['ins'][0]['privkey'])) signed = segwit_sign( partially_signed, 1, self.append_compressed_flag_to_privkey(tx['ins'][1]['privkey']), tx['ins'][1]['amount'] * 10**8) self.assertEqual(signed, tx['signed']) print('[Native P2WPKH] SIGHASH_ALL OK')
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) # 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 test_native_P2WPKH_SIGHASH_ALL(self): tx = TEST_CASES[0] deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs, locktime=tx['locktime']) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) partially_signed = p2pk_sign(stripped_tx, 0, self.append_compressed_flag_to_privkey(tx['ins'][0]['privkey'])) signed = segwit_sign(partially_signed, 1, self.append_compressed_flag_to_privkey(tx['ins'][1]['privkey']), tx['ins'][1]['amount'] * 10**8) self.assertEqual(signed, tx['signed']) print('[Native P2WPKH] SIGHASH_ALL OK')
def bech32_sign(tx, i, priv, amount, script=None, hashcode=SIGHASH_ALL): from bitcoin import deserialize, segwit_signature_form, ecdsa_raw_sign, der_encode_sig, serialize, compress i = int(i) txobj = tx if isinstance(tx, dict) else deserialize(tx) if len(priv) <= 33: priv = binascii.hexlify(priv) pub = compress(privkey_to_pubkey(priv)) script = script or ('76a914' + hash160(binascii.unhexlify(pub)) + '88ac') signing_tx = segwit_signature_form(tx, i, 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) txobj['ins'][i]['txinwitness'] = [sig, pub] return serialize(txobj)
def sign( self, privkey ): if( self.tx is None or self.redeemScript is None ): raise RuntimeError( "You have not entered in a tx to sign" ) try: pub = bitcoin.privtopub( privkey ) if pub not in self.pubs: pub = bitcoin.encode_pubkey( pub, 'hex_compressed' ) if pub not in self.pubs: raise ValueError( "Key doesn't match any public keys in redeemscript" ) stx = bitcoin.serialize( self.tx ) sigs = self.extract_sigs( self.tx ) sigs.append( bitcoin.multisign( stx, 0, self.redeemScript, privkey ) ) sigs = self.reorder_sigs( sigs ) stx = bitcoin.apply_multisignatures( stx, 0, self.redeemScript, sigs ) return stx, ( len(sigs) >= self.neededSigs ) except ValueError as e: raise RuntimeError( "Key Error", str( e ) ) except Exception as e: raise RuntimeError( "Unexpected Error", "Unexpected error formating key: " + str( e ) )
def push(self): tx = btc.serialize(self.latest_tx) log.debug('\n' + tx) self.txid = btc.txhash(tx) log.info('txid = ' + self.txid) tx_broadcast = jm_single().config.get('POLICY', 'tx_broadcast') if tx_broadcast == 'self': pushed = jm_single().bc_interface.pushtx(tx) elif tx_broadcast in ['random-peer', 'not-self']: n = len(self.active_orders) if tx_broadcast == 'random-peer': i = random.randrange(n + 1) else: i = random.randrange(n) if i == n: pushed = jm_single().bc_interface.pushtx(tx) else: self.msgchan.push_tx(self.active_orders.keys()[i], tx) pushed = True elif tx_broadcast == 'random-maker': crow = self.db.execute( 'SELECT DISTINCT counterparty FROM orderbook ORDER BY ' + 'RANDOM() LIMIT 1;' ).fetchone() counterparty = crow['counterparty'] log.info('pushing tx to ' + counterparty) self.msgchan.push_tx(counterparty, tx) pushed = True elif tx_broadcast == 'tor': socks5_host = jm_single().config.get("MESSAGING", "socks5_host").split(",")[0] socks5_port = int(jm_single().config.get("MESSAGING", "socks5_port").split(",")[0]) pushed = tor_broadcast_tx(tx, (socks5_host, socks5_port), testnet=(get_network() == "testnet")) if not pushed: log.error('unable to pushtx') return pushed
def push(self): tx = btc.serialize(self.latest_tx) log.debug('\n' + tx) self.txid = btc.txhash(tx) log.info('txid = ' + self.txid) tx_broadcast = jm_single().config.get('POLICY', 'tx_broadcast') if tx_broadcast == 'self': pushed = jm_single().bc_interface.pushtx(tx) elif tx_broadcast in ['random-peer', 'not-self']: n = len(self.active_orders) if tx_broadcast == 'random-peer': i = random.randrange(n + 1) else: i = random.randrange(n) if i == n: pushed = jm_single().bc_interface.pushtx(tx) else: self.msgchan.push_tx(self.active_orders.keys()[i], tx) pushed = True elif tx_broadcast == 'random-maker': crow = self.db.execute( 'SELECT DISTINCT counterparty FROM orderbook ORDER BY ' + 'RANDOM() LIMIT 1;').fetchone() counterparty = crow['counterparty'] log.info('pushing tx to ' + counterparty) self.msgchan.push_tx(counterparty, tx) pushed = True elif tx_broadcast == 'tor': socks5_host = jm_single().config.get("MESSAGING", "socks5_host").split(",")[0] socks5_port = int(jm_single().config.get( "MESSAGING", "socks5_port").split(",")[0]) pushed = tor_broadcast_tx(tx, (socks5_host, socks5_port), testnet=(get_network() == "testnet")) if not pushed: log.error('unable to pushtx') return pushed
def tx_sign_singlesig(tx, idx, private_key_info, hashcode=bitcoin.SIGHASH_ALL): """ Sign a p2pkh input Return the signed transaction TODO: move to virtualchain NOTE: implemented here instead of bitcoin, since bitcoin.sign() can cause a stack overflow while converting the private key to a public key. """ pk = virtualchain.BitcoinPrivateKey(str(private_key_info)) pubk = pk.public_key() pub = pubk.to_hex() addr = pubk.address() script = virtualchain.make_payment_script(addr) sig = tx_make_input_signature(tx, idx, script, private_key_info, hashcode) txobj = bitcoin.deserialize(str(tx)) txobj['ins'][idx]['script'] = bitcoin.serialize_script([sig, pub]) return bitcoin.serialize(txobj)
def sign(tx, i, priv, t="default", script="", hashcode=SIGHASH_ALL): i = int(i) #if (not is_python2 and isinstance(re, bytes)) or not re.match('^[0-9a-fA-F]*$', tx): if not re.match('^[0-9a-fA-F]*$', tx): return binascii.unhexlify(custom_sign(safe_hexlify(tx), i, priv, hashcode)) if len(priv) <= 33: priv = b.safe_hexlify(priv) pub = b.privkey_to_pubkey(priv) address = b.pubkey_to_address(pub) if t not in ["atomic_1", "atomic_2"]: script=b.mk_pubkey_script(address) if script=="": error() signing_tx = b.signature_form(tx, i, script, hashcode)#mk_pubkey_scrip needs to be our custom scriptn sig = b.ecdsa_tx_sign(signing_tx, priv, hashcode) txobj = b.deserialize(tx) if t=="atomic_1": txobj["ins"][i]["script"] = b.serialize_script([sig]) if t=="atomic_2": old_sig = txobj["ins"][i]["script"] txobj["ins"][i]["script"] = b.serialize_script([old_sig, sig, 1]) else: txobj["ins"][i]["script"] = b.serialize_script([sig, pub]) return b.serialize(txobj)
def test_serialization_roundtrip(tx_type, tx_id, tx_hex): assert tx_hex == btc.serialize(btc.deserialize(tx_hex))
def test_P2SH_P2WSH_ALL_SIGHASH(self): tx = TEST_CASES[3] VIN_AMOUNT = int(9.87654321 * 10**8) deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][0]) priv1 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][1]) priv2 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][2]) priv3 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][3]) priv4 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][4]) priv5 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][5]) witness_script = mk_multisig_script(privtopub(priv0), privtopub(priv1), privtopub(priv2), privtopub(priv3), privtopub(priv4), privtopub(priv5), 6) self.assertEqual(witness_script, tx['ins'][0]['witness_script']) sign0 = segwit_multisign(generated_tx, 0, witness_script, priv0, VIN_AMOUNT, hashcode=SIGHASH_ALL) sign1 = segwit_multisign(generated_tx, 0, witness_script, priv1, VIN_AMOUNT, hashcode=SIGHASH_NONE) sign2 = segwit_multisign(generated_tx, 0, witness_script, priv2, VIN_AMOUNT, hashcode=SIGHASH_SINGLE) sign3 = segwit_multisign(generated_tx, 0, witness_script, priv3, VIN_AMOUNT, hashcode=SIGHASH_ALL|SIGHASH_ANYONECANPAY) sign4 = segwit_multisign(generated_tx, 0, witness_script, priv4, VIN_AMOUNT, hashcode=SIGHASH_NONE|SIGHASH_ANYONECANPAY) sign5 = segwit_multisign(generated_tx, 0, witness_script, priv5, VIN_AMOUNT, hashcode=SIGHASH_SINGLE|SIGHASH_ANYONECANPAY) signed = apply_segwit_multisignatures(stripped_tx, 0, witness_script, [sign0, sign1, sign2, sign3, sign4, sign5], nested=True) self.assertEqual(signed, tx['signed']) print('[P2WSH 6-of-6 multisig NESTED in P2SH] SIGHASH_SINGLE\SIGHASH_ALL\SIGHASH_NONE & ANYONECANPAY')