From: genjix Date: Thu, 12 Apr 2012 12:50:19 +0000 (+0100) Subject: memory pool buffer used for looking up memory pool transactions in get_history. X-Git-Url: https://git.novaco.in/?p=electrum-server.git;a=commitdiff_plain;h=77d643dc5be10248b1d3a46128bb0bc5de2ae74b memory pool buffer used for looking up memory pool transactions in get_history. --- diff --git a/backends/libbitcoin/history.py b/backends/libbitcoin/history.py index 4fabe5a..ca629a8 100644 --- a/backends/libbitcoin/history.py +++ b/backends/libbitcoin/history.py @@ -1,5 +1,5 @@ import bitcoin -from bitcoin import bind, _1, _2, _3 +from bitcoin import _1, _2, _3 import threading class PaymentEntry: @@ -25,7 +25,8 @@ class PaymentEntry: class History: - def __init__(self, chain): + def __init__(self, service, chain): + self.wrap = bitcoin.Strand(service).wrap self.chain = chain self.lock = threading.Lock() self.statement = [] @@ -38,7 +39,8 @@ class History: address = bitcoin.payment_address(address) # To begin we fetch all the outputs (payments in) # associated with this address - self.chain.fetch_outputs(address, self.start_loading) + self.chain.fetch_outputs(address, + self.wrap(self.start_loading, _1, _2)) def stop(self): with self.lock: @@ -66,7 +68,7 @@ class History: self.statement.append(entry) # Attempt to fetch the spend of this output self.chain.fetch_spend(outpoint, - bind(self.load_spend, _1, _2, entry)) + self.wrap(self.load_spend, _1, _2, entry)) self.load_tx_info(outpoint, entry, False) def load_spend(self, ec, inpoint, entry): @@ -124,7 +126,7 @@ class History: # of the parent block, so we load the block depth and then # fetch the block header and hash it. self.chain.fetch_transaction_index(point.hash, - bind(self.tx_index, _1, _2, _3, entry, info)) + self.wrap(self.tx_index, _1, _2, _3, entry, info)) def tx_index(self, ec, block_depth, offset, entry, info): if self.stop_on_error(ec): @@ -132,7 +134,7 @@ class History: info["height"] = block_depth # And now for the block hash self.chain.fetch_block_header_by_depth(block_depth, - bind(self.block_header, _1, _2, entry, info)) + self.wrap(self.block_header, _1, _2, entry, info)) def block_header(self, ec, blk_head, entry, info): if self.stop_on_error(ec): @@ -142,7 +144,7 @@ class History: tx_hash = bitcoin.hash_digest(info["tx_hash"]) # Now load the actual main transaction for this input or output self.chain.fetch_transaction(tx_hash, - bind(self.load_tx, _1, _2, entry, info)) + self.wrap(self.load_tx, _1, _2, entry, info)) def load_tx(self, ec, tx, entry, info): if self.stop_on_error(ec): @@ -188,7 +190,7 @@ class History: continue prevout = tx_input.previous_output self.chain.fetch_transaction(prevout.hash, - bind(self.load_input_tx, _1, _2, + self.wrap(self.load_input_tx, _1, _2, prevout.index, entry, info, input_index)) def inputs_all_loaded(self, info_inputs): @@ -220,14 +222,19 @@ if __name__ == "__main__": def blockchain_started(ec, chain): print "Blockchain initialisation:", ec def finish(result): - print result + for line in result: + for k, v in line.iteritems(): + begin = k + ":" + print begin, " " * (12 - len(begin)), v + print service = bitcoin.async_service(1) prefix = "/home/genjix/libbitcoin/database" chain = bitcoin.bdb_blockchain(service, prefix, blockchain_started) address = "1Pbn3DLXfjqF1fFV9YPdvpvyzejZwkHhZE" print "Looking up", address - h = History(chain) + local_service = bitcoin.AsyncService() + h = History(local_service, chain) h.start(address, finish) raw_input() print "Stopping..." diff --git a/backends/libbitcoin/mempool_buffer.py b/backends/libbitcoin/mempool_buffer.py new file mode 100644 index 0000000..3ea5cc6 --- /dev/null +++ b/backends/libbitcoin/mempool_buffer.py @@ -0,0 +1,82 @@ +import bitcoin +from bitcoin import _1, _2 +import multimap + +class MemoryPoolBuffer: + + def __init__(self, service, txpool): + self.wrap = bitcoin.Strand(service).wrap + self.txpool = txpool + # prevout: inpoint + self.lookup_input = {} + # payment_address: outpoint + self.lookup_address = multimap.MultiMap() + + def recv_tx(self, tx): + tx_hash = bitcoin.hash_transaction(tx) + desc = (tx_hash, [], []) + for input in tx.inputs: + desc[1].append(input.previous_output) + for idx, output in enumerate(tx.outputs): + address = bitcoin.payment_address() + if address.extract(output.output_script): + desc[2].append((idx, address)) + self.txpool.store(tx, + self.wrap(self.confirmed, _1, desc), + self.wrap(self.mempool_stored, _1, desc)) + + def mempool_stored(self, ec, desc): + tx_hash, prevouts, addrs = desc + if ec: + print "Error storing memory pool transaction", tx_hash, ec + return + print "Accepted transaction", tx_hash + for idx, prevout in enumerate(prevouts): + inpoint = bitcoin.input_point() + inpoint.hash, inpoint.index = tx_hash, idx + self.lookup_input[prevout] = inpoint + for idx, address in addrs: + outpoint = bitcoin.output_point() + outpoint.hash, outpoint.index = tx_hash, idx + self.lookup_address[str(address)] = outpoint + + def confirmed(self, ec, desc): + tx_hash, prevouts, addrs = desc + if ec: + print "Problem confirming transaction", tx_hash, ec + return + print "Confirmed", tx_hash + for idx, prevout in enumerate(prevouts): + inpoint = bitcoin.input_point() + inpoint.hash, inpoint.index = tx_hash, idx + assert self.lookup_input[prevout] == inpoint + del self.lookup_input[prevout] + for idx, address in addrs: + outpoint = bitcoin.output_point() + outpoint.hash, outpoint.index = tx_hash, idx + self.lookup_address.delete(str(address), outpoint) + +if __name__ == "__main__": + ex = bitcoin.satoshi_exporter() + tx_a = bitcoin.data_chunk("0100000003d0406a31f628e18f5d894b2eaf4af719906dc61be4fb433a484ed870f6112d15000000008b48304502210089c11db8c1524d8839243803ac71e536f3d876e8265bbb3bc4a722a5d0bd40aa022058c3e59a7842ef1504b1c2ce048f9af2d69bbf303401dced1f68b38d672098a10141046060f6c8e355b94375eec2cc1d231f8044e811552d54a7c4b36fe8ee564861d07545c6c9d5b9f60d16e67d683b93486c01d3bd3b64d142f48af70bb7867d0ffbffffffff6152ed1552b1f2635317cea7be06615a077fc0f4aa62795872836c4182ca0f25000000008b48304502205f75a468ddb08070d235f76cb94c3f3e2a75e537bc55d087cc3e2a1559b7ac9b022100b17e4c958aaaf9b93359f5476aa5ed438422167e294e7207d5cfc105e897ed91014104a7108ec63464d6735302085124f3b7a06aa8f9363eab1f85f49a21689b286eb80fbabda7f838d9b6bff8550b377ad790b41512622518801c5230463dbbff6001ffffffff01c52914dcb0f3d8822e5a9e3374e5893a7b6033c9cfce5a8e5e6a1b3222a5cb010000008c4930460221009561f7206cc98f40f3eab5f3308b12846d76523bd07b5f058463f387694452b2022100b2684ec201760fa80b02954e588f071e46d0ff16562c1ab393888416bf8fcc44014104a7108ec63464d6735302085124f3b7a06aa8f9363eab1f85f49a21689b286eb80fbabda7f838d9b6bff8550b377ad790b41512622518801c5230463dbbff6001ffffffff02407e0f00000000001976a914c3b98829108923c41b3c1ba6740ecb678752fd5e88ac40420f00000000001976a914424648ea6548cc1c4ea707c7ca58e6131791785188ac00000000") + tx_a = ex.load_transaction(tx_a) + assert bitcoin.hash_transaction(tx_a) == "e72e4f025695446cfd5c5349d1720beb38801f329a00281f350cb7e847153397" + tx_b = bitcoin.data_chunk("0100000001e269f0d74b8e6849233953715bc0be3ba6727afe0bc5000d015758f9e67dde34000000008c4930460221008e305e3fdf4420203a8cced5be20b73738a3b51186dfda7c6294ee6bebe331b7022100c812ded044196132f5e796dbf4b566b6ee3246cc4915eca3cf07047bcdf24a9301410493b6ce24182a58fc3bd0cbee0ddf5c282e00c0c10b1293c7a3567e95bfaaf6c9a431114c493ba50398ad0a82df06254605d963d6c226db615646fadd083ddfd9ffffffff020f9c1208000000001976a91492fffb2cb978d539b6bcd12c968b263896c6aacf88ac8e3f7600000000001976a914654dc745e9237f86b5fcdfd7e01165af2d72909588ac00000000") + tx_b = ex.load_transaction(tx_b) + assert bitcoin.hash_transaction(tx_b) == "acfda6dbf4ae1b102326bfb7c9541702d5ebb0339bc57bd74d36746855be8eac" + + def blockchain_started(ec, chain): + print "Blockchain initialisation:", ec + + service = bitcoin.async_service(1) + prefix = "/home/genjix/libbitcoin/database" + chain = bitcoin.bdb_blockchain(service, prefix, blockchain_started) + txpool = bitcoin.transaction_pool(service, chain) + local_service = bitcoin.AsyncService() + membuf = MemoryPoolBuffer(local_service, txpool) + membuf.recv_tx(tx_a) + membuf.recv_tx(tx_b) + print "Started." + raw_input() + print "Stopping..." + diff --git a/backends/libbitcoin/multimap.py b/backends/libbitcoin/multimap.py new file mode 100644 index 0000000..02db35f --- /dev/null +++ b/backends/libbitcoin/multimap.py @@ -0,0 +1,37 @@ +class MultiMap: + + def __init__(self): + self.multi = {} + + def __getitem__(self, key): + return self.multi[key] + + def __setitem__(self, key, value): + if not self.multi.has_key(key): + self.multi[key] = [] + self.multi[key].append(value) + + def delete(self, key, value): + for i, item in enumerate(self.multi[key]): + if item == value: + del self.multi[key][i] + if not self.multi[key]: + del self.multi[key] + return + raise IndexError + + def __repr__(self): + return repr(self.multi) + def __str__(self): + return str(self.multi) + +if __name__ == "__main__": + m = MultiMap() + m["foo"] = 1 + m["foo"] = 1 + m["bar"] = 2 + print m["foo"] + m.delete("foo", 1) + m.delete("bar", 2) + print m.multi +