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
data/glueby.gemspec CHANGED
@@ -1,33 +1,33 @@
1
- require_relative 'lib/glueby/version'
2
-
3
- Gem::Specification.new do |spec|
4
- spec.name = "glueby"
5
- spec.version = Glueby::VERSION
6
- spec.authors = ["azuchi"]
7
- spec.email = ["azuchi@chaintope.com"]
8
-
9
- spec.summary = %q{A Ruby library of smart contracts that can be used on Tapyrus.}
10
- spec.description = %q{A Ruby library of smart contracts that can be used on Tapyrus.}
11
- spec.homepage = "https://github.com/chaintope/glueby"
12
- spec.license = "MIT"
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
-
15
-
16
- spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = "https://github.com/chaintope/glueby"
18
- spec.metadata["changelog_uri"] = "https://github.com/chaintope/glueby"
19
-
20
- # Specify which files should be added to the gem when it is released.
21
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
- end
25
- spec.bindir = "exe"
26
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
- spec.require_paths = ["lib"]
28
-
29
- spec.add_runtime_dependency 'tapyrus', '>= 0.2.9'
30
- spec.add_runtime_dependency 'activerecord', '~> 6.1.3'
31
- spec.add_development_dependency 'sqlite3'
32
- spec.add_development_dependency 'rails', '~> 6.1.3'
33
- end
1
+ require_relative 'lib/glueby/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "glueby"
5
+ spec.version = Glueby::VERSION
6
+ spec.authors = ["azuchi"]
7
+ spec.email = ["azuchi@chaintope.com"]
8
+
9
+ spec.summary = %q{A Ruby library of smart contracts that can be used on Tapyrus.}
10
+ spec.description = %q{A Ruby library of smart contracts that can be used on Tapyrus.}
11
+ spec.homepage = "https://github.com/chaintope/glueby"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/chaintope/glueby"
18
+ spec.metadata["changelog_uri"] = "https://github.com/chaintope/glueby"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_runtime_dependency 'tapyrus', '>= 0.2.9'
30
+ spec.add_runtime_dependency 'activerecord', '~> 6.1.3'
31
+ spec.add_development_dependency 'sqlite3'
32
+ spec.add_development_dependency 'rails', '~> 6.1.3'
33
+ end
@@ -1,8 +1,8 @@
1
- # Edit configuration for connection to tapyrus core
2
- Glueby.configure do |config|
3
- config.wallet_adapter = :activerecord
4
- config.rpc_config = { schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass' }
5
- end
6
-
7
- # Uncomment next line when using timestamp feature
8
- # Glueby::BlockSyncer.register_syncer(Glueby::Contract::Timestamp::Syncer)
1
+ # Edit configuration for connection to tapyrus core
2
+ Glueby.configure do |config|
3
+ config.wallet_adapter = :activerecord
4
+ config.rpc_config = { schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass' }
5
+ end
6
+
7
+ # Uncomment next line when using timestamp feature
8
+ # Glueby::BlockSyncer.register_syncer(Glueby::Contract::Timestamp::Syncer)
@@ -1,16 +1,16 @@
1
- class CreateKey < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- create_table :glueby_keys<%= table_options %> do |t|
4
- t.string :private_key
5
- t.string :public_key
6
- t.string :script_pubkey
7
- t.string :label, index: true
8
- t.integer :purpose
9
- t.belongs_to :wallet
10
- t.timestamps
11
- end
12
-
13
- add_index :glueby_keys, [:script_pubkey], unique: true
14
- add_index :glueby_keys, [:private_key], unique: true
15
- end
16
- end
1
+ class CreateKey < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :glueby_keys<%= table_options %> do |t|
4
+ t.string :private_key
5
+ t.string :public_key
6
+ t.string :script_pubkey
7
+ t.string :label, index: true
8
+ t.integer :purpose
9
+ t.belongs_to :wallet
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :glueby_keys, [:script_pubkey], unique: true
14
+ add_index :glueby_keys, [:private_key], unique: true
15
+ end
16
+ end
@@ -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
@@ -1,16 +1,16 @@
1
- class CreateUtxo < ActiveRecord::Migration<%= migration_version %>
2
- def change
3
- create_table :glueby_utxos<%= table_options %> do |t|
4
- t.string :txid
5
- t.integer :index
6
- t.bigint :value
7
- t.string :script_pubkey
8
- t.string :label, index: true
9
- t.integer :status
10
- t.belongs_to :key, null: true
11
- t.timestamps
12
- end
13
-
14
- add_index :glueby_utxos, [:txid, :index], unique: true
15
- end
16
- end
1
+ class CreateUtxo < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ create_table :glueby_utxos<%= table_options %> do |t|
4
+ t.string :txid
5
+ t.integer :index
6
+ t.bigint :value
7
+ t.string :script_pubkey
8
+ t.string :label, index: true
9
+ t.integer :status
10
+ t.belongs_to :key, null: true
11
+ t.timestamps
12
+ end
13
+
14
+ add_index :glueby_utxos, [:txid, :index], unique: true
15
+ end
16
+ end
@@ -1,98 +1,98 @@
1
- module Glueby
2
- # You can use BlockSyncer when you need to synchronize the state of
3
- # an application with the state of a blockchain. When BlockSyncer
4
- # detects the generation of a new block, it executes the registered
5
- # syncer code on a block-by-block or transaction-by-transaction basis.
6
- # By using this, an application can detect that the issued transaction
7
- # has been captured in blocks, receive a new remittance, and so on.
8
- #
9
- # # Syncer logic registration
10
- #
11
- # For registration, create a class that implements the method that performs
12
- # synchronization processing and registers it in BlockSyncer. Implement
13
- # methods with the following name in that class.
14
- #
15
- # Method name | Arguments | Call conditions
16
- # ------------------ | --------------------- | ------------------------------
17
- # block_sync (block) | block: Tapyrus::Block | When a new block is created
18
- # block_tx (tx) | tx: Tapyrus::Tx | When a new block is created, it is executed for each tx contained in that block.
19
- #
20
- # @example Register a synchronous logic
21
- # class Syncer
22
- # def block_sync (block)
23
- # # sync a block
24
- # end
25
- #
26
- # def tx_sync (tx)
27
- # # sync a tx
28
- # end
29
- # end
30
- # BlockSyncer.register_syncer(Syncer)
31
- #
32
- # @example Unregister the synchronous logic
33
- # BlockSyncer.unregister_syncer(Syncer)
34
- #
35
- # # Run BlockSyncer
36
- #
37
- # Run the `glueby: block_syncer: start` rake task periodically with a program
38
- # for periodic execution such as cron. If it detects the generation of a new
39
- # block when it is executed, the synchronization process will be executed.
40
- # Determine the execution interval according to the requirements of the application.
41
- class BlockSyncer
42
- # @!attribute [r] height
43
- # @return [Integer] The block height to be synced
44
- attr_reader :height
45
-
46
- class << self
47
- # @!attribute r syncers
48
- # @return [Array<Class>] The syncer classes that is registered
49
- attr_reader :syncers
50
-
51
- # Register syncer class
52
- # @param [Class] syncer The syncer to be registered.
53
- def register_syncer(syncer)
54
- @syncers ||= []
55
- @syncers << syncer
56
- end
57
-
58
- # Unregister syncer class
59
- # @param [Class] syncer The syncer to be unregistered.
60
- def unregister_syncer(syncer)
61
- @syncers ||= []
62
- @syncers.delete(syncer)
63
- end
64
- end
65
-
66
- # @param [Integer] height The block height to be synced in the instance
67
- def initialize(height)
68
- @height = height
69
- end
70
-
71
- # Run a block synchronization
72
- def run
73
- return if self.class.syncers.nil?
74
-
75
- self.class.syncers.each do |syncer|
76
- instance = syncer.new
77
- instance.block_sync(block) if instance.respond_to?(:block_sync)
78
-
79
- if instance.respond_to?(:tx_sync)
80
- block.transactions.each { |tx| instance.tx_sync(tx) }
81
- end
82
- end
83
- end
84
-
85
- private
86
-
87
- def block
88
- @block ||= begin
89
- block = Glueby::Internal::RPC.client.getblock(block_hash, 0)
90
- Tapyrus::Block.parse_from_payload(block.htb)
91
- end
92
- end
93
-
94
- def block_hash
95
- @block_hash ||= Glueby::Internal::RPC.client.getblockhash(height)
96
- end
97
- end
1
+ module Glueby
2
+ # You can use BlockSyncer when you need to synchronize the state of
3
+ # an application with the state of a blockchain. When BlockSyncer
4
+ # detects the generation of a new block, it executes the registered
5
+ # syncer code on a block-by-block or transaction-by-transaction basis.
6
+ # By using this, an application can detect that the issued transaction
7
+ # has been captured in blocks, receive a new remittance, and so on.
8
+ #
9
+ # # Syncer logic registration
10
+ #
11
+ # For registration, create a class that implements the method that performs
12
+ # synchronization processing and registers it in BlockSyncer. Implement
13
+ # methods with the following name in that class.
14
+ #
15
+ # Method name | Arguments | Call conditions
16
+ # ------------------ | --------------------- | ------------------------------
17
+ # block_sync (block) | block: Tapyrus::Block | When a new block is created
18
+ # block_tx (tx) | tx: Tapyrus::Tx | When a new block is created, it is executed for each tx contained in that block.
19
+ #
20
+ # @example Register a synchronous logic
21
+ # class Syncer
22
+ # def block_sync (block)
23
+ # # sync a block
24
+ # end
25
+ #
26
+ # def tx_sync (tx)
27
+ # # sync a tx
28
+ # end
29
+ # end
30
+ # BlockSyncer.register_syncer(Syncer)
31
+ #
32
+ # @example Unregister the synchronous logic
33
+ # BlockSyncer.unregister_syncer(Syncer)
34
+ #
35
+ # # Run BlockSyncer
36
+ #
37
+ # Run the `glueby: block_syncer: start` rake task periodically with a program
38
+ # for periodic execution such as cron. If it detects the generation of a new
39
+ # block when it is executed, the synchronization process will be executed.
40
+ # Determine the execution interval according to the requirements of the application.
41
+ class BlockSyncer
42
+ # @!attribute [r] height
43
+ # @return [Integer] The block height to be synced
44
+ attr_reader :height
45
+
46
+ class << self
47
+ # @!attribute r syncers
48
+ # @return [Array<Class>] The syncer classes that is registered
49
+ attr_reader :syncers
50
+
51
+ # Register syncer class
52
+ # @param [Class] syncer The syncer to be registered.
53
+ def register_syncer(syncer)
54
+ @syncers ||= []
55
+ @syncers << syncer
56
+ end
57
+
58
+ # Unregister syncer class
59
+ # @param [Class] syncer The syncer to be unregistered.
60
+ def unregister_syncer(syncer)
61
+ @syncers ||= []
62
+ @syncers.delete(syncer)
63
+ end
64
+ end
65
+
66
+ # @param [Integer] height The block height to be synced in the instance
67
+ def initialize(height)
68
+ @height = height
69
+ end
70
+
71
+ # Run a block synchronization
72
+ def run
73
+ return if self.class.syncers.nil?
74
+
75
+ self.class.syncers.each do |syncer|
76
+ instance = syncer.new
77
+ instance.block_sync(block) if instance.respond_to?(:block_sync)
78
+
79
+ if instance.respond_to?(:tx_sync)
80
+ block.transactions.each { |tx| instance.tx_sync(tx) }
81
+ end
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def block
88
+ @block ||= begin
89
+ block = Glueby::Internal::RPC.client.getblock(block_hash, 0)
90
+ Tapyrus::Block.parse_from_payload(block.htb)
91
+ end
92
+ end
93
+
94
+ def block_hash
95
+ @block_hash ||= Glueby::Internal::RPC.client.getblockhash(height)
96
+ end
97
+ end
98
98
  end
@@ -10,11 +10,17 @@ module Glueby
10
10
  # end
11
11
  class Configuration
12
12
 
13
- attr_reader :fee_provider_bears
13
+ attr_reader :fee_provider_bears, :use_utxo_provider
14
14
  alias_method :fee_provider_bears?, :fee_provider_bears
15
+ alias_method :use_utxo_provider?, :use_utxo_provider
16
+
17
+ module Errors
18
+ class InvalidConfiguration < StandardError; end
19
+ end
15
20
 
16
21
  def initialize
17
22
  @fee_provider_bears = false
23
+ @use_utxo_provider = false
18
24
  end
19
25
 
20
26
  # Specify wallet adapter.
@@ -54,9 +60,33 @@ module Glueby
54
60
  # Specify FeeProvider configuration.
55
61
  # @param [Hash] config
56
62
  # @option config [Integer] :fixed_fee - The fee that Fee Provider pays on each transaction.
57
- # @option config [Integer] :utxo_pool_size - Fee Provider tries to keep the number of utxo in utxo pool as this size using `glueby:fee_provider:manage_utxo_pool` rake task
63
+ # @option config [Integer] :utxo_pool_size - Fee Provider tries to keep the number of utxo in utxo pool as this size using `glueby:fee_provider:manage_utxo_pool` rake task. this size should not be greater than 2000.
58
64
  def fee_provider_config=(config)
59
65
  FeeProvider.configure(config)
60
66
  end
67
+
68
+ # Enable UtxoProvider feature
69
+ def enable_utxo_provider!
70
+ @use_utxo_provider = true
71
+ end
72
+
73
+ # Disable UtxoProvider feature
74
+ def disable_utxo_provider!
75
+ @use_utxo_provider = false
76
+ end
77
+
78
+ # Set UtxoProvider configuration
79
+ # @param [Hash] config
80
+ # @option config [Integer] :default_value - The fee that Fee Provider pays on each transaction.
81
+ # @option config [Integer] :utxo_pool_size - Utxo Provider tries to keep the number of utxo in utxo pool as this size using `glueby:utxo_provider:manage_utxo_pool` rake task. this size should not be greater than 2000.
82
+ def utxo_provider_config=(config)
83
+ UtxoProvider.configure(config)
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
61
91
  end
62
92
  end
@@ -4,15 +4,17 @@ 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)
16
18
  end
17
19
  end
18
20
  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
 
@@ -1,13 +1,13 @@
1
- module Glueby
2
- module Contract
3
- class Timestamp
4
- class Syncer
5
- def block_sync(block)
6
- Glueby::Contract::AR::Timestamp
7
- .where(txid: block.transactions.map(&:txid), status: :unconfirmed)
8
- .update_all(status: :confirmed)
9
- end
10
- end
11
- end
12
- end
13
- end
1
+ module Glueby
2
+ module Contract
3
+ class Timestamp
4
+ class Syncer
5
+ def block_sync(block)
6
+ Glueby::Contract::AR::Timestamp
7
+ .where(txid: block.transactions.map(&:txid), status: :unconfirmed)
8
+ .update_all(status: :confirmed)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end