def validateGAAddr(result, wallet): if sys.version_info.major < 3: addrscript = CScript(binascii.unhexlify(result['script'])) else: addrscript = CScript(binascii.unhexlify(result['script'])) addrdata = [x for x in addrscript] assert(len(addrdata) == 5) if sys.version_info.major < 3: secondpkh = binascii.hexlify(addrdata[2]) else: secondpkh = binascii.hexlify(addrdata[2]) print("Second pubkey hash: %s" % secondpkh) m = addrdata[0] assert(m == 2) n = addrdata[3] assert(n==2) assert(addrdata[4] == OP_CHECKMULTISIG) hexsubkey = wallet.subkey(1).subkey(result['pointer']).public_copy().sec_as_hex() if sys.version_info.major < 3: addrfromapi = P2SHBitcoinAddress.from_redeemScript(CScript(binascii.unhexlify(result['script']))) else: addrfromapi = P2SHBitcoinAddress.from_redeemScript(CScript(binascii.unhexlify(result['script']))) assert(hexsubkey == secondpkh.decode('utf8')) return addrfromapi
def analyze_tx(tx_hex_string): output = {} # get op_return from transaction hex = unhexlify(tx_hex_string) deserializedTransaction = CTransaction.deserialize(hex) op_return_vout = deserializedTransaction.vout[1].scriptPubKey # get redeem script redeem_script = '' for i in op_return_vout: script = bytes(i).decode('utf8') if 'REDEEM' in script: redeem_script_string = script.replace('REDEEM SCRIPT ', '') output['redeemScript'] = redeem_script_string # convert redeem script into list redeemScript = CScript(unhexlify(redeem_script_string)) redeem_script_array = [] for i in redeemScript: redeem_script_array.append(i) # get redeem script hash (hodl address) p2sh_address = P2SHBitcoinAddress.from_redeemScript(redeemScript) output['hodlAddress'] = str(p2sh_address) # get nlocktime from redeem script nlocktime_hex = b2lx(redeem_script_array[0]) nlocktime = int(nlocktime_hex, 16) output['nLockTime'] = nlocktime # get authorized key from redeem script pubkey = b2x(redeem_script_array[3]) # get address from authorized key pubkey = unhexlify(pubkey) P2PKHBitcoinAddress = bitcoin.wallet.P2PKHBitcoinAddress addr = P2PKHBitcoinAddress.from_pubkey(pubkey) output['authorizedAddress'] = str(addr) # get total sent to hodl address locked_satoshis = 0 for i in deserializedTransaction.vout: if i.nValue > 0: sPK = i.scriptPubKey amount = i.nValue try: vout_p2sh_addr = P2SHBitcoinAddress.from_scriptPubKey(sPK) # rewards only paid to really locked funds if str(p2sh_address) == str(vout_p2sh_addr): locked_satoshis += amount except: pass output["lockedSatoshis"] = locked_satoshis return (output)
def redeem_contract(self, contract, secret): print("Parsing script for redeem_contract...") scriptarray = self.parse_script(contract.redeemScript) redeemblocknum = scriptarray[8] self.redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6])) # refundPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[13])) p2sh = contract.p2sh # checking there are funds in the address amount = self.check_funds(p2sh) if(amount == 0): print("address ", p2sh, " not funded") quit() fundtx = self.find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN # print("Found fund_tx: ", fundtx) p2sh = P2SHBitcoinAddress(p2sh) if fundtx['address'] == p2sh: print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) blockcount = self.bitcoind.getblockcount() print("\nCurrent blocknum at time of redeem on Bitcoin:", blockcount) if blockcount < int(redeemblocknum): return self.redeem(contract, fundtx, secret) else: print("nLocktime exceeded, refunding") return self.refund(contract) else: print("No contract for this p2sh found in database", p2sh)
def test_json_roundtrip(self): VALUES = [ 42, 0, -42, 2100000000000000, -2100000000000000, "basic string", "\u1111Unicode", "\U00010000Wide Unicode", "\x00\n\t\r\nEscape codes", "\"'\"Quotes", "", None, b"\x00\x01\xFFBinary data", b"", CBase58Data.from_bytes(b'\x00\x01\xFF', 42), P2SHBitcoinAddress.from_bytes(b'\x00\x01\xFF'), P2PKHBitcoinAddress.from_bytes(b'\x00\x01\xFF'), CMutableTxIn(COutPoint(b'\x00' * 16 + b'\xFF' * 16, 42), CScript(b'\x00\x01\xFF'), 42), CMutableTxOut(42, CScript(b'\x00\x01\xFF')), CMutableTransaction([ CMutableTxIn(COutPoint(b'\x00' * 32, 42), CScript(b'\x00\x01\xFF'), 42), CMutableTxIn(COutPoint(b'\xFF' * 32, 42), CScript(b'\xFF\x01\x00'), 43) ], [ CMutableTxOut(42, CScript(b'\x00\x01\xFF')), CMutableTxOut(43, CScript(b'\xFF\x01\x00')) ], 42, 3), [ 1, b'\x00\x01\xFF', "List Test", ], { 'a': 1, 'key': b'\xFF\x01\x00', 1: 'Dictionary Test' }, [ { 3: [ 0, 1, 2, ], }, [ [ b'\xFFRecursion Test', ], ], ], ] for value in VALUES: self.assertEqual(from_json(to_json(value)), value)
def redeem_contract(self, contract, secret): print("Parsing script for redeem_contract...") scriptarray = self.parse_script(contract.redeemScript) redeemblocknum = scriptarray[8] redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6])) refundPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[13])) p2sh = contract.p2sh #checking there are funds in the address amount = self.check_funds(p2sh) if(amount == 0): print("address ", p2sh, " not funded") quit() fundtx = self.find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN # print("Found fund_tx: ", fundtx) p2sh = P2SHBitcoinAddress(p2sh) if fundtx['address'] == p2sh: print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) blockcount = self.bitcoind.getblockcount() print("\nCurrent blocknum at time of redeem on Zcash:", blockcount) if blockcount < int(redeemblocknum): print('redeemPubKey', redeemPubKey) zec_redeemScript = CScript(x(contract.redeemScript)) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. tx = CMutableTransaction([txin], [txout]) sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL) # TODO: protect privkey better, separate signing from rawtx creation privkey = self.bitcoind.dumpprivkey(redeemPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) preimage = secret.encode('utf-8') txin.scriptSig = CScript([sig, privkey.pub, preimage, OP_TRUE, zec_redeemScript]) # print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = zec_redeemScript.to_p2sh_scriptPubKey() print('Raw redeem transaction hex: ', b2x(tx.serialize())) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) print("Script verified, sending raw transaction...") txid = self.bitcoind.sendrawtransaction(tx) fund_tx = str(fundtx['outpoint']) redeem_tx = b2x(lx(b2x(txid))) return {"redeem_tx": redeem_tx, "fund_tx": fund_tx} else: print("nLocktime exceeded, refunding") print('refundPubKey', refundPubKey) txid = self.bitcoind.sendtoaddress(refundPubKey, fundtx['amount'] - FEE) fund_tx = str(fundtx['outpoint']) refund_tx = b2x(lx(b2x(txid))) return {"refund_tx": refund_tx, "fund_tx": fund_tx} else: print("No contract for this p2sh found in database", p2sh)
def syncWallet(result, wallet, gaitwallet, path): hexprivkey = wallet.subkey(1).subkey(result['pointer']).wif() hexpubkey = wallet.subkey(1).subkey(result['pointer']).public_copy().sec_as_hex() tproxy = Proxy() GAKey = gaitwallet.subkey(1).subkey_for_path(path).subkey(result['pointer']).sec_as_hex() addrfromapi = P2SHBitcoinAddress.from_redeemScript(CScript(binascii.unhexlify(result['script']))) print(addrfromapi) #tproxy.call("importprivkey", hexprivkey, "", False) print(tproxy.call("createmultisig", 2, [GAKey, hexpubkey])['address'])
def redeem_with_secret(contract, secret): # How to find redeemScript and redeemblocknum from blockchain? print("Redeeming contract using secret", contract.__dict__) p2sh = contract.p2sh minamount = float(contract.amount) #checking there are funds in the address amount = check_funds(p2sh) if (amount < minamount): print("address ", p2sh, " not sufficiently funded") return false fundtx = find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN p2sh = P2SHBitcoinAddress(p2sh) if fundtx['address'] == p2sh: print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) redeemPubKey = find_redeemAddr(contract) print('redeemPubKey', redeemPubKey) redeemScript = CScript(x(contract.redeemScript)) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. tx = CMutableTransaction([txin], [txout]) sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) # TODO: figure out how to better protect privkey privkey = bitcoind.dumpprivkey(redeemPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) print("SECRET", secret) preimage = secret.encode('utf-8') txin.scriptSig = CScript( [sig, privkey.pub, preimage, OP_TRUE, redeemScript]) # exit() # print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() # print('Redeem txhex', b2x(tx.serialize())) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH, )) print("script verified, sending raw tx") txid = bitcoind.sendrawtransaction(tx) print("Txid of submitted redeem tx: ", b2x(lx(b2x(txid)))) return b2x(lx(b2x(txid))) else: print("No contract for this p2sh found in database", p2sh)
def generate_multisig_address(redeemscript: str, testnet: bool = False) -> str: """ Generates a P2SH-multisig Bitcoin address from a redeem script Args: redeemscript: hex-encoded redeem script use generate_multisig_redeem_script to create the redeem script from three compressed public keys testnet: Should the address be testnet or mainnet? Example: TODO """ if testnet: bitcoin.SelectParams('testnet') redeem_script = CScript(bitcoin.core.x(redeemscript)) addr = P2SHBitcoinAddress.from_redeemScript(redeem_script) return str(addr)
def test_json_roundtrip(self): VALUES = [ 42, 0, -42, 2100000000000000, -2100000000000000, "basic string", "\u1111Unicode", "\U00010000Wide Unicode", "\x00\n\t\r\nEscape codes", '"\'"Quotes', "", None, b"\x00\x01\xFFBinary data", b"", CBase58Data.from_bytes(b"\x00\x01\xFF", 42), P2SHBitcoinAddress.from_bytes(b"\x00\x01\xFF"), P2PKHBitcoinAddress.from_bytes(b"\x00\x01\xFF"), CMutableTxIn(COutPoint(b"\x00" * 16 + b"\xFF" * 16, 42), CScript(b"\x00\x01\xFF"), 42), CMutableTxOut(42, CScript(b"\x00\x01\xFF")), CMutableTransaction( [ CMutableTxIn(COutPoint(b"\x00" * 32, 42), CScript(b"\x00\x01\xFF"), 42), CMutableTxIn(COutPoint(b"\xFF" * 32, 42), CScript(b"\xFF\x01\x00"), 43), ], [CMutableTxOut(42, CScript(b"\x00\x01\xFF")), CMutableTxOut(43, CScript(b"\xFF\x01\x00"))], 42, 3, ), [1, b"\x00\x01\xFF", "List Test"], {"a": 1, "key": b"\xFF\x01\x00", 1: "Dictionary Test"}, [{3: [0, 1, 2]}, [[b"\xFFRecursion Test"]]], ] for value in VALUES: self.assertEqual(from_json(to_json(value)), value)
def p2sh_addr(self): return P2SHBitcoinAddress.from_redeemScript(self.script)
def address(self): return P2SHBitcoinAddress.from_redeemScript(self.deposit_redeemScript)
def P2SHAddress(self): return P2SHBitcoinAddress.from_scriptPubKey(self.scriptPubkey())
def create_command(args): redeemScript = hodl_redeemScript(args.privkey, args.nLockTime) logging.debug('redeemScript: %s' % b2x(redeemScript)) addr = P2SHBitcoinAddress.from_redeemScript(redeemScript) print(addr)
def create_command(pubkey, nLockTime): redeemScript = hodl_redeemScript(pubkey, nLockTime) addr = P2SHBitcoinAddress.from_redeemScript(redeemScript) return ({'address': str(addr), 'redeemScript': b2x(redeemScript)})