txcatcher 0.2.9 → 0.2.10

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: 5e8a05764d26286691b2f3af9d1a11751024e56733be88316c85b8b7f6dc379d
4
- data.tar.gz: ab2f81174dd468ed0b9e2e0af7bbf5a8cf2c4c6357d12e8d1e43d9dd7ffb964e
3
+ metadata.gz: bb9065445b439bf8fbb85b5d4d04af848908d7b7425c10d3035ab4dd1b58d63b
4
+ data.tar.gz: 7a3b3b10e2c1a94e7189354fae0ff0366a4fc17274edbac21d96ff321b59157d
5
5
  SHA512:
6
- metadata.gz: fb55606e9b1df507effe4d9597e63d46c4ec28a03c422669b100f4dd121b9beb1a6ecbe59d3b7482d10ba83bbe5e4c9834aec0aedd722cbbc37d7434559a0d75
7
- data.tar.gz: 5ac2408b1e027bd15d9103082494383400f298d82483647cc501becb723f128b3f46d0d02076ab24353911a0f844f9001d64204936bff9a24a1d694ebbb2f7ec
6
+ metadata.gz: 3e9d926e86745773f08798185220e2ad3d8551994f8e552fd61f60f223cb96ae9bff2838235893210c8f26161d4d42e6f2d911c66cf850db44db52a1604b968a
7
+ data.tar.gz: 655b824f663d94ef2346007bc6735a32065d14a1347ed56e85dcca8e9ed52611bb99add794c561a43865d89b4c5d719ceee094d4f332344825b61bbaa4fde25a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.9
1
+ 0.2.10
@@ -105,12 +105,13 @@ module TxCatcher
105
105
  undetected_transactions_ids = block_transactions_ids - existing_transactions_ids
106
106
  undetected_transactions_ids.each { |txid| Transaction.create_from_rpc(txid) }
107
107
  Transaction.where(txid: existing_transactions_ids).update(block_height: height)
108
+ # Update RBF transactions and deposits if a transaction a with lower fee
109
+ # (no associated deposit) got accidentally confirmed.
110
+ TxCatcher::Transaction.where(block_height: height).exclude(rbf_next_transaction_id: nil).each do |t|
111
+ t.force_deposit_association_on_rbf!
112
+ end
108
113
  })
109
- # Update RBF transactions and deposits if a transaction a with lower fee (no associated deposit) got
110
- # accidentally confirmed.
111
- TxCatcher::Transaction.where(block_height: height).exclude(rbf_next_transaction_id: nil).each do |t|
112
- t.force_deposit_association_on_rbf!
113
- end
114
+
114
115
  end
115
116
 
116
117
  end # class Catcher
@@ -180,7 +180,7 @@ module TxCatcher
180
180
  end
181
181
 
182
182
  # Sometimes, even though an RBF transaction with higher fee was broadcasted,
183
- # miners accept one the lower-fee transactions instead. However, in txcatcher database, the
183
+ # miners accept the lower-fee transaction instead. However, in txcatcher database, the
184
184
  # deposits are already associated with the latest transaction. In this case,
185
185
  # we need to find the deposits in the DB set their transaction_id field to current transaction id.
186
186
  def force_deposit_association_on_rbf!
@@ -189,7 +189,10 @@ module TxCatcher
189
189
  tx = tx.rbf_next_transaction
190
190
  end
191
191
  tx.deposits.each do |d|
192
- d.update(transaction_id: self.id)
192
+ d.rbf_transaction_ids.delete(self.id)
193
+ d.rbf_transaction_ids.push(d.transaction_id)
194
+ d.transaction_id = self.id
195
+ d.save
193
196
  end
194
197
  end
195
198
 
data/spec/catcher_spec.rb CHANGED
@@ -8,78 +8,118 @@ require_relative '../lib/txcatcher/catcher'
8
8
 
9
9
  RSpec.describe TxCatcher::Catcher do
10
10
 
11
- before(:all) do
12
- @tx_sock = ZMQ::Context.create.socket(ZMQ::PUB)
13
- @block_sock = ZMQ::Context.create.socket(ZMQ::PUB)
11
+ # None of the unit tests here should require a running bitcoind
12
+ describe "(unit tests that require bitcoind to test)" do
14
13
 
15
- @tx_sock.bind("ipc:///tmp/bitcoind_test.rawtx")
16
- @block_sock.bind("ipc:///tmp/bitcoind_test.hashblock")
14
+ before(:all) do
15
+ @tx_sock = ZMQ::Context.create.socket(ZMQ::PUB)
16
+ @block_sock = ZMQ::Context.create.socket(ZMQ::PUB)
17
17
 
18
- @hextx = File.read(File.dirname(__FILE__) + "/fixtures/transaction.txt").strip
19
- @rawtx = unhexlify(File.read(File.dirname(__FILE__) + "/fixtures/transaction.txt"))
20
- @catcher = TxCatcher::Catcher.new(name: "bitcoind_test")
21
- sleep 1
22
- end
18
+ @tx_sock.bind("ipc:///tmp/bitcoind_test.rawtx")
19
+ @block_sock.bind("ipc:///tmp/bitcoind_test.hashblock")
23
20
 
24
- after(:all) do
25
- @catcher.close_all_connections
26
- @tx_sock.unbind("ipc:///tmp/bitcoind_test.rawtx")
27
- @block_sock.unbind('ipc:///tmp/bitcoind_test.hashblock')
28
- end
21
+ @hextx = File.read(File.dirname(__FILE__) + "/fixtures/transaction.txt").strip
22
+ @rawtx = unhexlify(File.read(File.dirname(__FILE__) + "/fixtures/transaction.txt"))
23
+ @catcher = TxCatcher::Catcher.new(name: "bitcoind_test")
24
+ sleep 1
25
+ end
29
26
 
30
- after(:each) do
31
- @catcher.sockets["rawtx"][:last_message] = nil
32
- @catcher.sockets["hashblock"][:last_message] = nil
33
- end
27
+ after(:all) do
28
+ @catcher.close_all_connections
29
+ @tx_sock.unbind("ipc:///tmp/bitcoind_test.rawtx")
30
+ @block_sock.unbind('ipc:///tmp/bitcoind_test.hashblock')
31
+ end
34
32
 
35
- it "creates a new transaction in the DB" do
36
- @tx_sock.send_strings(['rawtx', @rawtx])
37
- i = 0
38
- until (tx = TxCatcher::Transaction.last) || i > 3
39
- sleep 1
40
- i+=1
33
+ after(:each) do
34
+ @catcher.sockets["rawtx"][:last_message] = nil
35
+ @catcher.sockets["hashblock"][:last_message] = nil
41
36
  end
42
- expect(tx.hex).to eq(@hextx)
43
- end
44
37
 
45
- it "updates transactions block height upon receiving a new block " do
46
- transaction = TxCatcher::Transaction.create(hex: @hextx)
47
- expect(TxCatcher.rpc_node).to receive(:getblock).at_least(:once).and_return({ "height" => TxCatcher.current_block_height + 1, "tx" => [transaction.txid]})
38
+ it "creates a new transaction in the DB" do
39
+ @tx_sock.send_strings(['rawtx', @rawtx])
40
+ i = 0
41
+ until (tx = TxCatcher::Transaction.last) || i > 3
42
+ sleep 1
43
+ i+=1
44
+ end
45
+ expect(tx.hex).to eq(@hextx)
46
+ end
48
47
 
49
- @block_sock.send_strings(["hashblock", 'hello'])
48
+ it "updates transactions block height upon receiving a new block " do
49
+ transaction = TxCatcher::Transaction.create(hex: @hextx)
50
+ expect(TxCatcher.rpc_node).to receive(:getblock).at_least(:once).and_return({ "height" => TxCatcher.current_block_height + 1, "tx" => [transaction.txid]})
50
51
 
51
- i = 0
52
- begin
53
- sleep 1 and i += 1
54
- end until @catcher.sockets["hashblock"][:last_message] || i > 3
52
+ @block_sock.send_strings(["hashblock", 'hello'])
55
53
 
56
- expect(transaction.reload.block_height).to eq(TxCatcher.current_block_height)
57
- end
54
+ i = 0
55
+ begin
56
+ sleep 1 and i += 1
57
+ end until @catcher.sockets["hashblock"][:last_message] || i > 3
58
+
59
+ expect(transaction.reload.block_height).to eq(TxCatcher.current_block_height)
60
+ end
61
+
62
+ it "ignores validation errors" do
63
+ tx = eval File.read(File.dirname(__FILE__) + "/fixtures/transaction_decoded_no_outputs.txt")
64
+ expect(TxCatcher.rpc_node).to receive(:decoderawtransaction).at_least(:once).and_return(tx)
65
+ @tx_sock.send_strings(["rawtx", @rawtx])
58
66
 
59
- it "ignores validation errors" do
60
- tx = eval File.read(File.dirname(__FILE__) + "/fixtures/transaction_decoded_no_outputs.txt")
61
- expect(TxCatcher.rpc_node).to receive(:decoderawtransaction).at_least(:once).and_return(tx)
62
- @tx_sock.send_strings(["rawtx", @rawtx])
67
+ i = 0
68
+ begin
69
+ sleep 1 and i += 1
70
+ end until @catcher.sockets["rawtx"][:last_message] || i > 3
63
71
 
64
- i = 0
65
- begin
66
- sleep 1 and i += 1
67
- end until @catcher.sockets["rawtx"][:last_message] || i > 3
72
+ expect(File.exists?(ERRFILE)).to be_falsey
73
+ end
74
+
75
+ it "logs all other errors" do
76
+ sleep 1
77
+ expect(TxCatcher.rpc_node).to receive(:decoderawtransaction).at_least(:once).and_raise(StandardError)
78
+ @tx_sock.send_strings(["rawtx", @rawtx])
79
+
80
+ i = 0
81
+ begin
82
+ sleep 1 and i += 1
83
+ end until @catcher.sockets["rawtx"][:last_message] || i > 3
84
+ expect(File.read(ERRFILE)).not_to be_empty
85
+ end
68
86
 
69
- expect(File.exists?(ERRFILE)).to be_falsey
70
87
  end
71
88
 
72
- it "logs all other errors" do
89
+
90
+ it "updates deposits association with an RBF tx if a transaction with lower fee gets confirmed" do
91
+
92
+ class TxCatcher::Transaction
93
+ def assign_tx_hash(h)
94
+ @tx_hash = h
95
+ end
96
+ end
97
+
98
+ class CatcherStub < TxCatcher::Catcher
99
+ def listen_to_zeromq_channels(channel);end
100
+ end
101
+
102
+ hextx = File.read(File.dirname(__FILE__) + "/fixtures/transaction.txt").strip
103
+ tx1 = TxCatcher::Transaction.create(hex: hextx)
104
+ deposits = tx1.deposits
105
+ rbf_tx_hash = tx1.tx_hash
106
+ rbf_tx_hash["txid"] = "rbftxid1"
107
+ rbf_tx_hash["locktime"] = "1"
108
+ tx2 = TxCatcher::Transaction.new(hex: hextx)
109
+ tx2.assign_tx_hash(rbf_tx_hash)
110
+ tx2.save
111
+
112
+ catcher = CatcherStub.new(name: "bitcoind_test")
113
+ allow(TxCatcher.rpc_node).to receive(:getblock).and_return({ "tx" => [tx1.txid], "height" => 123 })
114
+ catcher.send(:handle_hashblock, "new block")
73
115
  sleep 1
74
- expect(TxCatcher.rpc_node).to receive(:decoderawtransaction).at_least(:once).and_raise(StandardError)
75
- @tx_sock.send_strings(["rawtx", @rawtx])
76
-
77
- i = 0
78
- begin
79
- sleep 1 and i += 1
80
- end until @catcher.sockets["rawtx"][:last_message] || i > 3
81
- expect(File.read(ERRFILE)).not_to be_empty
82
- end
83
116
 
117
+ deposits.each do |d|
118
+ expect(d.reload.transaction_id).to eq(tx1.id)
119
+ end
120
+
121
+ expect(tx1.reload.deposits.map(&:id)).to eq(deposits.map(&:id))
122
+ expect(tx2.reload.deposits.map(&:id)).to eq([])
123
+ end
84
124
 
85
125
  end
@@ -82,11 +82,15 @@ RSpec.describe TxCatcher::Transaction do
82
82
  rbf_tx.assign_tx_hash(rbf_tx_hash)
83
83
  rbf_tx.save
84
84
 
85
+ expect(rbf_tx.reload.deposits.size).to eq(2)
86
+ expect(@transaction.reload.deposits.size).to eq(0)
87
+
85
88
  @transaction.reload.force_deposit_association_on_rbf!
86
89
  expect(rbf_tx.reload.deposits).to be_empty
87
90
  expect(@transaction.reload.deposits.map(&:id)).to eq(deposit_ids)
91
+
88
92
  @transaction.deposits.each do |d|
89
- expect(d.rbf_transaction_ids).to eq([@transaction.id])
93
+ expect(d.rbf_transaction_ids).to eq([2])
90
94
  end
91
95
 
92
96
  end
@@ -96,7 +100,7 @@ RSpec.describe TxCatcher::Transaction do
96
100
  it "updates block height by searching if tx is included in one of the previous blocks" do
97
101
  expect(TxCatcher.rpc_node).to receive(:getblockhash).exactly(10).times.and_return("blockhash123")
98
102
  expect(TxCatcher.rpc_node).to receive(:getblock).exactly(10).times.and_return({ "height" => "123", "tx" => [@transaction.txid], "hash" => "blockhash123"})
99
- @transaction.check_block_height!
103
+ @transaction.update_block_height!
100
104
  expect(@transaction.block_height).to eq(123)
101
105
  end
102
106
 
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.9"
3
+ s.version = "0.2.10"
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]
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.9
4
+ version: 0.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Snitko
@@ -206,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
206
206
  - !ruby/object:Gem::Version
207
207
  version: '0'
208
208
  requirements: []
209
- rubygems_version: 3.0.3
209
+ rubygems_version: 3.0.8
210
210
  signing_key:
211
211
  specification_version: 4
212
212
  summary: An lightweight version of Bitpay's Insight, allows to check Bitcoin/Litecoin