txcatcher 0.2.6 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
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