coin-op 0.4.5 → 0.4.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: ddcac303efc3cea02f7d42a2a2a7a9c89d16c292
4
- data.tar.gz: 9a14fbb3178a73eeb5379fa486d6551c3c57835a
3
+ metadata.gz: daa2b1357a473f001974e80e34fcdd52358f906e
4
+ data.tar.gz: a0da314f07e56ad68d776de5234ddbbb8e49d4aa
5
5
  SHA512:
6
- metadata.gz: b7f368cf4336f909d61a54cad255936c9c8cc5b95bef6ffbdd6025df699b18d7bad1c6e25e2900a05a49df1586a2ed230260a5e1d9c8612d6dd52150ef9db041
7
- data.tar.gz: bc80f5346aa7d29608cb3d115188be258cf01e7b0d21b80b8a8d55a77a79fd636c44cd6d90b24ad9e070f25d1f2a3835af5901efcbe2b4ecb264a1937411cc87
6
+ metadata.gz: e076e686da9b9dc3a6212df1a21757317bd20792d4e9c342c6afaaa19d9acd41e60fb058f0e2b2859ea1ccf50b2f9a22c4ba2e4ac8e5945b42950be96b62c2ae
7
+ data.tar.gz: 4ff3f5c89ebb5d8e6ae0294904b9db02545bc3d2c1fe8b3598e20d293ebb518e86db9293170b609b862101fbc1865a831098a1cbb5f9d056d6e04d0ed7b0d3f6
@@ -1,3 +1,2 @@
1
- i��O��YI)1��p��E����W�4o�2����z�X�i�a,�Ga�Ӊ5� P���1��O۸� �Z��ҏ���U�n��7����i�˙��
2
- �~6,r� ��N��O&��}�ݶy���GPSk�ܸ��P�m`^˿�wwm�B�%?�3ǚ?N��Y�S�}�̮m��Nr Yҏt'�Hc[+gOT#%�l�����3�Q
3
- �h��U��
1
+ �.ˤ'-<��DmW
2
+ ��ɂ1 %�dvJQ/�$�1ſ��� ��.��@�nYC
data.tar.gz.sig CHANGED
Binary file
@@ -3,59 +3,76 @@ module CoinOp::Bit
3
3
 
4
4
  module Fee
5
5
 
6
+ # From http://bitcoinfees.com
7
+ AVG_P2PKH_BYTES = 148
8
+ AVG_OUTPUT_SIZE = 34
9
+
10
+ # From rough tests of Gem p2sh txs on 2015-09-08
11
+ AVG_P2SH_BYTES = 300
12
+
6
13
  module_function
7
14
 
8
15
  # Given an array of unspent Outputs and an array of Outputs for a
9
16
  # Transaction, estimate the fee required for the transaction to be
10
- # included in a block. Optionally takes an Integer specifying the
11
- # transaction size in bytes, which is necessary when using unspents
12
- # that deviate from the customary single signature.
17
+ # included in a block.
18
+ #
19
+ # Optionally takes an Integer tx_size specifying the transaction size in bytes
20
+ # This is useful if you have the scriptSigs for the unspents, because
21
+ # you can get a more accurate size than the estimate which is generated
22
+ # here by default
23
+ #
24
+ # Optionally takes an Integer fee_per_kb specifying the chosen cost per 1000
25
+ # bytes to use
13
26
  #
14
27
  # Returns the estimated fee in satoshis.
15
- def estimate(unspents, payees, tx_size=nil, network:)
28
+ def estimate(unspents, payees, network:, tx_size: nil, fee_per_kb: nil)
16
29
  # https://en.bitcoin.it/wiki/Transaction_fees
17
30
 
18
31
  # dupe because we'll need to add a change output
19
32
  payees = payees.dup
20
33
 
21
- unspent_total = unspents.inject(0) {|sum, output| sum += output.value}
22
- payee_total = payees.inject(0) {|sum, payee| sum += payee.value}
34
+ unspent_total = unspents.inject(0) { |sum, output| sum += output.value }
35
+ payee_total = payees.inject(0) { |sum, payee| sum += payee.value }
36
+
23
37
  nominal_change = unspent_total - payee_total
24
- payees << Output.new(value: nominal_change, network: network)
38
+ payees << Output.new(value: nominal_change, network: network) if nominal_change > 0
25
39
 
26
- tx_size ||= estimate_tx_size(unspents.size, payees.size)
27
- min = payees.min_by {|payee| payee.value }
40
+ tx_size ||= estimate_tx_size(unspents, payees)
28
41
 
42
+ # conditions for 0-fee transactions
29
43
  small = tx_size < 1000
30
- big_outputs = min.value > 1_000_000
31
44
 
32
- p = priority :size => tx_size, :unspents => (unspents.map do |output|
33
- {:value => output.value, :age => output.confirmations}
34
- end)
35
- high_priority = p > PRIORITY_THRESHOLD
45
+ min_payee = payees.min_by { |payee| payee.value }
46
+ big_outputs = min_payee.value > 1_000_000
47
+ high_priority = priority(
48
+ size: tx_size,
49
+ unspents: unspents.map { |output| { value: output.value, age: output.confirmations } }
50
+ ) > PRIORITY_THRESHOLD
36
51
 
37
- if small && big_outputs && high_priority
38
- 0
39
- else
40
- fee_for_bytes(tx_size, network: network)
41
- end
52
+ # 0-fee requirements met
53
+ return 0 if small && big_outputs && high_priority
42
54
 
55
+ # Otherwise, calculate the fee by size
56
+ fee_for_bytes(tx_size, network: network, fee_per_kb: fee_per_kb)
43
57
  end
44
58
 
45
- def fee_for_bytes(bytes, network:)
59
+ def fee_for_bytes(bytes, network:, fee_per_kb: nil)
46
60
  # https://en.bitcoin.it/wiki/Transaction_fees
47
61
  # > the reference implementation will round up the transaction size to the
48
62
  # > next thousand bytes and add a fee of 0.1 mBTC (0.0001 BTC) per thousand bytes
49
63
  size = (bytes / 1000) + 1
64
+ return size * fee_per_kb if fee_per_kb
50
65
  CoinOp.syncbit(network) { Bitcoin.network[:min_tx_fee] * size }
51
66
  end
52
67
 
53
- # From http://bitcoinfees.com. This estimation is only valid for
54
- # transactions with all inputs using the common "public key hash" method
55
- # for authorization.
56
- def estimate_tx_size(num_inputs, num_outputs)
57
- # From http://bitcoinfees.com.
58
- (148 * num_inputs) + (34 * num_outputs) + 10
68
+ def estimate_tx_size(inputs, outputs)
69
+ # tx overhead
70
+ 10 +
71
+ # outputs don't vary much in size
72
+ (AVG_OUTPUT_SIZE * outputs.size) +
73
+ # p2sh outputs are usually larger than p2pkh outputs, which don't vary much
74
+ inputs.inject(0) { |sum, input|
75
+ sum += input.script.type == :script_hash ? AVG_P2SH_BYTES : AVG_P2PKH_BYTES }
59
76
  end
60
77
 
61
78
 
@@ -10,8 +10,7 @@ module CoinOp::Bit
10
10
  transaction
11
11
  end
12
12
 
13
- # Construct a Transaction from a data structure of nested Hashes
14
- # and Arrays.
13
+ # Construct a Transaction from a data structure of nested Hashes and Arrays.
15
14
  def self.data(data, network:)
16
15
  version, lock_time, fee, inputs, outputs, confirmations =
17
16
  data.values_at :version, :lock_time, :fee, :inputs, :outputs, :confirmations
@@ -25,20 +24,17 @@ module CoinOp::Bit
25
24
  )
26
25
 
27
26
  outputs.each do |output_hash|
28
- transaction.add_output(Output.new(output_hash, network: network))
27
+ transaction.add_output(output_hash, network: network)
29
28
  end
30
29
 
31
30
  #FIXME: we're not handling sig_scripts for already signed inputs.
32
31
 
33
- if inputs
34
- # TODO: use #each instead of #each_with_index
35
- inputs.each_with_index do |input_hash, index|
36
- transaction.add_input(input_hash, network: network)
32
+ inputs.each do |input_hash|
33
+ transaction.add_input(input_hash, network: network)
37
34
 
38
- ## FIXME: verify that the supplied and computed sig_hashes match
39
- #puts :sig_hashes_match => (data[:sig_hash] == input.sig_hash)
40
- end
41
- end
35
+ ## FIXME: verify that the supplied and computed sig_hashes match
36
+ #puts :sig_hashes_match => (data[:sig_hash] == input.sig_hash)
37
+ end if inputs
42
38
 
43
39
  transaction
44
40
  end
@@ -160,17 +156,14 @@ module CoinOp::Bit
160
156
  # * an instance of Output
161
157
  # * a Hash describing an Output
162
158
  #
163
- def add_input(input, network:)
159
+ def add_input(input, network: @network)
164
160
  # TODO: allow specifying prev_tx and index with a Hash.
165
161
  # Possibly stop using SparseInput.
166
162
 
167
- unless input.is_a?(Input)
168
- input = Input.new input.merge(
169
- transaction: self,
170
- index: @inputs.size,
171
- network: network
172
- )
173
- end
163
+ input = Input.new(input.merge(transaction: self,
164
+ index: @inputs.size,
165
+ network: network)
166
+ ) unless input.is_a?(Input)
174
167
 
175
168
  @inputs << input
176
169
  self.update_native do |native|
@@ -180,15 +173,15 @@ module CoinOp::Bit
180
173
  end
181
174
 
182
175
  # Takes either an Output or a Hash describing an output.
183
- def add_output(output)
184
- unless output.is_a? Output
185
- output = Output.new(output, network: @network)
176
+ def add_output(output, network: @network)
177
+ if output.is_a?(Output)
178
+ output.set_transaction(self, @outputs.size)
179
+ else
180
+ output = Output.new(output.merge(transaction: self,
181
+ index: @outputs.size),
182
+ network: network)
186
183
  end
187
184
 
188
- index = @outputs.size
189
- # TODO: stop using set_transaction and just pass self to Output.new
190
- # Then remove output.set_transaction
191
- output.set_transaction self, index
192
185
  @outputs << output
193
186
  self.update_native do |native|
194
187
  native.add_out(output.native)
@@ -301,10 +294,11 @@ module CoinOp::Bit
301
294
  # Estimate the fee in satoshis for this transaction. Takes an optional
302
295
  # tx_size argument because it is impossible to determine programmatically
303
296
  # the size of the scripts used to create P2SH outputs.
304
- # Rough testing of the size of a 2of3 multisig p2sh input: 297
305
- def estimate_fee(tx_size=nil)
297
+ # Rough testing of the size of a 2of3 multisig p2sh input: 297 +/- 40 bytes
298
+ def estimate_fee(tx_size: nil, network: @network, fee_per_kb: nil)
306
299
  unspents = inputs.map(&:output)
307
- Fee.estimate(unspents, outputs, tx_size)
300
+ Fee.estimate(unspents, outputs,
301
+ network: network, tx_size: tx_size, fee_per_kb: fee_per_kb)
308
302
  end
309
303
 
310
304
  # Returns the transaction fee computed from the actual input and output
@@ -24,7 +24,7 @@ module CoinOp
24
24
 
25
25
  def int_to_byte_array(i, endianness: :little)
26
26
  arr = i.to_s(16).scan(/../).map { |x| x.hex.chr }
27
- if endianness = :little
27
+ if endianness == :little
28
28
  arr.reverse.join
29
29
  else
30
30
  arr.join
@@ -1,3 +1,3 @@
1
1
  module CoinOp
2
- VERSION = "0.4.5"
2
+ VERSION = "0.4.6"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coin-op
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew King
@@ -32,7 +32,7 @@ cert_chain:
32
32
  tdc4VS7IlSRxlZ3dBOgiigy9GXpJ+7F831AqjxL39EPwdr7RguTNz+pi//RKaT/U
33
33
  IlpVB+Xfk0vQdP7iYfjGxDzUf0FACMjsR95waJmadKW1Iy6STw2hwPhYIQz1Hu1A
34
34
  -----END CERTIFICATE-----
35
- date: 2015-08-07 00:00:00.000000000 Z
35
+ date: 2015-09-09 00:00:00.000000000 Z
36
36
  dependencies:
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: bitcoin-ruby
metadata.gz.sig CHANGED
Binary file