txcatcher 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f29602463f10ef91c91d32eef97b9a587f9005b7e63c1d4d5fb13585299f3c82
4
- data.tar.gz: 0b698f2d3528a4ba5395828079904fdf67574d0bdea8660c7583092cf1f903e1
3
+ metadata.gz: a2e24688c0b712c8752c126180e4ccdc7508bb51d83273c0ee95975ee683c45b
4
+ data.tar.gz: 0fc259dc40b77ff6f3ad51d31a389b6ad6c290e50e00fdd29b45dc9c0aff8706
5
5
  SHA512:
6
- metadata.gz: 2e1a21f9973c1cf4703228958522ffe1d4dd7e7a641aa3cdcbda0df8d825552833bfe7e3d926672d3de8565ab5b85d049fe61fcb70b5bf748e41124a9e1d74ec
7
- data.tar.gz: 5b9613759bd60fc5a36c2b7a8d7647cc81400928224eaf099abaae66ea4f2b72489d267f1e01df22eee5d49efb7830a7b3609fc07a02b5c0d6c4c618d70b6bfd
6
+ metadata.gz: fa710896fdaa6ff9a504e73168eef31eec3a69ba4b583817c7dce9132f8c1924e1579437a47162a8c1a5643dc366d54ef08cc9b41e102d6e0f738d291c9c3855
7
+ data.tar.gz: 0cd0b9f730fc45229c7a9547d19a4299b2a103549c7687e0b144f9e042e2ccdbb9d82960de72de154eb95c55f494c2e44ae202c1939d64f3522eef7f176e41b5
data/Gemfile.lock CHANGED
@@ -1,19 +1,19 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- addressable (2.6.0)
5
- public_suffix (>= 2.0.2, < 4.0)
4
+ addressable (2.7.0)
5
+ public_suffix (>= 2.0.2, < 5.0)
6
6
  async-rack (0.5.1)
7
7
  rack (~> 1.1)
8
8
  aws-eventstream (1.0.3)
9
- aws-partitions (1.196.0)
10
- aws-sdk-core (3.62.0)
9
+ aws-partitions (1.269.0)
10
+ aws-sdk-core (3.89.1)
11
11
  aws-eventstream (~> 1.0, >= 1.0.2)
12
- aws-partitions (~> 1.0)
12
+ aws-partitions (~> 1, >= 1.239.0)
13
13
  aws-sigv4 (~> 1.1)
14
14
  jmespath (~> 1.0)
15
- aws-sdk-ses (1.25.0)
16
- aws-sdk-core (~> 3, >= 3.61.1)
15
+ aws-sdk-ses (1.27.0)
16
+ aws-sdk-core (~> 3, >= 3.71.0)
17
17
  aws-sigv4 (~> 1.1)
18
18
  aws-sigv4 (1.1.0)
19
19
  aws-eventstream (~> 1.0, >= 1.0.2)
@@ -26,9 +26,9 @@ GEM
26
26
  addressable (>= 2.1.1)
27
27
  eventmachine (>= 0.12.9)
28
28
  eventmachine (1.2.7)
29
- faraday (0.15.4)
29
+ faraday (1.0.0)
30
30
  multipart-post (>= 1.2, < 3)
31
- ffi (1.11.1)
31
+ ffi (1.12.1)
32
32
  ffi-rzmq (2.0.7)
33
33
  ffi-rzmq-core (>= 1.0.7)
34
34
  ffi-rzmq-core (1.0.7)
@@ -48,32 +48,32 @@ GEM
48
48
  http_parser.rb (0.6.0)
49
49
  jmespath (1.4.0)
50
50
  log4r (1.1.10)
51
- multi_json (1.13.1)
51
+ multi_json (1.14.1)
52
52
  multipart-post (2.1.1)
53
- public_suffix (3.1.1)
54
- rack (1.6.11)
53
+ public_suffix (4.0.3)
54
+ rack (1.6.12)
55
55
  rack-accept-media-types (0.9)
56
56
  rack-contrib (1.8.0)
57
57
  rack (~> 1.4)
58
58
  rack-respond_to (0.9.8)
59
59
  rack-accept-media-types (>= 0.6)
60
- rspec (3.8.0)
61
- rspec-core (~> 3.8.0)
62
- rspec-expectations (~> 3.8.0)
63
- rspec-mocks (~> 3.8.0)
64
- rspec-core (3.8.2)
65
- rspec-support (~> 3.8.0)
66
- rspec-expectations (3.8.4)
60
+ rspec (3.9.0)
61
+ rspec-core (~> 3.9.0)
62
+ rspec-expectations (~> 3.9.0)
63
+ rspec-mocks (~> 3.9.0)
64
+ rspec-core (3.9.1)
65
+ rspec-support (~> 3.9.1)
66
+ rspec-expectations (3.9.0)
67
67
  diff-lcs (>= 1.2.0, < 2.0)
68
- rspec-support (~> 3.8.0)
69
- rspec-mocks (3.8.1)
68
+ rspec-support (~> 3.9.0)
69
+ rspec-mocks (3.9.1)
70
70
  diff-lcs (>= 1.2.0, < 2.0)
71
- rspec-support (~> 3.8.0)
72
- rspec-support (3.8.2)
73
- sentry-raven (2.11.0)
74
- faraday (>= 0.7.6, < 1.0)
75
- sequel (5.23.0)
76
- sqlite3 (1.4.1)
71
+ rspec-support (~> 3.9.0)
72
+ rspec-support (3.9.2)
73
+ sentry-raven (1.1.0)
74
+ faraday (>= 0.7.6)
75
+ sequel (5.28.0)
76
+ sqlite3 (1.4.2)
77
77
 
78
78
  PLATFORMS
79
79
  ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.6
1
+ 0.2.8
@@ -7,10 +7,29 @@ require 'json'
7
7
 
8
8
  class BitcoinRPC
9
9
 
10
+ class NoTxIndexErorr < StandardError;end
11
+
10
12
  def initialize(service_url)
11
13
  @uri = URI.parse(service_url)
12
14
  end
13
15
 
16
+ def txindex_enabled?
17
+ return @tx_index_enabled unless @tx_index_enabled.nil?
18
+ begin
19
+ txid = self.get_block_transactions(self.getblockcount-1000)["tx"].first
20
+ self.getrawtransaction(txid, 1)
21
+ TxCatcher::LOGGER.report "Pruning is off, -txindex enabled, can perform RPC requests to check block_height for transactions, that's much more reliable!"
22
+ return @tx_index_enabled = true
23
+ rescue BitcoinRPC::JSONRPCError => e
24
+ if e.message.include?("pruned data") || e.message.include?("-txindex")
25
+ TxCatcher::LOGGER.report "WARNING: Pruning is ON, will NOT be able to use RPC requests to check block_height for transactions!", :warn
26
+ return @tx_index_enabled = false
27
+ else
28
+ raise e
29
+ end
30
+ end
31
+ end
32
+
14
33
  def method_missing(name, *args)
15
34
  post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json
16
35
  resp = JSON.parse( http_post_request(post_body) )
@@ -81,36 +81,32 @@ module TxCatcher
81
81
  end
82
82
 
83
83
  def handle_rawtx(txhex)
84
- LOGGER.report "received tx hex: #{txhex[0..50]}..."
85
84
  @queue["rawtx"] << ( Proc.new {
86
85
  tx = TxCatcher::Transaction.new(hex: txhex)
86
+ tx.assign_transaction_attrs
87
87
  begin
88
- LOGGER.report "tx #{tx.txid} caught (id: #{tx.id}), deposits (outputs):"
89
88
  tx.save
90
89
  rescue Sequel::ValidationFailed => e
91
- if tx.errors[:txid].include?("is already taken")
92
- LOGGER.report " it's already in DB, no need to save it!"
93
- else
90
+ if !tx.errors[:txid] || !tx.errors[:txid].include?("is already taken")
94
91
  raise e
95
92
  end
96
93
  end
97
- tx.deposits.each do |d|
98
- LOGGER.report " id: #{d.id}, addr: #{d.address.address}, amount: #{CryptoUnit.new(Config["currency"], d.amount, from_unit: :primary).to_standart}"
99
- end
100
94
  })
101
95
  end
102
96
 
103
97
  def handle_hashblock(block_hex)
104
- block_hash = TxCatcher.rpc_node.getblock(block_hex)
105
- transactions = block_hash["tx"]
106
- height = TxCatcher.current_block_height = block_hash["height"].to_i
107
- LOGGER.report "*** Block #{height} mined, transactions received:\n #{transactions.join(" \n")}"
98
+ block_hash = TxCatcher.rpc_node.getblock(block_hex)
99
+ block_transactions_ids = block_hash["tx"]
100
+ height = TxCatcher.current_block_height = block_hash["height"].to_i
101
+ LOGGER.report "*** Block #{height} mined, transactions received:\n #{block_transactions_ids.join("\n\s\s")}"
108
102
  @queue["hashblock"] << ( Proc.new {
109
- existing_transactions = Transaction.where(txid: transactions).map(&:txid)
110
- LOGGER.report "*** Block #{height} mined, transactions received:\n #{transactions.join(" \n")}"
111
- Transaction.where(txid: transactions).update(block_height: height)
103
+ existing_transactions = Transaction.where(txid: block_transactions_ids)
104
+ existing_transactions_ids = existing_transactions.map(&:txid)
105
+ undetected_transactions_ids = block_transactions_ids - existing_transactions_ids
106
+ undetected_transactions_ids.each { |txid| Transaction.create_from_rpc(txid) }
107
+ Transaction.where(txid: existing_transactions_ids).update(block_height: height)
112
108
  })
113
- # Update RBF transactions and deposits if a transaction with lower fee (no associated deposit) got
109
+ # Update RBF transactions and deposits if a transaction a with lower fee (no associated deposit) got
114
110
  # accidentally confirmed.
115
111
  TxCatcher::Transaction.where(block_height: height).exclude(rbf_next_transaction_id: nil).each do |t|
116
112
  t.force_deposit_association_on_rbf!
@@ -123,6 +123,7 @@ module TxCatcher
123
123
  n = TxCatcher::Config.rpcnode
124
124
  print "Checking #{n["name"]} RPC connection... "
125
125
  TxCatcher.rpc_node = BitcoinRPC.new("http://#{n["user"]}:#{n["password"]}@#{n["host"]}:#{n["port"]}")
126
+ TxCatcher.rpc_node.txindex_enabled?
126
127
 
127
128
  i = 0 # try to connect to RPC 100 times before exiting with error
128
129
  until TxCatcher.current_block_height
@@ -20,34 +20,42 @@ module TxCatcher
20
20
  end
21
21
 
22
22
 
23
- def report(message, log_level=:info, data: nil, timestamp: false)
23
+ def report(message, log_level=:info, data: nil, timestamp: false, newline: "\n")
24
24
  @reporters.each do |out|
25
25
  if LOG_LEVELS[log_level] >= LOG_LEVELS[Config["logger"]["#{out}_level"].to_sym]
26
- send("report_to_#{out}", message, log_level, data: data, timestamp: timestamp)
26
+ send("report_to_#{out}", message, log_level, data: data, timestamp: timestamp, newline: newline)
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
31
  private
32
32
 
33
- def report_to_stdout(message, log_level, data: nil, timestamp: timestamp)
34
- $stdout.print prepare_message(message, timestamp: timestamp) + "\n"
35
- $stdout.print " additional data: #{data.to_s}\n" if data
36
- $stdout.print(@error_log_delimiter) if LOG_LEVELS[log_level] >= LOG_LEVELS[:error]
33
+ def report_to_stdout(message, log_level, data: nil, timestamp: timestamp, newline: "\n")
34
+ $stdout.print prepare_message(message, timestamp: timestamp)
35
+ $stdout.print "\n additional data: #{data.to_s}" if data
36
+ if LOG_LEVELS[log_level] >= LOG_LEVELS[:error]
37
+ $stdout.print(@error_log_delimiter)
38
+ elsif newline
39
+ $stdout.print newline
40
+ end
37
41
  end
38
42
 
39
- def report_to_logfile(message, log_level, data: nil, timestamp: true) # always gonna be forcing timestamp to be true here
43
+ def report_to_logfile(message, log_level, data: nil, timestamp: true, newline: true) # always gonna be forcing timestamp to be true here
40
44
  fn = LOG_LEVELS[log_level] >= LOG_LEVELS[:error] ? @error_log_file_name : @log_file_name
41
45
  fn = TxCatcher::Config.config_dir + "/#{fn}"
42
46
 
43
47
  File.open(fn, "a") do |f|
44
- f.print "#{prepare_message(message, timestamp: true)}\n"
45
- f.print " additional data: #{data.to_s}\n" if data
46
- f.print(@error_log_delimiter) if LOG_LEVELS[log_level] >= LOG_LEVELS[:error]
48
+ f.print "#{prepare_message(message, timestamp: true)}"
49
+ f.print "\n additional data: #{data.to_s}\n" if data
50
+ if LOG_LEVELS[log_level] >= LOG_LEVELS[:error]
51
+ f.print(@error_log_delimiter)
52
+ elsif newline
53
+ f.print newline
54
+ end
47
55
  end
48
56
  end
49
57
 
50
- def report_to_sentry(e, log_level, data: nil, timestamp: timestamp)
58
+ def report_to_sentry(e, log_level, data: nil, timestamp: timestamp, newline: true)
51
59
  return unless TxCatcher::Config["logger"]["sentry_dsn"]
52
60
  data ||= {}
53
61
  data.merge!(environment: Config["environment"], host: Config["host"], currency: Config["currency"])
@@ -5,23 +5,36 @@ module TxCatcher
5
5
  plugin :validation_helpers
6
6
  one_to_many :deposits
7
7
 
8
- def self.find_or_catch(txid)
8
+ attr_accessor :manual_rpc_request
9
+
10
+ def self.find_or_create_from_rpc(txid)
9
11
  if tx = self.where(txid: txid).first
12
+ tx.update_block_height!
10
13
  tx
11
14
  else
12
- self.catch(txid)
15
+ self.create_from_rpc(txid)
13
16
  end
14
17
  end
15
18
 
16
- def self.catch(txid)
17
- if txhex = TxCatcher.rpc_node.getrawtransaction(txid)
18
- LOGGER.report "received tx hex: #{txhex[0..50]}... (fetched via manual RPC request)"
19
- tx = self.new(hex: txhex)
19
+ def self.create_from_rpc(txid)
20
+ raise BitcoinRPC::NoTxIndexErorr, "Cannot create transaction from RPC request, (txid: #{txid}) please use -txindex and don't use pruning" unless TxCatcher.rpc_node.txindex_enabled?
21
+ if tx_from_rpc = TxCatcher.rpc_node.getrawtransaction(txid, 1)
22
+ tx = self.new(hex: tx_from_rpc["hex"], txid: txid)
23
+ tx.manual_rpc_request = true
24
+ tx.update_block_height(confirmations: tx_from_rpc["confirmations"])
20
25
  tx.save
21
26
  tx
22
27
  end
23
28
  end
24
29
 
30
+ def log_the_catch!
31
+ manual_rpc_request_caption = (self.manual_rpc_request ? " (fetched via a manual RPC request) " : " ")
32
+ LOGGER.report "tx #{self.txid} caught#{manual_rpc_request_caption}and saved to DB (id: #{self.id}), deposits (outputs):"
33
+ self.deposits.each do |d|
34
+ LOGGER.report " id: #{d.id}, addr: #{d.address.address}, amount: #{CryptoUnit.new(Config["currency"], d.amount, from_unit: :primary).to_standart}"
35
+ end
36
+ end
37
+
25
38
  # Updates only those transactions that have changed
26
39
  def self.update_all(transactions)
27
40
  transactions_to_update = transactions.select { |t| !t.column_changes.empty? }
@@ -57,13 +70,15 @@ module TxCatcher
57
70
  d.rbf_transaction_ids = d.rbf_transaction_ids.uniq
58
71
  end
59
72
  d.save
60
- self.rbf_previous_transaction&.update(rbf_next_transaction_id: self.id)
61
73
  end
74
+ self.rbf_previous_transaction&.update(rbf_next_transaction_id: self.id)
75
+ self.log_the_catch!
62
76
  end
63
77
 
64
78
  def tx_hash
65
- @tx_hash ||= parse_transaction
79
+ @tx_hash ||= TxCatcher.rpc_node.decoderawtransaction(self.hex)
66
80
  end
81
+ alias :parse_transaction :tx_hash
67
82
 
68
83
  def confirmations
69
84
  if self.block_height
@@ -73,19 +88,48 @@ module TxCatcher
73
88
  end
74
89
  end
75
90
 
76
- # Queries rpc node to check whether the transaction has been included in any of the blocks,
77
- # but only if current block_height is nil.
78
- def check_block_height!(dont_save: false, blocks: nil)
79
- return self.block_height if self.block_height
80
- blocks = TxCatcher.rpc_node.get_blocks(blocks_to_check_for_inclusion_if_unconfirmed) unless blocks
91
+ def update_block_height(confirmations: nil)
92
+ return false if self.block_height
93
+ if TxCatcher.rpc_node.txindex_enabled? || !confirmations.nil?
94
+ update_block_height_from_rpc(confirmations: confirmations)
95
+ else
96
+ self.update_block_height_from_latest_blocks
97
+ end
98
+
99
+ end
81
100
 
101
+ def update_block_height!(confirmations: nil)
102
+ return false if self.block_height
103
+ self.update_block_height(confirmations: confirmations)
104
+ self.save if self.column_changed?(:block_height)
105
+ end
106
+
107
+ # Checks the last n blocks to see if current transaction has been included in any of them,
108
+ # This is for cases when -txindex is not enabled and you can't make an RPC query for a particular
109
+ # txid, which would be more reliable.
110
+ def update_block_height_from_latest_blocks
111
+ blocks = TxCatcher.rpc_node.get_blocks(blocks_to_check_for_inclusion_if_unconfirmed) unless blocks
82
112
  for block in blocks.values do
83
113
  if block["tx"] && block["tx"].include?(self.txid)
84
114
  LOGGER.report "tx #{self.txid} block height updated to #{block["height"]}"
85
- self.update(block_height: block["height"]) if !dont_save
115
+ self.block_height = block["height"].to_i
86
116
  return block["height"].to_i
117
+ end
118
+ end
119
+ end
120
+
121
+ # Directly queries the RPC, fetches transaction confirmations number and calculates
122
+ # the block_height. Of confirmations number is provided, doesn't do the RPC request
123
+ # (used in Transaction.create_from_rpc).
124
+ def update_block_height_from_rpc(confirmations: nil)
125
+ begin
126
+ confirmations ||= TxCatcher.rpc_node.getrawtransaction(self.txid, 1)["confirmations"]
127
+ self.block_height = confirmations && confirmations > 0 ? TxCatcher.current_block_height - confirmations + 1 : nil
128
+ rescue BitcoinRPC::JSONRPCError => e
129
+ if e.message.include?("No such mempool or blockchain transaction") && self.rbf?
130
+ LOGGER.report "tx #{self.txid} is an RBF transcation with a lower fee, bitcoin RPC says it's not in the mempool anymore. No need to check for confirmations", :warn
87
131
  else
88
- return nil
132
+ raise e
89
133
  end
90
134
  end
91
135
  end
@@ -128,7 +172,7 @@ module TxCatcher
128
172
  end
129
173
 
130
174
  def input_hexes
131
- @input_hexes ||= self.tx_hash["vin"].map { |input| input["scriptSig"]["hex"] }.compact.sort
175
+ @input_hexes ||= self.tx_hash["vin"].select { |input| !input["scriptSig"].nil? }.map { |input| input["scriptSig"]["hex"] }.compact.sort
132
176
  end
133
177
 
134
178
  def output_addresses
@@ -150,34 +194,30 @@ module TxCatcher
150
194
  end
151
195
 
152
196
  def to_json
153
- #self.tx_hash.to_json
154
197
  self.tx_hash.merge(confirmations: self.confirmations, block_height: self.block_height).to_json
155
198
  end
156
199
 
157
- private
158
-
159
- def parse_transaction
160
- TxCatcher.rpc_node.decoderawtransaction(self.hex)
161
- end
200
+ def assign_transaction_attrs
201
+ self.txid = self.tx_hash["txid"] unless self.txid
202
+ self.block_height = self.tx_hash["block_height"] unless self.block_height
203
+ # In order to be able to identify RBF - those are normally transactions with
204
+ # identical inputs and outputs - we hash inputs and outputs that hash serves
205
+ # as an identifier that we store in our DB and thus can search all
206
+ # previous transactions which the current transaction might be an RBF transaction to.
207
+ #
208
+ # A few comments:
209
+ #
210
+ # 1. Although an RBF transaction may techinically have different outputs as per
211
+ # protocol specification, it is true in most cases that outputs will also be
212
+ # the same (that's how most wallets implement RBF). Thus,
213
+ # we're also incorporating outputs into the hashed value.
214
+ #
215
+ # 2. For inputs, we're using input hexes, because pruned bitcoin-core
216
+ # doesn't provide addresses.
217
+ self.inputs_outputs_hash ||= Digest::SHA256.hexdigest((self.input_hexes + self.output_addresses).join(""))
218
+ end
162
219
 
163
- def assign_transaction_attrs
164
- self.txid = self.tx_hash["txid"] unless self.txid
165
- # In order to be able to identify RBF - those are normally transactions with
166
- # identical inputs and outputs - we hash inputs and outputs that hash serves
167
- # as an identifier that we store in our DB and thus can search all
168
- # previous transactions which the current transaction might be an RBF transaction to.
169
- #
170
- # A few comments:
171
- #
172
- # 1. Although an RBF transaction may techinically have different outputs as per
173
- # protocol specification, it is true in most cases that outputs will also be
174
- # the same (that's how most wallets implement RBF). Thus,
175
- # we're also incorporating outputs into the hashed value.
176
- #
177
- # 2. For inputs, we're using input hexes, because pruned bitcoin-core
178
- # doesn't provide addresses.
179
- self.inputs_outputs_hash ||= Digest::SHA256.hexdigest((self.input_hexes + self.output_addresses).join(""))
180
- end
220
+ private
181
221
 
182
222
  def validate
183
223
  super
@@ -50,7 +50,7 @@ module TxCatcher
50
50
  deposits = deposits.map do |d|
51
51
  t = d.transaction
52
52
  t.update(protected: true) unless t.protected
53
- t.check_block_height!(dont_save: true)
53
+ t.update_block_height
54
54
  result = {
55
55
  txid: t.txid,
56
56
  amount: d.amount_in_btc,
@@ -73,8 +73,8 @@ module TxCatcher
73
73
  addr = path.last
74
74
 
75
75
  address = Address.find_or_create(address: addr)
76
- return [200, {}, "{}"] unless address.deposits.empty?
77
76
  deposits = Deposit.where(address_id: address.id).limit(params["limit"] || 100).eager(:transaction)
77
+ return [200, {}, "{}"] if address.deposits.empty?
78
78
 
79
79
  transactions = deposits.map { |d| d.transaction }
80
80
  transactions.sort! { |t1,t2| t2.created_at <=> t1.created_at }
@@ -82,7 +82,7 @@ module TxCatcher
82
82
  transactions.each do |t|
83
83
  # If we see a transaction with 0 confirmations, let's check if it got any news confirmations
84
84
  # by querying Bitcoind RPC.
85
- t.check_block_height!(dont_save: true) if t.confirmations == 0
85
+ t.update_block_height_from_rpc if t.confirmations == 0
86
86
  # If still not confirmed, let's make it protected so it's not deleted during cleanup.
87
87
  t.protected = true if t.confirmations == 0
88
88
  end
@@ -109,10 +109,10 @@ module TxCatcher
109
109
  def tx(path)
110
110
  path = path.sub(/\?.*/, '').split("/").delete_if { |i| i.empty? }
111
111
  txid = path.last
112
- tx = Transaction.find_or_catch(txid)
113
- tx = Transaction.where(txid: txid).first
112
+ tx = Transaction.find_or_create_from_rpc(txid)
114
113
 
115
- if tx && !tx.deposits.empty?
114
+ if tx && (!tx.deposits.empty? || tx.rbf?)
115
+ tx.update_block_height! if tx.block_height.nil?
116
116
  return [200, {}, tx.to_json]
117
117
  else
118
118
  return [404, {}, "Transaction not found"]
@@ -32,13 +32,6 @@ RSpec.describe TxCatcher::Transaction do
32
32
  expect(TxCatcher::Transaction.where(txid: transaction.txid).count).to eq(1)
33
33
  end
34
34
 
35
- it "updates block height by making manual requests to RPC and searching if tx is included in one of the previous blocks" do
36
- expect(TxCatcher.rpc_node).to receive(:getblockhash).exactly(10).times.and_return("blockhash123")
37
- expect(TxCatcher.rpc_node).to receive(:getblock).exactly(10).times.and_return({ "height" => "123", "tx" => [@transaction.txid], "hash" => "blockhash123"})
38
- @transaction.check_block_height!
39
- expect(@transaction.block_height).to eq(123)
40
- end
41
-
42
35
  it "updates multiple records at once" do
43
36
  transaction1 = TxCatcher::Transaction.create(hex: @hextx, txid: "123")
44
37
  transaction2 = TxCatcher::Transaction.create(hex: @hextx, txid: "1234")
@@ -98,4 +91,15 @@ RSpec.describe TxCatcher::Transaction do
98
91
 
99
92
  end
100
93
 
94
+ describe "updating block height" do
95
+
96
+ it "updates block height by searching if tx is included in one of the previous blocks" do
97
+ expect(TxCatcher.rpc_node).to receive(:getblockhash).exactly(10).times.and_return("blockhash123")
98
+ expect(TxCatcher.rpc_node).to receive(:getblock).exactly(10).times.and_return({ "height" => "123", "tx" => [@transaction.txid], "hash" => "blockhash123"})
99
+ @transaction.check_block_height!
100
+ expect(@transaction.block_height).to eq(123)
101
+ end
102
+
103
+ end
104
+
101
105
  end
data/txcatcher.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "txcatcher".freeze
3
- s.version = "0.2.6"
3
+ s.version = "0.2.8"
4
4
 
5
5
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
6
6
  s.require_paths = ["lib".freeze]
@@ -29,7 +29,6 @@ Gem::Specification.new do |s|
29
29
  "db/migrations/003_create_deposits.rb",
30
30
  "db/migrations/004_add_timestamps_to_transactions.rb",
31
31
  "db/migrations/005_add_protected_flag_to_transactions.rb",
32
- "db/schema.rb",
33
32
  "lib/tasks/db.rake",
34
33
  "lib/txcatcher.rb",
35
34
  "lib/txcatcher/bitcoin_rpc.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: txcatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Snitko
@@ -162,7 +162,6 @@ files:
162
162
  - db/migrations/003_create_deposits.rb
163
163
  - db/migrations/004_add_timestamps_to_transactions.rb
164
164
  - db/migrations/005_add_protected_flag_to_transactions.rb
165
- - db/schema.rb
166
165
  - lib/tasks/db.rake
167
166
  - lib/txcatcher.rb
168
167
  - lib/txcatcher/bitcoin_rpc.rb
data/db/schema.rb DELETED
@@ -1,31 +0,0 @@
1
- Sequel.migration do
2
- change do
3
- create_table(:addresses) do
4
- String :address, :size=>255, :null=>false
5
-
6
- primary_key [:address]
7
- end
8
-
9
- create_table(:deposits, :ignore_index_errors=>true) do
10
- primary_key :id
11
- Bignum :amount, :null=>false
12
- Integer :transaction_id
13
- Integer :address_id
14
-
15
- index [:address_id]
16
- index [:transaction_id]
17
- end
18
-
19
- create_table(:schema_info) do
20
- Integer :version, :default=>0, :null=>false
21
- end
22
-
23
- create_table(:transactions) do
24
- String :txid, :size=>255, :null=>false
25
- DateTime :created_at
26
- TrueClass :protected, :default=>false
27
-
28
- primary_key [:txid]
29
- end
30
- end
31
- end