glueby 0.4.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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,152 +1,154 @@
1
- module Glueby
2
- module Internal
3
- class Wallet
4
- # This is an abstract class for wallet adapters. If you want to use a wallet
5
- # component with Glueby modules, you can use it by adding subclass of this abstract
6
- # class for the wallet component.
7
- class AbstractWalletAdapter
8
- # Creates a new wallet inside the wallet component and returns `wallet_id`. The created
9
- # wallet is loaded from at first.
10
- # @params [String] wallet_id - Option. The wallet id that if for the wallet to be created. If this is nil, wallet adapter generates it.
11
- # @return [String] wallet_id
12
- # @raise [Glueby::Internal::Wallet::Errors::WalletAlreadyCreated] when the specified wallet has been already created.
13
- def create_wallet(wallet_id = nil)
14
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
15
- end
16
-
17
- # Delete the wallet inside the wallet component.
18
- # This method expect that the wallet will be removed completely
19
- # in the wallet and it cannot restore. It is assumed that the main use-case of
20
- # this method is for testing.
21
- #
22
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
23
- # @return [Boolean] The boolean value whether the deletion was success.
24
- def delete_wallet(wallet_id)
25
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
26
- end
27
-
28
- # Load the wallet inside the wallet component.
29
- # This method makes the wallet to possible to use on other methods like `balance`,
30
- # `list_unspent`, etc. All the methods that gets `wallet_id` as a argument needs to
31
- # load the wallet before use it.
32
- # If the wallet component doesn't need such as load operation to prepare to use the
33
- # wallet, `load_wallet` can be empty method.
34
- #
35
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
36
- # @raise [Glueby::Internal::Wallet::Errors::WalletAlreadyLoaded] when the specified wallet has been already loaded.
37
- # @raise [Glueby::Internal::Wallet::Errors::WalletNotFound] when the specified wallet is not found.
38
- def load_wallet(wallet_id)
39
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
40
- end
41
-
42
- # Unload the wallet inside the wallet component.
43
- #
44
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
45
- # @return [Boolean] The boolean value whether the unloading was success.
46
- def unload_wallet(wallet_id)
47
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
48
- end
49
-
50
- # Returns list of loaded wallet_id.
51
- #
52
- # @return [Array of String] - Array of wallet_id
53
- def wallets
54
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
55
- end
56
-
57
- # Returns amount of tapyrus that the wallet has.
58
- #
59
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
60
- # @param [Boolean] only_finalized - The balance includes only finalized UTXO value if it
61
- # is true. Default is true.
62
- # @return [Integer] The balance of the wallet. The unit is 'tapyrus'.
63
- # 1 TPC equals to 10^8 'tapyrus'.
64
- def balance(wallet_id, only_finalized = true)
65
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
66
- end
67
-
68
- # Returns the UTXOs that the wallet has.
69
- # If label is specified, return UTXOs filtered with label
70
- #
71
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
72
- # @param [Boolean] only_finalized - The UTXOs includes only finalized UTXO value if it
73
- # is true. Default is true.
74
- # @param [String] label - Label for filtering UTXOs
75
- # @return [Array of UTXO]
76
- #
77
- # ## The UTXO structure
78
- #
79
- # - txid: [String] Transaction id
80
- # - vout: [Integer] Output index
81
- # - amount: [Integer] Amount of the UTXO as tapyrus unit
82
- # - finalized: [Boolean] Whether the UTXO is finalized
83
- def list_unspent(wallet_id, only_finalized = true, label = nil)
84
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
85
- end
86
-
87
- # Sign to the transaction with a key in the wallet.
88
- #
89
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
90
- # @param [Tapyrus::Tx] tx - The transaction will be signed.
91
- # @param [Array] prevtxs - array of hash that represents unbroadcasted transaction outputs used by signing tx.
92
- # Each hash has `txid`, `vout`, `scriptPubKey`, `amount` fields.
93
- # @param [Integer] sighashtype - The sighash flag for each signature that would be produced here.
94
- # @return [Tapyrus::Tx]
95
- # @raise [Glueby::Internal::Wallet::Errors::InvalidSighashType] when the specified sighashtype is invalid
96
- def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
97
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
98
- end
99
-
100
- # Broadcast the transaction to the Tapyrus Network.
101
- #
102
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
103
- # @param [Tapyrus::Tx] tx - The transaction to be broadcasterd.
104
- # @yield Option. If a block given, the block is called before actual broadcasting.
105
- # @yieldparam [Tapyrus::Tx] tx - The tx that is going to be broadcasted as is.
106
- # @return [String] txid
107
- def broadcast(wallet_id, tx, &block)
108
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
109
- end
110
-
111
- # Returns an address to receive coin.
112
- #
113
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
114
- # @param [String] label The label associated with this address.
115
- # @return [String] P2PKH address
116
- def receive_address(wallet_id, label = nil)
117
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
118
- end
119
-
120
- # Returns an address to change coin.
121
- #
122
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
123
- # @return [String] P2PKH address
124
- def change_address(wallet_id)
125
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
126
- end
127
-
128
- # Returns a new public key.
129
- #
130
- # This method is expected to returns a new public key. The key would generate internally. This key is provided
131
- # for contracts that need public key such as multi sig transaction.
132
- #
133
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
134
- # @return [Tapyrus::Key]
135
- def create_pubkey(wallet_id)
136
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
137
- end
138
-
139
- # Returns an array of addresses
140
- #
141
- # This method is expected to return the list of addresses that wallet has.
142
- #
143
- # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
144
- # @param [String] label The label to filter the addresses.
145
- # @return [Array<String>] array of P2PKH address
146
- def get_addresses(wallet_id, label = nil)
147
- raise NotImplementedError, "You must implement #{self.class}##{__method__}"
148
- end
149
- end
150
- end
151
- end
1
+ module Glueby
2
+ module Internal
3
+ class Wallet
4
+ # This is an abstract class for wallet adapters. If you want to use a wallet
5
+ # component with Glueby modules, you can use it by adding subclass of this abstract
6
+ # class for the wallet component.
7
+ class AbstractWalletAdapter
8
+ # Creates a new wallet inside the wallet component and returns `wallet_id`. The created
9
+ # wallet is loaded from at first.
10
+ # @params [String] wallet_id - Option. The wallet id that if for the wallet to be created. If this is nil, wallet adapter generates it.
11
+ # @return [String] wallet_id
12
+ # @raise [Glueby::Internal::Wallet::Errors::WalletAlreadyCreated] when the specified wallet has been already created.
13
+ def create_wallet(wallet_id = nil)
14
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
15
+ end
16
+
17
+ # Delete the wallet inside the wallet component.
18
+ # This method expect that the wallet will be removed completely
19
+ # in the wallet and it cannot restore. It is assumed that the main use-case of
20
+ # this method is for testing.
21
+ #
22
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
23
+ # @return [Boolean] The boolean value whether the deletion was success.
24
+ def delete_wallet(wallet_id)
25
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
26
+ end
27
+
28
+ # Load the wallet inside the wallet component.
29
+ # This method makes the wallet to possible to use on other methods like `balance`,
30
+ # `list_unspent`, etc. All the methods that gets `wallet_id` as a argument needs to
31
+ # load the wallet before use it.
32
+ # If the wallet component doesn't need such as load operation to prepare to use the
33
+ # wallet, `load_wallet` can be empty method.
34
+ #
35
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
36
+ # @raise [Glueby::Internal::Wallet::Errors::WalletAlreadyLoaded] when the specified wallet has been already loaded.
37
+ # @raise [Glueby::Internal::Wallet::Errors::WalletNotFound] when the specified wallet is not found.
38
+ def load_wallet(wallet_id)
39
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
40
+ end
41
+
42
+ # Unload the wallet inside the wallet component.
43
+ #
44
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
45
+ # @return [Boolean] The boolean value whether the unloading was success.
46
+ def unload_wallet(wallet_id)
47
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
48
+ end
49
+
50
+ # Returns list of loaded wallet_id.
51
+ #
52
+ # @return [Array of String] - Array of wallet_id
53
+ def wallets
54
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
55
+ end
56
+
57
+ # Returns amount of tapyrus that the wallet has.
58
+ #
59
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
60
+ # @param [Boolean] only_finalized - The balance includes only finalized UTXO value if it
61
+ # is true. Default is true.
62
+ # @return [Integer] The balance of the wallet. The unit is 'tapyrus'.
63
+ # 1 TPC equals to 10^8 'tapyrus'.
64
+ def balance(wallet_id, only_finalized = true)
65
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
66
+ end
67
+
68
+ # Returns the UTXOs that the wallet has.
69
+ # If label is specified, return UTXOs filtered with label
70
+ #
71
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
72
+ # @param [Boolean] only_finalized - The UTXOs includes only finalized UTXO value if it
73
+ # is true. Default is true.
74
+ # @param [String] label - Label for filtering UTXOs
75
+ # - If label is nil or :unlabeled, only unlabeled UTXOs will be returned.
76
+ # - If label=:all, it will return all utxos
77
+ # @return [Array of UTXO]
78
+ #
79
+ # ## The UTXO structure
80
+ #
81
+ # - txid: [String] Transaction id
82
+ # - vout: [Integer] Output index
83
+ # - amount: [Integer] Amount of the UTXO as tapyrus unit
84
+ # - finalized: [Boolean] Whether the UTXO is finalized
85
+ def list_unspent(wallet_id, only_finalized = true, label = nil)
86
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
87
+ end
88
+
89
+ # Sign to the transaction with a key in the wallet.
90
+ #
91
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
92
+ # @param [Tapyrus::Tx] tx - The transaction will be signed.
93
+ # @param [Array] prevtxs - array of hash that represents unbroadcasted transaction outputs used by signing tx.
94
+ # Each hash has `txid`, `vout`, `scriptPubKey`, `amount` fields.
95
+ # @param [Integer] sighashtype - The sighash flag for each signature that would be produced here.
96
+ # @return [Tapyrus::Tx]
97
+ # @raise [Glueby::Internal::Wallet::Errors::InvalidSighashType] when the specified sighashtype is invalid
98
+ def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
99
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
100
+ end
101
+
102
+ # Broadcast the transaction to the Tapyrus Network.
103
+ #
104
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
105
+ # @param [Tapyrus::Tx] tx - The transaction to be broadcasterd.
106
+ # @yield Option. If a block given, the block is called before actual broadcasting.
107
+ # @yieldparam [Tapyrus::Tx] tx - The tx that is going to be broadcasted as is.
108
+ # @return [String] txid
109
+ def broadcast(wallet_id, tx, &block)
110
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
111
+ end
112
+
113
+ # Returns an address to receive coin.
114
+ #
115
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
116
+ # @param [String] label The label associated with this address.
117
+ # @return [String] P2PKH address
118
+ def receive_address(wallet_id, label = nil)
119
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
120
+ end
121
+
122
+ # Returns an address to change coin.
123
+ #
124
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
125
+ # @return [String] P2PKH address
126
+ def change_address(wallet_id)
127
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
128
+ end
129
+
130
+ # Returns a new public key.
131
+ #
132
+ # This method is expected to returns a new public key. The key would generate internally. This key is provided
133
+ # for contracts that need public key such as multi sig transaction.
134
+ #
135
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
136
+ # @return [Tapyrus::Key]
137
+ def create_pubkey(wallet_id)
138
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
139
+ end
140
+
141
+ # Returns an array of addresses
142
+ #
143
+ # This method is expected to return the list of addresses that wallet has.
144
+ #
145
+ # @param [String] wallet_id - The wallet id that is offered by `create_wallet()` method.
146
+ # @param [String] label The label to filter the addresses.
147
+ # @return [Array<String>] array of P2PKH address
148
+ def get_addresses(wallet_id, label = nil)
149
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
150
+ end
151
+ end
152
+ end
153
+ end
152
154
  end
@@ -1,51 +1,51 @@
1
- # frozen_string_literal: true
2
-
3
- module Glueby
4
- module Internal
5
- class Wallet
6
- module AR
7
- class Utxo < ::ActiveRecord::Base
8
- belongs_to :key
9
-
10
- validates :txid, uniqueness: { scope: :index, case_sensitive: false }
11
-
12
- enum status: { init: 0, broadcasted: 1, finalized: 2 }
13
-
14
- def color_id
15
- script = Tapyrus::Script.parse_from_payload(script_pubkey.htb)
16
- script.color_id&.to_hex
17
- end
18
-
19
- # Delete utxo spent by specified tx.
20
- #
21
- # @param [Tapyrus::Tx] the spending tx
22
- def self.destroy_for_inputs(tx)
23
- tx.inputs.each do |input|
24
- Utxo.destroy_by(txid: input.out_point.txid, index: input.out_point.index)
25
- end
26
- end
27
-
28
- # Create utxo or update utxo for tx outputs
29
- # if there is no key for script pubkey in an output, utxo for the output is not created.
30
- #
31
- # @param [Tapyrus::Tx] tx
32
- def self.create_or_update_for_outputs(tx, status: :finalized)
33
- tx.outputs.each.with_index do |output, index|
34
- key = Key.key_for_output(output)
35
- next unless key
36
-
37
- utxo = Utxo.find_or_initialize_by(txid: tx.txid, index: index)
38
- utxo.update!(
39
- label: key.label,
40
- script_pubkey: output.script_pubkey.to_hex,
41
- value: output.value,
42
- status: status,
43
- key: key
44
- )
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Glueby
4
+ module Internal
5
+ class Wallet
6
+ module AR
7
+ class Utxo < ::ActiveRecord::Base
8
+ belongs_to :key
9
+
10
+ validates :txid, uniqueness: { scope: :index, case_sensitive: false }
11
+
12
+ enum status: { init: 0, broadcasted: 1, finalized: 2 }
13
+
14
+ def color_id
15
+ script = Tapyrus::Script.parse_from_payload(script_pubkey.htb)
16
+ script.color_id&.to_hex
17
+ end
18
+
19
+ # Delete utxo spent by specified tx.
20
+ #
21
+ # @param [Tapyrus::Tx] the spending tx
22
+ def self.destroy_for_inputs(tx)
23
+ tx.inputs.each do |input|
24
+ Utxo.destroy_by(txid: input.out_point.txid, index: input.out_point.index)
25
+ end
26
+ end
27
+
28
+ # Create utxo or update utxo for tx outputs
29
+ # if there is no key for script pubkey in an output, utxo for the output is not created.
30
+ #
31
+ # @param [Tapyrus::Tx] tx
32
+ def self.create_or_update_for_outputs(tx, status: :finalized)
33
+ tx.outputs.each.with_index do |output, index|
34
+ key = Key.key_for_output(output)
35
+ next unless key
36
+
37
+ utxo = Utxo.find_or_initialize_by(txid: tx.txid, index: index)
38
+ utxo.update!(
39
+ label: key.label,
40
+ script_pubkey: output.script_pubkey.to_hex,
41
+ value: output.value,
42
+ status: status,
43
+ key: key
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,14 +1,14 @@
1
- module Glueby
2
- module Internal
3
- class Wallet
4
- class ActiveRecordWalletAdapter
5
- class Syncer
6
- def tx_sync(tx)
7
- Glueby::Internal::Wallet::AR::Utxo.destroy_for_inputs(tx)
8
- Glueby::Internal::Wallet::AR::Utxo.create_or_update_for_outputs(tx)
9
- end
10
- end
11
- end
12
- end
13
- end
1
+ module Glueby
2
+ module Internal
3
+ class Wallet
4
+ class ActiveRecordWalletAdapter
5
+ class Syncer
6
+ def tx_sync(tx)
7
+ Glueby::Internal::Wallet::AR::Utxo.destroy_for_inputs(tx)
8
+ Glueby::Internal::Wallet::AR::Utxo.create_or_update_for_outputs(tx)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
14
  end