iota-ruby 1.1.8-java

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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +8 -0
  3. data/.gitignore +15 -0
  4. data/.travis.yml +24 -0
  5. data/.yardopts +7 -0
  6. data/CHANGELOG.md +18 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +21 -0
  9. data/README.md +121 -0
  10. data/Rakefile +36 -0
  11. data/bin/iota-console +15 -0
  12. data/examples/multisig.rb +69 -0
  13. data/ext/ccurl/ccurl.c +134 -0
  14. data/ext/ccurl/extconf.rb +22 -0
  15. data/ext/jcurl/JCurl.java +126 -0
  16. data/ext/jcurl/JCurlService.java +36 -0
  17. data/ext/pow/ccurl-0.3.0.dll +0 -0
  18. data/ext/pow/libccurl-0.3.0.dylib +0 -0
  19. data/ext/pow/libccurl-0.3.0.so +0 -0
  20. data/iota-ruby.gemspec +37 -0
  21. data/lib/iota.rb +76 -0
  22. data/lib/iota/api/api.rb +251 -0
  23. data/lib/iota/api/commands.rb +113 -0
  24. data/lib/iota/api/transport.rb +43 -0
  25. data/lib/iota/api/wrappers.rb +429 -0
  26. data/lib/iota/crypto/bundle.rb +163 -0
  27. data/lib/iota/crypto/converter.rb +244 -0
  28. data/lib/iota/crypto/curl.rb +18 -0
  29. data/lib/iota/crypto/curl_c.rb +17 -0
  30. data/lib/iota/crypto/curl_java.rb +18 -0
  31. data/lib/iota/crypto/curl_ruby.rb +70 -0
  32. data/lib/iota/crypto/hmac.rb +27 -0
  33. data/lib/iota/crypto/kerl.rb +82 -0
  34. data/lib/iota/crypto/pow_provider.rb +27 -0
  35. data/lib/iota/crypto/private_key.rb +80 -0
  36. data/lib/iota/crypto/sha3_ruby.rb +122 -0
  37. data/lib/iota/crypto/signing.rb +97 -0
  38. data/lib/iota/models/account.rb +489 -0
  39. data/lib/iota/models/base.rb +13 -0
  40. data/lib/iota/models/bundle.rb +87 -0
  41. data/lib/iota/models/input.rb +38 -0
  42. data/lib/iota/models/seed.rb +33 -0
  43. data/lib/iota/models/transaction.rb +52 -0
  44. data/lib/iota/models/transfer.rb +44 -0
  45. data/lib/iota/multisig/address.rb +41 -0
  46. data/lib/iota/multisig/multisig.rb +244 -0
  47. data/lib/iota/utils/ascii.rb +50 -0
  48. data/lib/iota/utils/broker.rb +124 -0
  49. data/lib/iota/utils/input_validator.rb +149 -0
  50. data/lib/iota/utils/object_validator.rb +34 -0
  51. data/lib/iota/utils/utils.rb +324 -0
  52. data/lib/iota/version.rb +3 -0
  53. data/lib/jcurl.jar +0 -0
  54. data/lib/patch.rb +17 -0
  55. data/test/ascii_test.rb +114 -0
  56. data/test/curl_c_test.rb +31 -0
  57. data/test/curl_java_test.rb +31 -0
  58. data/test/curl_ruby_test.rb +27 -0
  59. data/test/kerl_test.rb +52 -0
  60. data/test/pow_provider_test.rb +36 -0
  61. data/test/sha3_test.rb +71 -0
  62. data/test/test_helper.rb +4 -0
  63. data/test/utils_test.rb +179 -0
  64. metadata +183 -0
@@ -0,0 +1,113 @@
1
+ module IOTA
2
+ module API
3
+ class Commands
4
+ def findTransactions(searchValues)
5
+ command = {
6
+ command: 'findTransactions'
7
+ }
8
+
9
+ searchValues.each { |k, v| command[k.to_sym] = v }
10
+
11
+ command
12
+ end
13
+
14
+ def getBalances(addresses, threshold)
15
+ {
16
+ command: 'getBalances',
17
+ addresses: addresses,
18
+ threshold: threshold
19
+ }
20
+ end
21
+
22
+ def getTrytes(hashes)
23
+ {
24
+ command: 'getTrytes',
25
+ hashes: hashes
26
+ }
27
+ end
28
+
29
+ def getInclusionStates(transactions, tips)
30
+ {
31
+ command: 'getInclusionStates',
32
+ transactions: transactions,
33
+ tips: tips
34
+ }
35
+ end
36
+
37
+ def getNodeInfo
38
+ { command: 'getNodeInfo'}
39
+ end
40
+
41
+ def getNeighbors
42
+ { command: 'getNeighbors' }
43
+ end
44
+
45
+ def addNeighbors(uris)
46
+ {
47
+ command: 'addNeighbors',
48
+ uris: uris
49
+ }
50
+ end
51
+
52
+ def removeNeighbors(uris)
53
+ {
54
+ command: 'removeNeighbors',
55
+ uris: uris
56
+ }
57
+ end
58
+
59
+ def getTips
60
+ { command: 'getTips' }
61
+ end
62
+
63
+ def getTransactionsToApprove(depth, reference = nil)
64
+ {
65
+ command: 'getTransactionsToApprove',
66
+ depth: depth
67
+ }.merge(reference.nil? ? {} : { reference: reference })
68
+ end
69
+
70
+ def attachToTangle(trunkTransaction, branchTransaction, minWeightMagnitude, trytes)
71
+ {
72
+ command: 'attachToTangle',
73
+ trunkTransaction: trunkTransaction,
74
+ branchTransaction: branchTransaction,
75
+ minWeightMagnitude: minWeightMagnitude,
76
+ trytes: trytes
77
+ }
78
+ end
79
+
80
+ def interruptAttachingToTangle
81
+ { command: 'interruptAttachingToTangle' }
82
+ end
83
+
84
+ def broadcastTransactions(trytes)
85
+ {
86
+ command: 'broadcastTransactions',
87
+ trytes: trytes
88
+ }
89
+ end
90
+
91
+ def storeTransactions(trytes)
92
+ {
93
+ command: 'storeTransactions',
94
+ trytes: trytes
95
+ }
96
+ end
97
+
98
+ def checkConsistency(tails)
99
+ {
100
+ command: 'checkConsistency',
101
+ tails: tails
102
+ }
103
+ end
104
+
105
+ def wereAddressesSpentFrom(addresses)
106
+ {
107
+ command: 'wereAddressesSpentFrom',
108
+ addresses: addresses
109
+ }
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,43 @@
1
+ module IOTA
2
+ module API
3
+ module Transport
4
+ def sendCommand(command, &callback)
5
+ @broker.send(command, &callback)
6
+ end
7
+
8
+ def sendBatchedCommand(command, &callback)
9
+ # Key and value both should be symbols
10
+ mapping = {
11
+ getTrytes: [ :hashes ],
12
+ getBalances: [ :addresses ],
13
+ wereAddressesSpentFrom: [ :addresses ],
14
+ getInclusionStates: [ :transactions ],
15
+ findTransactions: [ :bundles, :addresses, :tags, :approvees ]
16
+ }
17
+
18
+ command_name = command[:command].to_sym
19
+ if mapping[command_name]
20
+ results = []
21
+
22
+ keys_to_batch = mapping[command_name]
23
+ keys_to_batch.each do |key|
24
+ if command[key]
25
+ command[key].each_slice(@batch_size) do |group|
26
+ batchedCommand = command.clone.merge({ key => group })
27
+ sendCommand(batchedCommand) do |status, response|
28
+ if !status
29
+ return sendData(false, response, &callback)
30
+ end
31
+ results += response
32
+ end
33
+ end
34
+ end
35
+ end
36
+ return sendData(true, results, &callback)
37
+ else
38
+ return sendCommand(command, &callback)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,429 @@
1
+ module IOTA
2
+ module API
3
+ module Wrappers
4
+ def getTransactionsObjects(hashes, &callback)
5
+ # If not array of hashes, return error
6
+ if !@validator.isArrayOfHashes(hashes)
7
+ return sendData(false, "Invalid inputs provided", &callback)
8
+ end
9
+
10
+ ret_status = false
11
+ ret_data = nil
12
+ # get the trytes of the transaction hashes
13
+ getTrytes(hashes) do |status, trytes|
14
+ ret_status = status
15
+ if status
16
+ transactionObjects = []
17
+ trytes.each do |tryte|
18
+ if !tryte
19
+ transactionObjects << nil
20
+ else
21
+ transactionObjects << @utils.transactionObject(tryte)
22
+ end
23
+ end
24
+ ret_data = transactionObjects
25
+ else
26
+ ret_data = trytes
27
+ end
28
+ end
29
+
30
+ sendData(ret_status, ret_data, &callback)
31
+ end
32
+
33
+ def findTransactionObjects(input, &callback)
34
+ findTransactions(input) do |status, transactions|
35
+ if !status
36
+ return sendData(status, transactions, &callback)
37
+ else
38
+ return getTransactionsObjects(transactions, &callback)
39
+ end
40
+ end
41
+ end
42
+
43
+ def getLatestInclusion(hashes, &callback)
44
+ ret_status = false
45
+ ret_data = nil
46
+ getNodeInfo do |status, data|
47
+ if status
48
+ ret_status = true
49
+ ret_data = data['latestSolidSubtangleMilestone']
50
+ end
51
+ end
52
+
53
+ if ret_status
54
+ return getInclusionStates(hashes, [ret_data], &callback)
55
+ else
56
+ return sendData(ret_status, ret_data, &callback)
57
+ end
58
+ end
59
+
60
+ def storeAndBroadcast(trytes, &callback)
61
+ storeTransactions(trytes) do |status, data|
62
+ if !status
63
+ return sendData(status, data, &callback)
64
+ else
65
+ return broadcastTransactions(trytes, &callback)
66
+ end
67
+ end
68
+ end
69
+
70
+ def sendTrytes(trytes, depth, minWeightMagnitude, options = {}, &callback)
71
+ # Check if correct depth and minWeightMagnitude
72
+ if !@validator.isValue(depth) || !@validator.isValue(minWeightMagnitude)
73
+ return sendData(false, "Invalid inputs provided", &callback)
74
+ end
75
+
76
+ reference = options[:reference] || options['reference']
77
+
78
+ getTransactionsToApprove(depth, reference) do |status, approval_data|
79
+ if !status
80
+ return sendData(false, approval_data, &callback)
81
+ end
82
+
83
+ attachToTangle(approval_data['trunkTransaction'], approval_data['branchTransaction'], minWeightMagnitude, trytes) do |status1, attached_data|
84
+ if !status1
85
+ return sendData(false, attached_data, &callback)
86
+ end
87
+
88
+ # If the user is connected to the sandbox and local pow is not used, we have to monitor the POW queue to check if the POW job was completed
89
+ if @sandbox && @pow_provider.nil?
90
+ # Implement sandbox processing
91
+ jobUri = @sandbox + '/jobs/' + attached_data['id']
92
+
93
+ # Do the Sandbox send function
94
+ @broker.sandboxSend(jobUri) do |status2, sandbox_data|
95
+ if !status2
96
+ return sendData(false, sandbox_data, &callback)
97
+ end
98
+
99
+ storeAndBroadcast(sandbox_data) do |status3, data|
100
+ if status3
101
+ return sendData(false, data, &callback)
102
+ end
103
+
104
+ finalTxs = []
105
+
106
+ attachedTrytes.each do |trytes1|
107
+ finalTxs << @utils.transactionObject(trytes1)
108
+ end
109
+
110
+ return sendData(true, finalTxs, &callback)
111
+ end
112
+ end
113
+ else
114
+ # Broadcast and store tx
115
+ storeAndBroadcast(attached_data) do |status2, data|
116
+ if !status2
117
+ return sendData(false, data, &callback)
118
+ end
119
+
120
+ transactions = attached_data.map { |tryte| @utils.transactionObject(tryte) }
121
+
122
+ sendData(true, transactions, &callback)
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def bundlesFromAddresses(addresses, inclusionStates, &callback)
130
+ # call wrapper function to get txs associated with addresses
131
+ findTransactionObjects(addresses: addresses) do |status, transactionObjects|
132
+ if !status
133
+ return sendData(false, transactionObjects, &callback)
134
+ end
135
+
136
+ # set of tail transactions
137
+ tailTransactions = []
138
+ nonTailBundleHashes = []
139
+
140
+ transactionObjects.each do |trx|
141
+ # Sort tail and nonTails
142
+ if trx.currentIndex == 0
143
+ tailTransactions << trx.hash
144
+ else
145
+ nonTailBundleHashes << trx.bundle
146
+ end
147
+ end
148
+
149
+ # Get tail transactions for each nonTail via the bundle hash
150
+ findTransactionObjects(bundles: nonTailBundleHashes.uniq) do |st1, trxObjects|
151
+ if !st1
152
+ return sendData(false, trxObjects, &callback)
153
+ end
154
+
155
+ trxObjects.each do |trx|
156
+ tailTransactions << trx.hash if trx.currentIndex == 0
157
+ end
158
+
159
+ finalBundles = []
160
+ tailTransactions = tailTransactions.uniq
161
+ tailTxStates = []
162
+
163
+ # If inclusionStates, get the confirmation status of the tail transactions, and thus the bundles
164
+ if inclusionStates && tailTransactions.length > 0
165
+ getLatestInclusion(tailTransactions) do |st2, states|
166
+ # If error, return it to original caller
167
+ if !status
168
+ return sendData(false, states, &callback)
169
+ end
170
+
171
+ tailTxStates = states
172
+ end
173
+ end
174
+
175
+ tailTransactions.each do |tailTx|
176
+ getBundle(tailTx) do |st2, bundleTransactions|
177
+ if st2
178
+ if inclusionStates
179
+ thisInclusion = tailTxStates[tailTransactions.index(tailTx)]
180
+
181
+ bundleTransactions.each do |bundleTx|
182
+ bundleTx.persistence = thisInclusion
183
+ end
184
+ end
185
+
186
+ finalBundles << IOTA::Models::Bundle.new(bundleTransactions)
187
+ end
188
+ end
189
+ end
190
+ # Sort bundles by attachmentTimestamp
191
+ finalBundles = finalBundles.sort{|a, b| a.attachmentTimestamp <=> b.attachmentTimestamp}
192
+ return sendData(true, finalBundles, &callback)
193
+ end
194
+ end
195
+ end
196
+
197
+ def getBundle(transaction, &callback)
198
+ # Check if correct hash
199
+ if !@validator.isHash(transaction)
200
+ return sendData(false, "Invalid transaction input provided", &callback)
201
+ end
202
+
203
+ # Initiate traverseBundle
204
+ traverseBundle(transaction, nil, []) do |status, bundle|
205
+ if !status
206
+ return sendData(false, bundle, &callback)
207
+ end
208
+
209
+ if !@utils.isBundle(bundle)
210
+ return sendData(false, "Invalid Bundle provided", &callback)
211
+ end
212
+
213
+ return sendData(true, bundle, &callback)
214
+ end
215
+ end
216
+
217
+ # Replays or promote transactions based on tail consistency
218
+ def replayBundle(tail, depth, minWeightMagnitude, forcedReplay = false, &callback)
219
+ # Check if correct tail hash
220
+ if !@validator.isHash(tail)
221
+ return sendData(false, "Invalid trytes provided", &callback)
222
+ end
223
+
224
+ # Check if correct depth and minWeightMagnitude
225
+ if !@validator.isValue(depth) || !@validator.isValue(minWeightMagnitude)
226
+ return sendData(false, "Invalid inputs provided", &callback)
227
+ end
228
+
229
+ isPromotable = false
230
+ if !forcedReplay
231
+ checkConsistency([tail]) do |status, isConsistent|
232
+ isPromotable = status && isConsistent
233
+ end
234
+ end
235
+
236
+ getBundle(tail) do |status, transactions|
237
+ if !status
238
+ return sendData(false, transactions, &callback)
239
+ end
240
+
241
+ if !isPromotable
242
+ bundleTrytes = []
243
+ transactions.each do |trx|
244
+ bundleTrytes << @utils.transactionTrytes(trx);
245
+ end
246
+
247
+ return sendTrytes(bundleTrytes.reverse, depth, minWeightMagnitude, &callback)
248
+ else
249
+ account = IOTA::Models::Account.new(nil, transactions.first.address, self, @validator, @utils)
250
+
251
+ transfers = [{
252
+ address: '9' * 81,
253
+ value: 0,
254
+ message: '',
255
+ tag: ''
256
+ }]
257
+
258
+ begin
259
+ account.sendTransfer(depth, minWeightMagnitude, transfers, { reference: tail })
260
+ return sendData(status, transactions, &callback)
261
+ rescue => e
262
+ return sendData(false, e.message, &callback)
263
+ end
264
+ end
265
+ end
266
+ end
267
+
268
+ def broadcastBundle(tail, &callback)
269
+ # Check if correct tail hash
270
+ if !@validator.isHash(tail)
271
+ return sendData(false, "Invalid trytes provided", &callback)
272
+ end
273
+
274
+ getBundle(tail) do |status, transactions|
275
+ if !status
276
+ return sendData(false, transactions, &callback)
277
+ end
278
+
279
+ bundleTrytes = []
280
+ transactions.each do |trx|
281
+ bundleTrytes << @utils.transactionTrytes(trx);
282
+ end
283
+
284
+ return broadcastTransactions(bundleTrytes.reverse, &callback)
285
+ end
286
+ end
287
+
288
+ def traverseBundle(trunkTx, bundleHash, bundle, &callback)
289
+ # Get trytes of transaction hash
290
+ getTrytes([trunkTx]) do |status, trytesList|
291
+ if !status
292
+ return sendData(false, trytesList, &callback)
293
+ end
294
+
295
+ trytes = trytesList[0]
296
+
297
+ if !trytes
298
+ return sendData(false, "Bundle transactions not visible", &callback)
299
+ end
300
+
301
+ # get the transaction object
302
+ txObject = @utils.transactionObject(trytes)
303
+
304
+ if !trytes
305
+ return sendData(false, "Invalid trytes, could not create object", &callback)
306
+ end
307
+
308
+ # If first transaction to search is not a tail, return error
309
+ if !bundleHash && txObject.currentIndex != 0
310
+ return sendData(false, "Invalid tail transaction supplied", &callback)
311
+ end
312
+
313
+ # If no bundle hash, define it
314
+ if !bundleHash
315
+ bundleHash = txObject.bundle
316
+ end
317
+
318
+ # If different bundle hash, return with bundle
319
+ if bundleHash != txObject.bundle
320
+ return sendData(true, bundle, &callback)
321
+ end
322
+
323
+ # If only one bundle element, return
324
+ if txObject.lastIndex == 0 && txObject.currentIndex == 0
325
+ return sendData(true, [txObject], &callback)
326
+ end
327
+
328
+ # Define new trunkTransaction for search
329
+ trunkTx = txObject.trunkTransaction
330
+
331
+ # Add transaction object to bundle
332
+ bundle << txObject
333
+
334
+ # Continue traversing with new trunkTx
335
+ return traverseBundle(trunkTx, bundleHash, bundle, &callback)
336
+ end
337
+ end
338
+
339
+ def isReattachable(inputAddresses, &callback)
340
+ # if string provided, make array
341
+ inputAddresses = [inputAddresses] if @validator.isString(inputAddresses)
342
+
343
+ # Categorized value transactions
344
+ # hash -> txarray map
345
+ addressTxsMap = {}
346
+ addresses = []
347
+
348
+ inputAddresses.each do |address|
349
+ if !@validator.isAddress(address)
350
+ return sendData(false, "Invalid inputs provided", &callback)
351
+ end
352
+
353
+ address = @utils.noChecksum(address)
354
+
355
+ addressTxsMap[address] = []
356
+ addresses << address
357
+ end
358
+
359
+ findTransactionObjects(addresses: addresses) do |status, transactions|
360
+ if !status
361
+ return sendData(false, transactions, &callback)
362
+ end
363
+
364
+ valueTransactions = []
365
+
366
+ transactions.each do |trx|
367
+ if trx.value < 0
368
+ txAddress = trx.address
369
+ txHash = trx.hash
370
+
371
+ addressTxsMap[txAddress] << txHash
372
+ valueTransactions << txHash
373
+ end
374
+ end
375
+
376
+ if valueTransactions.length > 0
377
+ # get the includion states of all the transactions
378
+ getLatestInclusion(valueTransactions) do |st1, inclusionStates|
379
+ if !st1
380
+ return sendData(false, inclusionStates, &callback)
381
+ end
382
+
383
+ # bool array
384
+ results = addresses.map do |address|
385
+ txs = addressTxsMap[address]
386
+ numTxs = txs.length
387
+
388
+ if numTxs == 0
389
+ true
390
+ else
391
+ shouldReattach = true
392
+
393
+ (0...numTxs).step(1) do |i|
394
+ tx = txs[i]
395
+ txIndex = valueTransactions.index(tx)
396
+ isConfirmed = inclusionStates[txIndex]
397
+ shouldReattach = isConfirmed ? false : true
398
+ break if isConfirmed
399
+ end
400
+
401
+ shouldReattach
402
+ end
403
+ end
404
+
405
+ # If only one entry, return first
406
+ results = results.first if results.length == 1
407
+
408
+ return sendData(true, results, &callback)
409
+ end
410
+ else
411
+ results = [];
412
+ numAddresses = addresses.length;
413
+
414
+ # prepare results array if multiple addresses
415
+ if numAddresses > 1
416
+ numAddresses.each do |i|
417
+ results << true
418
+ end
419
+ else
420
+ results = true
421
+ end
422
+
423
+ return sendData(true, results, &callback)
424
+ end
425
+ end
426
+ end
427
+ end
428
+ end
429
+ end