7 class ExpiryQueue(threading.Thread):
10 self.lock = threading.Lock()
12 threading.Thread.__init__(self)
19 self.items = [i for i in self.items if not i.stopped()]
24 self.items.append(item)
26 expiry_queue = ExpiryQueue()
31 def __init__(self, output_point):
32 self.lock = threading.Lock()
33 self.output_point = output_point
34 self.output_loaded = None
35 self.input_point = None
36 self.input_loaded = None
37 self.raw_output_script = None
41 if self.output_loaded is None:
43 elif (self.input_point is not False and
44 self.input_loaded is None):
51 def __init__(self, chain):
53 self.lock = threading.Lock()
57 def run(self, address, handle_finish):
58 self.address = address
59 self.handle_finish = handle_finish
61 pubkey_hash = bitcoin.address_to_short_hash(address)
62 self.chain.fetch_outputs(pubkey_hash, self.start_loading)
64 def start_loading(self, ec, output_points):
66 for outpoint in output_points:
67 statement_line = StatementLine(outpoint)
68 self.statement.append(statement_line)
69 self.chain.fetch_spend(
71 bitcoin.bind(self.load_spend, bitcoin._1, bitcoin._2, statement_line)
73 self.load_tx_info(outpoint, statement_line, False)
75 def load_spend(self, ec, inpoint, statement_line):
76 with statement_line.lock:
78 statement_line.input_point = False
80 statement_line.input_point = inpoint
83 self.load_tx_info(inpoint, statement_line, True)
85 def finish_if_done(self):
87 if any(not line.is_loaded() for line in self.statement):
90 for line in self.statement:
92 line.input_loaded["value"] = -line.output_loaded["value"]
93 result.append(line.input_loaded)
95 line.output_loaded["raw_output_script"] = line.raw_output_script
96 result.append(line.output_loaded)
97 self.handle_finish(result)
108 def load_tx_info(self, point, statement_line, is_input):
110 info["tx_hash"] = str(point.hash)
111 info["index"] = point.index
112 info["is_input"] = 1 if is_input else 0
113 self.chain.fetch_transaction_index(
115 bitcoin.bind(self.tx_index, bitcoin._1, bitcoin._2, bitcoin._3, statement_line, info)
118 def tx_index(self, ec, block_depth, offset, statement_line, info):
119 info["height"] = block_depth
120 self.chain.fetch_block_header_by_depth(
122 bitcoin.bind(self.block_header, bitcoin._1, bitcoin._2, statement_line, info)
125 def block_header(self, ec, blk_head, statement_line, info):
126 info["timestamp"] = blk_head.timestamp
127 info["block_hash"] = str(bitcoin.hash_block_header(blk_head))
128 tx_hash = bitcoin.hash_digest(info["tx_hash"])
129 self.chain.fetch_transaction(
131 bitcoin.bind(self.load_tx, bitcoin._1, bitcoin._2, statement_line, info)
134 def load_tx(self, ec, tx, statement_line, info):
136 for tx_out in tx.outputs:
137 script = tx_out.output_script
138 if script.type() == bitcoin.payment_type.pubkey_hash:
139 pkh = bitcoin.short_hash(str(script.operations()[2].data))
140 outputs.append(bitcoin.public_key_hash_to_address(pkh))
142 outputs.append("Unknown")
143 info["outputs"] = outputs
144 info["inputs"] = [None for i in range(len(tx.inputs))]
145 if info["is_input"] == 1:
146 info["inputs"][info["index"]] = self.address
148 our_output = tx.outputs[info["index"]]
149 info["value"] = our_output.value
150 with statement_line.lock:
151 statement_line.raw_output_script = \
152 str(bitcoin.save_script(our_output.output_script))
153 if not [empty_in for empty_in in info["inputs"] if empty_in is None]:
154 # We have the sole input
155 assert(info["is_input"] == 1)
156 with statement_line.lock:
157 statement_line.input_loaded = info
158 self.finish_if_done()
159 for tx_idx, tx_in in enumerate(tx.inputs):
160 if info["is_input"] == 1 and info["index"] == tx_idx:
162 self.chain.fetch_transaction(
163 tx_in.previous_output.hash,
164 bitcoin.bind(self.load_input, bitcoin._1, bitcoin._2, tx_in.previous_output.index, statement_line, info, tx_idx)
167 def load_input(self, ec, tx, index, statement_line, info, inputs_index):
168 script = tx.outputs[index].output_script
169 if script.type() == bitcoin.payment_type.pubkey_hash:
170 pkh = bitcoin.short_hash(str(script.operations()[2].data))
171 info["inputs"][inputs_index] = \
172 bitcoin.public_key_hash_to_address(pkh)
174 info["inputs"][inputs_index] = "Unknown"
175 if not [empty_in for empty_in in info["inputs"] if empty_in is None]:
176 with statement_line.lock:
177 if info["is_input"] == 1:
178 statement_line.input_loaded = info
180 statement_line.output_loaded = info
181 self.finish_if_done()
184 def payment_history(chain, address, handle_finish):
185 ph = PaymentHistory(chain)
187 ph.run(address, handle_finish)
190 if __name__ == "__main__":
197 service = bitcoin.async_service(1)
198 prefix = "/home/genjix/libbitcoin/database"
199 chain = bitcoin.bdb_blockchain(service, prefix)
200 chain.fetch_last_depth(last)
201 address = "1Pbn3DLXfjqF1fFV9YPdvpvyzejZwkHhZE"
202 print "Looking up", address
203 payment_history(chain, address, finish)