5 class ExpiryQueue(threading.Thread):
8 self.lock = threading.Lock()
10 threading.Thread.__init__(self)
17 self.items = [i for i in self.items if not i.stopped()]
22 self.items.append(item)
24 expiry_queue = ExpiryQueue()
28 def __init__(self, output_point):
29 self.lock = threading.Lock()
30 self.output_point = output_point
31 self.output_loaded = None
32 self.input_point = None
33 self.input_loaded = None
37 if self.output_loaded is None:
39 elif (self.input_point is not False and
40 self.input_loaded is None):
46 def __init__(self, chain):
48 self.lock = threading.Lock()
52 def run(self, address, handle_finish):
53 self.address = address
54 self.handle_finish = handle_finish
56 pubkey_hash = bitcoin.address_to_short_hash(address)
57 self.chain.fetch_outputs(pubkey_hash, self.start_loading)
59 def start_loading(self, ec, output_points):
61 for outpoint in output_points:
62 statement_line = StatementLine(outpoint)
63 self.statement.append(statement_line)
64 self.chain.fetch_spend(outpoint,
65 bitcoin.bind(self.load_spend,
66 bitcoin._1, bitcoin._2, statement_line))
67 self.load_tx_info(outpoint, statement_line, False)
69 def load_spend(self, ec, inpoint, statement_line):
70 with statement_line.lock:
72 statement_line.input_point = False
74 statement_line.input_point = inpoint
77 self.load_tx_info(inpoint, statement_line, True)
79 def finish_if_done(self):
81 if any(not line.is_loaded() for line in self.statement):
84 for line in self.statement:
86 line.input_loaded["value"] = -line.output_loaded["value"]
87 result.append(line.input_loaded)
88 result.append(line.output_loaded)
89 self.handle_finish(result)
100 def load_tx_info(self, point, statement_line, is_input):
102 info["tx_hash"] = str(point.hash)
103 info["pos"] = point.index
104 info["is_in"] = 1 if is_input else 0
105 self.chain.fetch_transaction_index(point.hash,
106 bitcoin.bind(self.tx_index, bitcoin._1, bitcoin._2, bitcoin._3,
107 statement_line, info))
109 def tx_index(self, ec, block_depth, offset, statement_line, info):
110 info["height"] = block_depth
111 self.chain.fetch_block_header_by_depth(block_depth,
112 bitcoin.bind(self.block_header, bitcoin._1, bitcoin._2,
113 statement_line, info))
115 def block_header(self, ec, blk_head, statement_line, info):
116 info["time"] = blk_head.timestamp
117 info["blk_hash"] = str(bitcoin.hash_block_header(blk_head))
118 tx_hash = bitcoin.hash_digest(info["tx_hash"])
119 self.chain.fetch_transaction(tx_hash,
120 bitcoin.bind(self.load_tx, bitcoin._1, bitcoin._2,
121 statement_line, info))
123 def load_tx(self, ec, tx, statement_line, info):
125 for tx_out in tx.outputs:
126 script = tx_out.output_script
127 if script.type() == bitcoin.payment_type.pubkey_hash:
128 pkh = bitcoin.short_hash(str(script.operations()[2].data))
129 outputs.append(bitcoin.public_key_hash_to_address(pkh))
131 outputs.append("Unknown")
132 info["outputs"] = outputs
133 info["inputs"] = [None for i in range(len(tx.inputs))]
134 if info["is_in"] == 1:
135 info["inputs"][info["pos"]] = self.address
137 info["value"] = tx.outputs[info["pos"]].value
138 if not [empty_in for empty_in in info["inputs"] if empty_in is None]:
139 # We have the sole input
140 assert(info["is_in"] == 1)
141 with statement_line.lock:
142 statement_line.input_loaded = info
143 self.finish_if_done()
144 for tx_idx, tx_in in enumerate(tx.inputs):
145 if info["is_in"] == 1 and info["pos"] == tx_idx:
147 self.chain.fetch_transaction(tx_in.previous_output.hash,
148 bitcoin.bind(self.load_input, bitcoin._1, bitcoin._2,
149 tx_in.previous_output.index, statement_line, info, tx_idx))
151 def load_input(self, ec, tx, index, statement_line, info, inputs_index):
152 script = tx.outputs[index].output_script
153 if script.type() == bitcoin.payment_type.pubkey_hash:
154 pkh = bitcoin.short_hash(str(script.operations()[2].data))
155 info["inputs"][inputs_index] = \
156 bitcoin.public_key_hash_to_address(pkh)
158 info["inputs"][inputs_index] = "Unknown"
159 if not [empty_in for empty_in in info["inputs"] if empty_in is None]:
160 with statement_line.lock:
161 if info["is_in"] == 1:
162 statement_line.input_loaded = info
164 statement_line.output_loaded = info
165 self.finish_if_done()
167 def payment_history(chain, address, handle_finish):
168 ph = PaymentHistory(chain)
170 ph.run(address, handle_finish)
172 if __name__ == "__main__":
178 service = bitcoin.async_service(1)
179 prefix = "/home/genjix/libbitcoin/database"
180 chain = bitcoin.bdb_blockchain(service, prefix)
181 chain.fetch_last_depth(last)
182 address = "1Pbn3DLXfjqF1fFV9YPdvpvyzejZwkHhZE"
183 print "Looking up", address
184 payment_history(chain, address, finish)