lib/bitcoin/wallet/utxo_handler.rb in bitcoinrb-grpc-0.1.4 vs lib/bitcoin/wallet/utxo_handler.rb in bitcoinrb-grpc-0.1.5

- old
+ new

@@ -1,12 +1,13 @@ module Bitcoin module Wallet class UtxoHandler < Concurrent::Actor::Context - attr_reader :watchings, :spv, :utxo_db, :publisher + attr_reader :watchings, :spv, :utxo_db, :publisher, :pendings def initialize(spv, publisher) @watchings = [] + @pendings = [] @spv = spv @spv.add_observer(self) @utxo_db = spv.wallet.utxo_db @publisher = publisher @@ -19,10 +20,14 @@ def on_message(message) case message when Bitcoin::Grpc::WatchTxConfirmedRequest spv.filter_add(message.tx_hash) watchings << message + when Bitcoin::Grpc::WatchUtxoSpentRequest + outpoint = Bitcoin::OutPoint.new(message.tx_hash, message.output_index) + spv.filter_add(outpoint.to_payload.bth) + watchings << message when :watchings watchings end end @@ -40,25 +45,42 @@ publisher << Bitcoin::Grpc::EventUtxoRegistered.new(request_id: 0, tx_hash: tx.tx_hash, tx_payload: tx.to_payload.bth, utxo: utxo) if utxo end tx.inputs.each do |input| utxo = utxo_db.delete_utxo(input.out_point) - publisher << Bitcoin::Grpc::EventUtxoSpent.new(request_id: 0, tx_hash: tx.tx_hash, tx_payload: tx.to_payload.bth, utxo: utxo) if utxo + watchings + .select { |item| item.is_a? Bitcoin::Grpc::WatchUtxoSpentRequest } + .select { |item| input.out_point.hash == item.tx_hash && input.out_point.index == item.output_index } + .each do |item| + publisher << Bitcoin::Grpc::EventUtxoSpent.new( + request_id: item.id, + tx_hash: tx.tx_hash, + tx_payload: tx.to_payload.bth, + out_point: Bitcoin::Grpc::OutPoint.new(tx_hash: item.tx_hash, index: item.output_index), + utxo: utxo + ) + end end utxo_db.save_tx(tx.tx_hash, tx.to_payload.bth) publisher << Bitcoin::Grpc::WatchAssetIdAssignedRequest.new(tx_hash: tx.tx_hash, tx_payload: tx.to_payload.bth) if tx.colored? end def merkleblock(data) - block_height = spv.chain.latest_block.height - tree = Bitcoin::MerkleTree.build_partial(data.tx_count, data.hashes, Bitcoin.byte_to_bit(data.flags.htb)) tx_blockhash = data.header.block_hash + block = spv.chain.find_entry_by_hash(tx_blockhash) + if block + save_tx_position(data, block) + else + pendings << data + end + end - log(::Logger::DEBUG, "UtxoHandler#merkleblock:#{data.hashes}") - + def save_tx_position(data, block) + tree = Bitcoin::MerkleTree.build_partial(data.tx_count, data.hashes, Bitcoin.byte_to_bit(data.flags.htb)) + block_height = block.height watchings .select { |item| item.is_a? Bitcoin::Grpc::WatchTxConfirmedRequest } .select { |item| data.hashes.include?(item.tx_hash) } .each do |item| tx_index = tree.find_node(item.tx_hash).index @@ -67,11 +89,25 @@ utxo_db.save_tx_position(item.tx_hash, block_height, tx_index) end end def header(data) - log(::Logger::DEBUG, "UtxoHandler#header:#{[data, watchings]}") block_height = data[:height] + block_hash = data[:hash] + + if block_hash && block_height > 0 + publisher << Bitcoin::Grpc::BlockCreated.new(hash: block_hash, height: block_height) + end + + pendings.each do |pending_merkleblock| + tx_blockhash = pending_merkleblock.header.block_hash + block = spv.chain.find_entry_by_hash(tx_blockhash) + if block + save_tx_position(pending_merkleblock, block) + pendings.delete(pending_merkleblock) + end + end + watchings.select do |item| case item when Bitcoin::Grpc::WatchTxConfirmedRequest height, tx_index, tx_payload = utxo_db.get_tx(item.tx_hash) log(::Logger::DEBUG, "UtxoHandler#header:#{[block_height, height, tx_index, item.confirmations]}")