glueby 0.4.0 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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