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_immutable_tx_creation_with_mutable_parts_specified(self): tx = CTransaction( vin=[CMutableTxIn(prevout=COutPoint(hash=b'a' * 32, n=0))], vout=[CMutableTxOut(nValue=1)], witness=CMutableTxWitness( [CMutableTxInWitness(CScriptWitness([CScript([0])]))])) def check_immutable_parts(tx): self.assertTrue(tx.vin[0].is_immutable()) self.assertTrue(tx.vin[0].is_immutable()) self.assertTrue(tx.vout[0].is_immutable()) self.assertTrue(tx.wit.is_immutable()) self.assertTrue(tx.wit.vtxinwit[0].is_immutable()) check_immutable_parts(tx) # Test that if we deserialize with CTransaction, # all the parts are immutable tx = CTransaction.deserialize(tx.serialize()) check_immutable_parts(tx) # Test some parts separately, because when created via # CMutableTransaction instantiation, they are created with from_* # methods, and not directly txin = CTxIn(prevout=CMutableOutPoint(hash=b'a' * 32, n=0)) self.assertTrue(txin.prevout.is_immutable()) wit = CTxWitness((CMutableTxInWitness(), )) self.assertTrue(wit.vtxinwit[0].is_immutable())
def VerifySignature(txFrom, txTo, inIdx): """Verify a scriptSig signature can spend a txout Verifies that the scriptSig in txTo.vin[inIdx] is a valid scriptSig for the corresponding COutPoint in transaction txFrom. """ if inIdx < 0: raise VerifySignatureError("inIdx negative") if inIdx >= len(txTo.vin): raise VerifySignatureError("inIdx >= len(txTo.vin)") txin = txTo.vin[inIdx] if txin.prevout.n < 0: raise VerifySignatureError("txin prevout.n negative") if txin.prevout.n >= len(txFrom.vout): raise VerifySignatureError("txin prevout.n >= len(txFrom.vout)") txout = txFrom.vout[txin.prevout.n] if txin.prevout.hash != txFrom.GetTxid(): raise VerifySignatureError("prevout hash does not match txFrom") witness = None if txTo.wit: witness = txTo.wit.vtxinwit[inIdx].scriptWitness VerifyScript(txin.scriptSig, txout.scriptPubKey, txTo, inIdx, amount=txout.nValue, witness=witness or CScriptWitness([]))
def test_repr(self): def T(txout, expected): actual = repr(txout) self.assertEqual(actual, expected) T(CMutableTxInWitness(CScriptWitness([1])), "CBitcoinMutableTxInWitness(CScriptWitness([x('01')]))")
def test_repr(self) -> None: def T(txinwitness: CTxInWitness, expected: str) -> None: actual = repr(txinwitness) self.assertEqual(actual, expected) T(CMutableTxInWitness(CScriptWitness([1])), "CBitcoinMutableTxInWitness(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_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 VerifyScript( scriptSig, scriptPubKey, txTo, inIdx, # noqa flags=None, amount=0, witness=None): """Verify a scriptSig satisfies a scriptPubKey scriptSig - Signature scriptPubKey - PubKey txTo - Spending transaction inIdx - Index of the transaction input containing scriptSig Raises a ValidationError subclass if the validation fails. """ assert isinstance(scriptSig, CScript) assert type(scriptSig) == type(scriptPubKey),\ "scriptSig and scriptPubKey must be of the same script class" script_class = scriptSig.__class__ if flags is None: flags = STANDARD_SCRIPT_VERIFY_FLAGS - UNHANDLED_SCRIPT_VERIFY_FLAGS else: flags = set(flags) # might be passed as tuple if flags & UNHANDLED_SCRIPT_VERIFY_FLAGS: raise VerifyScriptError( "some of the flags cannot be handled by current code: {}".format( script_verify_flags_to_string( flags & UNHANDLED_SCRIPT_VERIFY_FLAGS))) stack = [] EvalScript(stack, scriptSig, txTo, inIdx, flags=flags) if SCRIPT_VERIFY_P2SH in flags: stackCopy = list(stack) EvalScript(stack, scriptPubKey, txTo, inIdx, flags=flags) if len(stack) == 0: raise VerifyScriptError("scriptPubKey left an empty stack") if not _CastToBool(stack[-1]): raise VerifyScriptError("scriptPubKey returned false") hadWitness = False if witness is None: witness = CScriptWitness([]) if SCRIPT_VERIFY_WITNESS in flags and scriptPubKey.is_witness_scriptpubkey( ): hadWitness = True if scriptSig: raise VerifyScriptError("scriptSig is not empty") VerifyWitnessProgram(witness, scriptPubKey.witness_version(), scriptPubKey.witness_program(), txTo, inIdx, flags=flags, amount=amount, script_class=script_class) # Bypass the cleanstack check at the end. The actual stack is obviously not clean # for witness programs. stack = stack[:1] # Additional validation for spend-to-script-hash transactions if SCRIPT_VERIFY_P2SH in flags and scriptPubKey.is_p2sh(): if not scriptSig.is_push_only(): raise VerifyScriptError("P2SH scriptSig not is_push_only()") # restore stack stack = stackCopy # stack cannot be empty here, because if it was the # P2SH HASH <> EQUAL scriptPubKey would be evaluated with # an empty stack and the EvalScript above would return false. assert len(stack) pubKey2 = script_class(stack.pop()) EvalScript(stack, pubKey2, txTo, inIdx, flags=flags) if not len(stack): raise VerifyScriptError( "P2SH inner scriptPubKey left an empty stack") if not _CastToBool(stack[-1]): raise VerifyScriptError("P2SH inner scriptPubKey returned false") # P2SH witness program if SCRIPT_VERIFY_WITNESS in flags and pubKey2.is_witness_scriptpubkey( ): hadWitness = True if scriptSig != script_class([pubKey2]): raise VerifyScriptError( "scriptSig is not exactly a single push of the redeemScript" ) VerifyWitnessProgram(witness, pubKey2.witness_version(), pubKey2.witness_program(), txTo, inIdx, flags=flags, amount=amount, script_class=script_class) # Bypass the cleanstack check at the end. The actual stack is obviously not clean # for witness programs. stack = stack[:1] if SCRIPT_VERIFY_CLEANSTACK in flags: assert SCRIPT_VERIFY_P2SH in flags if len(stack) == 0: raise VerifyScriptError("scriptPubKey left an empty stack") elif len(stack) != 1: raise VerifyScriptError("scriptPubKey left extra items on stack") if SCRIPT_VERIFY_WITNESS in flags: # We can't check for correct unexpected witness data if P2SH was off, so require # that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be # possible, which is not a softfork. assert SCRIPT_VERIFY_P2SH in flags, "SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH" if not hadWitness and witness: raise VerifyScriptError("Unexpected witness")
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()))
script_for_sighash = CElementsScript( [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] = CElementsTxInWitness( CScriptWitness([CScript(sig), CScript(key.pub)])).to_mutable() scriptpubkey = inner_scriptPubKey.to_p2sh_scriptPubKey() # VerifyScript does not know about confidential values. # Somewhen we might have VerifyElementsScript. # but for now, ignore the type error. VerifyScript( tx.vin[input_index].scriptSig, scriptpubkey, tx, input_index, amount=utxo.nValue, # type: ignore flags=(SCRIPT_VERIFY_P2SH, )) sys.stderr.write("Successfully signed\n")
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
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 load_test_vectors( name: str, skip_fixme: bool = True ) -> Iterator[Tuple[CScript, CScript, CScriptWitness, int, Set[ScriptVerifyFlag_Type], str, str, str]]: logging.basicConfig() log = logging.getLogger("Test_EvalScript") with open(os.path.dirname(__file__) + '/data/' + name, 'r') as fd: fixme_comment = None num_skipped = 0 for test_case in json.load(fd): if len(test_case) == 1: continue # comment if len(test_case) == 2: if not skip_fixme: assert test_case[0].startswith('FIXME'),\ "we do not expect anything other than FIXME* here" continue if test_case[0] == 'FIXME': fixme_comment = test_case[1] continue if test_case[0] == 'FIXME_END': log.warning("SKIPPED {} tests: {}".format( num_skipped, fixme_comment)) fixme_comment = None num_skipped = 0 continue if fixme_comment: num_skipped += 1 continue to_unpack = test_case.copy() witness = CScriptWitness() nValue = 0 if isinstance(to_unpack[0], list): wdata = to_unpack.pop(0) stack = [CScript(x(d)) for d in wdata[:-1]] witness = CScriptWitness(stack) nValue = int(round(wdata[-1] * 1e8)) if len(to_unpack) == 4: to_unpack.append('') # add missing comment assert len( to_unpack) == 5, "unexpected test data format: {}".format( to_unpack) scriptSig_str, scriptPubKey_str, flags, expected_result, comment = to_unpack scriptSig = parse_script(scriptSig_str) scriptPubKey = parse_script(scriptPubKey_str) flag_set = set() for flag in flags.split(','): if flag == '' or flag == 'NONE': pass else: try: flag = SCRIPT_VERIFY_FLAGS_BY_NAME[flag] except IndexError: raise Exception('Unknown script verify flag %r' % flag) flag_set.add(flag) yield (scriptSig, scriptPubKey, witness, nValue, flag_set, expected_result, comment, test_case) if fixme_comment is not None: raise Exception('Unbalanced FIXME blocks in test data')
def test_clone(self): txinwit = CMutableTxInWitness(CScriptWitness([1])) self.assertEqual(txinwit.serialize(), txinwit.clone().serialize())