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]}")