glueby 0.4.4 → 0.6.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +477 -387
  3. data/glueby.gemspec +33 -33
  4. data/lib/generators/glueby/contract/templates/initializer.rb.erb +8 -8
  5. data/lib/generators/glueby/contract/templates/key_table.rb.erb +16 -16
  6. data/lib/generators/glueby/contract/templates/timestamp_table.rb.erb +4 -1
  7. data/lib/generators/glueby/contract/templates/utxo_table.rb.erb +16 -16
  8. data/lib/glueby/block_syncer.rb +97 -97
  9. data/lib/glueby/configuration.rb +32 -2
  10. data/lib/glueby/contract/active_record/timestamp.rb +3 -1
  11. data/lib/glueby/contract/errors.rb +1 -0
  12. data/lib/glueby/contract/fee_estimator.rb +5 -1
  13. data/lib/glueby/contract/timestamp/syncer.rb +13 -13
  14. data/lib/glueby/contract/timestamp.rb +153 -102
  15. data/lib/glueby/contract/token.rb +270 -244
  16. data/lib/glueby/contract/tx_builder.rb +97 -30
  17. data/lib/glueby/fee_provider/tasks.rb +140 -140
  18. data/lib/glueby/fee_provider.rb +11 -0
  19. data/lib/glueby/internal/wallet/abstract_wallet_adapter.rb +153 -151
  20. data/lib/glueby/internal/wallet/active_record/utxo.rb +51 -51
  21. data/lib/glueby/internal/wallet/active_record_wallet_adapter/syncer.rb +13 -13
  22. data/lib/glueby/internal/wallet/active_record_wallet_adapter.rb +159 -151
  23. data/lib/glueby/internal/wallet/tapyrus_core_wallet_adapter.rb +194 -186
  24. data/lib/glueby/internal/wallet.rb +164 -162
  25. data/lib/glueby/railtie.rb +10 -9
  26. data/lib/glueby/utxo_provider/tasks.rb +135 -0
  27. data/lib/glueby/utxo_provider.rb +85 -0
  28. data/lib/glueby/version.rb +3 -3
  29. data/lib/glueby.rb +40 -39
  30. data/lib/tasks/glueby/block_syncer.rake +28 -28
  31. data/lib/tasks/glueby/contract/timestamp.rake +46 -39
  32. data/lib/tasks/glueby/fee_provider.rake +18 -18
  33. data/lib/tasks/glueby/utxo_provider.rake +18 -0
  34. metadata +5 -2
@@ -1,102 +1,153 @@
1
- module Glueby
2
- module Contract
3
- # Timestamp feature allows users to send transaction with op_return output which has sha256 hash of arbitary data.
4
- # Timestamp transaction has
5
- # * 1 or more inputs enough to afford transaction fee.
6
- # * 1 output which has op_return, application specific prefix, and sha256 hash of data.
7
- # * 1 output to send the change TPC back to the wallet.
8
- #
9
- # Storing timestamp transaction to the blockchain enables everyone to verify that the data existed at that time and a user signed it.
10
- class Timestamp
11
- include Glueby::Contract::TxBuilder
12
-
13
- autoload :Syncer, 'glueby/contract/timestamp/syncer'
14
-
15
- module Util
16
- include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
17
- module_function
18
-
19
- def create_tx(wallet, prefix, data, fee_estimator)
20
- tx = Tapyrus::Tx.new
21
- tx.outputs << Tapyrus::TxOut.new(value: 0, script_pubkey: create_script(prefix, data))
22
-
23
- fee = fee_estimator.fee(dummy_tx(tx))
24
- sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee)
25
- fill_input(tx, outputs)
26
-
27
- fill_change_tpc(tx, wallet, sum - fee)
28
- wallet.internal_wallet.sign_tx(tx)
29
- end
30
-
31
- def create_payload(prefix, data)
32
- payload = +''
33
- payload << prefix
34
- payload << data
35
- payload
36
- end
37
-
38
- def create_script(prefix, data)
39
- script = Tapyrus::Script.new
40
- script << Tapyrus::Script::OP_RETURN
41
- script << create_payload(prefix, data)
42
- script
43
- end
44
-
45
- def get_transaction(tx)
46
- Glueby::Internal::RPC.client.getrawtransaction(tx.txid, 1)
47
- end
48
- end
49
- include Glueby::Contract::Timestamp::Util
50
-
51
- attr_reader :tx, :txid
52
-
53
- # @param [String] content Data to be hashed and stored in blockchain.
54
- # @param [String] prefix prefix of op_return data
55
- # @param [Glueby::Contract::FeeEstimator] fee_estimator
56
- # @param [Symbol] digest type which select of:
57
- # - :sha256
58
- # - :double_sha256
59
- # - :none
60
- # @raise [Glueby::Contract::Errors::UnsupportedDigestType] if digest unsupport
61
- def initialize(
62
- wallet:,
63
- content:,
64
- prefix: '',
65
- fee_estimator: Glueby::Contract::FixedFeeEstimator.new,
66
- digest: :sha256
67
- )
68
- @wallet = wallet
69
- @content = content
70
- @prefix = prefix
71
- @fee_estimator = fee_estimator
72
- @digest = digest
73
- end
74
-
75
- # broadcast to Tapyrus Core
76
- # @return [String] txid
77
- # @raise [TxAlreadyBroadcasted] if tx has been broadcasted.
78
- # @raise [InsufficientFunds] if result of listunspent is not enough to pay the specified amount
79
- def save!
80
- raise Glueby::Contract::Errors::TxAlreadyBroadcasted if @txid
81
-
82
- @tx = create_tx(@wallet, @prefix, digest_content, @fee_estimator)
83
- @txid = @wallet.internal_wallet.broadcast(@tx)
84
- end
85
-
86
- private
87
-
88
- def digest_content
89
- case @digest&.downcase
90
- when :sha256
91
- Tapyrus.sha256(@content)
92
- when :double_sha256
93
- Tapyrus.double_sha256(@content)
94
- when :none
95
- @content
96
- else
97
- raise Glueby::Contract::Errors::UnsupportedDigestType
98
- end
99
- end
100
- end
101
- end
102
- end
1
+ module Glueby
2
+ module Contract
3
+ # Timestamp feature allows users to send transaction with op_return output which has sha256 hash of arbitary data.
4
+ # Timestamp transaction has
5
+ # * 1 or more inputs enough to afford transaction fee.
6
+ # * 1 output which has op_return, application specific prefix, and sha256 hash of data.
7
+ # * 1 output to send the change TPC back to the wallet.
8
+ #
9
+ # Storing timestamp transaction to the blockchain enables everyone to verify that the data existed at that time and a user signed it.
10
+ class Timestamp
11
+ include Glueby::Contract::TxBuilder
12
+
13
+ P2C_DEFAULT_VALUE = 1_000
14
+
15
+ autoload :Syncer, 'glueby/contract/timestamp/syncer'
16
+
17
+ module Util
18
+ include Glueby::Internal::Wallet::TapyrusCoreWalletAdapter::Util
19
+ module_function
20
+
21
+ # @param [Glueby::Wallet] wallet
22
+ # @param [Array] data The data to be used for generating pay-to-contract address
23
+ # @return [Array(String, String)]
24
+ # Return (pay-to-contract address, public key used for generating address)
25
+ def create_pay_to_contract_address(wallet, contents: nil)
26
+ pubkey = wallet.internal_wallet.create_pubkey.pubkey
27
+ # Calculate P + H(P || contents)G
28
+ group = ECDSA::Group::Secp256k1
29
+ p = Tapyrus::Key.new(pubkey: pubkey).to_point # P
30
+ commitment = Tapyrus.sha256(p.to_hex(true).htb + contents.join).bth.to_i(16) % group.order # H(P || contents)
31
+ point = p + group.generator.multiply_by_scalar(commitment) # P + H(P || contents)G
32
+ [Tapyrus::Key.new(pubkey: point.to_hex(true)).to_p2pkh, pubkey] # [p2c address, P]
33
+ end
34
+
35
+ def create_txs(wallet, prefix, data, fee_estimator, utxo_provider, type: :simple)
36
+ txb = Tapyrus::TxBuilder.new
37
+ if type == :simple
38
+ txb.data(prefix + data)
39
+ elsif type == :trackable
40
+ p2c_address, payment_base = create_pay_to_contract_address(wallet, contents: [prefix, data])
41
+ txb.pay(p2c_address, P2C_DEFAULT_VALUE)
42
+ end
43
+
44
+ fee = fee_estimator.fee(dummy_tx(txb.build))
45
+ if utxo_provider
46
+ script_pubkey = Tapyrus::Script.parse_from_addr(wallet.internal_wallet.receive_address)
47
+ funding_tx, index = utxo_provider.get_utxo(script_pubkey, fee)
48
+ txb.add_utxo({
49
+ script_pubkey: funding_tx.outputs[index].script_pubkey,
50
+ txid: funding_tx.txid,
51
+ index: index,
52
+ value: funding_tx.outputs[index].value
53
+ })
54
+ else
55
+ sum, outputs = wallet.internal_wallet.collect_uncolored_outputs(fee)
56
+ outputs.each do |utxo|
57
+ txb.add_utxo({
58
+ script_pubkey: Tapyrus::Script.parse_from_payload(utxo[:script_pubkey].htb),
59
+ txid: utxo[:txid],
60
+ index: utxo[:vout],
61
+ value: utxo[:amount]
62
+ })
63
+ end
64
+ end
65
+
66
+ prev_txs = if funding_tx
67
+ output = funding_tx.outputs.first
68
+ [{
69
+ txid: funding_tx.txid,
70
+ vout: 0,
71
+ scriptPubKey: output.script_pubkey.to_hex,
72
+ amount: output.value
73
+ }]
74
+ else
75
+ []
76
+ end
77
+
78
+ txb.fee(fee).change_address(wallet.internal_wallet.change_address)
79
+ [funding_tx, wallet.internal_wallet.sign_tx(txb.build, prev_txs), p2c_address, payment_base]
80
+ end
81
+
82
+ def get_transaction(tx)
83
+ Glueby::Internal::RPC.client.getrawtransaction(tx.txid, 1)
84
+ end
85
+ end
86
+ include Glueby::Contract::Timestamp::Util
87
+
88
+ attr_reader :tx, :txid
89
+
90
+ # p2c_address and payment_base is used in `trackable` type
91
+ attr_reader :p2c_address, :payment_base
92
+
93
+ # @param [String] content Data to be hashed and stored in blockchain.
94
+ # @param [String] prefix prefix of op_return data
95
+ # @param [Glueby::Contract::FeeEstimator] fee_estimator
96
+ # @param [Symbol] digest type which select of:
97
+ # - :sha256
98
+ # - :double_sha256
99
+ # - :none
100
+ # @param [Symbol] timestamp_type
101
+ # - :simple
102
+ # - :trackable
103
+ # @raise [Glueby::Contract::Errors::UnsupportedDigestType] if digest is unsupported
104
+ # @raise [Glueby::Contract::Errors::InvalidTimestampType] if timestamp_type is unsupported
105
+ def initialize(
106
+ wallet:,
107
+ content:,
108
+ prefix: '',
109
+ fee_estimator: Glueby::Contract::FixedFeeEstimator.new,
110
+ digest: :sha256,
111
+ utxo_provider: nil,
112
+ timestamp_type: :simple
113
+ )
114
+ @wallet = wallet
115
+ @content = content
116
+ @prefix = prefix
117
+ @fee_estimator = fee_estimator
118
+ raise Glueby::Contract::Errors::UnsupportedDigestType, "#{digest} is invalid digest, supported digest are :sha256, :double_sha256, and :none." unless [:sha256, :double_sha256, :none].include?(digest)
119
+ @digest = digest
120
+ @utxo_provider = utxo_provider
121
+ raise Glueby::Contract::Errors::InvalidTimestampType, "#{timestamp_type} is invalid type, supported types are :simple, and :trackable." unless [:simple, :trackable].include?(timestamp_type)
122
+ @timestamp_type = timestamp_type
123
+ end
124
+
125
+ # broadcast to Tapyrus Core
126
+ # @return [String] txid
127
+ # @raise [TxAlreadyBroadcasted] if tx has been broadcasted.
128
+ # @raise [InsufficientFunds] if result of listunspent is not enough to pay the specified amount
129
+ def save!
130
+ raise Glueby::Contract::Errors::TxAlreadyBroadcasted if @txid
131
+
132
+ funding_tx, @tx, @p2c_address, @payment_base = create_txs(@wallet, @prefix, digest_content, @fee_estimator, @utxo_provider, type: @timestamp_type)
133
+ @wallet.internal_wallet.broadcast(funding_tx) if funding_tx
134
+ @txid = @wallet.internal_wallet.broadcast(@tx)
135
+ end
136
+
137
+ private
138
+
139
+ def digest_content
140
+ case @digest&.downcase
141
+ when :sha256
142
+ Tapyrus.sha256(@content)
143
+ when :double_sha256
144
+ Tapyrus.double_sha256(@content)
145
+ when :none
146
+ @content
147
+ else
148
+ raise Glueby::Contract::Errors::UnsupportedDigestType
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end