def get_public_key_hex_from_tx(inputs, address): """ Given a list of inputs and the address of one of the inputs, find the public key. This only works for p2pkh scripts. We only really need this for NAMESPACE_REVEAL, but we included it in other transactions' consensus data for legacy reasons that now have to be supported forever :( """ ret = None for inp in inputs: input_scriptsig = inp['script'] input_script_code = virtualchain.btc_script_deserialize( input_scriptsig) if len(input_script_code) == 2: # signature pubkey pubkey_candidate = input_script_code[1] pubkey = None try: pubkey = virtualchain.BitcoinPublicKey(pubkey_candidate) except Exception as e: traceback.print_exc() log.warn("Invalid public key {}".format(pubkey_candidate)) continue if address != pubkey.address(): continue # success! return pubkey_candidate return None
def verify_multisig(address, hash_hex, scriptSig): script_parts = virtualchain.btc_script_deserialize(scriptSig) if len(script_parts) < 2: log.warn("Verfiying multisig failed, couldn't grab script parts") return False redeem_script = script_parts[-1] script_sigs = script_parts[1:-1] if virtualchain.btc_make_p2sh_address(redeem_script) != address: log.warn(("Address {} does not match the public key in the" + " provided scriptSig: provided redeemscript = {}").format( address, redeem_script)) return False m, pk_hexes = virtualchain.parse_multisig_redeemscript(redeem_script) if len(script_sigs) != m: log.warn("Failed to validate multi-sig, not correct number of signatures: have {}, require {}".format( len(script_sigs), m)) return False cur_pk = 0 for cur_sig in script_sigs: sig64 = base64.b64encode(binascii.unhexlify(cur_sig)) sig_passed = False while not sig_passed: if cur_pk >= len(pk_hexes): log.warn("Failed to validate multi-signature, ran out of pks to check") return False sig_passed = virtualchain.ecdsalib.verify_digest(hash_hex, pk_hexes[cur_pk], sig64) cur_pk += 1 return True
def scenario(wallets, **kw): txids = [] res = testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) txids.append(res['transaction_hash']) res = testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey, version_bits=blockstack.NAMESPACE_VERSION_PAY_WITH_STACKS) testlib.next_block(**kw) txids.append(res['transaction_hash']) res = testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) txids.append(res['transaction_hash']) res = testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) txids.append(res['transaction_hash']) res = testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) txids.append(res['transaction_hash']) res = testlib.blockstack_name_update("foo.test", "11" * 20, wallets[3].privkey) testlib.next_block(**kw) txids.append(res['transaction_hash']) for txid in txids: # fetch and parse them all. Make sure the use the alternative testnet ID rawtx = testlib.getrawtransaction(txid, 0) print str(rawtx) tx = virtualchain.btc_tx_deserialize(str(rawtx)) nullout = tx['outs'][0] script = nullout['script'] script_parts = virtualchain.btc_script_deserialize(script) payload = script_parts[1] assert payload.decode('hex')[0:2] == 'di', rawtx
def verify_singlesig(address, hash_hex, scriptSig): sighex, pubkey_hex = virtualchain.btc_script_deserialize(scriptSig) # verify pubkey_hex corresponds to address if keylib.ECPublicKey(pubkey_hex).address() != address: log.warn(("Address {} does not match the public key in the" + " provided scriptSig: provided pubkey = {}").format( address, pubkey_hex)) return False sig64 = base64.b64encode(binascii.unhexlify(sighex)) return virtualchain.ecdsalib.verify_digest(hash_hex, pubkey_hex, sig64)