tapyrus 0.1.0 → 0.2.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 +4 -4
- data/README.md +6 -14
- data/exe/tapyrusrbd +2 -2
- data/lib/openassets/util.rb +2 -4
- data/lib/schnorr.rb +83 -0
- data/lib/schnorr/signature.rb +38 -0
- data/lib/tapyrus.rb +9 -11
- data/lib/tapyrus/block.rb +1 -32
- data/lib/tapyrus/block_header.rb +7 -6
- data/lib/tapyrus/chain_params.rb +13 -26
- data/lib/tapyrus/chainparams/{testnet.yml → dev.yml} +7 -9
- data/lib/tapyrus/chainparams/{mainnet.yml → prod.yml} +7 -10
- data/lib/tapyrus/constants.rb +12 -34
- data/lib/tapyrus/ext.rb +5 -0
- data/lib/tapyrus/ext/json_parser.rb +47 -0
- data/lib/tapyrus/ext_key.rb +5 -10
- data/lib/tapyrus/key.rb +57 -29
- data/lib/tapyrus/message.rb +2 -2
- data/lib/tapyrus/message/base.rb +1 -0
- data/lib/tapyrus/message/block.rb +3 -3
- data/lib/tapyrus/message/cmpct_block.rb +3 -5
- data/lib/tapyrus/message/tx.rb +2 -2
- data/lib/tapyrus/network/peer.rb +1 -15
- data/lib/tapyrus/node/cli.rb +15 -11
- data/lib/tapyrus/node/configuration.rb +1 -1
- data/lib/tapyrus/node/spv.rb +1 -1
- data/lib/tapyrus/opcodes.rb +5 -0
- data/lib/tapyrus/out_point.rb +1 -1
- data/lib/tapyrus/rpc/request_handler.rb +3 -3
- data/lib/tapyrus/rpc/tapyrus_core_client.rb +17 -15
- data/lib/tapyrus/script/color.rb +79 -0
- data/lib/tapyrus/script/multisig.rb +0 -27
- data/lib/tapyrus/script/script.rb +74 -89
- data/lib/tapyrus/script/script_error.rb +8 -14
- data/lib/tapyrus/script/script_interpreter.rb +65 -86
- data/lib/tapyrus/script/tx_checker.rb +16 -4
- data/lib/tapyrus/secp256k1.rb +1 -0
- data/lib/tapyrus/secp256k1/rfc6979.rb +43 -0
- data/lib/tapyrus/secp256k1/ruby.rb +5 -31
- data/lib/tapyrus/store/chain_entry.rb +1 -0
- data/lib/tapyrus/tx.rb +18 -160
- data/lib/tapyrus/tx_in.rb +4 -11
- data/lib/tapyrus/tx_out.rb +2 -1
- data/lib/tapyrus/util.rb +8 -0
- data/lib/tapyrus/validation.rb +1 -6
- data/lib/tapyrus/version.rb +1 -1
- data/lib/tapyrus/wallet/account.rb +1 -0
- data/lib/tapyrus/wallet/master_key.rb +1 -0
- data/tapyrusrb.gemspec +3 -3
- metadata +42 -39
- data/lib/tapyrus/chainparams/regtest.yml +0 -38
- data/lib/tapyrus/descriptor.rb +0 -147
- data/lib/tapyrus/script_witness.rb +0 -38
data/lib/tapyrus/tx.rb
CHANGED
@@ -5,18 +5,14 @@ module Tapyrus
|
|
5
5
|
|
6
6
|
# Transaction class
|
7
7
|
class Tx
|
8
|
+
include Tapyrus::HexConverter
|
8
9
|
|
9
10
|
MAX_STANDARD_VERSION = 2
|
10
11
|
|
11
12
|
# The maximum weight for transactions we're willing to relay/mine
|
12
13
|
MAX_STANDARD_TX_WEIGHT = 400000
|
13
14
|
|
14
|
-
|
15
|
-
FLAG = 0x01
|
16
|
-
|
17
|
-
attr_accessor :version
|
18
|
-
attr_accessor :marker
|
19
|
-
attr_accessor :flag
|
15
|
+
attr_accessor :features
|
20
16
|
attr_reader :inputs
|
21
17
|
attr_reader :outputs
|
22
18
|
attr_accessor :lock_time
|
@@ -24,30 +20,19 @@ module Tapyrus
|
|
24
20
|
def initialize
|
25
21
|
@inputs = []
|
26
22
|
@outputs = []
|
27
|
-
@
|
23
|
+
@features = 1
|
28
24
|
@lock_time = 0
|
29
25
|
end
|
30
26
|
|
31
27
|
alias_method :in, :inputs
|
32
28
|
alias_method :out, :outputs
|
33
29
|
|
34
|
-
def self.parse_from_payload(payload
|
30
|
+
def self.parse_from_payload(payload)
|
35
31
|
buf = payload.is_a?(String) ? StringIO.new(payload) : payload
|
36
32
|
tx = new
|
37
|
-
tx.
|
33
|
+
tx.features = buf.read(4).unpack('V').first
|
38
34
|
|
39
35
|
in_count = Tapyrus.unpack_var_int_from_io(buf)
|
40
|
-
witness = false
|
41
|
-
if in_count.zero? && !non_witness
|
42
|
-
tx.marker = 0
|
43
|
-
tx.flag = buf.read(1).unpack('c').first
|
44
|
-
if tx.flag.zero?
|
45
|
-
buf.pos -= 1
|
46
|
-
else
|
47
|
-
in_count = Tapyrus.unpack_var_int_from_io(buf)
|
48
|
-
witness = true
|
49
|
-
end
|
50
|
-
end
|
51
36
|
|
52
37
|
in_count.times do
|
53
38
|
tx.inputs << TxIn.parse_from_payload(buf)
|
@@ -58,101 +43,46 @@ module Tapyrus
|
|
58
43
|
tx.outputs << TxOut.parse_from_payload(buf)
|
59
44
|
end
|
60
45
|
|
61
|
-
if witness
|
62
|
-
in_count.times do |i|
|
63
|
-
tx.inputs[i].script_witness = Tapyrus::ScriptWitness.parse_from_payload(buf)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
46
|
tx.lock_time = buf.read(4).unpack('V').first
|
68
47
|
|
69
48
|
tx
|
70
49
|
end
|
71
50
|
|
72
51
|
def hash
|
73
|
-
|
52
|
+
to_hex.to_i(16)
|
74
53
|
end
|
75
54
|
|
76
55
|
def tx_hash
|
77
|
-
Tapyrus.double_sha256(
|
56
|
+
Tapyrus.double_sha256(to_payload).bth
|
78
57
|
end
|
79
58
|
|
80
59
|
def txid
|
81
|
-
buf = [
|
60
|
+
buf = [features].pack('V')
|
82
61
|
buf << Tapyrus.pack_var_int(inputs.length) << inputs.map{|i|i.to_payload(use_malfix: true)}.join
|
83
62
|
buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join
|
84
63
|
buf << [lock_time].pack('V')
|
85
64
|
Tapyrus.double_sha256(buf).reverse.bth
|
86
65
|
end
|
87
66
|
|
88
|
-
def witness_hash
|
89
|
-
Tapyrus.double_sha256(to_payload).bth
|
90
|
-
end
|
91
|
-
|
92
|
-
def wtxid
|
93
|
-
witness_hash.rhex
|
94
|
-
end
|
95
|
-
|
96
|
-
# get the witness commitment of coinbase tx.
|
97
|
-
# if this tx does not coinbase or not have commitment, return nil.
|
98
|
-
def witness_commitment
|
99
|
-
return nil unless coinbase_tx?
|
100
|
-
outputs.each do |output|
|
101
|
-
commitment = output.script_pubkey.witness_commitment
|
102
|
-
return commitment if commitment
|
103
|
-
end
|
104
|
-
nil
|
105
|
-
end
|
106
|
-
|
107
67
|
def to_payload
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
# convert tx to hex format.
|
112
|
-
# @return [String] tx with hex format.
|
113
|
-
def to_hex
|
114
|
-
to_payload.bth
|
115
|
-
end
|
116
|
-
|
117
|
-
def coinbase_tx?
|
118
|
-
inputs.length == 1 && inputs.first.coinbase?
|
119
|
-
end
|
120
|
-
|
121
|
-
def witness?
|
122
|
-
!inputs.find { |i| !i.script_witness.empty? }.nil?
|
123
|
-
end
|
124
|
-
|
125
|
-
def ==(other)
|
126
|
-
to_payload == other.to_payload
|
127
|
-
end
|
128
|
-
|
129
|
-
# serialize tx with old tx format
|
130
|
-
def serialize_old_format
|
131
|
-
buf = [version].pack('V')
|
68
|
+
buf = [features].pack('V')
|
132
69
|
buf << Tapyrus.pack_var_int(inputs.length) << inputs.map(&:to_payload).join
|
133
70
|
buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join
|
134
71
|
buf << [lock_time].pack('V')
|
135
72
|
buf
|
136
73
|
end
|
137
74
|
|
138
|
-
|
139
|
-
|
140
|
-
def serialize_witness_format
|
141
|
-
buf = [version, MARKER, FLAG].pack('Vcc')
|
142
|
-
buf << Tapyrus.pack_var_int(inputs.length) << inputs.map(&:to_payload).join
|
143
|
-
buf << Tapyrus.pack_var_int(outputs.length) << outputs.map(&:to_payload).join
|
144
|
-
buf << witness_payload << [lock_time].pack('V')
|
145
|
-
buf
|
75
|
+
def coinbase_tx?
|
76
|
+
inputs.length == 1 && inputs.first.coinbase?
|
146
77
|
end
|
147
78
|
|
148
|
-
def
|
149
|
-
|
79
|
+
def ==(other)
|
80
|
+
to_payload == other.to_payload
|
150
81
|
end
|
151
82
|
|
152
83
|
# check this tx is standard.
|
153
84
|
def standard?
|
154
|
-
return false if
|
155
|
-
return false if weight > MAX_STANDARD_TX_WEIGHT
|
85
|
+
return false if features > MAX_STANDARD_VERSION
|
156
86
|
inputs.each do |i|
|
157
87
|
# Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed keys (remember the 520 byte limit on redeemScript size).
|
158
88
|
# That works out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
|
@@ -177,21 +107,6 @@ module Tapyrus
|
|
177
107
|
to_payload.bytesize
|
178
108
|
end
|
179
109
|
|
180
|
-
# The virtual transaction size (differs from size for witness transactions)
|
181
|
-
def vsize
|
182
|
-
(weight.to_f / 4).ceil
|
183
|
-
end
|
184
|
-
|
185
|
-
# calculate tx weight
|
186
|
-
# weight = (legacy tx payload) * 3 + (witness tx payload)
|
187
|
-
def weight
|
188
|
-
if witness?
|
189
|
-
serialize_old_format.bytesize * (WITNESS_SCALE_FACTOR - 1) + serialize_witness_format.bytesize
|
190
|
-
else
|
191
|
-
serialize_old_format.bytesize * WITNESS_SCALE_FACTOR
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
110
|
# get signature hash
|
196
111
|
# @param [Integer] input_index input index.
|
197
112
|
# @param [Integer] hash_type signature hash type
|
@@ -205,13 +120,7 @@ module Tapyrus
|
|
205
120
|
raise ArgumentError, 'does not exist input corresponding to input_index.' if input_index >= inputs.size
|
206
121
|
raise ArgumentError, 'script_pubkey must be specified.' unless output_script
|
207
122
|
raise ArgumentError, 'unsupported sig version specified.' unless SIG_VERSION.include?(sig_version)
|
208
|
-
|
209
|
-
if sig_version == :witness_v0 || Tapyrus.chain_params.fork_chain?
|
210
|
-
raise ArgumentError, 'amount must be specified.' unless amount
|
211
|
-
sighash_for_witness(input_index, output_script, hash_type, amount, skip_separator_index)
|
212
|
-
else
|
213
|
-
sighash_for_legacy(input_index, output_script, hash_type)
|
214
|
-
end
|
123
|
+
sighash_for_legacy(input_index, output_script, hash_type)
|
215
124
|
end
|
216
125
|
|
217
126
|
# verify input signature.
|
@@ -220,25 +129,15 @@ module Tapyrus
|
|
220
129
|
# @param [Integer] amount the amount of tapyrus, require for witness program only.
|
221
130
|
# @param [Array] flags the flags used when execute script interpreter.
|
222
131
|
def verify_input_sig(input_index, script_pubkey, amount: nil, flags: STANDARD_SCRIPT_VERIFY_FLAGS)
|
223
|
-
script_sig = inputs[input_index].script_sig
|
224
|
-
has_witness = inputs[input_index].has_witness?
|
225
|
-
|
226
132
|
if script_pubkey.p2sh?
|
227
133
|
flags << SCRIPT_VERIFY_P2SH
|
228
|
-
redeem_script = Script.parse_from_payload(script_sig.chunks.last)
|
229
|
-
script_pubkey = redeem_script if redeem_script.p2wpkh?
|
230
|
-
end
|
231
|
-
|
232
|
-
if has_witness || Tapyrus.chain_params.fork_chain?
|
233
|
-
verify_input_sig_for_witness(input_index, script_pubkey, amount, flags)
|
234
|
-
else
|
235
|
-
verify_input_sig_for_legacy(input_index, script_pubkey, flags)
|
236
134
|
end
|
135
|
+
verify_input_sig_for_legacy(input_index, script_pubkey, flags)
|
237
136
|
end
|
238
137
|
|
239
138
|
def to_h
|
240
139
|
{
|
241
|
-
txid: txid, hash:
|
140
|
+
txid: txid, hash: tx_hash, features: features, size: size, locktime: lock_time,
|
242
141
|
vin: inputs.map(&:to_h), vout: outputs.map.with_index{|tx_out, index| tx_out.to_h.merge({n: index})}
|
243
142
|
}
|
244
143
|
end
|
@@ -285,40 +184,12 @@ module Tapyrus
|
|
285
184
|
ins = [ins[index]]
|
286
185
|
end
|
287
186
|
|
288
|
-
buf = [[
|
187
|
+
buf = [[features].pack('V'), Tapyrus.pack_var_int(ins.size),
|
289
188
|
ins, out_size, outs, [lock_time, hash_type].pack('VV')].join
|
290
189
|
|
291
190
|
Tapyrus.double_sha256(buf)
|
292
191
|
end
|
293
192
|
|
294
|
-
# generate sighash with BIP-143 format
|
295
|
-
# https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
|
296
|
-
def sighash_for_witness(index, script_pubkey_or_script_code, hash_type, amount, skip_separator_index)
|
297
|
-
hash_prevouts = Tapyrus.double_sha256(inputs.map{|i|i.out_point.to_payload}.join)
|
298
|
-
hash_sequence = Tapyrus.double_sha256(inputs.map{|i|[i.sequence].pack('V')}.join)
|
299
|
-
outpoint = inputs[index].out_point.to_payload
|
300
|
-
amount = [amount].pack('Q')
|
301
|
-
nsequence = [inputs[index].sequence].pack('V')
|
302
|
-
hash_outputs = Tapyrus.double_sha256(outputs.map{|o|o.to_payload}.join)
|
303
|
-
|
304
|
-
script_code = script_pubkey_or_script_code.to_script_code(skip_separator_index)
|
305
|
-
|
306
|
-
case (hash_type & 0x1f)
|
307
|
-
when SIGHASH_TYPE[:single]
|
308
|
-
hash_outputs = index >= outputs.size ? "\x00".ljust(32, "\x00") : Tapyrus.double_sha256(outputs[index].to_payload)
|
309
|
-
hash_sequence = "\x00".ljust(32, "\x00")
|
310
|
-
when SIGHASH_TYPE[:none]
|
311
|
-
hash_sequence = hash_outputs = "\x00".ljust(32, "\x00")
|
312
|
-
end
|
313
|
-
|
314
|
-
if (hash_type & SIGHASH_TYPE[:anyonecanpay]) != 0
|
315
|
-
hash_prevouts = hash_sequence ="\x00".ljust(32, "\x00")
|
316
|
-
end
|
317
|
-
hash_type |= (Tapyrus.chain_params.fork_id << 8) if Tapyrus.chain_params.fork_chain?
|
318
|
-
buf = [ [version].pack('V'), hash_prevouts, hash_sequence, outpoint,
|
319
|
-
script_code ,amount, nsequence, hash_outputs, [@lock_time, hash_type].pack('VV')].join
|
320
|
-
Tapyrus.double_sha256(buf)
|
321
|
-
end
|
322
193
|
|
323
194
|
# verify input signature for legacy tx.
|
324
195
|
def verify_input_sig_for_legacy(input_index, script_pubkey, flags)
|
@@ -329,19 +200,6 @@ module Tapyrus
|
|
329
200
|
interpreter.verify_script(script_sig, script_pubkey)
|
330
201
|
end
|
331
202
|
|
332
|
-
# verify input signature for witness tx.
|
333
|
-
def verify_input_sig_for_witness(input_index, script_pubkey, amount, flags)
|
334
|
-
flags |= SCRIPT_VERIFY_WITNESS
|
335
|
-
flags |= SCRIPT_VERIFY_WITNESS_PUBKEYTYPE
|
336
|
-
checker = Tapyrus::TxChecker.new(tx: self, input_index: input_index, amount: amount)
|
337
|
-
interpreter = Tapyrus::ScriptInterpreter.new(checker: checker, flags: flags)
|
338
|
-
i = inputs[input_index]
|
339
|
-
|
340
|
-
script_sig = i.script_sig
|
341
|
-
witness = i.script_witness
|
342
|
-
interpreter.verify_script(script_sig, script_pubkey, witness)
|
343
|
-
end
|
344
|
-
|
345
203
|
end
|
346
204
|
|
347
205
|
end
|
data/lib/tapyrus/tx_in.rb
CHANGED
@@ -9,7 +9,6 @@ module Tapyrus
|
|
9
9
|
attr_accessor :out_point
|
10
10
|
attr_accessor :script_sig
|
11
11
|
attr_accessor :sequence
|
12
|
-
attr_accessor :script_witness
|
13
12
|
|
14
13
|
# Setting nSequence to this value for every input in a transaction disables nLockTime.
|
15
14
|
SEQUENCE_FINAL = 0xffffffff
|
@@ -24,10 +23,9 @@ module Tapyrus
|
|
24
23
|
# If TxIn#sequence encodes a relative lock-time, this mask is applied to extract that lock-time from the sequence field.
|
25
24
|
SEQUENCE_LOCKTIME_MASK = 0x0000ffff
|
26
25
|
|
27
|
-
def initialize(out_point: nil, script_sig: Tapyrus::Script.new,
|
26
|
+
def initialize(out_point: nil, script_sig: Tapyrus::Script.new, sequence: SEQUENCE_FINAL)
|
28
27
|
@out_point = out_point
|
29
28
|
@script_sig = script_sig
|
30
|
-
@script_witness = script_witness
|
31
29
|
@sequence = sequence
|
32
30
|
end
|
33
31
|
|
@@ -37,11 +35,10 @@ module Tapyrus
|
|
37
35
|
hash, index = buf.read(36).unpack('a32V')
|
38
36
|
i.out_point = OutPoint.new(hash.bth, index)
|
39
37
|
sig_length = Tapyrus.unpack_var_int_from_io(buf)
|
40
|
-
|
41
|
-
|
42
|
-
i.script_sig.chunks[0] = sig
|
38
|
+
if sig_length == 0
|
39
|
+
i.script_sig = Script.new
|
43
40
|
else
|
44
|
-
i.script_sig = Script.parse_from_payload(
|
41
|
+
i.script_sig = Script.parse_from_payload(buf.read(sig_length))
|
45
42
|
end
|
46
43
|
i.sequence = buf.read(4).unpack('V').first
|
47
44
|
i
|
@@ -61,15 +58,11 @@ module Tapyrus
|
|
61
58
|
p
|
62
59
|
end
|
63
60
|
|
64
|
-
def has_witness?
|
65
|
-
!script_witness.empty?
|
66
|
-
end
|
67
61
|
|
68
62
|
def to_h
|
69
63
|
sig = script_sig.to_h
|
70
64
|
sig.delete(:type)
|
71
65
|
h = {txid: out_point.txid, vout: out_point.index, script_sig: sig }
|
72
|
-
h[:txinwitness] = script_witness.stack.map(&:bth) if has_witness?
|
73
66
|
h[:sequence] = sequence
|
74
67
|
h
|
75
68
|
end
|
data/lib/tapyrus/tx_out.rb
CHANGED
@@ -7,6 +7,7 @@ module Tapyrus
|
|
7
7
|
class TxOut
|
8
8
|
|
9
9
|
include OpenAssets::MarkerOutput
|
10
|
+
include Tapyrus::Color::ColoredOutput
|
10
11
|
|
11
12
|
attr_accessor :value
|
12
13
|
attr_accessor :script_pubkey
|
@@ -62,7 +63,7 @@ module Tapyrus
|
|
62
63
|
def dust_threshold
|
63
64
|
return 0 if script_pubkey.unspendable?
|
64
65
|
n_size = size
|
65
|
-
n_size +=
|
66
|
+
n_size += (32 + 4 + 1 + 107 + 4)
|
66
67
|
fee = n_size * Tapyrus.chain_params.dust_relay_fee / 1000
|
67
68
|
if fee == 0 && n_size != 0
|
68
69
|
fee = Tapyrus.chain_params.dust_relay_fee > 0 ? 1 : -1
|
data/lib/tapyrus/util.rb
CHANGED
data/lib/tapyrus/validation.rb
CHANGED
@@ -13,11 +13,6 @@ module Tapyrus
|
|
13
13
|
return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-vout-empty')
|
14
14
|
end
|
15
15
|
|
16
|
-
# Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
|
17
|
-
if tx.serialize_old_format.bytesize * Tapyrus::WITNESS_SCALE_FACTOR > Tapyrus::MAX_BLOCK_WEIGHT
|
18
|
-
return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-txns-oversize')
|
19
|
-
end
|
20
|
-
|
21
16
|
# Check for negative or overflow output values
|
22
17
|
amount = 0
|
23
18
|
tx.outputs.each do |o|
|
@@ -34,7 +29,7 @@ module Tapyrus
|
|
34
29
|
end
|
35
30
|
|
36
31
|
if tx.coinbase_tx?
|
37
|
-
if tx.inputs[0].
|
32
|
+
if tx.inputs[0].out_point.index == 0xffffffff || tx.inputs[0].script_sig.size > 100
|
38
33
|
return state.DoS(100, reject_code: Message::Reject::CODE_INVALID, reject_reason: 'bad-cb-length')
|
39
34
|
end
|
40
35
|
else
|
data/lib/tapyrus/version.rb
CHANGED
data/tapyrusrb.gemspec
CHANGED
@@ -23,25 +23,25 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_runtime_dependency 'ecdsa'
|
24
24
|
spec.add_runtime_dependency 'eventmachine'
|
25
25
|
spec.add_runtime_dependency 'murmurhash3'
|
26
|
-
spec.add_runtime_dependency 'bech32', '~> 1.0.3'
|
27
26
|
spec.add_runtime_dependency 'daemon-spawn'
|
28
27
|
spec.add_runtime_dependency 'thor'
|
29
28
|
spec.add_runtime_dependency 'ffi'
|
30
29
|
spec.add_runtime_dependency 'leb128', '~> 1.0.0'
|
31
30
|
spec.add_runtime_dependency 'eventmachine_httpserver'
|
32
|
-
spec.add_runtime_dependency 'rest-client'
|
33
31
|
spec.add_runtime_dependency 'iniparse'
|
34
32
|
spec.add_runtime_dependency 'siphash'
|
35
33
|
spec.add_runtime_dependency 'protobuf', '3.8.5'
|
36
34
|
spec.add_runtime_dependency 'scrypt'
|
37
35
|
spec.add_runtime_dependency 'activesupport', '>= 5.2.3'
|
36
|
+
spec.add_runtime_dependency 'json_pure', '>= 2.3.1'
|
38
37
|
|
39
38
|
# for options
|
40
39
|
spec.add_development_dependency 'leveldb-native'
|
41
40
|
|
42
41
|
spec.add_development_dependency 'bundler'
|
43
|
-
spec.add_development_dependency 'rake', '
|
42
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
44
43
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
45
44
|
spec.add_development_dependency 'timecop'
|
45
|
+
spec.add_development_dependency 'webmock', '~> 3.0'
|
46
46
|
|
47
47
|
end
|