glueby 0.5.1 → 0.6.2

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
  SHA256:
3
- metadata.gz: 37c10a4359a509cd4f86c35726161717bde07bc1ce459e19b0ba4c053e8dba86
4
- data.tar.gz: 3cd0124ed69e0f34d1adf4ff5ed26005979689befc163c970b104245f267a479
3
+ metadata.gz: bd80045038551e7ffc41a613fb67401f3675c79098222e335359209070ff280a
4
+ data.tar.gz: f966a44bb7de60429e91d39681f63c6b827dbcb8806700cbfe6b5e961f013b2d
5
5
  SHA512:
6
- metadata.gz: 68729802e9bcb1a51148c12daa1e1565180c300d43cc811c2c512056804ad2fb8cd0bd8dd0e0d915e19da2177b3a47a941a4911ce7f6376a47f598edade087fe
7
- data.tar.gz: 902c5c0cf87cb940c9619e5f9af95367187a009ddc01d74a6604c22d8e9df9e50dec50df24455c6fb2f0a1a9020869e4d619bd879802739ba04118bf600fab6a
6
+ metadata.gz: 4e443a845c4d65eeba06c83d40617497b984f8a0c158e54debb1ac82d762af53ebba8073e8fc18855f93816370dc8969657bec8d8e95d5990df3fe50c9c7471a
7
+ data.tar.gz: 2c5f2670b48f6a1149052b239d89c626c323e21f222bd2deb201074b96d54ac935080624cb92a2399414aed03de44258a41da5b0fc4ecc5221d854ef201c06de
data/README.md CHANGED
@@ -443,6 +443,20 @@ Configuration:
443
443
 
444
444
  ```
445
445
 
446
+ ## Other configurations
447
+
448
+ ### Default fixed fee for the FixedFeeEstimator
449
+
450
+ The architecture of Glueby accepts any fee estimation strategies for paying transactions fee. However, we officially support only one strategy: the fixed fee strategy.
451
+ It just returns a fixed fee value without any estimation.
452
+ Here provides a configuration to modify the default fixed fee value it returns like this:
453
+
454
+ ```ruby
455
+ Glueby.configure do |config|
456
+ config.default_fixed_fee = 10_000
457
+ end
458
+ ```
459
+
446
460
 
447
461
  ## Development
448
462
 
@@ -2,10 +2,13 @@ class CreateTimestamp < ActiveRecord::Migration<%= migration_version %>
2
2
  def change
3
3
  create_table :glueby_timestamps<%= table_options %> do |t|
4
4
  t.string :txid
5
- t.integer :status
5
+ t.integer :status, null: false, default: 0
6
6
  t.string :content_hash
7
7
  t.string :prefix
8
8
  t.string :wallet_id
9
+ t.integer :timestamp_type, null: false, default: 0
10
+ t.string :p2c_address
11
+ t.string :payment_base
9
12
  end
10
13
  end
11
14
  end
@@ -82,5 +82,11 @@ module Glueby
82
82
  def utxo_provider_config=(config)
83
83
  UtxoProvider.configure(config)
84
84
  end
85
+
86
+ # Set default fixed fee to the FixedFeeEstimator
87
+ # @param [Integer] fee The default fee value in tapyrus to the FixedFeeEstimator
88
+ def default_fixed_fee=(fee)
89
+ Contract::FixedFeeEstimator.default_fixed_fee = fee
90
+ end
85
91
  end
86
92
  end
@@ -4,15 +4,22 @@ module Glueby
4
4
  class Timestamp < ::ActiveRecord::Base
5
5
  include Glueby::Contract::Timestamp::Util
6
6
  enum status: { init: 0, unconfirmed: 1, confirmed: 2 }
7
+ enum timestamp_type: { simple: 0, trackable: 1 }
7
8
 
8
9
  # @param [Hash] attributes attributes which consist of:
9
10
  # - wallet_id
10
11
  # - content
11
12
  # - prefix(optional)
13
+ # - timestamp_type(optional)
12
14
  def initialize(attributes = nil)
13
15
  @content_hash = Tapyrus.sha256(attributes[:content]).bth
14
16
  super(wallet_id: attributes[:wallet_id], content_hash: @content_hash,
15
- prefix: attributes[:prefix] ? attributes[:prefix] : '', status: :init)
17
+ prefix: attributes[:prefix] ? attributes[:prefix] : '', status: :init, timestamp_type: attributes[:timestamp_type] || :simple)
18
+ end
19
+
20
+ # Return true if timestamp type is 'trackable' and output in timestamp transaction has not been spent yet, otherwise return false.
21
+ def latest
22
+ trackable?
16
23
  end
17
24
  end
18
25
  end
@@ -5,6 +5,7 @@ module Glueby
5
5
  class InsufficientTokens < StandardError; end
6
6
  class InvalidAmount < StandardError; end
7
7
  class InvalidTokenType < StandardError; end
8
+ class InvalidTimestampType < StandardError; end
8
9
  class TxAlreadyBroadcasted < StandardError; end
9
10
  class UnsupportedTokenType < StandardError; end
10
11
  class UnknownScriptPubkey < StandardError; end
@@ -22,7 +22,11 @@ module Glueby
22
22
  class FixedFeeEstimator
23
23
  include FeeEstimator
24
24
 
25
- def initialize(fixed_fee: 10_000)
25
+ class << self
26
+ attr_accessor :default_fixed_fee
27
+ end
28
+
29
+ def initialize(fixed_fee: FixedFeeEstimator.default_fixed_fee || 10_000)
26
30
  @fixed_fee = fixed_fee
27
31
  end
28
32
 
@@ -9,6 +9,8 @@ module Glueby
9
9
  # Storing timestamp transaction to the blockchain enables everyone to verify that the data existed at that time and a user signed it.
10
10
  class Timestamp
11
11
  include Glueby::Contract::TxBuilder
12
+
13
+ P2C_DEFAULT_VALUE = 1_000
12
14
 
13
15
  autoload :Syncer, 'glueby/contract/timestamp/syncer'
14
16
 
@@ -16,9 +18,28 @@ module Glueby
16
18
  include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
17
19
  module_function
18
20
 
19
- def create_txs(wallet, prefix, data, fee_estimator, utxo_provider)
21
+ # @param [Glueby::Wallet] wallet
22
+ # @param [Array] contents The data to be used for generating pay-to-contract address
23
+ # @return [pay-to-contract address, public key used for generating address]
24
+ def create_pay_to_contract_address(wallet, contents: nil)
25
+ pubkey = wallet.internal_wallet.create_pubkey.pubkey
26
+ # Calculate P + H(P || contents)G
27
+ group = ECDSA::Group::Secp256k1
28
+ p = Tapyrus::Key.new(pubkey: pubkey).to_point # P
29
+ commitment = Tapyrus.sha256(p.to_hex(true).htb + contents.join).bth.to_i(16) % group.order # H(P || contents)
30
+ point = p + group.generator.multiply_by_scalar(commitment) # P + H(P || contents)G
31
+ [Tapyrus::Key.new(pubkey: point.to_hex(true)).to_p2pkh, pubkey] # [p2c address, P]
32
+ end
33
+
34
+ def create_txs(wallet, prefix, data, fee_estimator, utxo_provider, type: :simple)
20
35
  txb = Tapyrus::TxBuilder.new
21
- txb.data(prefix + data)
36
+ if type == :simple
37
+ txb.data(prefix + data)
38
+ elsif type == :trackable
39
+ p2c_address, payment_base = create_pay_to_contract_address(wallet, contents: [prefix, data])
40
+ txb.pay(p2c_address, P2C_DEFAULT_VALUE)
41
+ end
42
+
22
43
  fee = fee_estimator.fee(dummy_tx(txb.build))
23
44
  if utxo_provider
24
45
  script_pubkey = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
@@ -54,7 +75,7 @@ module Glueby
54
75
  end
55
76
 
56
77
  txb.fee(fee).change_address(wallet.internal_wallet.change_address)
57
- [funding_tx, wallet.internal_wallet.sign_tx(txb.build, prev_txs)]
78
+ [funding_tx, wallet.internal_wallet.sign_tx(txb.build, prev_txs), p2c_address, payment_base]
58
79
  end
59
80
 
60
81
  def get_transaction(tx)
@@ -65,6 +86,9 @@ module Glueby
65
86
 
66
87
  attr_reader :tx, :txid
67
88
 
89
+ # p2c_address and payment_base is used in `trackable` type
90
+ attr_reader :p2c_address, :payment_base
91
+
68
92
  # @param [String] content Data to be hashed and stored in blockchain.
69
93
  # @param [String] prefix prefix of op_return data
70
94
  # @param [Glueby::Contract::FeeEstimator] fee_estimator
@@ -72,21 +96,29 @@ module Glueby
72
96
  # - :sha256
73
97
  # - :double_sha256
74
98
  # - :none
75
- # @raise [Glueby::Contract::Errors::UnsupportedDigestType] if digest unsupport
99
+ # @param [Symbol] timestamp_type
100
+ # - :simple
101
+ # - :trackable
102
+ # @raise [Glueby::Contract::Errors::UnsupportedDigestType] if digest is unsupported
103
+ # @raise [Glueby::Contract::Errors::InvalidTimestampType] if timestamp_type is unsupported
76
104
  def initialize(
77
105
  wallet:,
78
106
  content:,
79
107
  prefix: '',
80
108
  fee_estimator: Glueby::Contract::FixedFeeEstimator.new,
81
109
  digest: :sha256,
82
- utxo_provider: nil
110
+ utxo_provider: nil,
111
+ timestamp_type: :simple
83
112
  )
84
113
  @wallet = wallet
85
114
  @content = content
86
115
  @prefix = prefix
87
116
  @fee_estimator = fee_estimator
117
+ raise Glueby::Contract::Errors::UnsupportedDigestType, "#{digest} is invalid digest, supported digest are :sha256, :double_sha256, and :none." unless [:sha256, :double_sha256, :none].include?(digest)
88
118
  @digest = digest
89
119
  @utxo_provider = utxo_provider
120
+ raise Glueby::Contract::Errors::InvalidTimestampType, "#{timestamp_type} is invalid type, supported types are :simple, and :trackable." unless [:simple, :trackable].include?(timestamp_type)
121
+ @timestamp_type = timestamp_type
90
122
  end
91
123
 
92
124
  # broadcast to Tapyrus Core
@@ -96,7 +128,7 @@ module Glueby
96
128
  def save!
97
129
  raise Glueby::Contract::Errors::TxAlreadyBroadcasted if @txid
98
130
 
99
- funding_tx, @tx = create_txs(@wallet, @prefix, digest_content, @fee_estimator, @utxo_provider)
131
+ funding_tx, @tx, @p2c_address, @payment_base = create_txs(@wallet, @prefix, digest_content, @fee_estimator, @utxo_provider, type: @timestamp_type)
100
132
  @wallet.internal_wallet.broadcast(funding_tx) if funding_tx
101
133
  @txid = @wallet.internal_wallet.broadcast(@tx)
102
134
  end
@@ -44,7 +44,7 @@ module Glueby
44
44
 
45
45
  fee = fee_estimator.fee(dummy_tx(txb.build))
46
46
  # The outputs need to be shuffled so that no utxos are spent twice as possible.
47
- sum, outputs = wallet.collect_uncolored_outputs(fee + value, nil, true, true)
47
+ sum, outputs = collect_uncolored_outputs(wallet, fee + value)
48
48
 
49
49
  outputs.each do |utxo|
50
50
  txb.add_utxo({
@@ -73,6 +73,20 @@ module Glueby
73
73
  end
74
74
  end
75
75
 
76
+ def collect_uncolored_outputs(wallet, amount)
77
+ utxos = wallet.list_unspent.select { |o| !o[:color_id] && o[:amount] == @default_value }
78
+ utxos.shuffle!
79
+
80
+ utxos.inject([0, []]) do |sum, output|
81
+ new_sum = sum[0] + output[:amount]
82
+ new_outputs = sum[1] << output
83
+ return [new_sum, new_outputs] if new_sum >= amount
84
+
85
+ [new_sum, new_outputs]
86
+ end
87
+ raise Glueby::Contract::Errors::InsufficientFunds
88
+ end
89
+
76
90
  def validate_config!
77
91
  if UtxoProvider.config
78
92
  utxo_pool_size = UtxoProvider.config[:utxo_pool_size]
@@ -1,3 +1,3 @@
1
1
  module Glueby
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.2"
3
3
  end
@@ -12,7 +12,7 @@ module Glueby
12
12
  timestamps.each do |t|
13
13
  begin
14
14
  wallet = Glueby::Wallet.load(t.wallet_id)
15
- funding_tx, tx = create_txs(wallet, t.prefix, t.content_hash, Glueby::Contract::FixedFeeEstimator.new, utxo_provider)
15
+ funding_tx, tx, p2c_address, payment_base = create_txs(wallet, t.prefix, t.content_hash, Glueby::Contract::FixedFeeEstimator.new, utxo_provider, type: t.timestamp_type.to_sym)
16
16
  if funding_tx
17
17
  ::ActiveRecord::Base.transaction do
18
18
  wallet.internal_wallet.broadcast(funding_tx)
@@ -21,7 +21,7 @@ module Glueby
21
21
  end
22
22
  ::ActiveRecord::Base.transaction do
23
23
  wallet.internal_wallet.broadcast(tx) do |tx|
24
- t.update(txid: tx.txid, status: :unconfirmed)
24
+ t.update(txid: tx.txid, status: :unconfirmed, p2c_address: p2c_address, payment_base: payment_base)
25
25
  end
26
26
  puts "timestamp tx was broadcasted (id=#{t.id}, txid=#{tx.txid})"
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glueby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-01 00:00:00.000000000 Z
11
+ date: 2021-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tapyrus