def test_mutable_tx_creation_with_immutable_parts_specified(self): tx = CMutableTransaction( vin=[CTxIn(prevout=COutPoint(hash=b'a' * 32, n=0))], vout=[CTxOut(nValue=1)], witness=CTxWitness([CTxInWitness()])) def check_mutable_parts(tx): self.assertTrue(tx.vin[0].is_mutable()) self.assertTrue(tx.vin[0].prevout.is_mutable()) self.assertTrue(tx.vout[0].is_mutable()) self.assertTrue(tx.wit.is_mutable()) self.assertTrue(tx.wit.vtxinwit[0].is_mutable()) check_mutable_parts(tx) # Test that if we deserialize with CMutableTransaction, # all the parts are mutable tx = CMutableTransaction.deserialize(tx.serialize()) check_mutable_parts(tx) # Test some parts separately, because when created via # CMutableTransaction instantiation, they are created with from_* # methods, and not directly txin = CMutableTxIn(prevout=COutPoint(hash=b'a' * 32, n=0)) self.assertTrue(txin.prevout.is_mutable()) wit = CMutableTxWitness((CTxInWitness(), )) self.assertTrue(wit.vtxinwit[0].is_mutable())
def sign_input(tx, input_index, utxo): """Sign an input of transaction. Single-signature signing with SIGHASH_ALL""" key = utxo['key'] src_addr = CCoinAddress(utxo['address']) script_for_sighash = CScript( [OP_DUP, OP_HASH160, Hash160(key.pub), OP_EQUALVERIFY, OP_CHECKSIG]) assert isinstance(src_addr, (P2PKHCoinAddress, P2SHCoinAddress, P2WPKHCoinAddress)),\ 'only p2pkh, p2wpkh and p2sh_p2wpkh addresses are supported' if isinstance(src_addr, P2PKHCoinAddress): sigversion = SIGVERSION_BASE else: sigversion = SIGVERSION_WITNESS_V0 if 'amountcommitment' in utxo: amountcommitment = CConfidentialValue(x(utxo['amountcommitment'])) else: amountcommitment = CConfidentialValue(coins_to_satoshi(utxo['amount'])) sighash = script_for_sighash.sighash(tx, input_index, SIGHASH_ALL, amount=amountcommitment, sigversion=sigversion) sig = key.sign(sighash) + bytes([SIGHASH_ALL]) if isinstance(src_addr, P2PKHCoinAddress): tx.vin[input_index].scriptSig = CScript( [CScript(sig), CScript(key.pub)]) scriptpubkey = src_addr.to_scriptPubKey() elif isinstance(src_addr, P2WPKHCoinAddress): tx.vin[input_index].scriptSig = CScript() tx.wit.vtxinwit[input_index] = CTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])) scriptpubkey = src_addr.to_scriptPubKey() else: # Assume that this is p2sh-wrapped p2wpkh address inner_scriptPubKey = CScript([0, Hash160(key.pub)]) tx.vin[input_index].scriptSig = CScript([inner_scriptPubKey]) tx.wit.vtxinwit[input_index] = CTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])) scriptpubkey = inner_scriptPubKey.to_p2sh_scriptPubKey() VerifyScript(tx.vin[input_index].scriptSig, scriptpubkey, tx, input_index, amount=amountcommitment, flags=(SCRIPT_VERIFY_P2SH, ))
def test_repr(self): def T(txout, expected): actual = repr(txout) self.assertEqual(actual, expected) T(CTxInWitness(CScriptWitness([1])), "CBitcoinTxInWitness(CScriptWitness([x('01')]))")
def test_repr(self) -> None: def T(txinwitness: CTxInWitness, expected: str) -> None: actual = repr(txinwitness) self.assertEqual(actual, expected) T(CTxInWitness(CScriptWitness([1])), "CBitcoinTxInWitness(CScriptWitness([x('01')]))")
def generate_transaction(amount, txin_txid, txin_vout, txout_addr, redeem_list): txin = CMutableTxIn(COutPoint(txin_txid, txin_vout)) txout = CMutableTxOut(amount * COIN, txout_addr.addr.to_scriptPubKey()) witness_script = CScriptWitness(tuple(redeem_list)) witness = CTxWitness(tuple([CTxInWitness(witness_script)])) tx = CMutableTransaction(vin=[txin], vout=[txout], witness=witness) return tx
def create_test_txs(self, scriptSig, scriptPubKey, witness, nValue): txCredit = CTransaction([CTxIn(COutPoint(), CScript([OP_0, OP_0]), nSequence=0xFFFFFFFF)], [CTxOut(nValue, scriptPubKey)], witness=CTxWitness(), nLockTime=0, nVersion=1) txSpend = CTransaction([CTxIn(COutPoint(txCredit.GetTxid(), 0), scriptSig, nSequence=0xFFFFFFFF)], [CTxOut(nValue, CScript())], nLockTime=0, nVersion=1, witness=CTxWitness([CTxInWitness(witness)])) return (txCredit, txSpend)
def create_btc_spend_tx(dst_addr, txid, vout_n, btc_contract, spend_key=None, branch_condition=True): # In real application, the fees should not be static, of course out_amount = (coins_to_satoshi(pre_agreed_amount) - coins_to_satoshi(fixed_fee_amount)) tx = CMutableTransaction( vin=[CTxIn(prevout=COutPoint(hash=lx(txid), n=vout_n))], vout=[ CTxOut(nValue=out_amount, scriptPubKey=dst_addr.to_scriptPubKey()) ]) if branch_condition is True: cond = b'\x01' else: tx.vin[0].nSequence = bitcoin_contract_timeout cond = b'' in_amount = coins_to_satoshi(pre_agreed_amount) # We used P2WSHCoinAddress to create the address that we sent bitcoin to, # so we know that we need to use SIGVERSION_WITNESS_V0 sighash = btc_contract.sighash(tx, 0, SIGHASH_ALL, amount=in_amount, sigversion=SIGVERSION_WITNESS_V0) spend_sig = spend_key.sign(sighash) + bytes([SIGHASH_ALL]) # This is script witness, not script. The condition for OP_IF # in our script is directly encoded as data in the witness. # We cannot use OP_TRUE/OP_FALSE here. We use DATA guard is to ensure that. witness = CScriptWitness([spend_sig, DATA(cond), btc_contract]) # empty scriptSig, because segwit tx.vin[0].scriptSig = CBitcoinScript([]) # all data to check the spend conditions is in the witness tx.wit.vtxinwit[0] = CTxInWitness(witness) # Cannot use VerifyScript for now, # because it does not support CHECKSEQUENCEVERIFY yet # # from_addr = P2WSHBitcoinAddress.from_redeemScript(btc_contract) # VerifyScript(tx.vin[0].scriptSig, from_addr.to_scriptPubKey(), # tx, 0, amount=in_amount) return tx
def sign_transaction(tx, privkeys): witness_list = list(tx.witness.vtxinwit[0].scriptWitness.stack) sighash = SignatureHash(tx.witness, tx, 0, SIGHASH_ALL) signatures = [] for privkey in privkeys: privkey = CBitcoinSecret.from_bytes(privkey) for privkey in privkeys: signatures.append(privkey.sign(sighash) + bytes([SIGHASH_ALL])) counter = 0 for signature in signatures: witness_list.insert(counter, signature) counter = counter + 1 witness_script = CScriptWitness(tuple(witness_list)) tx.witness = CTxWitness(tuple([CTxInWitness(witness_script)])) return tx.serialize()
def T(required: int, total: int, alt_total: Optional[int] = None) -> None: amount = 10000 keys = [ CKey.from_secret_bytes(os.urandom(32)) for _ in range(total) ] pubkeys = [k.pub for k in keys] if alt_total is not None: total = alt_total # for assertRaises checks redeem_script = standard_multisig_redeem_script(total=total, required=required, pubkeys=pubkeys) # Test with P2SH scriptPubKey = redeem_script.to_p2sh_scriptPubKey() (_, tx) = self.create_test_txs(CScript(), scriptPubKey, CScriptWitness([]), amount) tx = tx.to_mutable() sighash = redeem_script.sighash(tx, 0, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_BASE) sigs = [ k.sign(sighash) + bytes([SIGHASH_ALL]) for k in keys[:required] ] tx.vin[0].scriptSig = CScript( standard_multisig_witness_stack(sigs, redeem_script)) VerifyScript(tx.vin[0].scriptSig, scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH, )) # Test with P2WSH scriptPubKey = redeem_script.to_p2wsh_scriptPubKey() (_, tx) = self.create_test_txs(CScript(), scriptPubKey, CScriptWitness([]), amount) tx = tx.to_mutable() sighash = redeem_script.sighash(tx, 0, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) sigs = [ k.sign(sighash) + bytes([SIGHASH_ALL]) for k in keys[:required] ] witness_stack = standard_multisig_witness_stack( sigs, redeem_script) tx.vin[0].scriptSig = CScript([]) tx.wit.vtxinwit[0] = CTxInWitness( CScriptWitness(witness_stack)).to_mutable() VerifyScript(tx.vin[0].scriptSig, scriptPubKey, tx, 0, flags=(SCRIPT_VERIFY_WITNESS, SCRIPT_VERIFY_P2SH), amount=amount, witness=tx.wit.vtxinwit[0].scriptWitness) # Test with P2SH_P2WSH scriptPubKey = redeem_script.to_p2wsh_scriptPubKey() (_, tx) = self.create_test_txs(CScript(), scriptPubKey, CScriptWitness([]), amount) tx = tx.to_mutable() sighash = redeem_script.sighash(tx, 0, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) sigs = [ k.sign(sighash) + bytes([SIGHASH_ALL]) for k in keys[:required] ] witness_stack = standard_multisig_witness_stack( sigs, redeem_script) tx.vin[0].scriptSig = CScript([scriptPubKey]) tx.wit.vtxinwit[0] = CTxInWitness( CScriptWitness(witness_stack)).to_mutable() VerifyScript(tx.vin[0].scriptSig, scriptPubKey.to_p2sh_scriptPubKey(), tx, 0, flags=(SCRIPT_VERIFY_WITNESS, SCRIPT_VERIFY_P2SH), amount=amount, witness=tx.wit.vtxinwit[0].scriptWitness)
def sign(tx, i, priv, hashcode=SIGHASH_ALL, amount=None, native=False): """ Given a transaction tx of type CMutableTransaction, an input index i, and a raw privkey in bytes, updates the CMutableTransaction to contain the newly appended signature. Only four scriptPubKey types supported: p2pkh, p2wpkh, p2sh-p2wpkh, p2wsh. Note that signing multisig must be done outside this function, using the wrapped library. If native is not the default (False), and if native != "p2wpkh", then native must be a CScript object containing the redeemscript needed to sign. Returns: (signature, "signing succeeded") or: (None, errormsg) in case of failure """ # script verification flags flags = set([SCRIPT_VERIFY_STRICTENC]) def return_err(e): return None, "Error in signing: " + repr(e) assert isinstance(tx, CMutableTransaction) pub = privkey_to_pubkey(priv) if not amount: # p2pkh only supported here: input_scriptPubKey = pubkey_to_p2pkh_script(pub) sighash = SignatureHash(input_scriptPubKey, tx, i, hashcode) try: sig = ecdsa_raw_sign(sighash, priv, rawmsg=True) + bytes( [hashcode]) except Exception as e: return return_err(e) tx.vin[i].scriptSig = CScript([sig, pub]) # Verify the signature worked. try: VerifyScript(tx.vin[i].scriptSig, input_scriptPubKey, tx, i, flags=flags) except Exception as e: return return_err(e) return sig, "signing succeeded" else: # segwit case; we currently support p2wpkh native or under p2sh. # https://github.com/Simplexum/python-bitcointx/blob/648ad8f45ff853bf9923c6498bfa0648b3d7bcbd/bitcointx/core/scripteval.py#L1250-L1252 flags.add(SCRIPT_VERIFY_P2SH) if native and native != "p2wpkh": scriptCode = native input_scriptPubKey = redeem_script_to_p2wsh_script(native) else: # this covers both p2wpkh and p2sh-p2wpkh case: input_scriptPubKey = pubkey_to_p2wpkh_script(pub) # only created for convenience access to scriptCode: input_address = P2WPKHCoinAddress.from_scriptPubKey( input_scriptPubKey) # function name is misleading here; redeemScript only applies to p2sh. scriptCode = input_address.to_redeemScript() sighash = SignatureHash(scriptCode, tx, i, hashcode, amount=amount, sigversion=SIGVERSION_WITNESS_V0) try: sig = ecdsa_raw_sign(sighash, priv, rawmsg=True) + bytes( [hashcode]) except Exception as e: return return_err(e) if native: flags.add(SCRIPT_VERIFY_WITNESS) else: tx.vin[i].scriptSig = CScript([input_scriptPubKey]) if native and native != "p2wpkh": witness = [sig, scriptCode] else: witness = [sig, pub] ctxwitness = CTxInWitness(CScriptWitness(witness)) tx.wit.vtxinwit[i] = ctxwitness # Verify the signature worked. try: VerifyScript(tx.vin[i].scriptSig, input_scriptPubKey, tx, i, flags=flags, amount=amount, witness=tx.wit.vtxinwit[i].scriptWitness) except ValidationError as e: return return_err(e) return sig, "signing succeeded"
script_for_sighash = CScript( [OP_DUP, OP_HASH160, Hash160(key.pub), OP_EQUALVERIFY, OP_CHECKSIG]) sighash = script_for_sighash.sighash(tx, input_index, SIGHASH_ALL, amount=utxo.nValue, sigversion=SIGVERSION_WITNESS_V0) sig = key.sign(sighash) + bytes([SIGHASH_ALL]) inner_scriptPubKey = CScript([0, Hash160(key.pub)]) tx.vin[input_index].scriptSig = CScript([inner_scriptPubKey]) tx.wit.vtxinwit[input_index] = CTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])) scriptpubkey = inner_scriptPubKey.to_p2sh_scriptPubKey() VerifyScript(tx.vin[input_index].scriptSig, scriptpubkey, tx, input_index, amount=utxo.nValue, flags=(SCRIPT_VERIFY_P2SH, )) sys.stderr.write("Successfully signed\n") # Print out blinded and signed transaction, hex-encoded. print(b2x(tx.serialize()))
def test_clone(self): txinwit = CTxInWitness(CScriptWitness([1])) self.assertEqual(txinwit.serialize(), txinwit.clone().serialize())
def test_immutable(self): wit = CTxInWitness(CScriptWitness([1])) with self.assertRaises(AttributeError): wit.scriptWitness = CScriptWitness()
def test_clone(self): wit = CMutableTxWitness([CTxInWitness(CScriptWitness([1]))]) self.assertEqual(wit.serialize(), wit.clone().serialize())
def test_immutable(self): wit = CTxWitness([CTxInWitness(CScriptWitness([1]))]) with self.assertRaises(AttributeError): wit.vtxinwit = []
def _create_transaction(self, sources: List[Address], recipients: List[Address], values, n_locktime, n_sequence): # save cospends self.cospends.union_all([str(x.address) for x in sources]) if not values: values = [recipient.value for recipient in recipients] tx_ins = [ CMutableTxIn(COutPoint(source.txid, source.vout), nSequence=n_sequence) for source in sources ] tx_outs = [] cnt = 0 for recipient, value in zip(recipients, values): if value == 0: self.log.warning("Creating output with 0 BTC") recipient.vout = cnt tx_outs.append( CMutableTxOut( Coin(value).satoshi(), recipient.address.to_scriptPubKey())) cnt += 1 tx = CMutableTransaction(tx_ins, tx_outs, nLockTime=n_locktime) in_idx = 0 witnesses = [] for txin, source in zip(tx_ins, sources): key = source.key if source.type == 'p2pkh': script = source.address.to_redeemScript() elif source.type == 'p2sh': script = CScript([key.pub, OP_CHECKSIG]) elif source.type == 'p2wpkh': script = source.address.to_redeemScript() elif source.type == 'p2wsh': script = source.witness_program else: raise UnsupportedAddressTypeError() # Create signature amount = Coin(source.value).satoshi() sig = self._sign(script, tx, in_idx, amount, key, source.type) # Add signature to input or witness if source.type == 'p2pkh': txin.scriptSig = CScript([sig, key.pub]) witnesses.append(CTxInWitness()) elif source.type == 'p2sh': txin.scriptSig = CScript([sig, script]) witnesses.append(CTxInWitness()) elif source.type == 'p2wpkh': txin.scriptSig = CScript() witnesses.append(CTxInWitness(CScriptWitness([sig, key.pub]))) elif source.type == 'p2wsh': txin.scriptSig = CScript() witnesses.append(CTxInWitness(CScriptWitness([sig, script]))) in_idx += 1 tx.wit = CTxWitness(witnesses) return tx