def check_bip143_tx(self, tx_u_hex, tx_s_hex, txs_out_value_scripthex_pair, tx_in_count, tx_out_count, version, lock_time): tx_u = Tx.from_hex(tx_u_hex) tx_s = Tx.from_hex(tx_s_hex) txs_out = [ TxOut(int(coin_value * 1e8), h2b(script_hex)) for coin_value, script_hex in txs_out_value_scripthex_pair ] for tx in (tx_u, tx_s): self.assertEqual(len(tx.txs_in), tx_in_count) self.assertEqual(len(tx.txs_out), tx_out_count) self.assertEqual(tx.version, version) self.assertEqual(tx.lock_time, lock_time) tx.set_unspents(txs_out) self.check_unsigned(tx_u) self.check_signed(tx_s) tx_hex = tx_u.as_hex() self.assertEqual(tx_hex, tx_u_hex) tx_hex = tx_s.as_hex() self.assertEqual(tx_hex, tx_s_hex) tx_u_prime = self.unsigned_copy(tx_s) tx_hex = tx_u_prime.as_hex() self.assertEqual(tx_hex, tx_u_hex) self.assertEqual(b2h_rev(double_sha256(h2b(tx_s_hex))), tx_s.w_id()) self.assertEqual(b2h_rev(double_sha256(h2b(tx_u_hex))), tx_u.w_id()) self.assertEqual(b2h_rev(double_sha256(h2b(tx_u_hex))), tx_u.id()) return tx_u, tx_s
def check_bip143_tx( self, tx_u_hex, tx_s_hex, txs_out_value_scripthex_pair, tx_in_count, tx_out_count, version, lock_time): tx_u = Tx.from_hex(tx_u_hex) tx_s = Tx.from_hex(tx_s_hex) txs_out = [ TxOut(int(coin_value * 1e8), h2b(script_hex)) for coin_value, script_hex in txs_out_value_scripthex_pair ] for tx in (tx_u, tx_s): self.assertEqual(len(tx.txs_in), tx_in_count) self.assertEqual(len(tx.txs_out), tx_out_count) self.assertEqual(tx.version, version) self.assertEqual(tx.lock_time, lock_time) tx.set_unspents(txs_out) self.check_unsigned(tx_u) self.check_signed(tx_s) tx_hex = tx_u.as_hex() self.assertEqual(tx_hex, tx_u_hex) tx_hex = tx_s.as_hex() self.assertEqual(tx_hex, tx_s_hex) tx_u_prime = self.unsigned_copy(tx_s) tx_hex = tx_u_prime.as_hex() self.assertEqual(tx_hex, tx_u_hex) self.assertEqual(b2h_rev(double_sha256(h2b(tx_s_hex))), tx_s.w_id()) self.assertEqual(b2h_rev(double_sha256(h2b(tx_u_hex))), tx_u.w_id()) self.assertEqual(b2h_rev(double_sha256(h2b(tx_u_hex))), tx_u.id()) return tx_u, tx_s
def __repr__(self): local_block_chain = self._longest_local_block_chain() if local_block_chain: finish = b2h_rev(local_block_chain[0]) start = b2h_rev(local_block_chain[-1]) longest_chain = "longest chain %s to %s of size %d" % (start, finish, self.unlocked_length()) else: longest_chain = "no unlocked elements" return "<BlockChain with %d locked elements and %s>" % (self.locked_length(), longest_chain)
def __repr__(self): local_block_chain = self._longest_local_block_chain() if local_block_chain: finish = b2h_rev(local_block_chain[0]) start = b2h_rev(local_block_chain[-1]) longest_chain = "longest chain %s to %s of size %d" % ( start, finish, self.unlocked_length()) else: longest_chain = "no unlocked elements" return "<BlockChain with %d locked elements and %s>" % ( self.locked_length(), longest_chain)
def validate_unspents(self, tx_db): """ Spendable objects returned from blockchain.info or similar services contain coin_value information that must be trusted on faith. Mistaken coin_value data can result in coins being wasted to fees. This function solves this problem by iterating over the incoming transactions, fetching them from the tx_db in full, and verifying that the coin_values are as expected. Returns the fee for this transaction. If any of the spendables set by tx.set_unspents do not match the authenticated transactions, a ValidationFailureError is raised. """ tx_hashes = set((tx_in.previous_hash for tx_in in self.txs_in)) # build a local copy of the DB tx_lookup = {} for h in tx_hashes: if h == ZERO32: continue the_tx = tx_db.get(h) if the_tx is None: raise KeyError("hash id %s not in tx_db" % b2h_rev(h)) if the_tx.hash() != h: raise KeyError( "attempt to load Tx %s yielded a Tx with id %s" % (h2b_rev(h), the_tx.id())) tx_lookup[h] = the_tx for idx, tx_in in enumerate(self.txs_in): if tx_in.previous_hash == ZERO32: continue txs_out = tx_lookup[tx_in.previous_hash].txs_out if tx_in.previous_index > len(txs_out): raise BadSpendableError( "tx_out index %d is too big for Tx %s" % (tx_in.previous_index, b2h_rev(tx_in.previous_hash))) tx_out1 = txs_out[tx_in.previous_index] tx_out2 = self.unspents[idx] if tx_out1.coin_value != tx_out2.coin_value: raise BadSpendableError( "unspents[%d] coin value mismatch (%d vs %d)" % (idx, tx_out1.coin_value, tx_out2.coin_value)) if tx_out1.script != tx_out2.script: raise BadSpendableError("unspents[%d] script mismatch!" % idx) return self.fee()
def test_h2b(self): h = "000102" b = b"\x00\x01\x02" self.assertEqual(h2b(h), b) self.assertEqual(b2h(b), h) self.assertEqual(h2b_rev(h), b[::-1]) self.assertEqual(b2h_rev(b), "020100")
def tx_for_tx_hash(self, tx_hash): URL = "%s/getrawtransaction?txid=%s&decrypt=0" % (self.base_url, b2h_rev(tx_hash)) r = urlopen(URL).read().decode("utf8") tx = Tx.from_hex(r) if tx.hash() == tx_hash: return tx return None
def tx_for_tx_hash(self, tx_hash): URL = "%s/tx/%s" % (self.base_url, b2h_rev(tx_hash)) r = json.loads(urlopen(URL).read().decode("utf8")) tx = tx_from_json_dict(r) if tx.hash() == tx_hash: return tx return None
def w_id(self): """Return the segwit-specific binary hash for this :class:`Tx` object as a hex string. Note that this is a ``reversed`` version of :func:`Tx.w_hash <w_hash>`. :return: 64 character long hex string corresponding to the hash """ return b2h_rev(self.w_hash())
def test_block(self): expected_checksum = '0000000000089F7910F6755C10EA2795EC368A29B435D80770AD78493A6FECF1'.lower() block_data = h2b( "010000007480150B299A16BBCE5CCDB1D1BBC65CFC5893B01E6619107C552000000000" "007900A2B203D24C69710AB6A94BEB937E1B1ADD64C2327E268D8C3E5F8B41DBED8796" "974CED66471B204C324703010000000100000000000000000000000000000000000000" "00000000000000000000000000FFFFFFFF0804ED66471B024001FFFFFFFF0100F2052A" "010000004341045FEE68BAB9915C4EDCA4C680420ED28BBC369ED84D48AC178E1F5F7E" "EAC455BBE270DABA06802145854B5E29F0A7F816E2DF906E0FE4F6D5B4C9B92940E4F0" "EDAC000000000100000001F7B30415D1A7BF6DB91CB2A272767C6799D721A4178AA328" "E0D77C199CB3B57F010000008A4730440220556F61B84F16E637836D2E74B8CB784DE4" "0C28FE3EF93CCB7406504EE9C7CAA5022043BD4749D4F3F7F831AC696748AD8D8E79AE" "B4A1C539E742AA3256910FC88E170141049A414D94345712893A828DE57B4C2054E2F5" "96CDCA9D0B4451BA1CA5F8847830B9BE6E196450E6ABB21C540EA31BE310271AA00A49" "ED0BA930743D1ED465BAD0FFFFFFFF0200E1F505000000001976A914529A63393D63E9" "80ACE6FA885C5A89E4F27AA08988ACC0ADA41A000000001976A9145D17976537F30886" "5ED533CCCFDD76558CA3C8F088AC00000000010000000165148D894D3922EF5FFDA962" "BE26016635C933D470C8B0AB7618E869E3F70E3C000000008B48304502207F5779EBF4" "834FEAEFF4D250898324EB5C0833B16D7AF4C1CB0F66F50FCF6E85022100B78A65377F" "D018281E77285EFC31E5B9BA7CB7E20E015CF6B7FA3E4A466DD195014104072AD79E0A" "A38C05FA33DD185F84C17F611E58A8658CE996D8B04395B99C7BE36529CAB7606900A0" "CD5A7AEBC6B233EA8E0FE60943054C63620E05E5B85F0426FFFFFFFF02404B4C000000" "00001976A914D4CAA8447532CA8EE4C80A1AE1D230A01E22BFDB88AC8013A0DE010000" "001976A9149661A79AE1F6D487AF3420C13E649D6DF3747FC288AC00000000") # try to parse a block block = Block.parse(io.BytesIO(block_data)) assert b2h_rev(block.hash()) == expected_checksum block.check_merkle_hash() # parse already validated block block = Block.parse(io.BytesIO(block_data), check_merkle_hash=False) assert block.as_bin() == block_data
def save_spendable(self, spendable): tx_hash = b2h_rev(spendable.tx_hash) script = b2h(spendable.script) self._exec_sql( "insert or replace into Spendable values (?, ?, ?, ?, ?, ?, ?)", tx_hash, spendable.tx_out_index, spendable.coin_value, script, spendable.block_index_available, spendable.does_seem_spent, spendable.block_index_spent)
def validate_unspents(self, tx_db): """ Spendable objects returned from blockchain.info or similar services contain coin_value information that must be trusted on faith. Mistaken coin_value data can result in coins being wasted to fees. This function solves this problem by iterating over the incoming transactions, fetching them from the tx_db in full, and verifying that the coin_values are as expected. Returns the fee for this transaction. If any of the spendables set by tx.set_unspents do not match the authenticated transactions, a ValidationFailureError is raised. """ tx_hashes = set((tx_in.previous_hash for tx_in in self.txs_in)) # build a local copy of the DB tx_lookup = {} for h in tx_hashes: if h == ZERO32: continue the_tx = tx_db.get(h) if the_tx is None: raise KeyError("hash id %s not in tx_db" % b2h_rev(h)) if the_tx.hash() != h: raise KeyError("attempt to load Tx %s yielded a Tx with id %s" % (h2b_rev(h), the_tx.id())) tx_lookup[h] = the_tx for idx, tx_in in enumerate(self.txs_in): if tx_in.previous_hash == ZERO32: continue txs_out = tx_lookup[tx_in.previous_hash].txs_out if tx_in.previous_index > len(txs_out): raise BadSpendableError("tx_out index %d is too big for Tx %s" % (tx_in.previous_index, b2h_rev(tx_in.previous_hash))) tx_out1 = txs_out[tx_in.previous_index] tx_out2 = self.unspents[idx] if tx_out1.coin_value != tx_out2.coin_value: raise BadSpendableError( "unspents[%d] coin value mismatch (%d vs %d)" % ( idx, tx_out1.coin_value, tx_out2.coin_value)) if tx_out1.script != tx_out2.script: raise BadSpendableError("unspents[%d] script mismatch!" % idx) return self.fee()
def as_dict(self): # for use with JSON return dict(coin_value=self.coin_value, script_hex=b2h(self.script), tx_hash_hex=b2h_rev(self.tx_hash), tx_out_index=self.tx_out_index, block_index_available=self.block_index_available, does_seem_spent=int(self.does_seem_spent), block_index_spent=self.block_index_spent)
def put(self, tx): name = b2h_rev(tx.hash()) if self.writable_cache_path: try: path = os.path.join(self.writable_cache_path, "%s_tx.bin" % name) with open(path, "wb") as f: tx.stream(f) except IOError: pass
def tx_for_tx_hash(self, tx_hash): """ Get a Tx by its hash. """ url = "%s/rawtx/%s" % (self.url, b2h_rev(tx_hash)) d = urlopen(url).read() j = json.loads(d.decode("utf8")) tx = Tx.from_hex(j.get("rawtx", "")) if tx.hash() == tx_hash: return tx
def as_text(self): return "/".join([ b2h_rev(self.tx_hash), str(self.tx_out_index), b2h(self.script), str(self.coin_value), str(self.block_index_available), "%d" % self.does_seem_spent, str(self.block_index_spent) ])
def as_dict(self): # for use with JSON return dict( coin_value=self.coin_value, script_hex=b2h(self.script), tx_hash_hex=b2h_rev(self.tx_hash), tx_out_index=self.tx_out_index, block_index_available=self.block_index_available, does_seem_spent=int(self.does_seem_spent), block_index_spent=self.block_index_spent )
def post_unpack_merkleblock(d, f): """ A post-processing "post_unpack" to merkleblock messages. It validates the merkle proofs (throwing an exception if there's an error), and returns the list of transaction hashes in "tx_hashes". The transactions are supposed to be sent immediately after the merkleblock message. """ level_widths = [] count = d["total_transactions"] while count > 1: level_widths.append(count) count += 1 count //= 2 level_widths.append(1) level_widths.reverse() tx_acc = [] flags = d["flags"] hashes = list(reversed(d["hashes"])) left_hash, flag_index = _recurse(level_widths, 0, 0, hashes, flags, 0, tx_acc) if len(hashes) > 0: raise ValueError("extra hashes: %s" % hashes) idx, r = divmod(flag_index - 1, 8) if idx != len(flags) - 1: raise ValueError("not enough flags consumed") if flags[idx] > (1 << (r + 1)) - 1: raise ValueError("unconsumed 1 flag bits set") if left_hash != d["header"].merkle_root: raise ValueError( "merkle root %s does not match calculated hash %s" % (b2h_rev(d["header"].merkle_root), b2h_rev(left_hash))) d["tx_hashes"] = tx_acc return d
def tx_for_tx_hash(self, tx_hash): """ returns the pycoin.tx object for tx_hash """ try: url_append = "?token=%s&includeHex=true" % self.api_key url = self.base_url("txs/%s%s" % (b2h_rev(tx_hash), url_append)) result = json.loads(urlopen(url).read().decode("utf8")) tx = Tx.parse(io.BytesIO(h2b(result.get("hex")))) return tx except Exception: raise Exception
def post_unpack_merkleblock(d, f): """ A post-processing "post_unpack" to merkleblock messages. It validates the merkle proofs (throwing an exception if there's an error), and returns the list of transaction hashes in "tx_hashes". The transactions are supposed to be sent immediately after the merkleblock message. """ level_widths = [] count = d["total_transactions"] while count > 1: level_widths.append(count) count += 1 count //= 2 level_widths.append(1) level_widths.reverse() tx_acc = [] flags = d["flags"] hashes = list(reversed(d["hashes"])) left_hash, flag_index = _recurse(level_widths, 0, 0, hashes, flags, 0, tx_acc) if len(hashes) > 0: raise ValueError("extra hashes: %s" % hashes) idx, r = divmod(flag_index-1, 8) if idx != len(flags) - 1: raise ValueError("not enough flags consumed") if flags[idx] > (1 << (r+1))-1: raise ValueError("unconsumed 1 flag bits set") if left_hash != d["header"].merkle_root: raise ValueError( "merkle root %s does not match calculated hash %s" % ( b2h_rev(d["header"].merkle_root), b2h_rev(left_hash))) d["tx_hashes"] = tx_acc return d
def dump_block(output, block, network): blob = stream_to_bytes(block.stream) output.append("%d bytes block hash %s" % (len(blob), block.id())) output.append("version %d" % block.version) output.append("prior block hash %s" % b2h_rev(block.previous_block_hash)) output.append("merkle root %s" % b2h(block.merkle_root)) output.append("timestamp %s" % datetime.datetime.utcfromtimestamp(block.timestamp).isoformat()) output.append("difficulty %d" % block.difficulty) output.append("nonce %s" % block.nonce) output.append("%d transaction%s" % (len(block.txs), "s" if len(block.txs) != 1 else "")) for idx, tx in enumerate(block.txs): output.append("Tx #%d:" % idx) dump_tx( output, tx, network=network, verbose_signature=False, disassembly_level=0, do_trace=False, use_pdb=False) output.append("")
def unspents_from_db(self, tx_db, ignore_missing=False): unspents = [] for tx_in in self.txs_in: if tx_in.is_coinbase(): unspents.append(None) continue tx = tx_db.get(tx_in.previous_hash) if tx and tx.hash() == tx_in.previous_hash: unspents.append(tx.txs_out[tx_in.previous_index]) elif ignore_missing: unspents.append(None) else: raise KeyError( "can't find tx_out for %s:%d" % (b2h_rev(tx_in.previous_hash), tx_in.previous_index)) self.unspents = unspents
def spendable_for_hash_index(self, tx_hash, tx_out_index, spendable_class): tx_hash_hex = b2h_rev(tx_hash) SQL = ("select coin_value, script, block_index_available, " "does_seem_spent, block_index_spent from Spendable where " "tx_hash = ? and tx_out_index = ?") c = self._exec_sql(SQL, tx_hash_hex, tx_out_index) r = c.fetchone() if r is None: return r return spendable_class(coin_value=r[0], script=h2b(r[1]), tx_hash=tx_hash, tx_out_index=tx_out_index, block_index_available=r[2], does_seem_spent=r[3], block_index_spent=r[4])
def get_blockheader_with_transaction_hashes(self, block_hash): URL = "%s/block/%s" % (self.base_url, b2h_rev(block_hash)) r = json.loads(urlopen(URL).read().decode("utf8")) version = r.get("version") previous_block_hash = h2b_rev(r.get("previousblockhash")) merkle_root = h2b_rev(r.get("merkleroot")) timestamp = r.get("time") difficulty = int(r.get("bits"), 16) nonce = int(r.get("nonce")) tx_hashes = [h2b_rev(tx_hash) for tx_hash in r.get("tx")] blockheader = Block(version, previous_block_hash, merkle_root, timestamp, difficulty, nonce) if blockheader.hash() != block_hash: return None, None calculated_hash = merkle(tx_hashes, double_sha256) if calculated_hash != merkle_root: return None, None blockheader.height = r.get("height") return blockheader, tx_hashes
def dump_inputs(output, tx, network, verbose_signature, traceback_f, disassembly_level): for idx, tx_in in enumerate(tx.txs_in): if tx.is_coinbase(): output.append("%4d: COINBASE %12.5f m%s" % (idx, satoshi_to_mbtc(tx.total_in()), network.symbol)) continue suffix = "" if tx.missing_unspent(idx): tx_out = None address = tx_in.address(address_api=network.address) else: tx_out = tx.unspents[idx] sig_result = " sig ok" if tx.is_solution_ok(idx, traceback_f=traceback_f) else " BAD SIG" suffix = " %12.5f m%s %s" % (satoshi_to_mbtc(tx_out.coin_value), network.symbol, sig_result) address = network.address.for_script(tx_out.puzzle_script()) t = "%4d: %34s from %s:%-4d%s" % (idx, address, b2h_rev(tx_in.previous_hash), tx_in.previous_index, suffix) output.append(t.rstrip()) if disassembly_level > 0: dump_disassembly(output, tx, idx, network.annotate) if verbose_signature: dump_signatures(output, tx, tx_in, tx_out, idx, network, traceback_f)
def test_block(self): expected_checksum = '0000000000089F7910F6755C10EA2795EC368A29B435D80770AD78493A6FECF1'.lower( ) block_data = h2b( "010000007480150B299A16BBCE5CCDB1D1BBC65CFC5893B01E6619107C552000000000" "007900A2B203D24C69710AB6A94BEB937E1B1ADD64C2327E268D8C3E5F8B41DBED8796" "974CED66471B204C324703010000000100000000000000000000000000000000000000" "00000000000000000000000000FFFFFFFF0804ED66471B024001FFFFFFFF0100F2052A" "010000004341045FEE68BAB9915C4EDCA4C680420ED28BBC369ED84D48AC178E1F5F7E" "EAC455BBE270DABA06802145854B5E29F0A7F816E2DF906E0FE4F6D5B4C9B92940E4F0" "EDAC000000000100000001F7B30415D1A7BF6DB91CB2A272767C6799D721A4178AA328" "E0D77C199CB3B57F010000008A4730440220556F61B84F16E637836D2E74B8CB784DE4" "0C28FE3EF93CCB7406504EE9C7CAA5022043BD4749D4F3F7F831AC696748AD8D8E79AE" "B4A1C539E742AA3256910FC88E170141049A414D94345712893A828DE57B4C2054E2F5" "96CDCA9D0B4451BA1CA5F8847830B9BE6E196450E6ABB21C540EA31BE310271AA00A49" "ED0BA930743D1ED465BAD0FFFFFFFF0200E1F505000000001976A914529A63393D63E9" "80ACE6FA885C5A89E4F27AA08988ACC0ADA41A000000001976A9145D17976537F30886" "5ED533CCCFDD76558CA3C8F088AC00000000010000000165148D894D3922EF5FFDA962" "BE26016635C933D470C8B0AB7618E869E3F70E3C000000008B48304502207F5779EBF4" "834FEAEFF4D250898324EB5C0833B16D7AF4C1CB0F66F50FCF6E85022100B78A65377F" "D018281E77285EFC31E5B9BA7CB7E20E015CF6B7FA3E4A466DD195014104072AD79E0A" "A38C05FA33DD185F84C17F611E58A8658CE996D8B04395B99C7BE36529CAB7606900A0" "CD5A7AEBC6B233EA8E0FE60943054C63620E05E5B85F0426FFFFFFFF02404B4C000000" "00001976A914D4CAA8447532CA8EE4C80A1AE1D230A01E22BFDB88AC8013A0DE010000" "001976A9149661A79AE1F6D487AF3420C13E649D6DF3747FC288AC00000000") # try to parse a block block = Block.parse(io.BytesIO(block_data)) assert b2h_rev(block.hash()) == expected_checksum block.check_merkle_hash() # parse already validated block block = Block.parse(io.BytesIO(block_data), check_merkle_hash=False) assert block.as_bin() == block_data
def id(self): """Return the human-readable hash for this Tx object.""" return b2h_rev(self.hash())
def tx_for_tx_hash(self, tx_hash): raw_tx = self.connection.getrawtransaction(b2h_rev(tx_hash)) tx = Tx.from_hex(raw_tx) return tx
def unspent_to_bitcoind_dict(tx_in, tx_out): return dict( txid=b2h_rev(tx_in.previous_hash), vout=tx_in.previous_index, scriptPubKey=b2h(tx_out.script) )
def tx_for_tx_hash(self, tx_hash): "Get a Tx by its hash." URL = "https://blockchain.info/rawtx/%s?format=hex" % b2h_rev(tx_hash) tx = Tx.from_hex(urlopen(URL).read().decode("utf8")) return tx
def tx_for_tx_hash(self, tx_hash): "Get a Tx by its hash." url = self.base_url("get_tx", b2h_rev(tx_hash)) r = json.loads(urlopen(url).read().decode("utf8")) tx = Tx.parse(io.BytesIO(h2b(r.get("data").get("tx_hex")))) return tx
def __setitem__(self, key, val): if val.hash() != key: raise ValueError("bad key %s for %s" % (b2h_rev(key), val)) self.put(val)
def _test_sighash_single(self, network): Key = network.ui._key_class k0 = Key(secret_exponent=PRIV_KEYS[0], generator=secp256k1_generator, is_compressed=True) k1 = Key(secret_exponent=PRIV_KEYS[1], generator=secp256k1_generator, is_compressed=True) k2 = Key(secret_exponent=PRIV_KEYS[2], generator=secp256k1_generator, is_compressed=True) k3 = Key(secret_exponent=PRIV_KEYS[3], generator=secp256k1_generator, is_compressed=True) k4 = Key(secret_exponent=PRIV_KEYS[4], generator=secp256k1_generator, is_compressed=True) k5 = Key(secret_exponent=PRIV_KEYS[5], generator=secp256k1_generator, is_compressed=True) # Fake a coinbase transaction coinbase_tx = Tx.coinbase_tx(k0.sec(), 500000000) coinbase_tx.txs_out.append( TxOut(1000000000, BitcoinScriptTools.compile('%s OP_CHECKSIG' % b2h(k1.sec())))) coinbase_tx.txs_out.append( TxOut(1000000000, BitcoinScriptTools.compile('%s OP_CHECKSIG' % b2h(k2.sec())))) self.assertEqual( '2acbe1006f7168bad538b477f7844e53de3a31ffddfcfc4c6625276dd714155a', b2h_rev(coinbase_tx.hash())) script_for_address = network.ui.script_for_address # Make the test transaction txs_in = [ TxIn(coinbase_tx.hash(), 0), TxIn(coinbase_tx.hash(), 1), TxIn(coinbase_tx.hash(), 2), ] txs_out = [ TxOut(900000000, script_for_address(k3.address())), TxOut(800000000, script_for_address(k4.address())), TxOut(800000000, script_for_address(k5.address())), ] tx = Tx(1, txs_in, txs_out) tx.set_unspents(coinbase_tx.txs_out) self.assertEqual( '791b98ef0a3ac87584fe273bc65abd89821569fd7c83538ac0625a8ca85ba587', b2h_rev(tx.hash())) sig_type = SIGHASH_SINGLE solution_checker = BitcoinSolutionChecker(tx) sig_hash = solution_checker._signature_hash( coinbase_tx.txs_out[0].script, 0, sig_type) self.assertEqual( 0xcc52d785a3b4133504d1af9e60cd71ca422609cb41df3a08bbb466b2a98a885e, sig_hash) sig = sigmake(k0, sig_hash, sig_type) self.assertTrue(sigcheck(k0, sig_hash, sig[:-1])) tx.txs_in[0].script = BitcoinScriptTools.compile(b2h(sig)) self.assertTrue(tx.is_signature_ok(0)) sig_hash = solution_checker._signature_hash( coinbase_tx.txs_out[1].script, 1, sig_type) self.assertEqual( 0x93bb883d70fccfba9b8aa2028567aca8357937c65af7f6f5ccc6993fd7735fb7, sig_hash) sig = sigmake(k1, sig_hash, sig_type) self.assertTrue(sigcheck(k1, sig_hash, sig[:-1])) tx.txs_in[1].script = BitcoinScriptTools.compile(b2h(sig)) self.assertTrue(tx.is_signature_ok(1)) sig_hash = solution_checker._signature_hash( coinbase_tx.txs_out[2].script, 2, sig_type) self.assertEqual( 0x53ef7f67c3541bffcf4e0d06c003c6014e2aa1fb38ff33240b3e1c1f3f8e2a35, sig_hash) sig = sigmake(k2, sig_hash, sig_type) self.assertTrue(sigcheck(k2, sig_hash, sig[:-1])) tx.txs_in[2].script = BitcoinScriptTools.compile(b2h(sig)) self.assertTrue(tx.is_signature_ok(2)) sig_type = SIGHASH_SINGLE | SIGHASH_ANYONECANPAY sig_hash = solution_checker._signature_hash( coinbase_tx.txs_out[0].script, 0, sig_type) self.assertEqual( 0x2003393d246a7f136692ce7ab819c6eadc54ffea38eb4377ac75d7d461144e75, sig_hash) sig = sigmake(k0, sig_hash, sig_type) self.assertTrue(sigcheck(k0, sig_hash, sig[:-1])) tx.txs_in[0].script = BitcoinScriptTools.compile(b2h(sig)) self.assertTrue(tx.is_signature_ok(0)) sig_hash = solution_checker._signature_hash( coinbase_tx.txs_out[1].script, 1, sig_type) self.assertEqual( 0xe3f469ac88e9f35e8eff0bd8ad4ad3bf899c80eb7645947d60860de4a08a35df, sig_hash) sig = sigmake(k1, sig_hash, sig_type) self.assertTrue(sigcheck(k1, sig_hash, sig[:-1])) tx.txs_in[1].script = BitcoinScriptTools.compile(b2h(sig)) self.assertTrue(tx.is_signature_ok(1)) sig_hash = solution_checker._signature_hash( coinbase_tx.txs_out[2].script, 2, sig_type) self.assertEqual( 0xbacd7c3ab79cad71807312677c1788ad9565bf3c00ab9a153d206494fb8b7e6a, sig_hash) sig = sigmake(k2, sig_hash, sig_type) self.assertTrue(sigcheck(k2, sig_hash, sig[:-1])) tx.txs_in[2].script = BitcoinScriptTools.compile(b2h(sig)) self.assertTrue(tx.is_signature_ok(2))
def __str__(self): return 'Spendable<%s mbtc "%s:%d" %s/%s/%s>' % ( satoshi_to_mbtc(self.coin_value), b2h_rev(self.tx_hash), self.tx_out_index, self.block_index_available, self.does_seem_spent, self.block_index_spent)
def _test_sighash_single(self, network): flags = network.validator.flags k0, k1, k2, k3, k4, k5 = [ network.keys.private(secret_exponent=se, is_compressed=True) for se in PRIV_KEYS] # Fake a coinbase transaction coinbase_tx = network.tx.coinbase_tx(k0.sec(), 500000000) for k in [k1, k2]: coinbase_tx.txs_out.append(network.tx.TxOut( 1000000000, network.script.compile('%s OP_CHECKSIG' % b2h(k.sec())))) self.assertEqual('2acbe1006f7168bad538b477f7844e53de3a31ffddfcfc4c6625276dd714155a', b2h_rev(coinbase_tx.hash())) # Make the test transaction txs_in = [ network.tx.TxIn(coinbase_tx.hash(), 0), network.tx.TxIn(coinbase_tx.hash(), 1), network.tx.TxIn(coinbase_tx.hash(), 2), ] txs_out = [ network.tx.TxOut(900000000, network.contract.for_address(k3.address())), network.tx.TxOut(800000000, network.contract.for_address(k4.address())), network.tx.TxOut(800000000, network.contract.for_address(k5.address())), ] tx = network.tx(1, txs_in, txs_out) tx.set_unspents(coinbase_tx.txs_out) self.assertEqual('791b98ef0a3ac87584fe273bc65abd89821569fd7c83538ac0625a8ca85ba587', b2h_rev(tx.hash())) sig_type = flags.SIGHASH_SINGLE solution_checker = network.tx.SolutionChecker(tx) sig_hash = solution_checker._signature_hash(coinbase_tx.txs_out[0].script, 0, sig_type) self.assertEqual(0xcc52d785a3b4133504d1af9e60cd71ca422609cb41df3a08bbb466b2a98a885e, sig_hash) sig = sigmake(k0, sig_hash, sig_type) self.assertTrue(sigcheck(k0, sig_hash, sig[:-1])) tx.txs_in[0].script = network.script.compile(b2h(sig)) self.assertTrue(tx.is_solution_ok(0)) sig_hash = solution_checker._signature_hash(coinbase_tx.txs_out[1].script, 1, sig_type) self.assertEqual(0x93bb883d70fccfba9b8aa2028567aca8357937c65af7f6f5ccc6993fd7735fb7, sig_hash) sig = sigmake(k1, sig_hash, sig_type) self.assertTrue(sigcheck(k1, sig_hash, sig[:-1])) tx.txs_in[1].script = network.script.compile(b2h(sig)) self.assertTrue(tx.is_solution_ok(1)) sig_hash = solution_checker._signature_hash(coinbase_tx.txs_out[2].script, 2, sig_type) self.assertEqual(0x53ef7f67c3541bffcf4e0d06c003c6014e2aa1fb38ff33240b3e1c1f3f8e2a35, sig_hash) sig = sigmake(k2, sig_hash, sig_type) self.assertTrue(sigcheck(k2, sig_hash, sig[:-1])) tx.txs_in[2].script = network.script.compile(b2h(sig)) self.assertTrue(tx.is_solution_ok(2)) sig_type = flags.SIGHASH_SINGLE | flags.SIGHASH_ANYONECANPAY sig_hash = solution_checker._signature_hash(coinbase_tx.txs_out[0].script, 0, sig_type) self.assertEqual(0x2003393d246a7f136692ce7ab819c6eadc54ffea38eb4377ac75d7d461144e75, sig_hash) sig = sigmake(k0, sig_hash, sig_type) self.assertTrue(sigcheck(k0, sig_hash, sig[:-1])) tx.txs_in[0].script = network.script.compile(b2h(sig)) self.assertTrue(tx.is_solution_ok(0)) sig_hash = solution_checker._signature_hash(coinbase_tx.txs_out[1].script, 1, sig_type) self.assertEqual(0xe3f469ac88e9f35e8eff0bd8ad4ad3bf899c80eb7645947d60860de4a08a35df, sig_hash) sig = sigmake(k1, sig_hash, sig_type) self.assertTrue(sigcheck(k1, sig_hash, sig[:-1])) tx.txs_in[1].script = network.script.compile(b2h(sig)) self.assertTrue(tx.is_solution_ok(1)) sig_hash = solution_checker._signature_hash(coinbase_tx.txs_out[2].script, 2, sig_type) self.assertEqual(0xbacd7c3ab79cad71807312677c1788ad9565bf3c00ab9a153d206494fb8b7e6a, sig_hash) sig = sigmake(k2, sig_hash, sig_type) self.assertTrue(sigcheck(k2, sig_hash, sig[:-1])) tx.txs_in[2].script = network.script.compile(b2h(sig)) self.assertTrue(tx.is_solution_ok(2))
def __str__(self): return 'Spendable<%s mbtc "%s:%d" %s/%s/%s>' % ( satoshi_to_mbtc(self.coin_value), b2h_rev( self.tx_hash), self.tx_out_index, self.block_index_available, self.does_seem_spent, self.block_index_spent)
def tx_for_tx_hash(self, tx_hash): "Get a Tx by its hash." URL = self.api_domain + ("/rawtx/%s?format=hex" % b2h_rev(tx_hash)) tx = Tx.from_hex(urlopen(URL).read().decode("utf8")) return tx
def paths_for_hash(self, hash): name = b2h_rev(hash) for base_dir in self.read_only_paths: p = os.path.join(base_dir, "%s_tx.bin" % name) if os.path.exists(p): yield p
def unspent_to_bitcoind_dict(tx_in, tx_out): return dict(txid=b2h_rev(tx_in.previous_hash), vout=tx_in.previous_index, scriptPubKey=b2h(tx_out.script))
def delete_spendable(self, tx_hash, tx_out_index): self._exec_sql( "delete from Spendable where tx_hash = ? and tx_out_index = ?", b2h_rev(tx_hash), tx_out_index)
def __str__(self): if self.is_coinbase(): return 'TxIn<COINBASE: %s>' % b2h(self.script) return 'TxIn<%s[%d] "%s">' % ( b2h_rev(self.previous_hash), self.previous_index, ScriptTools.disassemble(self.script))
def __str__(self): INV_TYPES = ["?", "Tx", "Block", "Merkle"] idx = self.item_type if not 0 < idx < 4: idx = 0 return "InvItem %s [%s]" % (INV_TYPES[idx], b2h_rev(self.data))
def as_text(self): return "/".join([b2h_rev(self.tx_hash), str(self.tx_out_index), b2h(self.script), str(self.coin_value), str(self.block_index_available), "%d" % self.does_seem_spent, str(self.block_index_spent)])