ic_agent 0.1.4 → 0.2.1

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.
@@ -8,10 +8,56 @@ module IcAgent
8
8
  end
9
9
 
10
10
  class Certificate
11
+ # Performs a lookup operation in the certificate tree based on the given path.
12
+ #
13
+ # Parameters:
14
+ # - path: The path to lookup.
15
+ # - cert: The certificate object containing the tree.
16
+ #
17
+ # Returns: The value found at the specified path in the tree.
11
18
  def self.lookup(path, cert)
12
19
  lookup_path(path, cert.value['tree'])
13
20
  end
14
21
 
22
+ # Retrieves the signature from a certificate.
23
+ #
24
+ # Parameters:
25
+ # - cert: The certificate object.
26
+ #
27
+ # Returns: The signature value.
28
+ def self.signature(cert)
29
+ cert.value['signature']
30
+ end
31
+
32
+ # Retrieves the delegation from a certificate.
33
+ #
34
+ # Parameters:
35
+ # - cert: The certificate object.
36
+ #
37
+ # Returns: The delegation value.
38
+ def self.delegation(cert)
39
+ cert.value['delegation']
40
+ end
41
+
42
+ # Retrieves the tree from a certificate.
43
+ #
44
+ # Parameters:
45
+ # - cert: The certificate object.
46
+ #
47
+ # Returns: The tree value.
48
+ def self.tree(cert)
49
+ cert.value['tree']
50
+ end
51
+
52
+ private
53
+
54
+ # Recursive helper method for performing the lookup operation.
55
+ #
56
+ # Parameters:
57
+ # - path: The remaining path to lookup.
58
+ # - tree: The current tree node to search in.
59
+ #
60
+ # Returns: The value found at the specified path in the tree.
15
61
  def self.lookup_path(path, tree)
16
62
  offset = 0
17
63
  if path.length == 0
@@ -29,6 +75,12 @@ module IcAgent
29
75
  end
30
76
  end
31
77
 
78
+ # Flattens fork nodes in the tree into a single array.
79
+ #
80
+ # Parameters:
81
+ # - t: The tree node to flatten.
82
+ #
83
+ # Returns: The flattened array of tree nodes.
32
84
  def self.flatten_forks(t)
33
85
  if t[0] == NodeId::EMPTY
34
86
  []
@@ -42,6 +94,13 @@ module IcAgent
42
94
  end
43
95
  end
44
96
 
97
+ # Finds a labeled tree node with the specified label in the given array of trees.
98
+ #
99
+ # Parameters:
100
+ # - l: The label to search for.
101
+ # - trees: The array of trees to search in.
102
+ #
103
+ # Returns: The labeled tree node with the matching label, or nil if not found.
45
104
  def self.find_label(l, trees)
46
105
  trees.each do |t|
47
106
  if t[0] == NodeId::LABELED
@@ -51,5 +110,44 @@ module IcAgent
51
110
  end
52
111
  nil
53
112
  end
113
+
114
+ # Recursively reconstructs the hash value of a tree node.
115
+ #
116
+ # Parameters:
117
+ # - t: The tree node to reconstruct.
118
+ #
119
+ # Returns: The reconstructed hash value of the tree node.
120
+ def self.reconstruct(t)
121
+ case t[0]
122
+ when IcAgent::NodeId::EMPTY
123
+ domain_sep = domain_sep('ic-hashtree-empty')
124
+ Digest::SHA256.digest(domain_sep)
125
+ when IcAgent::NodeId::PRUNED
126
+ t[1]
127
+ when IcAgent::NodeId::LEAF
128
+ domain_sep = domain_sep('ic-hashtree-leaf')
129
+ Digest::SHA256.digest(domain_sep + t[1])
130
+ when IcAgent::NodeId::LABELED
131
+ domain_sep = domain_sep('ic-hashtree-labeled')
132
+ Digest::SHA256.digest(domain_sep + t[1] + reconstruct(t[2]))
133
+ when IcAgent::NodeId::FORK
134
+ domain_sep = domain_sep('ic-hashtree-fork')
135
+ Digest::SHA256.digest(domain_sep + reconstruct(t[1]) + reconstruct(t[2]))
136
+ else
137
+ raise 'unreachable'
138
+ end
139
+ end
140
+
141
+ # Generates the domain separation prefix for hash computations.
142
+ #
143
+ # Parameters:
144
+ # - s: The domain separation string.
145
+ #
146
+ # Returns: The domain separation prefix as a binary string.
147
+ def self.domain_sep(s)
148
+ len = [s.bytesize].pack('C')
149
+ str = s.encode(Encoding::UTF_8)
150
+ len + str
151
+ end
54
152
  end
55
153
  end
@@ -5,6 +5,10 @@ module IcAgent
5
5
  DEFAULT_TIMEOUT = 120
6
6
  DEFAULT_TIMEOUT_QUERY = 30
7
7
 
8
+ # Initializes a new instance of the Client class.
9
+ #
10
+ # Parameters:
11
+ # - url: The URL of the IC agent. Defaults to 'https://ic0.app'.
8
12
  def initialize(url = 'https://ic0.app')
9
13
  @url = url
10
14
  @conn = Faraday.new(url: url) do |faraday|
@@ -16,6 +20,13 @@ module IcAgent
16
20
  end
17
21
  end
18
22
 
23
+ # Sends a query to a canister.
24
+ #
25
+ # Parameters:
26
+ # - canister_id: The ID of the canister to query.
27
+ # - data: The data to send with the query.
28
+ #
29
+ # Returns: The response from the canister as a UTF-8 encoded string.
19
30
  def query(canister_id, data)
20
31
  endpoint = "/api/v2/canister/#{canister_id}/query"
21
32
  ret = @conn.post(endpoint, data)
@@ -23,6 +34,14 @@ module IcAgent
23
34
  ret.body
24
35
  end
25
36
 
37
+ # Calls a function on a canister.
38
+ #
39
+ # Parameters:
40
+ # - canister_id: The ID of the canister to call.
41
+ # - req_id: The request ID.
42
+ # - data: The data to send with the call.
43
+ #
44
+ # Returns: The request ID.
26
45
  def call(canister_id, req_id, data)
27
46
  endpoint = "/api/v2/canister/#{canister_id}/call"
28
47
  ret = @conn.post(endpoint, data)
@@ -30,6 +49,13 @@ module IcAgent
30
49
  req_id
31
50
  end
32
51
 
52
+ # Reads the state of a canister.
53
+ #
54
+ # Parameters:
55
+ # - canister_id: The ID of the canister to read the state from.
56
+ # - data: The data to send with the read_state request.
57
+ #
58
+ # Returns: The response from the canister as a UTF-8 encoded string.
33
59
  def read_state(canister_id, data)
34
60
  endpoint = "/api/v2/canister/#{canister_id}/read_state"
35
61
  ret = @conn.post(endpoint, data)
@@ -37,6 +63,12 @@ module IcAgent
37
63
  ret.body
38
64
  end
39
65
 
66
+ # Retrieves the status of the IC agent.
67
+ #
68
+ # Parameters:
69
+ # - timeout: The timeout for the status request. Defaults to DEFAULT_TIMEOUT_QUERY.
70
+ #
71
+ # Returns: The response from the status endpoint as a UTF-8 encoded string.
40
72
  def status(timeout: DEFAULT_TIMEOUT_QUERY)
41
73
  endpoint = '/api/v2/status'
42
74
  ret = @conn.get(endpoint, timeout: timeout)
@@ -261,6 +261,11 @@ module IcAgent
261
261
 
262
262
  attr_accessor :identity, :client, :agent, :canister
263
263
 
264
+ # Constructor for the CyclesWallet class.
265
+ #
266
+ # Parameters:
267
+ # - iden: (Optional) An instance of the Identity class.
268
+ # - wallet_id: The ID of the CyclesWallet.
264
269
  def initialize(iden = nil, wallet_id)
265
270
  @identity = iden.nil? ? IcAgent::Identity.new : iden
266
271
  @client = IcAgent::Client.new
@@ -355,6 +355,10 @@ module IcAgent
355
355
 
356
356
  attr_accessor :identity, :client, :agent, :canister
357
357
 
358
+ # Constructor for the Governance class.
359
+ #
360
+ # Parameters:
361
+ # - iden: (Optional) An instance of the Identity class.
358
362
  def initialize(iden = nil)
359
363
  @identity = iden.nil? ? IcAgent::Identity.new : iden
360
364
  @client = IcAgent::Client.new
@@ -166,6 +166,10 @@ module IcAgent
166
166
 
167
167
  attr_accessor :identity, :client, :agent, :canister
168
168
 
169
+ # Constructor for the Ledger class.
170
+ #
171
+ # Parameters:
172
+ # - iden: (Optional) An instance of the Identity class.
169
173
  def initialize(iden = nil)
170
174
  @identity = iden.nil? ? IcAgent::Identity.new : iden
171
175
  @client = IcAgent::Client.new
@@ -182,6 +182,10 @@ module IcAgent
182
182
 
183
183
  attr_accessor :identity, :client, :agent, :canister
184
184
 
185
+ # Constructor for the Management class.
186
+ #
187
+ # Parameters:
188
+ # - iden: (Optional) An instance of the Identity class.
185
189
  def initialize(iden = nil)
186
190
  @identity = iden.nil? ? IcAgent::Identity.new : iden
187
191
  @client = IcAgent::Client.new
@@ -11,6 +11,12 @@ module IcAgent
11
11
  class Identity
12
12
  attr_reader :privkey, :pubkey, :der_pubkey, :sk, :vk, :key_type
13
13
 
14
+ # Initializes a new instance of the Identity class.
15
+ #
16
+ # Parameters:
17
+ # - privkey: The private key of the identity in hexadecimal format. Defaults to an empty string.
18
+ # - type: The key type of the identity. Defaults to 'ed25519'.
19
+ # - anonymous: A flag indicating whether the identity is anonymous. Defaults to false.
14
20
  def initialize(privkey = '', type = 'ed25519', anonymous = false)
15
21
  privkey = [privkey].pack('H*')
16
22
  @anonymous = anonymous
@@ -37,6 +43,12 @@ module IcAgent
37
43
  end
38
44
  end
39
45
 
46
+ # Creates a new Identity instance from a seed phrase (mnemonic).
47
+ #
48
+ # Parameters:
49
+ # - mnemonic: The seed phrase (mnemonic) used to generate the identity.
50
+ #
51
+ # Returns: The Identity instance.
40
52
  def self.from_seed(mnemonic)
41
53
  seed = Bitcoin::Trezor::Mnemonic.to_seed(mnemonic)
42
54
  privkey = seed[0..63]
@@ -44,6 +56,9 @@ module IcAgent
44
56
  Identity.new(privkey = privkey, type = key_type)
45
57
  end
46
58
 
59
+ # Returns the sender Principal associated with the Identity.
60
+ #
61
+ # Returns: The sender Principal.
47
62
  def sender
48
63
  if @anonymous
49
64
  IcAgent::Principal.anonymous
@@ -52,6 +67,12 @@ module IcAgent
52
67
  end
53
68
  end
54
69
 
70
+ # Signs a message using the Identity.
71
+ #
72
+ # Parameters:
73
+ # - msg: The message to sign.
74
+ #
75
+ # Returns: An array containing the DER-encoded public key and the signature.
55
76
  def sign(msg)
56
77
  if @anonymous
57
78
  [nil, nil]
@@ -65,6 +86,13 @@ module IcAgent
65
86
  end
66
87
  end
67
88
 
89
+ # Verifies a message signature using the Identity.
90
+ #
91
+ # Parameters:
92
+ # - msg: The message to verify.
93
+ # - sig: The signature to verify.
94
+ #
95
+ # Returns: `true` if the signature is valid, otherwise `false`.
68
96
  def verify(msg, sig)
69
97
  if @anonymous
70
98
  false
@@ -73,6 +101,9 @@ module IcAgent
73
101
  end
74
102
  end
75
103
 
104
+ # Returns the PEM-encoded private key of the Identity.
105
+ #
106
+ # Returns: The PEM-encoded private key.
76
107
  def to_pem
77
108
  der = @key_type == 'secp256k1' ? "#{IcAgent::IC_PUBKEY_SECP_DER_HERD}#{@sk.data.unpack1('H*')}".hex2str : "#{IcAgent::IC_PUBKEY_ED_DER_HEAD}#{@sk.to_bytes.unpack1('H*')}".hex2str
78
109
  b64 = Base64.strict_encode64(der)
@@ -92,20 +123,41 @@ module IcAgent
92
123
  class DelegateIdentity
93
124
  attr_reader :identity, :delegations, :der_pubkey
94
125
 
126
+ # Initializes a new instance of the DelegateIdentity class.
127
+ #
128
+ # Parameters:
129
+ # - identity: The Identity associated with the DelegateIdentity.
130
+ # - delegation: The delegation JSON object containing the delegated keys.
95
131
  def initialize(identity, delegation)
96
132
  @identity = identity
97
133
  @delegations = delegation['delegations'].map { |d| d }
98
134
  @der_pubkey = [delegation['publicKey']].pack('H*')
99
135
  end
100
136
 
137
+ # Signs a message using the DelegateIdentity.
138
+ #
139
+ # Parameters:
140
+ # - msg: The message to sign.
141
+ #
142
+ # Returns: An array containing the DER-encoded public key and the signature.
101
143
  def sign(msg)
102
144
  @identity.sign(msg)
103
145
  end
104
146
 
147
+ # Returns the sender Principal associated with the DelegateIdentity.
148
+ #
149
+ # Returns: The sender Principal.
105
150
  def sender
106
151
  Principal.self_authenticating(@der_pubkey)
107
152
  end
108
153
 
154
+ # Creates a new DelegateIdentity instance from JSON representations of the Identity and delegation.
155
+ #
156
+ # Parameters:
157
+ # - ic_identity: The JSON representation of the Identity.
158
+ # - ic_delegation: The JSON representation of the delegation.
159
+ #
160
+ # Returns: The DelegateIdentity instance.
109
161
  def self.from_json(ic_identity, ic_delegation)
110
162
  parsed_ic_identity = JSON.parse(ic_identity)
111
163
  parsed_ic_delegation = JSON.parse(ic_delegation)
@@ -7,16 +7,21 @@ module IcAgent
7
7
  MAX_LENGTH_IN_BYTES = 29
8
8
 
9
9
  class PrincipalSort
10
- OpaqueId = 1
11
- SelfAuthenticating = 2
12
- DerivedId = 3
13
- Anonymous = 4
10
+ OPAQUE_ID = 1
11
+ SELF_AUTHENTICATING = 2
12
+ DERIVED_ID = 3
13
+ ANONYMOUS = 4
14
14
  # Unassigned
15
15
  end
16
16
 
17
+ # Base class for Principal.
17
18
  class Principal
18
19
  attr_reader :len, :bytes, :is_principal, :hex
19
20
 
21
+ # Initializes a new instance of the Principal class.
22
+ #
23
+ # Parameters:
24
+ # - bytes: The bytes representing the principal. Defaults to an empty string.
20
25
  def initialize(bytes: ''.b)
21
26
  @len = bytes.length
22
27
  @bytes = bytes
@@ -24,23 +29,41 @@ module IcAgent
24
29
  @is_principal = true
25
30
  end
26
31
 
32
+ # Creates a new Principal instance representing the management canister.
33
+ #
34
+ # Returns: The Principal instance representing the management canister.
27
35
  def self.management_canister
28
36
  Principal.new
29
37
  end
30
38
 
39
+ # Creates a new self-authenticating Principal.
40
+ #
41
+ # Parameters:
42
+ # - pubkey: The public key associated with the self-authenticating Principal.
43
+ #
44
+ # Returns: The self-authenticating Principal instance.
31
45
  def self.self_authenticating(pubkey)
32
46
  # check pubkey.size for is ed25519 or secp256k1
33
47
  pubkey = [pubkey].pack('H*') if pubkey.size != 44 && pubkey.size != 88
34
48
 
35
49
  hash_ = OpenSSL::Digest::SHA224.digest(pubkey)
36
- hash_ += [PrincipalSort::SelfAuthenticating].pack('C')
50
+ hash_ += [PrincipalSort::SELF_AUTHENTICATING].pack('C')
37
51
  Principal.new(bytes: hash_)
38
52
  end
39
53
 
54
+ # Creates a new anonymous Principal.
55
+ #
56
+ # Returns: The anonymous Principal instance.
40
57
  def self.anonymous
41
58
  Principal.new(bytes: "\x04".b)
42
59
  end
43
60
 
61
+ # Creates a new Principal from a string representation.
62
+ #
63
+ # Parameters:
64
+ # - s: The string representation of the Principal.
65
+ #
66
+ # Returns: The Principal instance.
44
67
  def self.from_str(s)
45
68
  s1 = s.delete('-')
46
69
  pad_len = ((s1.length / 8.0).ceil * 8) - s1.length
@@ -53,10 +76,19 @@ module IcAgent
53
76
  p
54
77
  end
55
78
 
79
+ # Creates a new Principal from a hexadecimal string representation.
80
+ #
81
+ # Parameters:
82
+ # - s: The hexadecimal string representation of the Principal.
83
+ #
84
+ # Returns: The Principal instance.
56
85
  def self.from_hex(s)
57
86
  Principal.new(bytes: [s].pack('H*'))
58
87
  end
59
88
 
89
+ # Converts the Principal to a string representation.
90
+ #
91
+ # Returns: The string representation of the Principal.
60
92
  def to_str
61
93
  checksum = Zlib.crc32(@bytes) & 0xFFFFFFFF
62
94
  b = ''
@@ -71,6 +103,12 @@ module IcAgent
71
103
  ret + s
72
104
  end
73
105
 
106
+ # Converts the Principal to an AccountIdentifier.
107
+ #
108
+ # Parameters:
109
+ # - sub_account: The sub-account identifier. Defaults to 0.
110
+ #
111
+ # Returns: The AccountIdentifier instance.
74
112
  def to_account_id(sub_account = 0)
75
113
  AccountIdentifier.generate(self, sub_account)
76
114
  end
@@ -78,17 +116,70 @@ module IcAgent
78
116
  def to_s
79
117
  to_str
80
118
  end
119
+
120
+ # Compares the Principal with another Principal.
121
+ #
122
+ # Parameters:
123
+ # - other: The other Principal to compare with.
124
+ #
125
+ # Returns: The comparison result as a string ('lt', 'eq', or 'gt').
126
+ def compare_to(other)
127
+ (0...[self.bytes.length, other.bytes.length].min).each do |i|
128
+ if self.bytes[i] < other.bytes[i]
129
+ return 'lt'
130
+ elsif self.bytes[i] > other.bytes[i]
131
+ return 'gt'
132
+ end
133
+ end
134
+
135
+ if self.bytes.length < other.bytes.length
136
+ 'lt'
137
+ elsif self.bytes.length > other.bytes.length
138
+ 'gt'
139
+ else
140
+ 'eq'
141
+ end
142
+ end
143
+
144
+ # Utility method checking whether a provided Principal is less than or equal to the current one using the `compare_to` method.
145
+ #
146
+ # Parameters:
147
+ # - other: The other Principal to compare with.
148
+ #
149
+ # Returns: `true` if the current Principal is less than or equal to the provided Principal, otherwise `false`.
150
+ def lt_eq(other)
151
+ cmp = compare_to(other)
152
+ %w[lt eq].include?(cmp)
153
+ end
154
+
155
+ # Utility method checking whether a provided Principal is greater than or equal to the current one using the `compare_to` method.
156
+ #
157
+ # Parameters:
158
+ # - other: The other Principal to compare with.
159
+ #
160
+ # Returns: `true` if the current Principal is greater than or equal to the provided Principal, otherwise `false`.
161
+ def gt_eq(other)
162
+ cmp = compare_to(other)
163
+ %w[gt eq].include?(cmp)
164
+ end
81
165
  end
82
166
 
83
167
  class AccountIdentifier
84
168
  attr_reader :bytes
85
169
 
170
+ # Initializes a new instance of the AccountIdentifier class.
171
+ #
172
+ # Parameters:
173
+ # - hash: The hash representing the AccountIdentifier.
86
174
  def initialize(hash)
87
175
  raise 'Invalid hash length' unless hash.length == 32
88
176
 
89
177
  @bytes = hash
90
178
  end
91
179
 
180
+ # Converts the AccountIdentifier to a string representation.
181
+ #
182
+ # Returns: The string representation of the AccountIdentifier.
92
183
  def to_str
93
184
  '0x' + @bytes.unpack1('H*')
94
185
  end
@@ -97,12 +188,19 @@ module IcAgent
97
188
  to_str
98
189
  end
99
190
 
191
+ # Generates a new AccountIdentifier from a Principal.
192
+ #
193
+ # Parameters:
194
+ # - principal: The Principal associated with the AccountIdentifier.
195
+ # - sub_account: The sub-account identifier. Defaults to 0.
196
+ #
197
+ # Returns: The AccountIdentifier instance.
100
198
  def self.generate(principal, sub_account = 0)
101
199
  sha224 = OpenSSL::Digest::SHA224.new
102
200
  sha224 << "\naccount-id"
103
201
  sha224 << principal.bytes
104
202
  format_sub_account = "%08d" % sub_account
105
- sub_account = format_sub_account.chars.map {|c| c.to_i}.pack('N*')
203
+ sub_account = format_sub_account.chars.map { |c| c.to_i }.pack('N*')
106
204
  sha224 << sub_account
107
205
  hash = sha224.digest
108
206
  checksum = Zlib.crc32(hash) & 0xFFFFFFFF
@@ -5,6 +5,13 @@ require 'cbor'
5
5
 
6
6
  module IcAgent
7
7
  class SyetemState
8
+ # Retrieves the system time from a canister's state.
9
+ #
10
+ # Parameters:
11
+ # - agent: The IcAgent::Client instance.
12
+ # - canister_id: The ID of the canister.
13
+ #
14
+ # Returns: The system time as a timestamp.
8
15
  def self.time(agent, canister_id)
9
16
  cert = agent.read_state_raw(canister_id, [['time']])
10
17
  timestamp = Certificate.lookup(['time'], cert)
@@ -12,6 +19,14 @@ module IcAgent
12
19
  LEB128.decode_signed(str_io)
13
20
  end
14
21
 
22
+ # Retrieves the public key of a subnet from a canister's state.
23
+ #
24
+ # Parameters:
25
+ # - agent: The IcAgent::Client instance.
26
+ # - canister_id: The ID of the canister.
27
+ # - subnet_id: The ID of the subnet.
28
+ #
29
+ # Returns: The public key of the subnet in hexadecimal format.
15
30
  def self.subnet_public_key(agent, canister_id, subnet_id)
16
31
  path = ['subnet', Principal.from_str(subnet_id).bytes, 'public_key']
17
32
  cert = agent.read_state_raw(canister_id, [path])
@@ -19,6 +34,14 @@ module IcAgent
19
34
  pubkey.str2hex
20
35
  end
21
36
 
37
+ # Retrieves the canister ranges of a subnet from a canister's state.
38
+ #
39
+ # Parameters:
40
+ # - agent: The IcAgent::Client instance.
41
+ # - canister_id: The ID of the canister.
42
+ # - subnet_id: The ID of the subnet.
43
+ #
44
+ # Returns: An array of canister ranges, where each range is represented as an array of Principal instances.
22
45
  def self.subnet_canister_ranges(agent, canister_id, subnet_id)
23
46
  path = ['subnet', Principal.from_str(subnet_id).bytes, 'canister_ranges']
24
47
  cert = agent.read_state_raw(canister_id, [path])
@@ -26,6 +49,13 @@ module IcAgent
26
49
  CBOR.decode(ranges).value.map { |range| range.map { |item| Principal.new(bytes: item) } }
27
50
  end
28
51
 
52
+ # Retrieves the module hash of a canister from a canister's state.
53
+ #
54
+ # Parameters:
55
+ # - agent: The IcAgent::Client instance.
56
+ # - canister_id: The ID of the canister.
57
+ #
58
+ # Returns: The module hash of the canister in hexadecimal format.
29
59
  def self.canister_module_hash(agent, canister_id)
30
60
  path = ['canister', Principal.from_str(canister_id).bytes, 'module_hash']
31
61
  cert = agent.read_state_raw(canister_id, [path])
@@ -33,6 +63,13 @@ module IcAgent
33
63
  module_hash.str2hex
34
64
  end
35
65
 
66
+ # Retrieves the controllers of a canister from a canister's state.
67
+ #
68
+ # Parameters:
69
+ # - agent: The IcAgent::Client instance.
70
+ # - canister_id: The ID of the canister.
71
+ #
72
+ # Returns: An array of Principal instances representing the controllers of the canister.
36
73
  def self.canister_controllers(agent, canister_id)
37
74
  path = ['canister', Principal.from_str(canister_id).bytes, 'controllers']
38
75
  cert = agent.read_state_raw(canister_id, [path])
@@ -3,6 +3,12 @@ require 'leb128'
3
3
 
4
4
  module IcAgent
5
5
  module Utils
6
+ # Encodes a list of items into a binary string.
7
+ #
8
+ # Parameters:
9
+ # - l: The list of items to encode.
10
+ #
11
+ # Returns: The binary string representation of the encoded list.
6
12
  def self.encode_list(l)
7
13
  ret = ''
8
14
  l.each do |item|
@@ -21,7 +27,12 @@ module IcAgent
21
27
  ret
22
28
  end
23
29
 
24
- # used for sort record by key
30
+ # Computes a hash value for sorting records by key.
31
+ #
32
+ # Parameters:
33
+ # - s: The key to hash.
34
+ #
35
+ # Returns: The computed hash value.
25
36
  def self.label_hash(s)
26
37
  if s =~ /(^_\d+_$)|(^_0x[0-9a-fA-F]+_$)/
27
38
  num = s[1..-2]
@@ -41,6 +52,12 @@ module IcAgent
41
52
  idl_hash(s)
42
53
  end
43
54
 
55
+ # Computes a hash value for an IDL string.
56
+ #
57
+ # Parameters:
58
+ # - s: The IDL string to hash.
59
+ #
60
+ # Returns: The computed hash value.
44
61
  def self.idl_hash(s)
45
62
  h = 0
46
63
  s.bytes.each do |c|
@@ -49,6 +66,12 @@ module IcAgent
49
66
  h
50
67
  end
51
68
 
69
+ # Converts a data structure into a request ID.
70
+ #
71
+ # Parameters:
72
+ # - d: The data structure to convert.
73
+ #
74
+ # Returns: The request ID as a binary string.
52
75
  def self.to_request_id(d)
53
76
  return nil unless d.is_a?(Hash)
54
77
 
@@ -67,9 +90,14 @@ module IcAgent
67
90
  Digest::SHA256.digest(s)
68
91
  end
69
92
 
93
+ # Decodes a binary blob into a string.
94
+ #
95
+ # Parameters:
96
+ # - blob_bytes: The binary blob to decode.
97
+ #
98
+ # Returns: The decoded string.
70
99
  def self.decode_blob(blob_bytes)
71
100
  blob_bytes.pack('C*')
72
101
  end
73
102
  end
74
103
  end
75
-
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IcAgent
4
- VERSION = '0.1.4'
4
+ VERSION = '0.2.1'
5
5
  end