Commit 2bccd8e4e0200cc88bb2fa3308207fbebedd5d00

Authored by Marius Hanne
1 parent 337584850a
Exists in electrum_server

make electrum server work with unconfirmed tx

Showing 3 changed files with 68 additions and 13 deletions Side-by-side Diff

lib/bitcoin/electrum/server.rb
... ... @@ -98,8 +98,13 @@
98 98 if @subscribed_headers
99 99 send_response(method: "blockchain.headers.subscribe", params: [get_header])
100 100 end
101   - block.tx.each {|tx| check_tx(tx, block.hash) }
  101 + block.tx.each do |tx|
  102 + check_tx(tx, block.hash)
  103 + end
102 104 end
  105 + @tx_channel = @server.node.subscribe(:tx) do |tx, conf|
  106 + check_tx(tx)
  107 + end
103 108 log.info { "client connected" }
104 109 end
105 110  
106 111  
... ... @@ -171,11 +176,16 @@
171 176 txs << { tx_hash: tx.hash, height: block[:depth] }
172 177 next unless txin = txout.get_next_in
173 178 tx = txin.get_tx
174   - binding.pry unless tx
175 179 block = store.db[:blk][id: tx.blk_id]
176 180 txs << { tx_hash: tx.hash, height: block[:depth] }
177 181 end
178   - txs.uniq.sort_by {|t| t[:height] }
  182 +
  183 + @server.node.unconfirmed.each do |tx_hash, tx|
  184 + next unless outs = get_all_outs(tx)
  185 + txs << { tx_hash: tx.hash, height: 0 } if outs.map {|o|
  186 + o.parsed_script.get_addresses.include?(addr) }.any?
  187 + end
  188 + txs.uniq.sort_by {|t| [t[:height], t[:tx_hash]] }.reverse
179 189 end
180 190  
181 191 def subscribe_address addr
... ... @@ -200,7 +210,9 @@
200 210 end
201 211  
202 212 def get_transaction hash
203   - store.get_tx(hash).to_payload.unpack("H*")[0]
  213 + tx = store.get_tx(hash) || @server.node.unconfirmed[hash]
  214 + return nil unless tx
  215 + tx.to_payload.unpack("H*")[0]
204 216 end
205 217  
206 218 def get_merkle hash
207 219  
... ... @@ -220,13 +232,26 @@
220 232 }.join.unpack("H*")[0]
221 233 end
222 234  
223   - def check_tx tx, block_hash = "mempool:x"
  235 + # check if our client is interested in this tx and if so, send it.
  236 + # TODO: proper mempool, make it work for chains of unconfirmed tx
  237 + def check_tx tx, block_hash = nil, addr = nil
  238 + return unless outs = get_all_outs(tx)
  239 + outs.map {|o| o.parsed_script.get_addresses & @subscribed_addresses }
  240 + .flatten.uniq.each {|a|
  241 + return true if addr
  242 + hash = block_hash || get_status(a)
  243 + send_response(method: "blockchain.address.subscribe", params: [a, hash])
  244 + }
  245 + end
  246 +
  247 + # get all outputs affected by this tx (all prev_outs and the outputs of this tx)
  248 + def get_all_outs tx
  249 + return unless tx
224 250 prev_outs = tx.in[0].coinbase? ? [] : tx.in.map {|i|
225   - store.get_tx(i.prev_out.reverse_hth).out[i.prev_out_index] }
226   - (prev_outs + tx.out).compact.map {|o|
227   - Bitcoin::Script.new(o.pk_script).get_addresses & @subscribed_addresses
228   - }.flatten.uniq.each {|a|
229   - send_response(method: "blockchain.address.subscribe", params: [a, block_hash]) }
  251 + return unless prev_tx = store.get_tx(i.prev_out.reverse_hth)
  252 + return unless prev_tx
  253 + prev_tx.out[i.prev_out_index] }
  254 + (prev_outs + tx.out).compact
230 255 end
231 256  
232 257 end
233 258  
... ... @@ -236,11 +261,10 @@
236 261 include ConnectionHandler
237 262  
238 263 def initialize server
239   - @buf = BufferedTokenizer.new("\n")
240   -
241 264 @server = server
242 265 @subscribed_addresses = []
243 266 @subscribed_numblocks = false
  267 + @buf = BufferedTokenizer.new("\n")
244 268 end
245 269  
246 270 def post_init
lib/bitcoin/network/node.rb
... ... @@ -44,6 +44,9 @@
44 44 # time when the last main chain block was added
45 45 attr_reader :last_block_time
46 46  
  47 + # unconfirmed transactions
  48 + attr_accessor :unconfirmed
  49 +
47 50 attr_accessor :tx_to_relay
48 51 attr_accessor :relay_propagation
49 52  
... ... @@ -423,7 +426,12 @@
423 426 drop = @unconfirmed.size - @config[:max][:unconfirmed] + 1
424 427 drop.times { @unconfirmed.shift } if drop > 0
425 428 unless @unconfirmed[obj[1].hash]
426   - @unconfirmed[obj[1].hash] = obj[1]
  429 + begin
  430 + @unconfirmed[obj[1].hash] = obj[1]
  431 + rescue
  432 + sleep 0.01
  433 + retry
  434 + end
427 435 push_notification(:tx, [obj[1], 0])
428 436  
429 437 if @notifiers[:output]
  1 +{
  2 + "hash":"19aa42fee0fa57c45d3b16488198b27caaacc4ff5794510d0c17f173f05587ff",
  3 + "ver":1,
  4 + "vin_sz":1,
  5 + "vout_sz":1,
  6 + "lock_time":0,
  7 + "size":796,
  8 + "in":[
  9 + {
  10 + "prev_out":{
  11 + "hash":"801d1ddbf9066dc0f08988d2a1d3e77e5da0c7bc9bd0f44f003a513a6433217a",
  12 + "n":0
  13 + },
  14 + "scriptSig":"0 3044022011cb94542051b8be5563b39da022d7531673ed4b53b6b3f8536794150f7d75e802205a6774c0630964457c2d4a087e5a23167155f661082746dc711ba348ca4d418701 5121033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b21033d1d799df4bbb828cb8fd9146407ec974948609031e50224b491a6291b77d76b5fae"
  15 + }
  16 + ],
  17 + "out":[
  18 + {
  19 + "value":"0.00100000",
  20 + "scriptPubKey":"3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 OP_DROP 2 0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 2 OP_CHECKMULTISIG"
  21 + }
  22 + ]
  23 +}