universa 0.1.9 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -0
- data/lib/universa.rb +3 -0
- data/lib/universa/binder.rb +8 -2
- data/lib/universa/chain_store.rb +54 -0
- data/lib/universa/client.rb +4 -3
- data/lib/universa/contract.rb +56 -12
- data/lib/universa/errors.rb +10 -0
- data/lib/universa/fs_store/entry.rb +118 -0
- data/lib/universa/fs_store/file_store.rb +63 -0
- data/lib/universa/stored_contract.rb +76 -0
- data/lib/universa/tools.rb +11 -9
- data/lib/universa/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff86a735f983f4cb94e6ca82be229c8c47749d975483fe52d11972a8664853d8
|
4
|
+
data.tar.gz: f1625ae689ba6bd1ff017c2a3926e16e3b6efcc71f90f7896b60ccce19839413
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd4b45a562f5340511e659fb1019642599b74d431cdb5c8277a168e014ac1c085518798232d6c156de43377a3bdb3eec819ff935518bd107aef65726515f60db
|
7
|
+
data.tar.gz: 00a4544555433540ca9317ee4ce3bb7a090c649b5489809b364e79a36d784d4905f2af5b42534ade5b79b809ba19fe1d98a63ea784aff4cb19bf0aeb3af514ca
|
data/README.md
CHANGED
@@ -6,6 +6,18 @@ for direct access to remote objects.
|
|
6
6
|
This is an under-construction official gem from [Universa][universa] to facilitate access to the
|
7
7
|
Java library using Universa's UMI protocol.
|
8
8
|
|
9
|
+
## News
|
10
|
+
|
11
|
+
- alfa version of the local FS-based contract store.
|
12
|
+
- ability to edit `contract.state` and `contract.transactional` in new revisions.
|
13
|
+
- fixed errors with interchange builder and set based objects
|
14
|
+
- ruby sugar for Universa native classes: Role, Adapter, Contract, Binder, HashId.
|
15
|
+
- Contract creation, revocation, changing owner in ruby way
|
16
|
+
- Network operation for white keys/private networks: parallel state check, contract recistration.
|
17
|
+
|
18
|
+
This gem is already used in new Universa projects and is being actively tested.
|
19
|
+
|
20
|
+
|
9
21
|
## Installation
|
10
22
|
|
11
23
|
### Prerequisites
|
data/lib/universa.rb
CHANGED
data/lib/universa/binder.rb
CHANGED
@@ -68,8 +68,8 @@ module Universa
|
|
68
68
|
end
|
69
69
|
|
70
70
|
# @return an array of values returned by the block
|
71
|
-
# @
|
72
|
-
def map
|
71
|
+
# @yield [key,value] pairs.
|
72
|
+
def map(&block)
|
73
73
|
keys.map {|k| block.call [k, __getobj__.get(k)]}
|
74
74
|
end
|
75
75
|
|
@@ -86,7 +86,13 @@ module Universa
|
|
86
86
|
|
87
87
|
end
|
88
88
|
|
89
|
+
# enhance Hash with UMI access convenience methods.
|
89
90
|
class Hash
|
91
|
+
# Convert the hash to the {}Binder} stored in the remote side and suitable for
|
92
|
+
# Universa UMI calls.
|
93
|
+
#
|
94
|
+
# @return [Binder] constructed reference to the remotely created Binder.
|
95
|
+
#
|
90
96
|
def to_binder
|
91
97
|
Binder.of self
|
92
98
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Universa
|
4
|
+
|
5
|
+
# The storage interface capable to store contracts in chains, providing search and attributes.
|
6
|
+
# This class is not a store itself but the base class for it, having common boilerplate and
|
7
|
+
# sort of interface to implement.
|
8
|
+
class ChainStore
|
9
|
+
|
10
|
+
# Save contract to the store. When this method returns, the contract must me already stored.
|
11
|
+
# If the contract with such hasId is already stored, just returns it.
|
12
|
+
#
|
13
|
+
# @param [Object] contract to store
|
14
|
+
# @return [StoredContract] for this contract
|
15
|
+
def store_contract(contract)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
# Same as {#store_contract} but returns store
|
20
|
+
# @param [Contract] contract to add
|
21
|
+
# @return [ChainStore] self
|
22
|
+
def <<(contract)
|
23
|
+
store_contract(contract)
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Contract] with the corresponding id or nil
|
28
|
+
# @param [HashId] hash_id instance to look for
|
29
|
+
def find_by_id(hash_id)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
# Count contracts in the store. This operation could be slow.
|
34
|
+
def count
|
35
|
+
raise NotImplementedError
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [Contract] with the corresponding id or raise.
|
39
|
+
# @param [HashId] hash_id instance to look for
|
40
|
+
# @raise [NotFoundError]
|
41
|
+
def find_by_id! hash_id
|
42
|
+
find_by_id(hash_id) or raise NotFoundError
|
43
|
+
end
|
44
|
+
|
45
|
+
# Find all contracts with this parent id.
|
46
|
+
# @param [HashId] hash_id of the parent contract
|
47
|
+
# @return [Array] all the contracts that match this criterion
|
48
|
+
def find_by_parent(hash_id)
|
49
|
+
raise NotImplementedError
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/universa/client.rb
CHANGED
@@ -172,9 +172,9 @@ module Universa
|
|
172
172
|
# Register a single contract (on private network or if you have white key allowing free operations)
|
173
173
|
# on a single node.
|
174
174
|
#
|
175
|
-
# @param [Contract] contract
|
175
|
+
# @param [Contract] contract must be sealed ({Contract#seal})
|
176
176
|
# @return [ContractState] of the result. Could contain errors.
|
177
|
-
def register_single
|
177
|
+
def register_single(contract)
|
178
178
|
retry_with_timeout(15, 3) {
|
179
179
|
result = ContractState.new(execute "approve", packedItem: contract.packed)
|
180
180
|
while result.is_pending
|
@@ -205,8 +205,9 @@ module Universa
|
|
205
205
|
# to the node.
|
206
206
|
#
|
207
207
|
# @param [String|Symbol] name of the command
|
208
|
+
# @param kwargs arguments to call
|
208
209
|
# @return [SmartHash] with the command result
|
209
|
-
def execute
|
210
|
+
def execute(name, **kwargs)
|
210
211
|
connection.command name.to_s, *kwargs.to_a.flatten
|
211
212
|
end
|
212
213
|
|
data/lib/universa/contract.rb
CHANGED
@@ -34,11 +34,12 @@ module Universa
|
|
34
34
|
invoke_static 'with_digest', digest_bytes
|
35
35
|
end
|
36
36
|
|
37
|
-
# Construct from string representation of the ID, not to confuse with binary one.
|
37
|
+
# Construct from string representation of the ID, not to confuse with binary one. This method takes both
|
38
|
+
# regular base64 representation and RFC3548 url-safe modification, as from {#to_url_safe_string}.
|
38
39
|
#
|
39
40
|
# @param [String] string_id id string representation, like from +hash_id_instance.to_s+. See {#to_s}.
|
40
41
|
def self.from_string(string_id)
|
41
|
-
string_id.force_encoding
|
42
|
+
string_id.force_encoding('utf-8').gsub('-','+').gsub('_','/')
|
42
43
|
invoke_static 'with_digest', string_id
|
43
44
|
end
|
44
45
|
|
@@ -57,6 +58,28 @@ module Universa
|
|
57
58
|
def to_s
|
58
59
|
Base64.encode64(get_digest).gsub(/\s/, '')
|
59
60
|
end
|
61
|
+
|
62
|
+
# Converts to URL-safe varianot of base64, as RFC 3548 suggests:
|
63
|
+
# the 63:nd / character with the underscore _
|
64
|
+
# the 62:nd + character with the minus -
|
65
|
+
#
|
66
|
+
# Could be decoded safely back with {HashId.from_string} but not (most likely) with JAVA API itself
|
67
|
+
# @return [String] RFC3548 modified base64
|
68
|
+
def to_url_safe_string
|
69
|
+
Base64.encode64(get_digest).gsub(/\s/, '').gsub('/','_').gsub('+', '-')
|
70
|
+
end
|
71
|
+
|
72
|
+
# To use it as a hash key_address.
|
73
|
+
# @return hash calculated over the digest bytes
|
74
|
+
def hash
|
75
|
+
bytes.hash
|
76
|
+
end
|
77
|
+
|
78
|
+
# To use it as a hash key_address. Same as this == other.
|
79
|
+
def eql? other
|
80
|
+
self == other
|
81
|
+
end
|
82
|
+
|
60
83
|
end
|
61
84
|
|
62
85
|
# Universa contract adapter.
|
@@ -66,17 +89,17 @@ module Universa
|
|
66
89
|
# Create simple contract with preset critical parts:
|
67
90
|
#
|
68
91
|
# - expiration set to 90 days unless specified else
|
69
|
-
# - issuer role is set to the address of the issuer
|
92
|
+
# - issuer role is set to the address of the issuer key_address, short ot long
|
70
93
|
# - creator role is set as link to issuer
|
71
94
|
# - owner role is set as link to issuer
|
72
95
|
# - change owner permission is set to link to owner
|
73
96
|
#
|
74
|
-
# The while contract is then signed by the issuer
|
97
|
+
# The while contract is then signed by the issuer key_address. Not that it will not seal it: caller almost always
|
75
98
|
# will add more data before it, then must call #seal().
|
76
99
|
#
|
77
100
|
# @param [PrivateKey] issuer_key also will be used to sign it
|
78
101
|
# @param [Time] expires_at defaults to 90 days
|
79
|
-
# @param [Boolean] use_short_address set to true to use short address of the issuer
|
102
|
+
# @param [Boolean] use_short_address set to true to use short address of the issuer key_address in the role
|
80
103
|
# @return [Contract] simple contact, not sealed
|
81
104
|
def self.create issuer_key, expires_at: (Time.now + 90 * 24 * 60 * 60), use_short_address: false
|
82
105
|
contract = Contract.new
|
@@ -92,6 +115,7 @@ module Universa
|
|
92
115
|
|
93
116
|
# Load from transaction pack
|
94
117
|
def self.from_packed packed
|
118
|
+
packed.nil? and raise ArgumentError, "packed contract required"
|
95
119
|
packed.force_encoding 'binary'
|
96
120
|
self.invoke_static "fromPackedTransaction", packed
|
97
121
|
end
|
@@ -124,8 +148,10 @@ module Universa
|
|
124
148
|
get_owner
|
125
149
|
end
|
126
150
|
|
127
|
-
|
128
|
-
|
151
|
+
# Set owner to the key_address, usable only in the simplest case where owner is the single address.
|
152
|
+
# @param [KeyAddress | PublicKey] key_address
|
153
|
+
def owner=(key_address)
|
154
|
+
set_owner_key key_address
|
129
155
|
end
|
130
156
|
|
131
157
|
# Shortcut for is_ok
|
@@ -134,16 +160,29 @@ module Universa
|
|
134
160
|
end
|
135
161
|
|
136
162
|
# shortcut for getHashId
|
163
|
+
# @return [HashId] of the contracr
|
137
164
|
def hash_id
|
138
|
-
|
165
|
+
getId()
|
166
|
+
end
|
167
|
+
|
168
|
+
# @return [HashId] of the origin contract
|
169
|
+
def origin
|
170
|
+
getOrigin()
|
139
171
|
end
|
140
172
|
|
141
|
-
#
|
173
|
+
# @return [HashId] pf the parent contracr
|
174
|
+
def parent
|
175
|
+
getParent()
|
176
|
+
end
|
177
|
+
|
178
|
+
# shortcut for get_expires_at. Get the contract expiration time.
|
142
179
|
def expires_at
|
143
180
|
get_expires_at
|
144
181
|
end
|
145
182
|
|
146
|
-
|
183
|
+
# set +expires_at+ field
|
184
|
+
# @param [Time] time when this contract will be expired, if yet +APPROVED+.
|
185
|
+
def expires_at=(time)
|
147
186
|
set_expires_at time
|
148
187
|
end
|
149
188
|
|
@@ -152,6 +191,7 @@ module Universa
|
|
152
191
|
@definition ||= get_definition.get_data
|
153
192
|
end
|
154
193
|
|
194
|
+
# Return +state+ binder. Shortcut for Java API +getStateData()+
|
155
195
|
def state
|
156
196
|
@state ||= getStateData()
|
157
197
|
end
|
@@ -175,7 +215,7 @@ module Universa
|
|
175
215
|
# Write helper for many token-like contracts containing state.data.amount. Saves value
|
176
216
|
# in state.data.anomount and properly encodes it so it will be preserved on packing.
|
177
217
|
#
|
178
|
-
# @param [Object] value
|
218
|
+
# @param [Object] value should be some representation of a number (also string)
|
179
219
|
def amount= (value)
|
180
220
|
state[:amount] = value.to_s.force_encoding('utf-8')
|
181
221
|
end
|
@@ -203,7 +243,11 @@ module Universa
|
|
203
243
|
getErrors.map {|e| "(#{e.object || ''}): #{e.error}"}.join(', ').strip
|
204
244
|
end
|
205
245
|
|
206
|
-
|
246
|
+
# Test that some set of keys could be used to perform some role.
|
247
|
+
#
|
248
|
+
# @param [String] name of the role to check
|
249
|
+
# @param [PublicKey] keys instances to check against
|
250
|
+
def can_perform_role(name, *keys)
|
207
251
|
getRole(name.to_s).isAllowedForKeys(Set.new keys.map {|x|
|
208
252
|
x.is_a?(PrivateKey) ? x.public_key : x
|
209
253
|
})
|
data/lib/universa/errors.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
module Universa::FSStore
|
2
|
+
|
3
|
+
# The {StoredContract} implementation to work with {FileStore}.
|
4
|
+
#
|
5
|
+
# @!method name
|
6
|
+
# @return [String] the +contract.definition.data.name+ value or nil.
|
7
|
+
#
|
8
|
+
# @!method currency
|
9
|
+
# @return [String] the +contract.definition.data.currency+ value or nil.
|
10
|
+
#
|
11
|
+
# @!method amount
|
12
|
+
# @return [BigDecimal] +contract.state.data.amount+ or nil. See {Contract#amount} for more.
|
13
|
+
#
|
14
|
+
class Entry < Universa::StoredContract
|
15
|
+
|
16
|
+
extend Forwardable
|
17
|
+
|
18
|
+
# (see StoredContract#load)
|
19
|
+
def load(hash_id)
|
20
|
+
init_with_hash_id hash_id
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# initialize new instance with an existing contract
|
25
|
+
# @param [Contract] contract to store
|
26
|
+
def init_with_contract(contract)
|
27
|
+
self.contract = contract
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
# initialize new instance with attributes YAML file
|
32
|
+
# @param [String] file_name of the +.unicon.yaml+ file
|
33
|
+
def load_from_yaml_file(file_name)
|
34
|
+
init_with_yaml_file_name file_name
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# (see StoredContract#hash_id)
|
39
|
+
def hash_id
|
40
|
+
@id
|
41
|
+
end
|
42
|
+
|
43
|
+
# (see StoredContract#contract=)
|
44
|
+
def contract= new_contract
|
45
|
+
@id = new_contract.hash_id
|
46
|
+
prepare_file_names
|
47
|
+
super
|
48
|
+
# we will always rewrite existing file to be sure it is correct
|
49
|
+
open(@file_name, 'wb') {|f| f << contract.packed}
|
50
|
+
# now we are to extract and rewrite attributes
|
51
|
+
load_attributes_from_contract # it will save them too
|
52
|
+
end
|
53
|
+
|
54
|
+
# Implement lazy load logic
|
55
|
+
# @return [Contract] instance loaded at first call only
|
56
|
+
def contract
|
57
|
+
# load it if it is not
|
58
|
+
self.packed_contract = open(@file_name, 'rb') {|f| f.read} unless has_contract?
|
59
|
+
# @attributes must already be set
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
def_delegators :@attributes, :name, :currency, :amount
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
# initialize instance for an existing file. Should be a contract already stored in the connected store.
|
68
|
+
# @param [Object] hash_id to construct from
|
69
|
+
def init_with_hash_id(hash_id)
|
70
|
+
raise IllegalStateError, "already initialized" if @id
|
71
|
+
@id = hash_id
|
72
|
+
prepare_file_names
|
73
|
+
load_attributes_from_file
|
74
|
+
# attrs are already in the file so we need not to save them
|
75
|
+
end
|
76
|
+
|
77
|
+
# Load from attributes file name
|
78
|
+
def init_with_yaml_file_name file_name
|
79
|
+
@attr_file_name = file_name
|
80
|
+
load_attributes_from_file
|
81
|
+
prepare_file_names
|
82
|
+
end
|
83
|
+
|
84
|
+
# save attributes to .yaml file
|
85
|
+
def save_attributes
|
86
|
+
open(@attr_file_name, 'w') {|f| YAML.dump(@attributes, f)}
|
87
|
+
end
|
88
|
+
|
89
|
+
# load attributes from a contract (already assigned) and store them in the .yaml file
|
90
|
+
def load_attributes_from_contract
|
91
|
+
state = contract.state
|
92
|
+
definition = contract.definition
|
93
|
+
@attributes = SmartHash.new({
|
94
|
+
id: hash_id.to_s,
|
95
|
+
parent: parent&.to_s,
|
96
|
+
origin: origin.to_s,
|
97
|
+
name: definition.name,
|
98
|
+
currency: definition.currency,
|
99
|
+
amount: state.amount
|
100
|
+
})
|
101
|
+
save_attributes
|
102
|
+
end
|
103
|
+
|
104
|
+
# load attributes from the .yaml file
|
105
|
+
def load_attributes_from_file
|
106
|
+
@attributes = SmartHash.new(YAML.load_file(@attr_file_name))
|
107
|
+
@id = HashId.from_string @attributes.id
|
108
|
+
end
|
109
|
+
|
110
|
+
# prepare file name fields (@file_name and @attr_file_name)
|
111
|
+
# @param [HashId] hash_id or ni to use one already set in @id
|
112
|
+
def prepare_file_names(hash_id = nil)
|
113
|
+
@file_name = "#{chain_store.root}/#{@id.to_url_safe_string[0..27]}.unicon"
|
114
|
+
@attr_file_name = "#@file_name.yaml"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require_relative './entry'
|
3
|
+
|
4
|
+
# Filesystem-based storage. See {FileStore}.
|
5
|
+
module Universa::FSStore
|
6
|
+
|
7
|
+
# Simple file-based store that could be efficiently user with per-file cloud storages like Dropbox,
|
8
|
+
# Google Disk, NextCloud and like.
|
9
|
+
#
|
10
|
+
# Notes to developers:
|
11
|
+
#
|
12
|
+
# - attributes are eager loaded: should always be contructed from contract or from file
|
13
|
+
# - contract is lazy loaded
|
14
|
+
class FileStore < Universa::ChainStore
|
15
|
+
|
16
|
+
# [String] The file store root path
|
17
|
+
attr :root
|
18
|
+
|
19
|
+
# Construct store in the path supplied. If the path is not empty, it will be scanned for stored contracts.
|
20
|
+
# @param [String] root_path of the store, must exist.
|
21
|
+
def initialize(root_path)
|
22
|
+
@root = root_path
|
23
|
+
@root = @root[0...-1] while (@root[-1] == '/')
|
24
|
+
init_cache
|
25
|
+
end
|
26
|
+
|
27
|
+
# (see ChainStore#store_contract)
|
28
|
+
def store_contract contract
|
29
|
+
entry = FSStore::Entry.new(self)
|
30
|
+
entry = entry.init_with_contract(contract)
|
31
|
+
add_to_cache entry
|
32
|
+
end
|
33
|
+
|
34
|
+
# (see ChainStore#find_by_id)
|
35
|
+
def find_by_id hash_id
|
36
|
+
@cache[hash_id]
|
37
|
+
end
|
38
|
+
|
39
|
+
# (see ChainStore#count)
|
40
|
+
def count
|
41
|
+
@cache.size
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
# scan the root folder for attribute files and store them in the cache
|
47
|
+
def init_cache
|
48
|
+
@cache = {}
|
49
|
+
Dir[@root + "/*.unicon.yaml"].each {|name|
|
50
|
+
add_to_cache Entry.new(self).load_from_yaml_file(name)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
# add single entry to the cache
|
55
|
+
# @param [Entry] entry to add. Could have contract not yet loaded but should be configured with attributes.
|
56
|
+
def add_to_cache(entry)
|
57
|
+
raise ArgumentError, "entry can't be nil" unless entry
|
58
|
+
@cache[entry.hash_id] = entry
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Universa
|
2
|
+
|
3
|
+
# this is a base class for a contract stored in some contract chain. The implementation
|
4
|
+
# must inherit and implement its {#load} and {#save} methods at least. To do it,
|
5
|
+
# inherit and implement {ChainStore} to work with it.
|
6
|
+
#
|
7
|
+
# Notable features:
|
8
|
+
#
|
9
|
+
# - contract could be assigned only once, no matter how, so its fields could be cached.
|
10
|
+
# - origin, hash_id and parent are cached. So other contract parameters should be.
|
11
|
+
#
|
12
|
+
class StoredContract
|
13
|
+
|
14
|
+
# {ChainStore} instance to which it is connected
|
15
|
+
attr :chain_store
|
16
|
+
# {Contract} instance stored in it. Can be lazy-loaded
|
17
|
+
attr :contract
|
18
|
+
# {HashId} of the {#contract}
|
19
|
+
attr :hash_id
|
20
|
+
|
21
|
+
# @return [HashId] {#contract}.origin. See {Contract#origin}
|
22
|
+
def origin
|
23
|
+
@origin ||= @contract.origin
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [HashId] {#contract}.origin. See {Contract#parent}
|
27
|
+
def parent
|
28
|
+
@parent ||= @contract.parent
|
29
|
+
end
|
30
|
+
|
31
|
+
# Construct implementation connected to a given store
|
32
|
+
# @param [ChainStore] chain_store descendant class
|
33
|
+
def initialize(chain_store)
|
34
|
+
@chain_store = chain_store
|
35
|
+
@chain_store.is_a?(ChainStore) or raise ArgumentError, "ChainStore instance required"
|
36
|
+
@chain_store = chain_store
|
37
|
+
end
|
38
|
+
|
39
|
+
# For implementation logic, in particular, to make lazy loads.
|
40
|
+
# @return true if the stored contract is loaded into this instance
|
41
|
+
def has_contract?
|
42
|
+
!@contract.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
# Shortcut for `contract.packed`. See {Contract#packed}
|
46
|
+
# @return [String] binary string with contained contract packed transaction.
|
47
|
+
def packed_contract
|
48
|
+
@contract.packed
|
49
|
+
end
|
50
|
+
|
51
|
+
# override it to save the contract in the connected contract chain.
|
52
|
+
def save
|
53
|
+
raise NotFoundError
|
54
|
+
end
|
55
|
+
|
56
|
+
# override it to load the contract from the connected contract chain.
|
57
|
+
def load hash_id
|
58
|
+
raise NotFoundError
|
59
|
+
end
|
60
|
+
|
61
|
+
# Assign contract to the instance.
|
62
|
+
# @param [Contracy] new_contract to store
|
63
|
+
def contract=(new_contract)
|
64
|
+
raise IllegalStateError, "contract can't be reassigned" if has_contract?
|
65
|
+
@contract = new_contract
|
66
|
+
@hash_id = @contract.hash_id
|
67
|
+
@origin = @parent = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
# Convenience method. Unoacks and stores the contract.
|
71
|
+
def packed_contract=(new_packed_contract)
|
72
|
+
self.contract = Contract.from_packed(new_packed_contract)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/lib/universa/tools.rb
CHANGED
@@ -7,14 +7,16 @@ module Universa
|
|
7
7
|
class SmartHash < Farcall::SmartHash
|
8
8
|
end
|
9
9
|
|
10
|
-
def retry_with_timeout(max_timeout =
|
10
|
+
def retry_with_timeout(max_timeout = 25, max_times = 3, &block)
|
11
11
|
attempt = 0
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
begin
|
13
|
+
Timeout::timeout(max_timeout, &block)
|
14
|
+
rescue
|
15
|
+
attempt += 1
|
16
|
+
puts "timeout: retry (#$!): #{attempt}"
|
17
|
+
retry if attempt < max_times
|
18
|
+
raise
|
19
|
+
end
|
18
20
|
end
|
19
21
|
|
20
22
|
module Parallel
|
@@ -26,7 +28,7 @@ module Universa
|
|
26
28
|
|
27
29
|
@@pool = CachedThreadPool.new
|
28
30
|
|
29
|
-
# Enumerates in parallel all items. Like
|
31
|
+
# Enumerates in parallel all items. Like +Enumerable#each_with_index+, but requires block.
|
30
32
|
# Blocks until all items are processed.
|
31
33
|
#
|
32
34
|
# @param [Proc] block to call with (object, index) parameters
|
@@ -55,7 +57,7 @@ module Universa
|
|
55
57
|
each_with_index {|x, i| block.call(x)}
|
56
58
|
end
|
57
59
|
|
58
|
-
# Parallel version of the
|
60
|
+
# Parallel version of the +Enumerable#map+. Creates a new array containing the values returned by the block,
|
59
61
|
# using parallel execution in threads.
|
60
62
|
#
|
61
63
|
# @return new array containing the values returned by the block.
|
data/lib/universa/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: universa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sergeych
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: farcall
|
@@ -154,11 +154,15 @@ files:
|
|
154
154
|
- exe/universa
|
155
155
|
- lib/universa.rb
|
156
156
|
- lib/universa/binder.rb
|
157
|
+
- lib/universa/chain_store.rb
|
157
158
|
- lib/universa/client.rb
|
158
159
|
- lib/universa/contract.rb
|
159
160
|
- lib/universa/errors.rb
|
161
|
+
- lib/universa/fs_store/entry.rb
|
162
|
+
- lib/universa/fs_store/file_store.rb
|
160
163
|
- lib/universa/keys.rb
|
161
164
|
- lib/universa/service.rb
|
165
|
+
- lib/universa/stored_contract.rb
|
162
166
|
- lib/universa/string_utils.rb
|
163
167
|
- lib/universa/tools.rb
|
164
168
|
- lib/universa/umi.rb
|
@@ -185,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
189
|
version: '0'
|
186
190
|
requirements: []
|
187
191
|
rubyforge_project:
|
188
|
-
rubygems_version: 2.7.
|
192
|
+
rubygems_version: 2.7.6
|
189
193
|
signing_key:
|
190
194
|
specification_version: 4
|
191
195
|
summary: Expose Universa Java API to ruby
|