txcatcher 0.1.100 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/txcatcher/bitcoin_rpc.rb +15 -0
- data/lib/txcatcher/models/transaction.rb +19 -17
- data/lib/txcatcher/server.rb +9 -2
- data/spec/models/transaction_spec.rb +2 -2
- data/txcatcher.gemspec +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bf1548d64396f39c3f5dd29ce44c08db1cf0a8b7a561621964d93157afb2736
|
4
|
+
data.tar.gz: c84ec5f6b8c02b5edc5c37bc53550079ad80ff899778959d59b7162f8bedd62b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c753e7883e49dbd218424f43e3edde6431bbec2a9d3817991424933c38515f27c118bfd65ac7778a725ed08a0becb6e93a6ee7330ecf0b7fa607f9c397d4f25a
|
7
|
+
data.tar.gz: 4bba3d57d20cddad92b8221984df9d8913e46cbbbda3db744529e5e4f577a8327e99b390d5c8a94ed60b3691070562d71478f41666284d20e68d36d2e89985de
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -27,6 +27,21 @@ class BitcoinRPC
|
|
27
27
|
http.request(request).body
|
28
28
|
end
|
29
29
|
|
30
|
+
def get_block_transactions(block_height)
|
31
|
+
TxCatcher::LOGGER.report "--- checking transactions in block #{block_height}"
|
32
|
+
block_hash = self.getblockhash(block_height)
|
33
|
+
TxCatcher.rpc_node.getblock(block_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_blocks(limit=100)
|
37
|
+
blocks = []
|
38
|
+
limit.times do |i|
|
39
|
+
height = TxCatcher.current_block_height - i
|
40
|
+
blocks << get_block_transactions(height)
|
41
|
+
end
|
42
|
+
blocks
|
43
|
+
end
|
44
|
+
|
30
45
|
class JSONRPCError < RuntimeError
|
31
46
|
attr_accessor :data
|
32
47
|
def initialize(data)
|
@@ -44,33 +44,35 @@ module TxCatcher
|
|
44
44
|
|
45
45
|
# Queries rpc node to check whether the transaction has been included in any of the blocks,
|
46
46
|
# but only if current block_height is nil.
|
47
|
-
def update_block_height!(
|
48
|
-
|
49
|
-
# This calculates the approximate number of blocks to check.
|
50
|
-
# So, for example, if transaction is less than 10 minutes old,
|
51
|
-
# there's probably no reason to try and check more than 2-3 blocks back.
|
52
|
-
# However, to make absolute sure, we always bump up this number for 10 blocks.
|
53
|
-
# Over larger periods of time, the avg block per minute value should even out, so
|
54
|
-
# it's probably going to be fine either way.
|
55
|
-
created_minutes_ago = ((self.created_at - Time.now).to_i/60)
|
56
|
-
blocks_to_check = (created_minutes_ago / 10).abs + 10
|
47
|
+
def update_block_height!(dont_save: false, blocks: nil)
|
57
48
|
return self.block_height if self.block_height
|
58
|
-
|
49
|
+
blocks = TxCatcher.rpc_node.get_blocks(blocks_to_check_for_inclusion_if_unconfirmed) unless blocks
|
59
50
|
|
60
|
-
|
61
|
-
while i <= blocks_to_check
|
62
|
-
block_hash = TxCatcher.rpc_node.getblockhash(TxCatcher.current_block_height - i)
|
63
|
-
block = TxCatcher.rpc_node.getblock(block_hash)
|
64
|
-
i += 1
|
65
|
-
LOGGER.report "--- checking block #{TxCatcher.current_block_height - i} for tx #{self.txid}"
|
51
|
+
for block in blocks do
|
66
52
|
if block["tx"] && block["tx"].include?(self.txid)
|
67
53
|
LOGGER.report "tx #{self.txid} block height updated to #{block["height"]}"
|
68
54
|
self.update(block_height: block["height"]) if !dont_save
|
69
55
|
return block["height"].to_i
|
56
|
+
else
|
57
|
+
return nil
|
70
58
|
end
|
71
59
|
end
|
72
60
|
end
|
73
61
|
|
62
|
+
# This calculates the approximate number of blocks to check.
|
63
|
+
# So, for example, if transaction is less than 10 minutes old,
|
64
|
+
# there's probably no reason to try and check more than 2-3 blocks back.
|
65
|
+
# However, to make absolute sure, we always bump up this number by 10 blocks.
|
66
|
+
# Over larger periods of time, the avg block per minute value should even out, so
|
67
|
+
# it's probably going to be fine either way.
|
68
|
+
def blocks_to_check_for_inclusion_if_unconfirmed(limit=100)
|
69
|
+
return false if self.block_height
|
70
|
+
created_minutes_ago = ((self.created_at - Time.now).to_i/60)
|
71
|
+
blocks_to_check = (created_minutes_ago / 10).abs + 10
|
72
|
+
blocks_to_check = limit if blocks_to_check > limit
|
73
|
+
blocks_to_check
|
74
|
+
end
|
75
|
+
|
74
76
|
private
|
75
77
|
|
76
78
|
def parse_transaction
|
data/lib/txcatcher/server.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'ruby-prof'
|
1
2
|
module TxCatcher
|
2
3
|
|
3
4
|
class Server < Goliath::API
|
@@ -9,9 +10,12 @@ module TxCatcher
|
|
9
10
|
begin
|
10
11
|
return route_for(uri)
|
11
12
|
rescue BitcoinRPC::JSONRPCError => e
|
13
|
+
puts e.to_s
|
14
|
+
puts e.backtrace.join("\n")
|
12
15
|
return [400, {}, { error: e.data }.to_json]
|
13
16
|
rescue Exception => e
|
14
|
-
|
17
|
+
puts e.to_s
|
18
|
+
puts e.backtrace.join("\n")
|
15
19
|
return [500, {}, { error: e.to_s }.to_json]
|
16
20
|
end
|
17
21
|
end
|
@@ -72,6 +76,7 @@ module TxCatcher
|
|
72
76
|
newly_confirmed_txs_to_update = []
|
73
77
|
|
74
78
|
transactions = model.deposits.map { |d| d.transaction }
|
79
|
+
transactions.sort! { |t1,t2| t2.created_at <=> t1.created_at }
|
75
80
|
utxos = transactions.map do |t|
|
76
81
|
outs = t.tx_hash["vout"].select { |out| out["scriptPubKey"]["addresses"] == [addr] }
|
77
82
|
outs.map! do |out|
|
@@ -84,8 +89,10 @@ module TxCatcher
|
|
84
89
|
outs
|
85
90
|
end.flatten
|
86
91
|
|
92
|
+
blocks = TxCatcher.rpc_node.get_blocks(unconfirmed_txs_to_update.first.blocks_to_check_for_inclusion_if_unconfirmed)
|
93
|
+
|
87
94
|
unconfirmed_txs_to_update = unconfirmed_txs_to_update.map do |t|
|
88
|
-
tx_block_height = t.update_block_height!(
|
95
|
+
tx_block_height = t.update_block_height!(dont_save: true, blocks: blocks)
|
89
96
|
if tx_block_height && tx_block_height > 0
|
90
97
|
newly_confirmed_txs_to_update << t
|
91
98
|
nil
|
@@ -27,8 +27,8 @@ RSpec.describe TxCatcher::Transaction do
|
|
27
27
|
end
|
28
28
|
|
29
29
|
it "updates block height by making manual requests to RPC and searching if tx is included in one of the previous blocks" do
|
30
|
-
expect(TxCatcher.rpc_node).to receive(:getblockhash).and_return("blockhash123")
|
31
|
-
expect(TxCatcher.rpc_node).to receive(:getblock).and_return({ "height" => "123", "tx" => [@transaction.txid], "hash" => "blockhash123"})
|
30
|
+
expect(TxCatcher.rpc_node).to receive(:getblockhash).exactly(10).times.and_return("blockhash123")
|
31
|
+
expect(TxCatcher.rpc_node).to receive(:getblock).exactly(10).times.and_return({ "height" => "123", "tx" => [@transaction.txid], "hash" => "blockhash123"})
|
32
32
|
@transaction.update_block_height!
|
33
33
|
expect(@transaction.block_height).to eq(123)
|
34
34
|
end
|
data/txcatcher.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: txcatcher 0.
|
5
|
+
# stub: txcatcher 0.2.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "txcatcher".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|