def dump_failure_info(spend_tx, script_in, script_out, flags, flags_string, expected, actual, message, comment): return print() print(flags_string) print("EXPECTED: %s" % expected) print("ACTUAL: %s" % actual) print("MESSAGE: %s" % message) print(comment) print(disassemble(compile(script_in))) print(disassemble(compile(script_out))) from pycoin.serialize import b2h def tbf(*args): pc, opcode, data, stack, altstack, is_signature, is_condition = args from pycoin.tx.script.tools import disassemble_for_opcode_data opd = disassemble_for_opcode_data(opcode, data) if len(altstack) == 0: altstack = '' print("%s %s\n %3x %s" % (stack, altstack, pc, opd)) import pdb pdb.set_trace() print("test failed: '%s' '%s' : %s %s" % (script_in, script_out, comment, flags_string)) try: check_solution(spend_tx, tx_in_idx=0, traceback_f=tbf, flags=flags) except Exception as ex: print(ex) try: check_solution(spend_tx, tx_in_idx=0, traceback_f=tbf, flags=flags) except Exception as ex: print(ex) import pdb; pdb.set_trace()
def get_tx(tx_hash): """ Get a Tx by its hash. """ # TODO: fix this j = get_json_for_hash(tx_hash) txs_in = [] for j_in in j.get("in"): if j_in.get("coinbase"): txs_in.append( TxIn.coinbase_tx_in(binascii.unhexlify(j_in["coinbase"]))) else: txs_in.append( TxIn(h2b_rev(j_in["prev_out"]["hash"]), int(j_in["prev_out"]["n"]), tools.compile(j_in["scriptSig"]))) txs_out = [] for j_out in j.get("out"): txs_out.append( TxOut(int(btc_to_satoshi(j_out["value"])), tools.compile(j_out["scriptPubKey"]))) tx = Tx(int(j["ver"]), txs_in, txs_out, int(j["lock_time"])) assert tx.hash() == tx_hash return tx
def tx_from_json_dict(r): version = r.get("version") lock_time = r.get("locktime") txs_in = [] for vin in r.get("vin"): if "coinbase" in vin: previous_hash = b'\0' * 32 script = h2b(vin.get("coinbase")) previous_index = 4294967295 else: previous_hash = h2b_rev(vin.get("txid")) scriptSig = vin.get("scriptSig") if "hex" in scriptSig: script = h2b(scriptSig.get("hex")) else: script = tools.compile(scriptSig.get("asm")) previous_index = vin.get("vout") sequence = vin.get("sequence") txs_in.append(TxIn(previous_hash, previous_index, script, sequence)) txs_out = [] for vout in r.get("vout"): coin_value = btc_to_satoshi(decimal.Decimal(vout.get("value"))) script = tools.compile(vout.get("scriptPubKey").get("asm")) txs_out.append(TxOut(coin_value, script)) tx = Tx(version, txs_in, txs_out, lock_time) bh = r.get("blockhash") if bh: bh = h2b_rev(bh) tx.confirmation_block_hash = bh return tx
class TxScript(): TEMPLATES = [ tools.compile("OP_PUBKEY OP_CHECKSIG"), tools.compile( "OP_DUP OP_HASH160 OP_PUBKEYHASH OP_EQUALVERIFY OP_CHECKSIG"), tools.compile("OP_1 OP_PUBKEY OP_PUBKEY OP_2 OP_CHECKMULTISIG"), ] def __init__(self, script): self.script = script def match_script_to_templates(self): """Examine the script passed in by tx_out_script and see if it matches the form of one of the templates in TEMPLATES. If so, return the form it matches; otherwise, return None.""" for script2 in TxScript.TEMPLATES: r = [] pc1 = pc2 = 0 while 1: if pc1 == len(self.script) and pc2 == len(script2): return r opcode1, data1, pc1 = tools.get_opcode(self.script, pc1) opcode2, data2, pc2 = tools.get_opcode(script2, pc2) if opcode2 == opcodes.OP_PUBKEY: l1 = len(data1) if l1 < 33 or l1 > 120: break r.append((opcode2, data1)) elif opcode2 == opcodes.OP_PUBKEYHASH: if len(data1) != 160 / 8: break r.append((opcode2, data1)) elif (opcode1, data1) != (opcode2, data2): break raise SolvingError("don't recognize output script") def bitcoin_address_for_script(self, is_test=False): try: r = self.match_script_to_templates() if len(r) != 1 or len(r[0]) != 2: return None if r[0][0] == opcodes.OP_PUBKEYHASH: return hash160_sec_to_bitcoin_address(r[0][1], is_test=is_test) if r[0][0] == opcodes.OP_PUBKEY: sec = r[0][1] return public_pair_to_bitcoin_address( sec_to_public_pair(sec), compressed=is_sec_compressed(sec), is_test=is_test) except SolvingError: pass return None def to_asm(self): return tools.disassemble(self.script)
def make_script_test(script_in, script_out, flags_string, comment, expected, coin_value, script_witness): script_in_bin = compile(script_in) script_out_bin = compile(script_out) script_witness_bin = [h2b(w) for w in script_witness] flags = parse_flags(flags_string) def f(self): try: credit_tx = build_credit_tx(script_out_bin, coin_value) spend_tx = build_spending_tx(script_in_bin, credit_tx) spend_tx.txs_in[0].witness = script_witness_bin msg = '' check_solution(spend_tx, tx_in_idx=0, flags=flags) r = 0 except ScriptError as se: r = se.error_code() msg = se.args[0] except: r = -1 # for now, just deal with 0 versus nonzero expect_error = getattr(errno, expected) if r != expect_error: dump_failure_info(spend_tx, script_in, script_out, flags, flags_string, expected, r, msg, comment) self.assertEqual(r, expect_error) return f
def dump_failure_info(spend_tx, script_in, script_out, flags, flags_string, expected, actual, message, comment): return print() print(flags_string) print("EXPECTED: %s" % expected) print("ACTUAL: %s" % actual) print("MESSAGE: %s" % message) print(comment) print(disassemble(compile(script_in))) print(disassemble(compile(script_out))) from pycoin.serialize import b2h def tbf(*args): pc, opcode, data, stack, altstack, is_signature, is_condition = args from pycoin.tx.script.tools import disassemble_for_opcode_data opd = disassemble_for_opcode_data(opcode, data) if len(altstack) == 0: altstack = '' print("%s %s\n %3x %s" % (stack, altstack, pc, opd)) import pdb pdb.set_trace() print("test failed: '%s' '%s' : %s %s" % (script_in, script_out, comment, flags_string)) try: check_solution(spend_tx, tx_in_idx=0, traceback_f=tbf, flags=flags) except Exception as ex: print(ex) try: check_solution(spend_tx, tx_in_idx=0, traceback_f=tbf, flags=flags) except Exception as ex: print(ex) import pdb pdb.set_trace()
def setUp(self): self.path = ":memory:" self.config = { 'dw_master_key': 'test', 'testnet': True, 'ccc': { 'colordb_path': self.path }, 'bip0032': False } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, ['']) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c' self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7' script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD('test') def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = 'test' self.wc.issue_coins(self.moniker, 'obc', 10000, 1) self.asset = self.model.get_asset_definition_manager( ).get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager( ).get_asset_by_moniker('bitcoin') self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash)
def test_nulldata(self): OP_RETURN = tools.compile("OP_RETURN") # note that because chr() is used samples with length > 255 will not work for sample in [b'test', b'me', b'a', b'39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q', b'', b'0'*80]: sample_script = OP_RETURN + tools.bin_script([sample]) nd = ScriptNulldata(sample) self.assertEqual(nd.nulldata, sample) self.assertEqual(nd.script(), sample_script) nd2 = ScriptNulldata.from_script(sample_script) self.assertEqual(nd.nulldata, nd2.nulldata) out = TxOut(1, nd.script()) tx = Tx(0, [], [out]) # ensure we can create a tx self.assertEqual(nd.script(), tools.compile(tools.disassemble(nd.script()))) # convert between asm and back to ensure no bugs with compilation
def f(self): script_in_bin = compile(script_in) script_out_bin = compile(script_out) flags = parse_flags(flags_string) try: credit_tx = build_credit_tx(script_out_bin) spend_tx = build_spending_tx(script_in_bin, credit_tx) r = spend_tx.is_signature_ok(tx_in_idx=0, flags=flags) except ScriptError: r = False except: r = -1 if r != expect_valid: dump_failure_info(spend_tx, script_in, script_out, flags, comment) self.assertEqual(r, expect_valid)
def test_issue_225(self): script = tools.compile("OP_RETURN 'foobar'") tx_out = TxOut(1, script) address = tx_out.bitcoin_address(netcode="XTN") self.assertEqual(address, "(nulldata 666f6f626172)") address = tx_out.bitcoin_address(netcode="BTC") self.assertEqual(address, "(nulldata 666f6f626172)")
def solve_finalize_commit(self, **kwargs): hash160_lookup = kwargs.get("hash160_lookup") sign_value = kwargs.get("sign_value") signature_type = kwargs.get("signature_type") existing_script = kwargs.get("existing_script") # FIXME validate on receiving the commit # validate payer sig opcode, data, pc = tools.get_opcode(existing_script, 0) # OP_0 opcode, payer_sig, pc = tools.get_opcode(existing_script, pc) sig_pair, actual_signature_type = parse_signature_blob(payer_sig) try: public_pair = encoding.sec_to_public_pair(self.payer_sec) sig_pair, signature_type = parse_signature_blob(payer_sig) valid = ecdsa.verify(ecdsa.generator_secp256k1, public_pair, sign_value, sig_pair) if not valid: raise Exception("Invalid payer public_pair!") except (encoding.EncodingError, UnexpectedDER): raise Exception("Invalid payer public_pair!") # sign private_key = hash160_lookup.get(encoding.hash160(self.payee_sec)) secret_exponent, public_pair, compressed = private_key payee_sig = self._create_script_signature( secret_exponent, sign_value, signature_type ) script_text = "OP_0 {payer_sig} {payee_sig} OP_1".format( payer_sig=b2h(payer_sig), payee_sig=b2h(payee_sig) ) return tools.compile(script_text)
def hash160data_txout(hexdata, dust_limit=common.DUST_LIMIT): data = binary(hexdata) if len(data) != 20: # 160 bit raise exceptions.InvalidHash160DataSize(len(data)) script_text = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % b2h(data) script_bin = tools.compile(script_text) return TxOut(dust_limit, script_bin)
def build_tx(tx, redeem_script): for i in range(0, len(tx.txs_in)): asm = "OP_0 {sigs} {redeem_script}".format( sigs=" ".join(tx.txs_in[i].sigs), redeem_script=b2h(redeem_script)) solution = tools.compile(asm) tx.txs_in[i].script = solution return tx
def make_bare_tx(candidate, change_address, rs_asm, version=1): # <Tx> components spendables = [] ins = [] outs = [] # estimate the final (signed) bytesize per input based on the redeemscript redeem_script = tools.compile(rs_asm) in_size = estimate_input_size(redeem_script) # initialize size and amount counters in_amount = Decimal(0) est_size = TX_COMPONENTS.version + TX_COMPONENTS.out_count + TX_COMPONENTS.in_count # add output size est_size += OUTSIZE * 2 # iterate over unspents for utxo in candidate.utxos: value = Decimal(utxo.amount) * COIN in_amount += value script = h2b(utxo.script) # for now: test if the in_script we figured we would need, actually matches the in script :D # reverse that tx hash prevtx = h2b_rev(utxo.hash) # output index outnum = utxo.outpoint # create "spendable" spdbl = Spendable(value, script, prevtx, outnum) spendables.append(spdbl) # also create this as input as_input = spdbl.tx_in() as_input.sigs = [] ins.append(as_input) # add the estimated size per input est_size += in_size # calc fee and out amount fee = (Decimal(math.ceil(est_size / 1000)) * COIN * NETWORK_FEE) + FEE_MARGIN change_amount = Decimal( math.floor(in_amount - (candidate.amount * COIN) - fee)) # create outputs outs.append( TxOut(int(candidate.amount * COIN), make_payto(candidate.address))) outs.append(TxOut(int(change_amount), make_payto_script(change_address))) # create bare tx without sigs tx = Tx(version, ins, outs, 0, spendables) return tx
def add_coins(self): script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.address0.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.addr0, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 20000, script) self.model.ccc.metastore.set_as_scanned(self.colorid0, self.blockhash) self.model.ccc.cdstore.add(self.colorid0, self.txhash, 0, 100, '')
def nulldata_txout(hexdata): data = binary(hexdata) if len(data) > 40: raise exceptions.MaxNulldataExceeded(len(data)) script_text = "OP_RETURN %s" % b2h(data) script_bin = tools.compile(script_text) return TxOut(0, script_bin)
def nulldata_txout(hexdata): data = binary(hexdata) if len(data) > common.MAX_NULLDATA: raise exceptions.MaxNulldataExceeded(len(data), common.MAX_NULLDATA) script_text = "OP_RETURN %s" % b2h(data) script_bin = tools.compile(script_text) return TxOut(0, script_bin)
def hash160data_txout(hexdata, value=548): data = binary(hexdata) if len(data) != 20: # 160 bit raise exceptions.InvalidHash160DataSize(len(data)) script_text = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % b2h(data) script_bin = tools.compile(script_text) return TxOut(value, script_bin)
def verify_script(script_signature, script_public_key, signature_for_hash_type_f, expected_hash_type=None): stack = [] is_p2h = (len(script_public_key) == 23 and script_public_key[0] == opcodes.OP_HASH160 and script_public_key[-1] == opcodes.OP_EQUAL) if not eval_script(script_signature, signature_for_hash_type_f, expected_hash_type, stack): logging.debug("script_signature did not evaluate") return False if is_p2h: signatures, alt_script_public_key = stack[:-1], stack[-1] from pycoin.tx.script import tools from pycoin import serialize def sub(x): if x == '00': return '0' return x s1 = [sub(serialize.b2h(s)) for s in signatures] alt_script_signature = tools.compile(" ".join(s1)) if not eval_script(script_public_key, signature_for_hash_type_f, expected_hash_type, stack): logging.debug("script_public_key did not evaluate") return False if is_p2h and stack[-1] == VCH_TRUE: return verify_script(alt_script_signature, alt_script_public_key, signature_for_hash_type_f, expected_hash_type=expected_hash_type) return stack[-1] == VCH_TRUE
def solve_revoke(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] revoke_secret = kwargs["revoke_secret"] private_key = hash160_lookup.get(encoding.hash160(self.payer_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_sig(secret_exponent, **kwargs) return tools.compile( REVOKE_SCRIPTSIG.format(sig=b2h(sig), revoke_secret=revoke_secret))
def setUp(self): self.path = ":memory:" self.config = {'dw_master_key': 'test', 'testnet': True, 'ccc': { 'colordb_path' : self.path }, 'bip0032': False } self.pwallet = PersistentWallet(self.path, self.config) self.pwallet.init_model() self.model = self.pwallet.get_model() self.wc = WalletController(self.model) self.wc.testing = True self.wc.debug = True self.colormap = self.model.get_color_map() self.bcolorset = ColorSet(self.colormap, ['']) wam = self.model.get_address_manager() self.baddress = wam.get_new_address(self.bcolorset) self.baddr = self.baddress.get_address() self.blockhash = '00000000c927c5d0ee1ca362f912f83c462f644e695337ce3731b9f7c5d1ca8c' self.txhash = '4fe45a5ba31bab1e244114c4555d9070044c73c98636231c77657022d76b87f7' script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 0, 100, script) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( self.baddress.rawPubkey().encode("hex"))).encode("hex") self.model.utxo_man.store.add_utxo(self.baddr, self.txhash, 1, 1000000000, script) self.model.ccc.blockchain_state.bitcoind = MockBitcoinD('test') def x(s): return self.blockhash, True self.model.ccc.blockchain_state.get_tx_blockhash = x self.moniker = 'test' self.wc.issue_coins(self.moniker, 'obc', 10000, 1) self.asset = self.model.get_asset_definition_manager( ).get_asset_by_moniker(self.moniker) self.basset = self.model.get_asset_definition_manager( ).get_asset_by_moniker('bitcoin') self.color_id = list(self.asset.color_set.color_id_set)[0] self.model.ccc.metastore.set_as_scanned(self.color_id, self.blockhash)
def solve_timeout(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] private_key = hash160_lookup.get(encoding.hash160(self.payer_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_script_signature( secret_exponent, kwargs["sign_value"], kwargs["signature_type"] ) return tools.compile("{sig} OP_0 OP_0".format(sig=b2h(sig)))
def txout(testnet, targetaddress, value): testnet = flag(testnet) targetaddress = address(testnet, targetaddress) value = positive_integer(value) prefix = b'\x6f' if testnet else b"\0" hash160 = b2h(bitcoin_address_to_hash160_sec(targetaddress, prefix)) script_text = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % hash160 script_bin = tools.compile(script_text) return TxOut(value, script_bin)
def solve_payout(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] spend_secret = kwargs["spend_secret"] private_key = hash160_lookup.get(encoding.hash160(self.payee_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_sig(secret_exponent, **kwargs) return tools.compile( PAYOUT_SCRIPTSIG.format(sig=b2h(sig), spend_secret=spend_secret))
def txout(testnet, target_address, value): testnet = flag(testnet) target_address = address(testnet, target_address) value = positive_integer(value) prefix = b'\x6f' if testnet else b"\0" hash160 = b2h(bitcoin_address_to_hash160_sec(target_address, prefix)) script_text = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % hash160 script_bin = tools.compile(script_text) return TxOut(value, script_bin)
def op_return_this(privatekey, text, prefix = "KEYSTAMP:", bitcoin_fee = 10000): bitcoin_keyobj = get_key(privatekey) bitcoin_address = bitcoin_keyobj.bitcoin_address() ## Get the spendable outputs we are going to use to pay the fee all_spendables = get_spendables_blockcypher(bitcoin_address) spendables = [] value = 0 for unspent in all_spendables: while value < bitcoin_fee + 10000: coin_value = unspent.get("value") script = h2b(unspent.get("script_hex")) previous_hash = h2b_rev(unspent.get("tx_hash")) previous_index = unspent.get("index") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) value += coin_value bitcoin_sum = sum(spendable.coin_value for spendable in spendables) if(bitcoin_sum < bitcoin_fee): print "ERROR: not enough balance: available: %s - fee: %s" %(bitcoin_sum, bitcoin_fee) return False ## Create the inputs we are going to use inputs = [spendable.tx_in() for spendable in spendables] ## If we will have change left over create an output to send it back outputs = [] if (bitcoin_sum > bitcoin_fee): change_output_script = standard_tx_out_script(bitcoin_address) total_amout = bitcoin_sum - bitcoin_fee outputs.append(TxOut(total_amout, change_output_script)) # home_address = standard_tx_out_script(bitcoin_address) # #TODO: it needs some love and IQ on input mananagement stuff # outputs.append(TxOut((bitcoin_sum - bitcoin_fee), home_address)) ## Build the OP_RETURN output with our message if prefix is not None and (len(text) + len(prefix) <= 80): text = prefix + text message = hexlify(text.encode()).decode('utf8') op_return_output_script = tools.compile("OP_RETURN %s" % message) outputs.append(TxOut(0, op_return_output_script)) ## Create the transaction and sign it with the private key tx = Tx(version=1, txs_in=inputs, txs_out=outputs) # print tx.as_hex() # print spendables tx.set_unspents(spendables) sign_tx(tx, wifs=[privatekey]) print "singed_tx: %s" %tx.as_hex() #TODO: uncomment this when its ready to push data to blockchian tx_hash = broadcast_tx_blockr(tx.as_hex()) return tx_hash
def coinbase_tx(cls, public_key_sec, coin_value, coinbase_bytes=b'', version=1, lock_time=0, state=0): """ Create the special "first in block" transaction that includes the mining fees. """ tx_in = cls.TransactionIn.coinbase_tx_in(script=coinbase_bytes) COINBASE_SCRIPT_OUT = "%s OP_CHECKSIG" script_text = COINBASE_SCRIPT_OUT % b2h(public_key_sec) script_bin = tools.compile(script_text) tx_out = cls.TransactionOut(coin_value, script_bin) return cls(version, [tx_in], [tx_out], lock_time, state)
def __call__(self, tx_out_script, signature_hash, signature_type): """Figure out how to create a signature for the incoming transaction, and sign it. tx_out_script: the tx_out script that needs to be "solved" signature_hash: the bignum hash value of the new transaction reassigning the coins signature_type: always SIGHASH_ALL (1) """ if signature_hash == 0: raise SolvingError("signature_hash can't be 0") tx_script = TxScript(tx_out_script) opcode_value_list = tx_script.match_script_to_templates() ba = bytearray() compressed = True for opcode, v in opcode_value_list: if opcode == opcodes.OP_PUBKEY: public_pair = sec_to_public_pair(v) bitcoin_address = public_pair_to_bitcoin_address( public_pair, compressed=compressed) elif opcode == opcodes.OP_PUBKEYHASH: bitcoin_address = hash160_sec_to_bitcoin_address(v) else: raise SolvingError("can't determine how to sign this script") secret_exponent = self.wallet.getsecretexponent(bitcoin_address) r, s = ecdsa.sign(ecdsa.generator_secp256k1, secret_exponent, signature_hash) sig = der.sigencode_der(r, s) + bytes_from_int(signature_type) ba += tools.compile(binascii.hexlify(sig).decode("utf8")) if opcode == opcodes.OP_PUBKEYHASH: public_pair = ecdsa.public_pair_for_secret_exponent( ecdsa.generator_secp256k1, secret_exponent) ba += tools.compile( binascii.hexlify( public_pair_to_sec( public_pair, compressed=compressed)).decode("utf8")) return bytes(ba)
def main(): the_hash = sys.argv[1] j = get_json_for_hash(the_hash) txs_in = [] for j_in in j.get("in"): txs_in.append( TxIn(h2b_rev(j_in["prev_out"]["hash"]), int(j_in["prev_out"]["n"]), tools.compile(j_in["scriptSig"])) ) txs_out = [] for j_out in j.get("out"): txs_out.append(TxOut(int(float(j_out["value"]) * 1e8 + 0.5), tools.compile(j_out["scriptPubKey"]))) tx = Tx(int(j["ver"]), txs_in, txs_out, int(j["lock_time"])) assert tx.id() == the_hash s = io.BytesIO() tx.stream(s) v = s.getvalue() print(linebreak(binascii.b2a_base64(v).decode("utf8"), 72))
def solve_create_commit(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] private_key = hash160_lookup.get(encoding.hash160(self.payer_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_sig(secret_exponent, **kwargs) signature_placeholder = kwargs.get("signature_placeholder", DEFAULT_PLACEHOLDER_SIGNATURE) script_asm = COMMIT_SCRIPTSIG.format( payer_sig=b2h(sig), payee_sig=b2h(signature_placeholder)) return tools.compile(script_asm)
def __init__(self, secret_exponents): super(OfflineAwareSolver, self).__init__(secret_exponents) STANDARD_SCRIPT_OUT = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" self.script_hash160 = [] for se in secret_exponents: pp = public_pair_for_secret_exponent(generator_secp256k1, se) h160sec = public_pair_to_hash160_sec(pp, False) script_text = STANDARD_SCRIPT_OUT % b2h(h160sec) print script_text self.script_hash160.append(compile(script_text))
def compile_commit_script(payer_pubkey, payee_pubkey, spend_secret_hash, revoke_secret_hash, delay_time): script_text = COMMIT_SCRIPT.format( payer_pubkey=payer_pubkey, payee_pubkey=payee_pubkey, spend_secret_hash=spend_secret_hash, revoke_secret_hash=revoke_secret_hash, delay_time=str(delay_time) ) return tools.compile(script_text)
def solve_change(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] spend_secret = kwargs["spend_secret"] private_key = hash160_lookup.get(encoding.hash160(self.payer_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_sig(secret_exponent, **kwargs) spend_secret_hash = get_deposit_spend_secret_hash(b2h(self.script)) provided_spend_secret_hash = b2h(encoding.hash160(h2b(spend_secret))) assert (spend_secret_hash == provided_spend_secret_hash) script_asm = CHANGE_SCRIPTSIG.format(sig=b2h(sig), secret=spend_secret) return tools.compile(script_asm)
def main(): the_hash = sys.argv[1] j = get_json_for_hash(the_hash) txs_in = [] for j_in in j.get("in"): txs_in.append( TxIn(h2b_rev(j_in["prev_out"]["hash"]), int(j_in["prev_out"]["n"]), tools.compile(j_in["scriptSig"]))) txs_out = [] for j_out in j.get("out"): txs_out.append( TxOut(int(float(j_out["value"]) * 1e8 + 0.5), tools.compile(j_out["scriptPubKey"]))) tx = Tx(int(j["ver"]), txs_in, txs_out, int(j["lock_time"])) assert tx.id() == the_hash s = io.BytesIO() tx.stream(s) v = s.getvalue() print(linebreak(binascii.b2a_base64(v).decode("utf8"), 72))
def fake_transaction(model=MockModel()): key = "5Kb8kLf9zgWQnogidDA76MzPL6TsZZY36hWXMssSzNydYXYB9KF" address = LooseAddressRecord(address_data=key) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( address.rawPubkey().encode("hex"))).encode("hex") txin = utxodb.UTXO("D34DB33F", 0, 1, script) txin.address_rec = address txout = txspec.ComposedTxSpec.TxOut(1, address.get_address()) composed = txspec.ComposedTxSpec([txin], [txout]) return txcons.RawTxSpec.from_composed_tx_spec(model, composed), address
def solve_create_commit(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] private_key = hash160_lookup.get(encoding.hash160(self.payer_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_script_signature( secret_exponent, kwargs["sign_value"], kwargs["signature_type"] ) signature_placeholder = kwargs.get("signature_placeholder", DEFAULT_PLACEHOLDER_SIGNATURE) script_text = "OP_0 {payer_sig} {payee_sig} OP_1".format( payer_sig=b2h(sig), payee_sig=b2h(signature_placeholder) ) return tools.compile(script_text)
def __call__(self, tx_out_script, signature_hash, signature_type): """Figure out how to create a signature for the incoming transaction, and sign it. tx_out_script: the tx_out script that needs to be "solved" signature_hash: the bignum hash value of the new transaction reassigning the coins signature_type: always SIGHASH_ALL (1) """ if signature_hash == 0: raise SolvingError("signature_hash can't be 0") tx_script = TxScript(tx_out_script) opcode_value_list = tx_script.match_script_to_templates() ba = bytearray() compressed = True for opcode, v in opcode_value_list: if opcode == opcodes.OP_PUBKEY: public_pair = sec_to_public_pair(v) bitcoin_address = public_pair_to_bitcoin_address(public_pair, compressed=compressed) elif opcode == opcodes.OP_PUBKEYHASH: bitcoin_address = hash160_sec_to_bitcoin_address(v) else: raise SolvingError("can't determine how to sign this script") secret_exponent = self.wallet.getsecretexponent(bitcoin_address) r, s = ecdsa.sign(ecdsa.generator_secp256k1, secret_exponent, signature_hash) sig = der.sigencode_der(r, s) + bytes_from_int(signature_type) ba += tools.compile(binascii.hexlify(sig).decode("utf8")) if opcode == opcodes.OP_PUBKEYHASH: public_pair = ecdsa.public_pair_for_secret_exponent(ecdsa.generator_secp256k1, secret_exponent) ba += tools.compile( binascii.hexlify(public_pair_to_sec(public_pair, compressed=compressed)).decode("utf8") ) return bytes(ba)
def construct_standard_tx(composed_tx_spec, is_test): txouts = [] STANDARD_SCRIPT_OUT = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" for txout in composed_tx_spec.get_txouts(): hash160 = bitcoin_address_to_hash160_sec(txout.target_addr, is_test) script_text = STANDARD_SCRIPT_OUT % b2h(hash160) script_bin = tools.compile(script_text) txouts.append(TxOut(txout.value, script_bin)) txins = [] for cts_txin in composed_tx_spec.get_txins(): txins.append(TxIn(cts_txin.get_txhash(), cts_txin.prevout.n)) version = 1 lock_time = 0 return Tx(version, txins, txouts, lock_time)
def get_tx(tx_hash): """ Get a Tx by its hash. """ # TODO: fix this j = get_json_for_hash(tx_hash) txs_in = [] for j_in in j.get("in"): if j_in.get("coinbase"): txs_in.append(TxIn.coinbase_tx_in(binascii.unhexlify(j_in["coinbase"]))) else: txs_in.append(TxIn( h2b_rev(j_in["prev_out"]["hash"]), int(j_in["prev_out"]["n"]), tools.compile(j_in["scriptSig"]))) txs_out = [] for j_out in j.get("out"): txs_out.append(TxOut(int(btc_to_satoshi(j_out["value"])), tools.compile(j_out["scriptPubKey"]))) tx = Tx(int(j["ver"]), txs_in, txs_out, int(j["lock_time"])) assert tx.hash() == tx_hash return tx
def solve_change(self, **kwargs): hash160_lookup = kwargs["hash160_lookup"] spend_secret = kwargs["spend_secret"] private_key = hash160_lookup.get(encoding.hash160(self.payer_sec)) secret_exponent, public_pair, compressed = private_key sig = self._create_script_signature( secret_exponent, kwargs["sign_value"], kwargs["signature_type"] ) spend_secret_hash = get_deposit_spend_secret_hash(self.script) provided_spend_secret_hash = b2h(hash160(h2b(spend_secret))) assert(spend_secret_hash == provided_spend_secret_hash) script_text = "{sig} {secret} OP_1 OP_0".format( sig=b2h(sig), secret=spend_secret ) return tools.compile(script_text)
def fake_transaction(model=None): key = ecdsa.SigningKey.from_string( "\xe8\x00\xb8\xd4\xa1b\xb7o\x0f;\xf2\xcf\xca\xfd\x1a$\xb9\xa9" "\xeb\x0b\x08X\x9f}9C\xe4\x88\xfdD\x11b", curve=ecdsa.curves.SECP256k1) address = Address.fromPrivkey(key) script = tools.compile( "OP_DUP OP_HASH160 {0} OP_EQUALVERIFY OP_CHECKSIG".format( address.rawPubkey()[1:-4].encode("hex"))).encode("hex") utxo = utxodb.UTXO("D34DB33F", 0, 1, script) utxo.address_rec = object() utxo.address_rec = AddressRec(address) txin = txspec.ComposedTxSpec.TxIn(utxo) txout = txspec.ComposedTxSpec.TxOut(1, address.pubkey) composed = txspec.ComposedTxSpec([txin], [txout]) return txcons.SignedTxSpec(model, composed, False), address
def spendables_for_address(bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ json_response = fetch_json( "addresses/%s/unspent-outputs" % bitcoin_address) spendables = [] for tx_out_info in json_response.get("data", {}).get("outputs"): if tx_out_info.get("to_address") == bitcoin_address: coin_value = tx_out_info["value"] script = tools.compile(tx_out_info.get("script_pub_key")) previous_hash = h2b_rev(tx_out_info.get("transaction_hash")) previous_index = tx_out_info.get("transaction_index") spendables.append( Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def construct_data_tx(data, _from): # inputs coins_from = blockchain_info.coin_sources_for_address(_from) min_coin_value, min_idx, min_h, min_script = max((tx_out.coin_value, idx, h, tx_out.script) for h, idx, tx_out in coins_from) unsigned_txs_out = [UnsignedTxOut(min_h, min_idx, min_coin_value, min_script)] # outputs if min_coin_value > TX_FEES * 2: return 'max output greater than twice the threshold, too big.' if min_coin_value < TX_FEES: return 'max output smaller than threshold, too small.' script_text = 'OP_RETURN %s' % data.encode('hex') script_bin = tools.compile(script_text) new_txs_out = [TxOut(0, script_bin)] version = 1 lock_time = 0 unsigned_tx = UnsignedTx(version, unsigned_txs_out, new_txs_out, lock_time) return unsigned_tx
def txs_from_json(path): """ Read tests from ./data/tx_??valid.json Format is an array of arrays Inner arrays are either [ "comment" ] or [[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...], serializedTransaction, verifyFlags] ... where all scripts are stringified scripts. verifyFlags is a comma separated list of script verification flags to apply, or "NONE" """ comments = None with open(path, 'r') as f: for tvec in json.load(f): if len(tvec) == 1: comments = tvec[0] continue assert len(tvec) == 3 prevouts = tvec[0] for prevout in prevouts: assert len(prevout) in (3, 4) tx_hex = tvec[1] flag_mask = parse_flags(tvec[2]) try: tx = Tx.from_hex(tx_hex) except: print("Cannot parse tx_hex: %s" % tx_hex) raise spendable_db = {} blank_spendable = Spendable(0, b'', b'\0' * 32, 0) for prevout in prevouts: coin_value = 1000000 if len(prevout) == 4: coin_value = prevout[3] spendable = Spendable(coin_value=coin_value, script=compile(prevout[2]), tx_hash=h2b_rev(prevout[0]), tx_out_index=prevout[1]) spendable_db[(spendable.tx_hash, spendable.tx_out_index)] = spendable unspents = [ spendable_db.get((tx_in.previous_hash, tx_in.previous_index), blank_spendable) for tx_in in tx.txs_in] tx.set_unspents(unspents) yield (tx, flag_mask, comments)
def spendables_for_address(bitcoin_address): """ Return a list of Spendable objects for the given bitcoin address. """ URL = "https://api.biteasy.com/blockchain/v1/addresses/%s/unspent-outputs" % bitcoin_address r = Request(URL, headers={"content-type": "application/json", "accept": "*/*", "User-Agent": "curl/7.29.0"}) d = urlopen(r).read() json_response = json.loads(d.decode("utf8")) spendables = [] for tx_out_info in json_response.get("data", {}).get("outputs"): if tx_out_info.get("to_address") == bitcoin_address: coin_value = tx_out_info["value"] script = tools.compile(tx_out_info.get("script_pub_key")) previous_hash = h2b_rev(tx_out_info.get("transaction_hash")) previous_index = tx_out_info.get("transaction_index") spendables.append(Spendable(coin_value, script, previous_hash, previous_index)) return spendables
def construct_data_tx(data, _from, unused_utxo): coins_from = spendables_for_address(_from, unused_utxo) #Ahora if len(coins_from) < 1: ErrorNotification.new('No bitcoins available to spend') return 'No bitcoins available to spend' txs_in = [TxIn(coins_from[0].tx_hash, coins_from[0].tx_out_index, coins_from[0].script)] script_text = 'OP_RETURN %s' % data.encode('hex') script_bin = tools.compile(script_text) new_txs_out = [TxOut(0, script_bin)] version = 1 lock_time = 0 unsigned_tx = Tx(version, txs_in, new_txs_out, lock_time, coins_from) return unsigned_tx