glueby 0.4.0 → 0.4.4

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.
@@ -1,146 +1,162 @@
1
- module Glueby
2
- module Internal
3
- # # Glueby::Internal::Wallet
4
- #
5
- # This module provides the way to deal about wallet that includes key management, address management, getting UTXOs.
6
- #
7
- # ## How to use
8
- #
9
- # First, you need to configure which wallet implementation is used in Glueby::Internal::Wallet. For now, below wallets are
10
- # supported.
11
- #
12
- # * [Tapyrus Core](https://github.com/chaintope/tapyrus-core)
13
- #
14
- # Here shows an example to use Tapyrus Core wallet.
15
- #
16
- # ```ruby
17
- # # Setup Tapyrus Core RPC connection
18
- # config = {schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass'}
19
- # Glueby::Internal::RPC.configure(config)
20
- #
21
- # # Setup wallet adapter
22
- # Glueby::Internal::Wallet.wallet_adapter = Glueby::Internal::Wallet::TapyrusCoreWalletAdapter.new
23
- #
24
- # # Create wallet
25
- # wallet = Glueby::Internal::Wallet.create
26
- # wallet.balance # => 0
27
- # wallet.list_unspent
28
- # ```
29
- class Wallet
30
- autoload :AbstractWalletAdapter, 'glueby/internal/wallet/abstract_wallet_adapter'
31
- autoload :AR, 'glueby/internal/wallet/active_record'
32
- autoload :TapyrusCoreWalletAdapter, 'glueby/internal/wallet/tapyrus_core_wallet_adapter'
33
- autoload :ActiveRecordWalletAdapter, 'glueby/internal/wallet/active_record_wallet_adapter'
34
- autoload :Errors, 'glueby/internal/wallet/errors'
35
-
36
- class << self
37
- attr_writer :wallet_adapter
38
-
39
- def create(wallet_id = nil)
40
- begin
41
- wallet_id = wallet_adapter.create_wallet(wallet_id)
42
- rescue Errors::WalletAlreadyCreated => _
43
- # Ignore when wallet is already created.
44
- end
45
- new(wallet_id)
46
- end
47
-
48
- def load(wallet_id)
49
- begin
50
- wallet_adapter.load_wallet(wallet_id)
51
- rescue Errors::WalletAlreadyLoaded => _
52
- # Ignore when wallet is already loaded.
53
- end
54
- new(wallet_id)
55
- end
56
-
57
- def wallets
58
- wallet_adapter.wallets.map { |id| new(id) }
59
- end
60
-
61
- def wallet_adapter
62
- @wallet_adapter or
63
- raise Errors::ShouldInitializeWalletAdapter, 'You should initialize wallet adapter using `Glueby::Internal::Wallet.wallet_adapter = some wallet adapter instance`.'
64
- end
65
- end
66
-
67
- attr_reader :id
68
-
69
- def initialize(wallet_id)
70
- @id = wallet_id
71
- end
72
-
73
- def balance(only_finalized = true)
74
- wallet_adapter.balance(id, only_finalized)
75
- end
76
-
77
- def list_unspent(only_finalized = true)
78
- wallet_adapter.list_unspent(id, only_finalized)
79
- end
80
-
81
- def delete
82
- wallet_adapter.delete_wallet(id)
83
- end
84
-
85
- # @param [Tapyrus::Tx] tx The tx that is signed
86
- # @param [Array<Hash>] prev_txs An array of hash that represents unbroadcasted transaction outputs used by signing tx
87
- # @option prev_txs [String] :txid
88
- # @option prev_txs [Integer] :vout
89
- # @option prev_txs [String] :scriptPubkey
90
- # @option prev_txs [Integer] :amount
91
- # @param [Boolean] for_fee_provider_input The flag to notify whether the caller is FeeProvider and called for signing a input that is by FeeProvider.
92
- def sign_tx(tx, prev_txs = [], for_fee_provider_input: false)
93
- sighashtype = Tapyrus::SIGHASH_TYPE[:all]
94
-
95
- if !for_fee_provider_input && Glueby.configuration.fee_provider_bears?
96
- sighashtype |= Tapyrus::SIGHASH_TYPE[:anyonecanpay]
97
- end
98
-
99
- wallet_adapter.sign_tx(id, tx, prev_txs, sighashtype: sighashtype)
100
- end
101
-
102
- def broadcast(tx)
103
- tx = FeeProvider.provide(tx) if Glueby.configuration.fee_provider_bears?
104
- wallet_adapter.broadcast(id, tx)
105
- tx
106
- end
107
-
108
- def receive_address
109
- wallet_adapter.receive_address(id)
110
- end
111
-
112
- def change_address
113
- wallet_adapter.change_address(id)
114
- end
115
-
116
- def create_pubkey
117
- wallet_adapter.create_pubkey(id)
118
- end
119
-
120
- def collect_uncolored_outputs(amount)
121
- utxos = list_unspent
122
-
123
- utxos.inject([0, []]) do |sum, output|
124
- next sum if output[:color_id]
125
-
126
- new_sum = sum[0] + output[:amount]
127
- new_outputs = sum[1] << output
128
- return [new_sum, new_outputs] if new_sum >= amount
129
-
130
- [new_sum, new_outputs]
131
- end
132
- raise Glueby::Contract::Errors::InsufficientFunds
133
- end
134
-
135
- def get_addresses
136
- wallet_adapter.get_addresses(id)
137
- end
138
-
139
- private
140
-
141
- def wallet_adapter
142
- self.class.wallet_adapter
143
- end
144
- end
145
- end
146
- end
1
+ module Glueby
2
+ module Internal
3
+ # # Glueby::Internal::Wallet
4
+ #
5
+ # This module provides the way to deal about wallet that includes key management, address management, getting UTXOs.
6
+ #
7
+ # ## How to use
8
+ #
9
+ # First, you need to configure which wallet implementation is used in Glueby::Internal::Wallet. For now, below wallets are
10
+ # supported.
11
+ #
12
+ # * [Tapyrus Core](https://github.com/chaintope/tapyrus-core)
13
+ #
14
+ # Here shows an example to use Tapyrus Core wallet.
15
+ #
16
+ # ```ruby
17
+ # # Setup Tapyrus Core RPC connection
18
+ # config = {schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass'}
19
+ # Glueby::Internal::RPC.configure(config)
20
+ #
21
+ # # Setup wallet adapter
22
+ # Glueby::Internal::Wallet.wallet_adapter = Glueby::Internal::Wallet::TapyrusCoreWalletAdapter.new
23
+ #
24
+ # # Create wallet
25
+ # wallet = Glueby::Internal::Wallet.create
26
+ # wallet.balance # => 0
27
+ # wallet.list_unspent
28
+ # ```
29
+ class Wallet
30
+ autoload :AbstractWalletAdapter, 'glueby/internal/wallet/abstract_wallet_adapter'
31
+ autoload :AR, 'glueby/internal/wallet/active_record'
32
+ autoload :TapyrusCoreWalletAdapter, 'glueby/internal/wallet/tapyrus_core_wallet_adapter'
33
+ autoload :ActiveRecordWalletAdapter, 'glueby/internal/wallet/active_record_wallet_adapter'
34
+ autoload :Errors, 'glueby/internal/wallet/errors'
35
+
36
+ class << self
37
+ def create(wallet_id = nil)
38
+ begin
39
+ wallet_id = wallet_adapter.create_wallet(wallet_id)
40
+ rescue Errors::WalletAlreadyCreated => _
41
+ # Ignore when wallet is already created.
42
+ end
43
+ new(wallet_id)
44
+ end
45
+
46
+ def load(wallet_id)
47
+ begin
48
+ wallet_adapter.load_wallet(wallet_id)
49
+ rescue Errors::WalletAlreadyLoaded => _
50
+ # Ignore when wallet is already loaded.
51
+ end
52
+ new(wallet_id)
53
+ end
54
+
55
+ def wallets
56
+ wallet_adapter.wallets.map { |id| new(id) }
57
+ end
58
+
59
+ def wallet_adapter=(adapter)
60
+ if adapter.is_a?(ActiveRecordWalletAdapter)
61
+ BlockSyncer.register_syncer(ActiveRecordWalletAdapter::Syncer)
62
+ else
63
+ BlockSyncer.unregister_syncer(ActiveRecordWalletAdapter::Syncer)
64
+ end
65
+
66
+ @wallet_adapter = adapter
67
+ end
68
+
69
+ def wallet_adapter
70
+ @wallet_adapter or
71
+ raise Errors::ShouldInitializeWalletAdapter, 'You should initialize wallet adapter using `Glueby::Internal::Wallet.wallet_adapter = some wallet adapter instance`.'
72
+ end
73
+ end
74
+
75
+ attr_reader :id
76
+
77
+ def initialize(wallet_id)
78
+ @id = wallet_id
79
+ end
80
+
81
+ def balance(only_finalized = true)
82
+ wallet_adapter.balance(id, only_finalized)
83
+ end
84
+
85
+ # @param only_finalized [Boolean] The flag to get a UTXO with status only finalized
86
+ # @param label [String] This label is used to filtered the UTXOs with labeled if a key or Utxo is labeled.
87
+ # - If label is not specified (label=nil), all UTXOs will be returned.
88
+ # - If label=:unlabeled, only unlabeled UTXOs will be returned.
89
+ def list_unspent(only_finalized = true, label = nil)
90
+ wallet_adapter.list_unspent(id, only_finalized, label)
91
+ end
92
+
93
+ def delete
94
+ wallet_adapter.delete_wallet(id)
95
+ end
96
+
97
+ # @param [Tapyrus::Tx] tx The tx that is signed
98
+ # @param [Array<Hash>] prev_txs An array of hash that represents unbroadcasted transaction outputs used by signing tx
99
+ # @option prev_txs [String] :txid
100
+ # @option prev_txs [Integer] :vout
101
+ # @option prev_txs [String] :scriptPubkey
102
+ # @option prev_txs [Integer] :amount
103
+ # @param [Boolean] for_fee_provider_input The flag to notify whether the caller is FeeProvider and called for signing a input that is by FeeProvider.
104
+ def sign_tx(tx, prev_txs = [], for_fee_provider_input: false)
105
+ sighashtype = Tapyrus::SIGHASH_TYPE[:all]
106
+
107
+ if !for_fee_provider_input && Glueby.configuration.fee_provider_bears?
108
+ sighashtype |= Tapyrus::SIGHASH_TYPE[:anyonecanpay]
109
+ end
110
+
111
+ wallet_adapter.sign_tx(id, tx, prev_txs, sighashtype: sighashtype)
112
+ end
113
+
114
+ # Broadcast a transaction via Tapyrus Core RPC
115
+ # @param [Tapyrus::Tx] tx The tx that would be broadcasted
116
+ # @option [Boolean] without_fee_provider The flag to avoid to use FeeProvider temporary.
117
+ # @param [Proc] block The block that is called before broadcasting. It can be used to handle tx that is modified by FeeProvider.
118
+ def broadcast(tx, without_fee_provider: false, &block)
119
+ tx = FeeProvider.provide(tx) if !without_fee_provider && Glueby.configuration.fee_provider_bears?
120
+ wallet_adapter.broadcast(id, tx, &block)
121
+ tx
122
+ end
123
+
124
+ def receive_address(label = nil)
125
+ wallet_adapter.receive_address(id, label)
126
+ end
127
+
128
+ def change_address
129
+ wallet_adapter.change_address(id)
130
+ end
131
+
132
+ def create_pubkey
133
+ wallet_adapter.create_pubkey(id)
134
+ end
135
+
136
+ def collect_uncolored_outputs(amount, label = nil, only_finalized = true)
137
+ utxos = list_unspent(only_finalized, label)
138
+
139
+ utxos.inject([0, []]) do |sum, output|
140
+ next sum if output[:color_id]
141
+
142
+ new_sum = sum[0] + output[:amount]
143
+ new_outputs = sum[1] << output
144
+ return [new_sum, new_outputs] if new_sum >= amount
145
+
146
+ [new_sum, new_outputs]
147
+ end
148
+ raise Glueby::Contract::Errors::InsufficientFunds
149
+ end
150
+
151
+ def get_addresses(label = nil)
152
+ wallet_adapter.get_addresses(id, label)
153
+ end
154
+
155
+ private
156
+
157
+ def wallet_adapter
158
+ self.class.wallet_adapter
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,10 @@
1
+ module Glueby
2
+ class Railtie < ::Rails::Railtie
3
+ rake_tasks do
4
+ load "tasks/glueby/contract.rake"
5
+ load "tasks/glueby/contract/timestamp.rake"
6
+ load "tasks/glueby/block_syncer.rake"
7
+ load "tasks/glueby/fee_provider.rake"
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
- module Glueby
2
- VERSION = "0.4.0"
3
- end
1
+ module Glueby
2
+ VERSION = "0.4.4"
3
+ end
data/lib/glueby.rb CHANGED
@@ -1,49 +1,39 @@
1
- require "glueby/version"
2
- require 'tapyrus'
3
-
4
- module Glueby
5
- autoload :Contract, 'glueby/contract'
6
- autoload :Generator, 'glueby/generator'
7
- autoload :Wallet, 'glueby/wallet'
8
- autoload :Internal, 'glueby/internal'
9
- autoload :AR, 'glueby/active_record'
10
- autoload :FeeProvider, 'glueby/fee_provider'
11
- autoload :Configuration, 'glueby/configuration'
12
-
13
- # Add prefix to activerecord table names
14
- def self.table_name_prefix
15
- 'glueby_'
16
- end
17
-
18
- begin
19
- class Railtie < ::Rails::Railtie
20
- rake_tasks do
21
- load "tasks/glueby/contract.rake"
22
- load "tasks/glueby/contract/timestamp.rake"
23
- load "tasks/glueby/contract/wallet_adapter.rake"
24
- load "tasks/glueby/contract/block_syncer.rake"
25
- load "tasks/glueby/fee_provider.rake"
26
- end
27
- end
28
- rescue
29
- # Rake task is unavailable
30
- puts "Rake task is unavailable"
31
- end
32
-
33
- # Returns the global [Configuration](RSpec/Core/Configuration) object.
34
- def self.configuration
35
- @configuration ||= Glueby::Configuration.new
36
- end
37
-
38
- # Yields the global configuration to a block.
39
- # @yield [Configuration] global configuration
40
- #
41
- # @example
42
- # Glueby.configure do |config|
43
- # config.wallet_adapter = :activerecord
44
- # config.rpc_config = { schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass' }
45
- # end
46
- def self.configure
47
- yield configuration if block_given?
48
- end
49
- end
1
+ require "glueby/version"
2
+ require 'tapyrus'
3
+
4
+ module Glueby
5
+ autoload :Contract, 'glueby/contract'
6
+ autoload :Generator, 'glueby/generator'
7
+ autoload :Wallet, 'glueby/wallet'
8
+ autoload :Internal, 'glueby/internal'
9
+ autoload :AR, 'glueby/active_record'
10
+ autoload :FeeProvider, 'glueby/fee_provider'
11
+ autoload :Configuration, 'glueby/configuration'
12
+ autoload :BlockSyncer, 'glueby/block_syncer'
13
+
14
+ if defined? ::Rails::Railtie
15
+ require 'glueby/railtie'
16
+ end
17
+
18
+ # Add prefix to activerecord table names
19
+ def self.table_name_prefix
20
+ 'glueby_'
21
+ end
22
+
23
+ # Returns the global [Configuration](RSpec/Core/Configuration) object.
24
+ def self.configuration
25
+ @configuration ||= Glueby::Configuration.new
26
+ end
27
+
28
+ # Yields the global configuration to a block.
29
+ # @yield [Configuration] global configuration
30
+ #
31
+ # @example
32
+ # Glueby.configure do |config|
33
+ # config.wallet_adapter = :activerecord
34
+ # config.rpc_config = { schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass' }
35
+ # end
36
+ def self.configure
37
+ yield configuration if block_given?
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ namespace :glueby do
2
+ namespace :contract do
3
+ namespace :block_syncer do
4
+ desc '[Deprecated use glueby:block_syncer:start instead] sync block into database'
5
+ task :start, [] => [:environment] do |_, _|
6
+ puts '[Deprecated] glueby:contract:block_syncer:start is deprecated. Use \'glueby:block_syncer:start\''
7
+ Rake::Task['glueby:block_syncer:start'].execute
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+
14
+ namespace :glueby do
15
+ namespace :block_syncer do
16
+ desc 'sync block into database'
17
+ task :start, [] => [:environment] do |_, _|
18
+ latest_block_num = Glueby::Internal::RPC.client.getblockcount
19
+ synced_block = Glueby::AR::SystemInformation.synced_block_height
20
+ (synced_block.int_value + 1..latest_block_num).each do |height|
21
+ ::ActiveRecord::Base.transaction do
22
+ Glueby::BlockSyncer.new(height).run
23
+ synced_block.update(info_value: height.to_s)
24
+ end
25
+ puts "success in synchronization (block height=#{height})"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,62 +1,40 @@
1
- module Glueby
2
- module Contract
3
- module Task
4
- module Timestamp
5
- module_function
6
- extend Glueby::Contract::TxBuilder
7
- extend Glueby::Contract::Timestamp::Util
8
-
9
- def create
10
- timestamps = Glueby::Contract::AR::Timestamp.where(status: :init)
11
- timestamps.each do |t|
12
- begin
13
- ::ActiveRecord::Base.transaction do
14
- wallet = Glueby::Wallet.load(t.wallet_id)
15
- tx = create_tx(wallet, t.prefix, t.content_hash, Glueby::Contract::FixedFeeEstimator.new)
16
- t.update(txid: tx.txid, status: :unconfirmed)
17
-
18
- wallet.internal_wallet.broadcast(tx)
19
- puts "broadcasted (id=#{t.id}, txid=#{tx.txid})"
20
- end
21
- rescue => e
22
- puts "failed to broadcast (id=#{t.id}, reason=#{e.message})"
23
- end
24
- end
25
- end
26
-
27
- def confirm
28
- timestamps = Glueby::Contract::AR::Timestamp.where(status: :unconfirmed)
29
- timestamps.each do |t|
30
- begin
31
- ::ActiveRecord::Base.transaction do
32
- tx = get_transaction(t)
33
- if tx['confirmations'] && tx['confirmations'] > 0
34
- t.update(status: :confirmed)
35
- puts "confirmed (id=#{t.id}, txid=#{tx['txid']})"
36
- end
37
- end
38
- rescue => e
39
- puts "failed to confirm (id=#{t.id}, reason=#{e.message})"
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
46
- end
47
-
48
- namespace :glueby do
49
- namespace :contract do
50
- namespace :timestamp do
51
- desc 'create and broadcast glueby timestamp tx'
52
- task :create, [] => [:environment] do |_, _|
53
- Glueby::Contract::Task::Timestamp.create
54
- end
55
-
56
- desc 'confirm glueby timestamp tx'
57
- task :confirm, [] => [:environment] do |_, _|
58
- Glueby::Contract::Task::Timestamp.confirm
59
- end
60
- end
61
- end
1
+ module Glueby
2
+ module Contract
3
+ module Task
4
+ module Timestamp
5
+ module_function
6
+ extend Glueby::Contract::TxBuilder
7
+ extend Glueby::Contract::Timestamp::Util
8
+
9
+ def create
10
+ timestamps = Glueby::Contract::AR::Timestamp.where(status: :init)
11
+ timestamps.each do |t|
12
+ begin
13
+ ::ActiveRecord::Base.transaction do
14
+ wallet = Glueby::Wallet.load(t.wallet_id)
15
+ tx = create_tx(wallet, t.prefix, t.content_hash, Glueby::Contract::FixedFeeEstimator.new)
16
+ wallet.internal_wallet.broadcast(tx) do |tx|
17
+ t.update(txid: tx.txid, status: :unconfirmed)
18
+ end
19
+ puts "broadcasted (id=#{t.id}, txid=#{tx.txid})"
20
+ end
21
+ rescue => e
22
+ puts "failed to broadcast (id=#{t.id}, reason=#{e.message})"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ namespace :glueby do
32
+ namespace :contract do
33
+ namespace :timestamp do
34
+ desc 'create and broadcast glueby timestamp tx'
35
+ task :create, [] => [:environment] do |_, _|
36
+ Glueby::Contract::Task::Timestamp.create
37
+ end
38
+ end
39
+ end
62
40
  end