txcatcher 0.1.5 → 0.1.6

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
  SHA1:
3
- metadata.gz: 909ad770012c2bacccbb1e9f7438bf97e4c92d15
4
- data.tar.gz: ec40ed49c4f006e30f4ff07be84fce1d2f05523f
3
+ metadata.gz: 57275484854984cda01f4f29c6660d19db19ff71
4
+ data.tar.gz: 6bb6d1e3de974824ffcfd8e918545b112b4bd0d5
5
5
  SHA512:
6
- metadata.gz: f12b5d7ef16ba43904ec6cebc3ab77a3f1c8fad8588a67b5ad17d1f5076260dee01f21d20928a5f6ae287955ab6c5a83233a05402d8350bd79523e0700095b02
7
- data.tar.gz: 3f737f4a9d32f9ae4c8f9011a3a03856cd55cf9dd4af3e517e0ded3d0dfd656d938bcf8a59008b6a32b9cfc37379ef90e1e0f78317be7f7e8d2b8ca438a3b061
6
+ metadata.gz: e81da207158daf3c4b8cf61636deecd85088c2edb7bd191b52007f47639fe00cbc89c923019fc92566a69ac675a56d792e90247338c33b5a787208ddf46b9b2c
7
+ data.tar.gz: dbf857e7c92d76e34e4adfbe3c792115084159d6c2be8b90af2bec9d69b0b417ac1ccc520a208185e36f3de69c8ddfcc91f7e44965c5636ced454742487b28b9
data/Gemfile.lock CHANGED
@@ -30,7 +30,7 @@ GEM
30
30
  hashie (>= 3.4)
31
31
  mime-types (>= 1.16, < 3.0)
32
32
  oauth2 (~> 1.0)
33
- goliath (1.0.5)
33
+ goliath (1.0.6)
34
34
  async-rack
35
35
  einhorn
36
36
  em-synchrony (>= 1.0.0)
@@ -42,8 +42,8 @@ GEM
42
42
  rack (>= 1.2.2)
43
43
  rack-contrib
44
44
  rack-respond_to
45
- hashie (3.5.6)
46
- highline (1.7.8)
45
+ hashie (3.5.7)
46
+ highline (1.7.10)
47
47
  http_parser.rb (0.6.0)
48
48
  jeweler (2.3.7)
49
49
  builder
@@ -59,12 +59,12 @@ GEM
59
59
  jwt (1.5.6)
60
60
  log4r (1.1.10)
61
61
  mime-types (2.99.3)
62
- mini_portile2 (2.2.0)
63
- multi_json (1.12.1)
62
+ mini_portile2 (2.3.0)
63
+ multi_json (1.13.1)
64
64
  multi_xml (0.6.0)
65
65
  multipart-post (2.0.0)
66
- nokogiri (1.8.0)
67
- mini_portile2 (~> 2.2.0)
66
+ nokogiri (1.8.1)
67
+ mini_portile2 (~> 2.3.0)
68
68
  oauth2 (1.4.0)
69
69
  faraday (>= 0.8, < 0.13)
70
70
  jwt (~> 1.0)
@@ -74,28 +74,28 @@ GEM
74
74
  psych (2.2.4)
75
75
  rack (1.6.8)
76
76
  rack-accept-media-types (0.9)
77
- rack-contrib (1.5.0)
77
+ rack-contrib (1.8.0)
78
78
  rack (~> 1.4)
79
79
  rack-respond_to (0.9.8)
80
80
  rack-accept-media-types (>= 0.6)
81
- rake (12.0.0)
82
- rdoc (5.1.0)
83
- rspec (3.6.0)
84
- rspec-core (~> 3.6.0)
85
- rspec-expectations (~> 3.6.0)
86
- rspec-mocks (~> 3.6.0)
87
- rspec-core (3.6.0)
88
- rspec-support (~> 3.6.0)
89
- rspec-expectations (3.6.0)
81
+ rake (12.3.0)
82
+ rdoc (6.0.1)
83
+ rspec (3.7.0)
84
+ rspec-core (~> 3.7.0)
85
+ rspec-expectations (~> 3.7.0)
86
+ rspec-mocks (~> 3.7.0)
87
+ rspec-core (3.7.1)
88
+ rspec-support (~> 3.7.0)
89
+ rspec-expectations (3.7.0)
90
90
  diff-lcs (>= 1.2.0, < 2.0)
91
- rspec-support (~> 3.6.0)
92
- rspec-mocks (3.6.0)
91
+ rspec-support (~> 3.7.0)
92
+ rspec-mocks (3.7.0)
93
93
  diff-lcs (>= 1.2.0, < 2.0)
94
- rspec-support (~> 3.6.0)
95
- rspec-support (3.6.0)
94
+ rspec-support (~> 3.7.0)
95
+ rspec-support (3.7.0)
96
96
  satoshi-unit (0.2.2)
97
97
  semver2 (3.4.2)
98
- sequel (4.49.0)
98
+ sequel (5.4.0)
99
99
  sqlite3 (1.3.13)
100
100
  thread_safe (0.3.6)
101
101
 
@@ -113,4 +113,4 @@ DEPENDENCIES
113
113
  sqlite3
114
114
 
115
115
  BUNDLED WITH
116
- 1.15.4
116
+ 1.16.0
data/README.md CHANGED
@@ -71,7 +71,7 @@ Installation
71
71
 
72
72
  Install txcatcher: `gem install txcatcher`
73
73
 
74
- Configuring & Runing
74
+ Configuring & Running
75
75
  --------------------
76
76
  You're going to need a simple config file. By default, txcatcher looks in `~/.txcatcher` dir,
77
77
  so create the dir and the file there: `mkdir ~/.txcatcher && touch ~/.txcatcher/config.yml`
@@ -79,7 +79,7 @@ Example config file can be found in [templates/config.yml](templates/config.yml)
79
79
  to copy the contents and edit it.
80
80
 
81
81
  Once your bitcoin/litecoind finished syncing, you can start txcatcher with a simple command: `txcatcher`.
82
- You can srart multiple instances of txcatcher, when, for example, you want instances of it
82
+ You can start multiple instances of txcatcher, when, for example, you want instances of it
83
83
  tracking both litecoin and bitcoin transactions:
84
84
 
85
85
  txcatcher -c ~/.txcatcher/litecoin_config.yml
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.1.6
@@ -0,0 +1,7 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table :transactions do
4
+ add_column :created_at, DateTime
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ Sequel.migration do
2
+ change do
3
+ alter_table :transactions do
4
+ # This flag means someone has checked it once through the API and we might not want to remove
5
+ # it from the DB (upon scheduled cleanup) because it's of a potential interest.
6
+ add_column :protected, FalseClass, default: false
7
+ end
8
+ end
9
+ end
@@ -93,7 +93,7 @@ module TxCatcher
93
93
  block_hash = TxCatcher.rpc_node.getblock(block_hex)
94
94
  transactions = block_hash["tx"]
95
95
  height = TxCatcher.current_block_height = block_hash["height"].to_i
96
- $stdout.puts "Block #{height} mined, transactions received:\n #{transactions.join(" \n")}"
96
+ $stdout.puts "*** Block #{height} mined, transactions received:\n #{transactions.join(" \n")}"
97
97
  @queue["hashblock"] << ( Proc.new {
98
98
  Transaction.where(txid: transactions).update(block_height: height)
99
99
  })
@@ -17,7 +17,11 @@ module TxCatcher
17
17
  Thread.new do
18
18
  loop do
19
19
  @@cleaning_counter = { transactions: 0, deposits: 0, addresses: 0 }
20
- db_tx_count = TxCatcher::Transaction.last.id - TxCatcher::Transaction.first.id + 1
20
+ db_tx_count = if Config.protected_transactions
21
+ TxCatcher::Transaction.where(Sequel.~(protected: true)).count
22
+ else
23
+ TxCatcher::Transaction.count
24
+ end
21
25
  $stdout.print "Cleaning transactions in DB..."
22
26
  $stdout.print "#{db_tx_count} now, needs to be below #{Config.max_db_transactions_stored}\n"
23
27
  if db_tx_count > Config.max_db_transactions_stored
@@ -42,7 +46,9 @@ module TxCatcher
42
46
  end
43
47
 
44
48
  def clean_transactions(n)
45
- transactions = Transaction.order("created_at ASC").limit(n).each do |t|
49
+ transactions = Transaction.order("created_at ASC")
50
+ transactions.where(Sequel.~(protected: true)) if Config.protected_transactions
51
+ transactions.limit(n).each do |t|
46
52
  clean_deposits(t)
47
53
  t.delete
48
54
  @@cleaning_counter[:transactions] += 1
@@ -19,6 +19,10 @@ module TxCatcher
19
19
  end
20
20
  end
21
21
 
22
+ def before_create
23
+ self.created_at = Time.now
24
+ end
25
+
22
26
  def after_create
23
27
  self.deposits.each do |d|
24
28
  d.transaction = self
@@ -38,6 +42,35 @@ module TxCatcher
38
42
  end
39
43
  end
40
44
 
45
+ # Queries rpc node to check whether the transaction has been included in any of the blocks,
46
+ # but only if current block_height is nil.
47
+ def update_block_height!(limit=100)
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
57
+ return self.block_height if self.block_height
58
+ blocks_to_check = limit if blocks_to_check > limit
59
+
60
+ i = 0
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
+ $stdout.puts "--- checking block #{TxCatcher.current_block_height - i} for tx #{self.txid}"
66
+ if block["tx"] && block["tx"].include?(self.txid)
67
+ $stdout.puts "tx #{self.txid} block height updated to #{block["height"]}"
68
+ self.update(block_height: block["height"])
69
+ return block["height"].to_i
70
+ end
71
+ end
72
+ end
73
+
41
74
  private
42
75
 
43
76
  def parse_transaction
@@ -32,7 +32,9 @@ module TxCatcher
32
32
  if address
33
33
  transactions_ids = address.deposits.map { |d| d.transaction.txid }
34
34
  deposits = address.deposits.map do |d|
35
+ t.update(protected: true) unless t.protected
35
36
  t = d.transaction
37
+ t.update_block_height!
36
38
  {
37
39
  txid: t.txid,
38
40
  amount: d.amount_in_btc,
@@ -52,11 +54,15 @@ module TxCatcher
52
54
  path.pop
53
55
  addr = path.last
54
56
 
55
- model = Address.where(address: addr).eager(deposits: :transactions).first
57
+ model = Address.where(address: addr).eager(deposits: :transactions).first
58
+ return [200, {}, "{}"] unless model
59
+
56
60
  transactions = model.deposits.map { |d| d.transaction }
57
61
  utxos = transactions.map do |t|
58
62
  outs = t.tx_hash["vout"].select { |out| out["scriptPubKey"]["addresses"] == [addr] }
59
63
  outs.map! do |out|
64
+ t.update(protected: true) unless t.protected
65
+ t.update_block_height!
60
66
  out["confirmations"] = t.confirmations || 0
61
67
  out["txid"] = t.txid
62
68
  out
data/spec/catcher_spec.rb CHANGED
@@ -41,17 +41,22 @@ RSpec.describe TxCatcher::Catcher do
41
41
 
42
42
  end
43
43
 
44
- it "upon receiving a new block updates transactions block height" do
45
- transaction = TxCatcher::Transaction.create(hex: @hextx)
46
- expect(TxCatcher.rpc_node).to receive(:getblock).and_return({ "height" => TxCatcher.current_block_height + 1, "tx" => [transaction.txid]})
47
- @block_sock.send_string('hashblock', ZMQ::SNDMORE)
48
- @block_sock.send_string("hello")
44
+ describe "upon receiving a new block" do
45
+
46
+ it "updates transactions block height" do
47
+ transaction = TxCatcher::Transaction.create(hex: @hextx)
48
+ allow(TxCatcher.rpc_node).to receive(:getblock).and_return({ "height" => TxCatcher.current_block_height + 1, "tx" => [transaction.txid]})
49
+ @block_sock.send_string('hashblock', ZMQ::SNDMORE)
50
+ @block_sock.send_string("hello")
51
+ #transaction.update_block_height!
52
+
53
+ i = 0
54
+ until transaction.reload.confirmations == 1
55
+ sleep 1 and i += 1
56
+ end
57
+ expect(transaction.block_height).to eq(TxCatcher.current_block_height)
49
58
 
50
- i = 0
51
- until transaction.reload.confirmations == 1
52
- sleep 1 and i += 1
53
59
  end
54
- expect(transaction.block_height).to eq(TxCatcher.current_block_height)
55
60
 
56
61
  end
57
62
 
data/spec/cleaner_spec.rb CHANGED
@@ -42,13 +42,23 @@ RSpec.describe TxCatcher::Cleaner do
42
42
  expect(TxCatcher::Address.count).to eq(10)
43
43
  end
44
44
 
45
+ it "protects checked transactions" do
46
+ protected_txs = create_transactions(3, { protected: true })
47
+ regular_txs = create_transactions(15)
48
+ clean_transactions
49
+ expect(TxCatcher::Transaction.count).to eq(12)
50
+ expect(TxCatcher::Deposit.count).to eq(12)
51
+ expect(TxCatcher::Address.count).to eq(12)
52
+ end
53
+
45
54
 
46
- def create_transactions(n)
47
- (1..n).to_a.each do |i|
55
+ def create_transactions(n, attrs={})
56
+ (1..n).to_a.map do |i|
48
57
  d = TxCatcher::Deposit.new(address_string: "addr#{i}", amount: 0)
49
- tx = TxCatcher::Transaction.new
58
+ tx = TxCatcher::Transaction.new(attrs)
50
59
  tx.deposits << d
51
60
  tx.save
61
+ tx
52
62
  end
53
63
  end
54
64
 
@@ -20,3 +20,4 @@ rpcnode:
20
20
  # zeromq: bitcoind
21
21
  max_db_transactions_stored: 10
22
22
  db_clean_period_seconds: 300
23
+ protected_transactions: true
@@ -26,4 +26,11 @@ RSpec.describe TxCatcher::Transaction do
26
26
  expect(TxCatcher::Transaction.where(txid: transaction.txid).count).to eq(1)
27
27
  end
28
28
 
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"})
32
+ @transaction.update_block_height!
33
+ expect(@transaction.block_height).to eq(123)
34
+ end
35
+
29
36
  end
data/spec/spec_helper.rb CHANGED
@@ -31,6 +31,8 @@ end
31
31
 
32
32
  RSpec.configure do |config|
33
33
 
34
+ config.default_formatter = 'doc'
35
+
34
36
  config.before(:all) do
35
37
  end
36
38
 
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.1.5 ruby lib
5
+ # stub: txcatcher 0.1.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "txcatcher"
9
- s.version = "0.1.5"
9
+ s.version = "0.1.6"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: txcatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Snitko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-25 00:00:00.000000000 Z
11
+ date: 2018-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: goliath
@@ -120,6 +120,8 @@ files:
120
120
  - db/migrations/001_create_transactions.rb
121
121
  - db/migrations/002_create_addresses.rb
122
122
  - db/migrations/003_create_deposits.rb
123
+ - db/migrations/004_add_timestamps_to_transactions.rb
124
+ - db/migrations/005_add_protected_flag_to_transactions.rb
123
125
  - db/schema.rb
124
126
  - lib/tasks/db.rake
125
127
  - lib/txcatcher.rb
@@ -136,10 +138,8 @@ files:
136
138
  - spec/catcher_spec.rb
137
139
  - spec/cleaner_spec.rb
138
140
  - spec/config/config.yml.sample
139
- - spec/config/txcatcher_test.db
140
141
  - spec/fixtures/transaction.txt
141
142
  - spec/fixtures/transaction_decoded_no_outputs.txt
142
- - spec/models/address_spec.rb
143
143
  - spec/models/transaction_spec.rb
144
144
  - spec/spec_helper.rb
145
145
  - templates/config.yml
Binary file
@@ -1,5 +0,0 @@
1
- require_relative '../spec_helper'
2
- require_relative '../../lib/txcatcher/models/address'
3
-
4
- RSpec.describe TxCatcher::Address do
5
- end