cryptocoin_payable 1.2.0 → 1.3.0
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 +5 -5
- data/README.md +2 -2
- data/cryptocoin_payable.gemspec +3 -0
- data/features/step_definitions/coin_payment_steps.rb +3 -3
- data/features/support/env.rb +2 -0
- data/lib/cryptocoin_payable/adapters/base.rb +4 -4
- data/lib/cryptocoin_payable/adapters/bitcoin.rb +6 -6
- data/lib/cryptocoin_payable/adapters/ethereum.rb +3 -3
- data/lib/cryptocoin_payable/coin_payment.rb +14 -17
- data/lib/cryptocoin_payable/commands/payment_processor.rb +49 -18
- data/lib/cryptocoin_payable/commands/pricing_processor.rb +1 -4
- data/lib/cryptocoin_payable/version.rb +1 -1
- data/lib/generators/cryptocoin_payable/templates/create_coin_payment_transactions.rb +1 -1
- data/spec/acceptance/adapters/bitcoin_cash_spec.rb +3 -3
- data/spec/acceptance/adapters/bitcoin_spec.rb +6 -6
- data/spec/acceptance/adapters/ethereum_spec.rb +12 -12
- data/spec/acceptance/commands/payment_processor_spec.rb +50 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/{20171227225133_create_coin_payment_transactions.rb → 20181015141952_create_coin_payment_transactions.rb} +1 -1
- data/spec/dummy/db/schema.rb +2 -1
- data/spec/spec_helper.rb +6 -0
- metadata +49 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 69a13a8a0c2157e87c41dde92831b8ad336aab77a9d58314adfddedf4808509d
|
4
|
+
data.tar.gz: 216d48f0578f487fd0420469d7d0a6214b7dc205aae65aab92d21f837fafe723
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3ceadd2dd62f11a419119583a0fbeeaee72418c9d7c318caba1542809a91dbc06f671f6eed7afc1136cc3556ddc5c535df475b501fa741cd03d2270c493ad81
|
7
|
+
data.tar.gz: 0b340f0086b3411eef2df4f434bc46b12166969ddea73741227382c64d78cc8e88fbaeee9843a26eed3cbf64f07821cd3b658bb4cc628a7262616c7ede99e122
|
data/README.md
CHANGED
@@ -48,7 +48,7 @@ And then execute:
|
|
48
48
|
|
49
49
|
$ bundle exec rake db:migrate
|
50
50
|
|
51
|
-
$ populate
|
51
|
+
$ populate cryptocoin_payable.rb (see below)
|
52
52
|
|
53
53
|
$ bundle exec rake cryptocoin_payable:process_prices (see below)
|
54
54
|
|
@@ -65,7 +65,7 @@ And then execute:
|
|
65
65
|
|
66
66
|
### Configuration
|
67
67
|
|
68
|
-
config/initializers/
|
68
|
+
config/initializers/cryptocoin_payable.rb
|
69
69
|
|
70
70
|
CryptocoinPayable.configure do |config|
|
71
71
|
# config.currency = :usd
|
data/cryptocoin_payable.gemspec
CHANGED
@@ -26,12 +26,15 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency 'database_cleaner', '~> 1.7'
|
27
27
|
spec.add_development_dependency 'rails', '>= 4.0.0'
|
28
28
|
spec.add_development_dependency 'rake', '~> 12.3'
|
29
|
+
spec.add_development_dependency 'rspec-benchmark', '~> 0.4'
|
29
30
|
spec.add_development_dependency 'rspec-rails', '~> 3.7'
|
31
|
+
spec.add_development_dependency 'rspec-retry', '~> 0.6'
|
30
32
|
spec.add_development_dependency 'rubocop', '~> 0.59'
|
31
33
|
spec.add_development_dependency 'sqlite3', '~> 1.3'
|
32
34
|
spec.add_development_dependency 'vcr', '~> 4.0'
|
33
35
|
spec.add_development_dependency 'webmock', '~> 3.4'
|
34
36
|
|
37
|
+
spec.add_dependency 'activerecord-import', '~> 0.27'
|
35
38
|
spec.add_dependency 'cash-addr', '~> 0.2'
|
36
39
|
spec.add_dependency 'eth', '0.4.8'
|
37
40
|
spec.add_dependency 'money-tree', '0.10.0'
|
@@ -22,11 +22,11 @@ end
|
|
22
22
|
Given(/^a payment is made for (\d+) percent$/) do |percentage|
|
23
23
|
CryptocoinPayable::Adapters::Bitcoin.any_instance.stub(:fetch_transactions).and_return(
|
24
24
|
[{
|
25
|
-
|
25
|
+
transaction_hash: SecureRandom.uuid,
|
26
26
|
block_hash: '00000000000000606aa74093ed91d657192a3772732ee4d99a7b7be8075eafa2',
|
27
27
|
block_time: DateTime.iso8601('2017-12-26T21:38:44.000+00:00'),
|
28
|
-
|
29
|
-
|
28
|
+
estimated_time: DateTime.iso8601('2017-12-26T21:30:19.858+00:00'),
|
29
|
+
estimated_value: @coin_amount_due * (percentage.to_f / 100.0),
|
30
30
|
confirmations: 1
|
31
31
|
}]
|
32
32
|
)
|
data/features/support/env.rb
CHANGED
@@ -4,6 +4,8 @@ ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '../../../spec/dummy'
|
|
4
4
|
require 'cucumber/rails'
|
5
5
|
require 'cucumber/rspec/doubles'
|
6
6
|
|
7
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT) if defined?(ActiveRecord::Base)
|
8
|
+
|
7
9
|
# Remove/comment out the lines below if your app doesn't have a database.
|
8
10
|
# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
|
9
11
|
begin
|
@@ -16,14 +16,14 @@ module CryptocoinPayable
|
|
16
16
|
# Queries an API like etherscan.io and returns a list of transactions
|
17
17
|
# which conform to the following shape:
|
18
18
|
# {
|
19
|
-
#
|
19
|
+
# transaction_hash: string,
|
20
20
|
# block_hash: string,
|
21
21
|
# block_time: nil | string,
|
22
|
-
#
|
23
|
-
#
|
22
|
+
# estimated_time: nil | string,
|
23
|
+
# estimated_value: integer,
|
24
24
|
# confirmations: integer,
|
25
25
|
# }
|
26
|
-
# `block_time` and `
|
26
|
+
# `block_time` and `estimated_time` are optional strings conforming to
|
27
27
|
# date format ISO 8601.
|
28
28
|
#
|
29
29
|
# Can optionally raise ApiLimitedReached if needed.
|
@@ -52,11 +52,11 @@ module CryptocoinPayable
|
|
52
52
|
|
53
53
|
def convert_block_explorer_transactions(transaction, address)
|
54
54
|
{
|
55
|
-
|
55
|
+
transaction_hash: transaction['txid'],
|
56
56
|
block_hash: transaction['blockhash'],
|
57
57
|
block_time: parse_timestamp(transaction['blocktime']),
|
58
|
-
|
59
|
-
|
58
|
+
estimated_time: parse_timestamp(transaction['time']),
|
59
|
+
estimated_value: parse_total_tx_value_block_explorer(transaction['vout'], address),
|
60
60
|
confirmations: transaction['confirmations']
|
61
61
|
}
|
62
62
|
end
|
@@ -83,11 +83,11 @@ module CryptocoinPayable
|
|
83
83
|
|
84
84
|
def convert_block_cypher_transactions(transaction, address)
|
85
85
|
{
|
86
|
-
|
86
|
+
transaction_hash: transaction['hash'],
|
87
87
|
block_hash: transaction['block_hash'],
|
88
88
|
block_time: parse_time(transaction['confirmed']),
|
89
|
-
|
90
|
-
|
89
|
+
estimated_time: parse_time(transaction['received']),
|
90
|
+
estimated_value: parse_total_tx_value_block_cypher(transaction['outputs'], address),
|
91
91
|
confirmations: transaction['confirmations'].to_i
|
92
92
|
}
|
93
93
|
end
|
@@ -63,11 +63,11 @@ module CryptocoinPayable
|
|
63
63
|
# }
|
64
64
|
def convert_transactions(transaction, _address)
|
65
65
|
{
|
66
|
-
|
66
|
+
transaction_hash: transaction['hash'],
|
67
67
|
block_hash: transaction['block_hash'],
|
68
68
|
block_time: nil, # Not supported
|
69
|
-
|
70
|
-
|
69
|
+
estimated_time: parse_timestamp(transaction['timeStamp']),
|
70
|
+
estimated_value: transaction['value'].to_i, # Units here are 'Wei'
|
71
71
|
confirmations: transaction['confirmations'].to_i
|
72
72
|
}
|
73
73
|
end
|
@@ -4,20 +4,7 @@ require 'state_machine'
|
|
4
4
|
module CryptocoinPayable
|
5
5
|
class CoinPayment < ActiveRecord::Base
|
6
6
|
belongs_to :payable, polymorphic: true
|
7
|
-
|
8
|
-
has_many :transactions, class_name: 'CryptocoinPayable::CoinPaymentTransaction' do
|
9
|
-
def create_from_tx_data!(tx_data, coin_conversion)
|
10
|
-
create!(
|
11
|
-
estimated_value: tx_data[:estimated_tx_value],
|
12
|
-
transaction_hash: tx_data[:tx_hash],
|
13
|
-
block_hash: tx_data[:block_hash],
|
14
|
-
block_time: tx_data[:block_time],
|
15
|
-
estimated_time: tx_data[:estimated_tx_time],
|
16
|
-
coin_conversion: coin_conversion,
|
17
|
-
confirmations: tx_data[:confirmations]
|
18
|
-
)
|
19
|
-
end
|
20
|
-
end
|
7
|
+
has_many :transactions, class_name: 'CryptocoinPayable::CoinPaymentTransaction'
|
21
8
|
|
22
9
|
validates :reason, presence: true
|
23
10
|
validates :price, presence: true
|
@@ -93,8 +80,18 @@ module CryptocoinPayable
|
|
93
80
|
end
|
94
81
|
|
95
82
|
def calculate_coin_amount_due
|
96
|
-
|
97
|
-
|
83
|
+
adapter.convert_main_to_subunit(currency_amount_due / coin_conversion.to_f).ceil
|
84
|
+
end
|
85
|
+
|
86
|
+
def coin_conversion
|
87
|
+
@coin_conversion ||= CurrencyConversion.where(coin_type: coin_type).last.price
|
88
|
+
end
|
89
|
+
|
90
|
+
def update_coin_amount_due(rate: coin_conversion)
|
91
|
+
update!(
|
92
|
+
coin_amount_due: calculate_coin_amount_due,
|
93
|
+
coin_conversion: rate
|
94
|
+
)
|
98
95
|
end
|
99
96
|
|
100
97
|
def transactions_confirmed?
|
@@ -112,7 +109,7 @@ module CryptocoinPayable
|
|
112
109
|
def populate_currency_and_amount_due
|
113
110
|
self.currency ||= CryptocoinPayable.configuration.currency
|
114
111
|
self.coin_amount_due = calculate_coin_amount_due
|
115
|
-
self.coin_conversion =
|
112
|
+
self.coin_conversion = coin_conversion
|
116
113
|
end
|
117
114
|
|
118
115
|
def populate_address
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'activerecord-import'
|
2
|
+
|
1
3
|
module CryptocoinPayable
|
2
4
|
class PaymentProcessor
|
3
5
|
def self.perform
|
@@ -5,22 +7,7 @@ module CryptocoinPayable
|
|
5
7
|
end
|
6
8
|
|
7
9
|
def self.update_transactions_for(payment)
|
8
|
-
|
9
|
-
|
10
|
-
transactions.each do |tx|
|
11
|
-
tx.symbolize_keys!
|
12
|
-
|
13
|
-
transaction = payment.transactions.find_by_transaction_hash(tx[:tx_hash])
|
14
|
-
if transaction
|
15
|
-
transaction.update(confirmations: tx[:confirmations])
|
16
|
-
else
|
17
|
-
payment.transactions.create_from_tx_data!(tx, payment.coin_conversion)
|
18
|
-
payment.update(
|
19
|
-
coin_amount_due: payment.calculate_coin_amount_due,
|
20
|
-
coin_conversion: CurrencyConversion.where(coin_type: payment.coin_type).last.price
|
21
|
-
)
|
22
|
-
end
|
23
|
-
end
|
10
|
+
new.update_transactions_for(payment)
|
24
11
|
end
|
25
12
|
|
26
13
|
def perform
|
@@ -32,7 +19,7 @@ module CryptocoinPayable
|
|
32
19
|
next if payment.confirmed?
|
33
20
|
|
34
21
|
begin
|
35
|
-
|
22
|
+
update_transactions_for(payment)
|
36
23
|
rescue StandardError => error
|
37
24
|
STDERR.puts 'PaymentProcessor: Unknown error encountered, skipping transaction'
|
38
25
|
STDERR.puts error
|
@@ -48,7 +35,51 @@ module CryptocoinPayable
|
|
48
35
|
end
|
49
36
|
end
|
50
37
|
|
51
|
-
|
38
|
+
def update_transactions_for(payment)
|
39
|
+
transactions = Adapters.for(payment.coin_type).fetch_transactions(payment.address)
|
40
|
+
|
41
|
+
payment.transaction do
|
42
|
+
if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
|
43
|
+
update_via_bulk_insert(payment, transactions)
|
44
|
+
else
|
45
|
+
update_via_many_insert(payment, transactions)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
transactions
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def update_via_bulk_insert(payment, transactions)
|
55
|
+
transactions.each do |t|
|
56
|
+
t[:coin_conversion] = payment.coin_conversion
|
57
|
+
t[:coin_payment_id] = payment.id
|
58
|
+
end
|
59
|
+
|
60
|
+
CoinPaymentTransaction.import(
|
61
|
+
transactions,
|
62
|
+
on_duplicate_key_update: {
|
63
|
+
conflict_target: [:transaction_hash],
|
64
|
+
columns: [:coin_conversion]
|
65
|
+
}
|
66
|
+
)
|
67
|
+
payment.reload
|
68
|
+
payment.update_coin_amount_due
|
69
|
+
end
|
70
|
+
|
71
|
+
def update_via_many_insert(payment, transactions)
|
72
|
+
transactions.each do |tx|
|
73
|
+
transaction = payment.transactions.find_by_transaction_hash(tx[:transaction_hash])
|
74
|
+
if transaction
|
75
|
+
transaction.update(confirmations: tx[:confirmations])
|
76
|
+
else
|
77
|
+
tx[:coin_conversion] = payment.coin_conversion
|
78
|
+
payment.transactions.create!(tx)
|
79
|
+
payment.update_coin_amount_due
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
52
83
|
|
53
84
|
def update_payment_state(payment)
|
54
85
|
if payment.currency_amount_paid >= payment.price
|
@@ -25,10 +25,7 @@ module CryptocoinPayable
|
|
25
25
|
# Loop through all unpaid payments and update them with the new price if
|
26
26
|
# it has been 30 mins since they have been updated.
|
27
27
|
CoinPayment.unpaid.stale.find_each do |payment|
|
28
|
-
payment.
|
29
|
-
coin_amount_due: payment.calculate_coin_amount_due,
|
30
|
-
coin_conversion: rates[payment.coin_type.to_sym].price
|
31
|
-
)
|
28
|
+
payment.update_coin_amount_due(coin_conversion: rates[payment.coin_type.to_sym].price)
|
32
29
|
end
|
33
30
|
end
|
34
31
|
|
@@ -2,7 +2,7 @@ class CreateCoinPaymentTransactions < ActiveRecord::Migration[5.1]
|
|
2
2
|
def change
|
3
3
|
create_table :coin_payment_transactions do |t|
|
4
4
|
t.decimal :estimated_value, precision: 24, scale: 0
|
5
|
-
t.string :transaction_hash
|
5
|
+
t.string :transaction_hash, index: { unique: true }
|
6
6
|
t.string :block_hash
|
7
7
|
t.datetime :block_time
|
8
8
|
t.datetime :estimated_time
|
@@ -8,11 +8,11 @@ describe CryptocoinPayable::Adapters::BitcoinCash, :vcr do
|
|
8
8
|
expect(response).to eq(
|
9
9
|
[
|
10
10
|
{
|
11
|
-
|
11
|
+
transaction_hash: '10d9d3927a21d90c573a5fbbb347f409af37219ceb93f7475d6c4cca4231d29f',
|
12
12
|
block_hash: '0000000000000000015493ab50fde669130f9b64f0918031a5b6dcc44f14698f',
|
13
13
|
block_time: DateTime.iso8601('2018-10-12T07:28:21.000000000+00:00'),
|
14
|
-
|
15
|
-
|
14
|
+
estimated_time: DateTime.iso8601('2018-10-12T07:28:21.000000000+00:00'),
|
15
|
+
estimated_value: 4_128_450,
|
16
16
|
confirmations: 2
|
17
17
|
}
|
18
18
|
]
|
@@ -6,19 +6,19 @@ describe CryptocoinPayable::Adapters::Bitcoin, :vcr do
|
|
6
6
|
expect(response).to match_array(
|
7
7
|
[
|
8
8
|
{
|
9
|
-
|
9
|
+
transaction_hash: '5bdeaf7829148d7e0e1e7b5233512a2c5ae54ef7ccbc8e68b2f85b7e49c917a0',
|
10
10
|
block_hash: '0000000000000000048e8ea3fdd2c3a59ddcbcf7575f82cb96ce9fd17da9f2f4',
|
11
11
|
block_time: DateTime.iso8601('2016-09-13T15:41:00.000000000+00:00'),
|
12
|
-
|
13
|
-
|
12
|
+
estimated_time: be_within(1.day).of(DateTime.iso8601('2016-09-13T15:41:00.000000000+00:00')),
|
13
|
+
estimated_value: 499_000_000,
|
14
14
|
confirmations: 116_077
|
15
15
|
},
|
16
16
|
{
|
17
|
-
|
17
|
+
transaction_hash: 'e7bcdb13d9c903973bd8a740054d4c056a559bae67d4e8f6d0a42b4bab552623',
|
18
18
|
block_hash: '000000000000000001af27feb303ad97af81a5882157f166781784c639f8e896',
|
19
19
|
block_time: DateTime.iso8601('2016-09-13T15:22:42.000000000+00:00'),
|
20
|
-
|
21
|
-
|
20
|
+
estimated_time: be_within(1.day).of(DateTime.iso8601('2016-09-13T15:22:42.000000000+00:00')),
|
21
|
+
estimated_value: 1_000_000,
|
22
22
|
confirmations: 116_080
|
23
23
|
}
|
24
24
|
]
|
@@ -6,35 +6,35 @@ describe CryptocoinPayable::Adapters::Ethereum, :vcr do
|
|
6
6
|
expect(response).to match_array(
|
7
7
|
[
|
8
8
|
{
|
9
|
-
|
9
|
+
transaction_hash: '0xa88b799514e9621962e3d0de25e7e0bc7a123e33085f322c7acdb99cc2585c6d',
|
10
10
|
block_hash: '0x752c50e426f65820f5bf6fd49acbb08d79464f8e7e8ea5b77e2299b69fd6398b',
|
11
11
|
block_time: nil,
|
12
|
-
|
13
|
-
|
12
|
+
estimated_time: be_within(1.day).of(DateTime.iso8601('2018-07-05T12:58:33.000000000+07:00')),
|
13
|
+
estimated_value: 33_753_640_000_000_000,
|
14
14
|
confirmations: 569_771
|
15
15
|
},
|
16
16
|
{
|
17
|
-
|
17
|
+
transaction_hash: '0xb325a8cf241f332bca92c7f715987e4d34be9a6b3bb78d2425c83086b4aced26',
|
18
18
|
block_hash: '0x1c2b73a16fd8c4d25feeccaa2f0bf5c82b8f415f1beaf4d34aaf870daf89689d',
|
19
19
|
block_time: nil,
|
20
|
-
|
21
|
-
|
20
|
+
estimated_time: be_within(1.day).of(DateTime.iso8601('2018-07-05T13:35:07.000000000+07:00')),
|
21
|
+
estimated_value: 2_190_144_444_444_444,
|
22
22
|
confirmations: 569_629
|
23
23
|
},
|
24
24
|
{
|
25
|
-
|
25
|
+
transaction_hash: '0xcd874917be5ad177e7ebd88b5c4a7d4283796e00e43345da5b63fb4f78130b37',
|
26
26
|
block_hash: '0x4ce71d11146445f123680ea9beba7db968b04dc675caddf60248c9d9d6f5739e',
|
27
27
|
block_time: nil,
|
28
|
-
|
29
|
-
|
28
|
+
estimated_time: be_within(1.day).of(DateTime.iso8601('2018-07-05T13:55:53.000000000+07:00')),
|
29
|
+
estimated_value: 1_007_518_888_888_888,
|
30
30
|
confirmations: 569_549
|
31
31
|
},
|
32
32
|
{
|
33
|
-
|
33
|
+
transaction_hash: '0x799ec2aaafbddbc2e746334f96f59f6127dec62e5693480576db351aaf840bfb',
|
34
34
|
block_hash: '0xc1361b19b2266e2259ac433b9e18b4fbc81339304988bbc62dd93aa24fac6449',
|
35
35
|
block_time: nil,
|
36
|
-
|
37
|
-
|
36
|
+
estimated_time: be_within(1.day).of(DateTime.iso8601('2018-08-26T16:05:44.000000000+07:00')),
|
37
|
+
estimated_value: 15_678_420_000_000_000,
|
38
38
|
confirmations: 261_969
|
39
39
|
}
|
40
40
|
]
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'database_cleaner'
|
3
|
+
require 'cryptocoin_payable/orm/activerecord'
|
4
|
+
|
5
|
+
describe CryptocoinPayable::PaymentProcessor do
|
6
|
+
def build_fake_transactions_data
|
7
|
+
transactions = []
|
8
|
+
300.times do
|
9
|
+
transactions << {
|
10
|
+
transaction_hash: '5bdeaf7829148d7e0e1e7b5233512a2c5ae54ef7ccbc8e68b2f85b7e49c917a0',
|
11
|
+
block_hash: '0000000000000000048e8ea3fdd2c3a59ddcbcf7575f82cb96ce9fd17da9f2f4',
|
12
|
+
block_time: DateTime.iso8601('2016-09-13T15:41:00.000000000+00:00'),
|
13
|
+
estimated_time: DateTime.iso8601('2016-09-13T15:41:00.000000000+00:00'),
|
14
|
+
estimated_value: 499_000_000,
|
15
|
+
confirmations: 116_077
|
16
|
+
}
|
17
|
+
end
|
18
|
+
transactions
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when testing performance of database interaction' do
|
22
|
+
before(:all) do
|
23
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'spec/dummy/db/test.sqlite3')
|
24
|
+
DatabaseCleaner.strategy = :truncation
|
25
|
+
GC.disable
|
26
|
+
end
|
27
|
+
|
28
|
+
after(:all) do
|
29
|
+
GC.enable
|
30
|
+
end
|
31
|
+
|
32
|
+
before do
|
33
|
+
DatabaseCleaner.clean
|
34
|
+
CryptocoinPayable::CurrencyConversion.create!(coin_type: :btc, currency: 1, price: 1)
|
35
|
+
adapter = CryptocoinPayable::Adapters.bitcoin_adapter
|
36
|
+
allow(adapter).to receive(:fetch_transactions) { build_fake_transactions_data }
|
37
|
+
end
|
38
|
+
|
39
|
+
after do
|
40
|
+
DatabaseCleaner.clean
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should insert 300 transactions in under 300ms', retry: 3 do
|
44
|
+
payment = CryptocoinPayable::CoinPayment.create!(reason: 'test', price: 1, coin_type: :btc)
|
45
|
+
payment.update(address: '3HR9xYD7MybbE7JLVTjwijYse48BtfEKni')
|
46
|
+
|
47
|
+
expect { subject.update_transactions_for(payment) }.to perform_under(300).ms
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
Binary file
|
@@ -2,7 +2,7 @@ class CreateCoinPaymentTransactions < ActiveRecord::Migration[5.1]
|
|
2
2
|
def change
|
3
3
|
create_table :coin_payment_transactions do |t|
|
4
4
|
t.decimal :estimated_value, precision: 24, scale: 0
|
5
|
-
t.string :transaction_hash
|
5
|
+
t.string :transaction_hash, index: { unique: true }
|
6
6
|
t.string :block_hash
|
7
7
|
t.datetime :block_time
|
8
8
|
t.datetime :estimated_time
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 20_181_015_141_952) do
|
14
14
|
create_table 'coin_payment_transactions', force: :cascade do |t|
|
15
15
|
t.decimal 'estimated_value', precision: 24
|
16
16
|
t.string 'transaction_hash'
|
@@ -21,6 +21,7 @@ ActiveRecord::Schema.define(version: 20_171_227_225_134) do
|
|
21
21
|
t.decimal 'coin_conversion', precision: 24
|
22
22
|
t.integer 'confirmations', default: 0
|
23
23
|
t.index ['coin_payment_id'], name: 'index_coin_payment_transactions_on_coin_payment_id'
|
24
|
+
t.index ['transaction_hash'], name: 'index_coin_payment_transactions_on_transaction_hash', unique: true
|
24
25
|
end
|
25
26
|
|
26
27
|
create_table 'coin_payments', force: :cascade do |t|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'vcr'
|
2
2
|
require 'webmock/rspec'
|
3
3
|
require 'active_support/time'
|
4
|
+
require 'rspec-benchmark'
|
5
|
+
require 'rspec/retry'
|
6
|
+
|
7
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT) if defined?(ActiveRecord::Base)
|
4
8
|
|
5
9
|
VCR.configure do |config|
|
6
10
|
config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
@@ -59,6 +63,8 @@ RSpec.configure do |config|
|
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
66
|
+
config.include RSpec::Benchmark::Matchers
|
67
|
+
|
62
68
|
# The settings below are suggested to provide a good initial experience
|
63
69
|
# with RSpec, but feel free to customize to your heart's content.
|
64
70
|
# # This allows you to limit a spec run to individual examples or groups
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cryptocoin_payable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Salis
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-10-
|
12
|
+
date: 2018-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -95,6 +95,20 @@ dependencies:
|
|
95
95
|
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '12.3'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rspec-benchmark
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0.4'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0.4'
|
98
112
|
- !ruby/object:Gem::Dependency
|
99
113
|
name: rspec-rails
|
100
114
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +123,20 @@ dependencies:
|
|
109
123
|
- - "~>"
|
110
124
|
- !ruby/object:Gem::Version
|
111
125
|
version: '3.7'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rspec-retry
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0.6'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0.6'
|
112
140
|
- !ruby/object:Gem::Dependency
|
113
141
|
name: rubocop
|
114
142
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,6 +193,20 @@ dependencies:
|
|
165
193
|
- - "~>"
|
166
194
|
- !ruby/object:Gem::Version
|
167
195
|
version: '3.4'
|
196
|
+
- !ruby/object:Gem::Dependency
|
197
|
+
name: activerecord-import
|
198
|
+
requirement: !ruby/object:Gem::Requirement
|
199
|
+
requirements:
|
200
|
+
- - "~>"
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: '0.27'
|
203
|
+
type: :runtime
|
204
|
+
prerelease: false
|
205
|
+
version_requirements: !ruby/object:Gem::Requirement
|
206
|
+
requirements:
|
207
|
+
- - "~>"
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0.27'
|
168
210
|
- !ruby/object:Gem::Dependency
|
169
211
|
name: cash-addr
|
170
212
|
requirement: !ruby/object:Gem::Requirement
|
@@ -276,6 +318,7 @@ files:
|
|
276
318
|
- spec/acceptance/adapters/bitcoin_cash_spec.rb
|
277
319
|
- spec/acceptance/adapters/bitcoin_spec.rb
|
278
320
|
- spec/acceptance/adapters/ethereum_spec.rb
|
321
|
+
- spec/acceptance/commands/payment_processor_spec.rb
|
279
322
|
- spec/dummy/README.rdoc
|
280
323
|
- spec/dummy/Rakefile
|
281
324
|
- spec/dummy/app/assets/images/.keep
|
@@ -314,8 +357,8 @@ files:
|
|
314
357
|
- spec/dummy/db/development.sqlite3
|
315
358
|
- spec/dummy/db/migrate/20140510023211_create_widgets.rb
|
316
359
|
- spec/dummy/db/migrate/20171227225132_create_coin_payments.rb
|
317
|
-
- spec/dummy/db/migrate/20171227225133_create_coin_payment_transactions.rb
|
318
360
|
- spec/dummy/db/migrate/20171227225134_create_currency_conversions.rb
|
361
|
+
- spec/dummy/db/migrate/20181015141952_create_coin_payment_transactions.rb
|
319
362
|
- spec/dummy/db/schema.rb
|
320
363
|
- spec/dummy/lib/assets/.keep
|
321
364
|
- spec/dummy/log/.keep
|
@@ -355,7 +398,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
355
398
|
version: 1.3.6
|
356
399
|
requirements: []
|
357
400
|
rubyforge_project:
|
358
|
-
rubygems_version: 2.
|
401
|
+
rubygems_version: 2.7.7
|
359
402
|
signing_key:
|
360
403
|
specification_version: 4
|
361
404
|
summary: Cryptocurrency payment processor
|
@@ -372,6 +415,7 @@ test_files:
|
|
372
415
|
- spec/acceptance/adapters/bitcoin_cash_spec.rb
|
373
416
|
- spec/acceptance/adapters/bitcoin_spec.rb
|
374
417
|
- spec/acceptance/adapters/ethereum_spec.rb
|
418
|
+
- spec/acceptance/commands/payment_processor_spec.rb
|
375
419
|
- spec/dummy/README.rdoc
|
376
420
|
- spec/dummy/Rakefile
|
377
421
|
- spec/dummy/app/assets/images/.keep
|
@@ -410,8 +454,8 @@ test_files:
|
|
410
454
|
- spec/dummy/db/development.sqlite3
|
411
455
|
- spec/dummy/db/migrate/20140510023211_create_widgets.rb
|
412
456
|
- spec/dummy/db/migrate/20171227225132_create_coin_payments.rb
|
413
|
-
- spec/dummy/db/migrate/20171227225133_create_coin_payment_transactions.rb
|
414
457
|
- spec/dummy/db/migrate/20171227225134_create_currency_conversions.rb
|
458
|
+
- spec/dummy/db/migrate/20181015141952_create_coin_payment_transactions.rb
|
415
459
|
- spec/dummy/db/schema.rb
|
416
460
|
- spec/dummy/lib/assets/.keep
|
417
461
|
- spec/dummy/log/.keep
|