txcatcher 0.2.9 → 0.2.10

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: 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