lib/universa/contract.rb in universa-0.1.9 vs lib/universa/contract.rb in universa-0.2.1
- old
+ new
@@ -32,15 +32,16 @@
def self.from_digest(digest_bytes)
digest_bytes.force_encoding 'binary'
invoke_static 'with_digest', digest_bytes
end
- # Construct from string representation of the ID, not to confuse with binary one.
+ # Construct from string representation of the ID, not to confuse with binary one. This method takes both
+ # regular base64 representation and RFC3548 url-safe modification, as from {#to_url_safe_string}.
#
# @param [String] string_id id string representation, like from +hash_id_instance.to_s+. See {#to_s}.
def self.from_string(string_id)
- string_id.force_encoding 'utf-8'
+ string_id.force_encoding('utf-8').gsub('-','+').gsub('_','/')
invoke_static 'with_digest', string_id
end
# Get binary representation. It is shorter than string representation but contain non-printable characters and
# can cause problems if treated like a string. Use {#to_s} to get string representation instead.
@@ -55,30 +56,52 @@
#
# @return [String] string representation
def to_s
Base64.encode64(get_digest).gsub(/\s/, '')
end
+
+ # Converts to URL-safe varianot of base64, as RFC 3548 suggests:
+ # the 63:nd / character with the underscore _
+ # the 62:nd + character with the minus -
+ #
+ # Could be decoded safely back with {HashId.from_string} but not (most likely) with JAVA API itself
+ # @return [String] RFC3548 modified base64
+ def to_url_safe_string
+ Base64.encode64(get_digest).gsub(/\s/, '').gsub('/','_').gsub('+', '-')
+ end
+
+ # To use it as a hash key_address.
+ # @return hash calculated over the digest bytes
+ def hash
+ bytes.hash
+ end
+
+ # To use it as a hash key_address. Same as this == other.
+ def eql? other
+ self == other
+ end
+
end
# Universa contract adapter.
class Contract < RemoteAdapter
remote_class "com.icodici.universa.contract.Contract"
# Create simple contract with preset critical parts:
#
# - expiration set to 90 days unless specified else
- # - issuer role is set to the address of the issuer key, short ot long
+ # - issuer role is set to the address of the issuer key_address, short ot long
# - creator role is set as link to issuer
# - owner role is set as link to issuer
# - change owner permission is set to link to owner
#
- # The while contract is then signed by the issuer key. Not that it will not seal it: caller almost always
+ # The while contract is then signed by the issuer key_address. Not that it will not seal it: caller almost always
# will add more data before it, then must call #seal().
#
# @param [PrivateKey] issuer_key also will be used to sign it
# @param [Time] expires_at defaults to 90 days
- # @param [Boolean] use_short_address set to true to use short address of the issuer key in the role
+ # @param [Boolean] use_short_address set to true to use short address of the issuer key_address in the role
# @return [Contract] simple contact, not sealed
def self.create issuer_key, expires_at: (Time.now + 90 * 24 * 60 * 60), use_short_address: false
contract = Contract.new
contract.set_expires_at expires_at
contract.set_issuer_keys(use_short_address ? issuer_key.short_address : issuer_key.long_address)
@@ -90,10 +113,11 @@
contract
end
# Load from transaction pack
def self.from_packed packed
+ packed.nil? and raise ArgumentError, "packed contract required"
packed.force_encoding 'binary'
self.invoke_static "fromPackedTransaction", packed
end
# seal the contract
@@ -122,38 +146,54 @@
# @return [Role] owner role
def owner
get_owner
end
- def owner= key
- set_owner_key key
+ # Set owner to the key_address, usable only in the simplest case where owner is the single address.
+ # @param [KeyAddress | PublicKey] key_address
+ def owner=(key_address)
+ set_owner_key key_address
end
# Shortcut for is_ok
def ok?
is_ok
end
# shortcut for getHashId
+ # @return [HashId] of the contracr
def hash_id
- get_id
+ getId()
end
- # shortcut for get_expires_at
+ # @return [HashId] of the origin contract
+ def origin
+ getOrigin()
+ end
+
+ # @return [HashId] pf the parent contracr
+ def parent
+ getParent()
+ end
+
+ # shortcut for get_expires_at. Get the contract expiration time.
def expires_at
get_expires_at
end
- def expires_at= time
+ # set +expires_at+ field
+ # @param [Time] time when this contract will be expired, if yet +APPROVED+.
+ def expires_at=(time)
set_expires_at time
end
# @return definition data
def definition
@definition ||= get_definition.get_data
end
+ # Return +state+ binder. Shortcut for Java API +getStateData()+
def state
@state ||= getStateData()
end
# Get +transactional.data+ section creating it if need
@@ -173,11 +213,11 @@
end
# Write helper for many token-like contracts containing state.data.amount. Saves value
# in state.data.anomount and properly encodes it so it will be preserved on packing.
#
- # @param [Object] value, should be some representation of a number (also string)
+ # @param [Object] value should be some representation of a number (also string)
def amount= (value)
state[:amount] = value.to_s.force_encoding('utf-8')
end
# Get packed transaction containing the serialized signed contract and all its counterparts.
@@ -201,10 +241,14 @@
# @return [String] possibly empty ''
def errors_string
getErrors.map {|e| "(#{e.object || ''}): #{e.error}"}.join(', ').strip
end
- def can_perform_role name, *keys
+ # Test that some set of keys could be used to perform some role.
+ #
+ # @param [String] name of the role to check
+ # @param [PublicKey] keys instances to check against
+ def can_perform_role(name, *keys)
getRole(name.to_s).isAllowedForKeys(Set.new keys.map {|x|
x.is_a?(PrivateKey) ? x.public_key : x
})
end
\ No newline at end of file