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.
- checksums.yaml +7 -0
- data/.editorconfig +8 -0
- data/.gitignore +15 -0
- data/.travis.yml +24 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +121 -0
- data/Rakefile +36 -0
- data/bin/iota-console +15 -0
- data/examples/multisig.rb +69 -0
- data/ext/ccurl/ccurl.c +134 -0
- data/ext/ccurl/extconf.rb +22 -0
- data/ext/jcurl/JCurl.java +126 -0
- data/ext/jcurl/JCurlService.java +36 -0
- data/ext/pow/ccurl-0.3.0.dll +0 -0
- data/ext/pow/libccurl-0.3.0.dylib +0 -0
- data/ext/pow/libccurl-0.3.0.so +0 -0
- data/iota-ruby.gemspec +37 -0
- data/lib/iota.rb +76 -0
- data/lib/iota/api/api.rb +251 -0
- data/lib/iota/api/commands.rb +113 -0
- data/lib/iota/api/transport.rb +43 -0
- data/lib/iota/api/wrappers.rb +429 -0
- data/lib/iota/crypto/bundle.rb +163 -0
- data/lib/iota/crypto/converter.rb +244 -0
- data/lib/iota/crypto/curl.rb +18 -0
- data/lib/iota/crypto/curl_c.rb +17 -0
- data/lib/iota/crypto/curl_java.rb +18 -0
- data/lib/iota/crypto/curl_ruby.rb +70 -0
- data/lib/iota/crypto/hmac.rb +27 -0
- data/lib/iota/crypto/kerl.rb +82 -0
- data/lib/iota/crypto/pow_provider.rb +27 -0
- data/lib/iota/crypto/private_key.rb +80 -0
- data/lib/iota/crypto/sha3_ruby.rb +122 -0
- data/lib/iota/crypto/signing.rb +97 -0
- data/lib/iota/models/account.rb +489 -0
- data/lib/iota/models/base.rb +13 -0
- data/lib/iota/models/bundle.rb +87 -0
- data/lib/iota/models/input.rb +38 -0
- data/lib/iota/models/seed.rb +33 -0
- data/lib/iota/models/transaction.rb +52 -0
- data/lib/iota/models/transfer.rb +44 -0
- data/lib/iota/multisig/address.rb +41 -0
- data/lib/iota/multisig/multisig.rb +244 -0
- data/lib/iota/utils/ascii.rb +50 -0
- data/lib/iota/utils/broker.rb +124 -0
- data/lib/iota/utils/input_validator.rb +149 -0
- data/lib/iota/utils/object_validator.rb +34 -0
- data/lib/iota/utils/utils.rb +324 -0
- data/lib/iota/version.rb +3 -0
- data/lib/jcurl.jar +0 -0
- data/lib/patch.rb +17 -0
- data/test/ascii_test.rb +114 -0
- data/test/curl_c_test.rb +31 -0
- data/test/curl_java_test.rb +31 -0
- data/test/curl_ruby_test.rb +27 -0
- data/test/kerl_test.rb +52 -0
- data/test/pow_provider_test.rb +36 -0
- data/test/sha3_test.rb +71 -0
- data/test/test_helper.rb +4 -0
- data/test/utils_test.rb +179 -0
- metadata +183 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
can_compile_extensions = false
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'mkmf'
|
5
|
+
can_compile_extensions = true
|
6
|
+
rescue Exception
|
7
|
+
# This will appear only in verbose mode.
|
8
|
+
$stderr.puts "Could not require 'mkmf'. Not fatal, the extensions are optional."
|
9
|
+
end
|
10
|
+
|
11
|
+
if can_compile_extensions && have_header('ruby.h')
|
12
|
+
extension_name = 'ccurl'
|
13
|
+
dir_config(extension_name) # The destination
|
14
|
+
create_makefile(extension_name) # Create Makefile
|
15
|
+
else
|
16
|
+
# Create a dummy Makefile, to satisfy Gem::Installer#install
|
17
|
+
mfile = open("Makefile", "wb")
|
18
|
+
mfile.puts '.PHONY: install'
|
19
|
+
mfile.puts 'install:'
|
20
|
+
mfile.puts "\t" + '@echo "Extensions not installed, falling back to pure Ruby version."'
|
21
|
+
mfile.close
|
22
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
package com.vmarakana;
|
2
|
+
|
3
|
+
import java.util.Arrays;
|
4
|
+
|
5
|
+
import org.jruby.Ruby;
|
6
|
+
import org.jruby.RubyArray;
|
7
|
+
import org.jruby.RubyClass;
|
8
|
+
import org.jruby.RubyInteger;
|
9
|
+
import org.jruby.RubyNil;
|
10
|
+
import org.jruby.RubyObject;
|
11
|
+
import org.jruby.anno.JRubyMethod;
|
12
|
+
import org.jruby.runtime.ThreadContext;
|
13
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
14
|
+
|
15
|
+
public class JCurl extends RubyObject {
|
16
|
+
/**
|
17
|
+
* The hash length.
|
18
|
+
*/
|
19
|
+
public static final int HASH_LENGTH = 243;
|
20
|
+
private static final int STATE_LENGTH = 3 * HASH_LENGTH;
|
21
|
+
|
22
|
+
public static final int NUMBER_OF_ROUNDS = 81;
|
23
|
+
private int numberOfRounds;
|
24
|
+
|
25
|
+
private static final int[] TRUTH_TABLE = {1, 0, -1, 2, 1, -1, 0, 2, -1, 1, 0};
|
26
|
+
private final int[] scratchpad = new int[STATE_LENGTH];
|
27
|
+
private int[] state;
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Java constructor
|
31
|
+
* @param ruby Ruby
|
32
|
+
* @param metaclass RubyClass
|
33
|
+
*/
|
34
|
+
public JCurl(Ruby ruby, RubyClass rubyClass) {
|
35
|
+
super(ruby, rubyClass);
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
*
|
40
|
+
* @param context ThreadContext
|
41
|
+
* @param klass IRubyObject
|
42
|
+
* @param args optional (no args rounds = NUMBER_OF_ROUNDS)
|
43
|
+
* @return new Vec3 object (ruby)
|
44
|
+
*/
|
45
|
+
@JRubyMethod(name = "new", meta = true, rest = true)
|
46
|
+
public static IRubyObject rbNew(ThreadContext context, IRubyObject klass, IRubyObject... args) {
|
47
|
+
JCurl jcurl = (JCurl) ((RubyClass) klass).allocate();
|
48
|
+
jcurl.init(context, args);
|
49
|
+
return jcurl;
|
50
|
+
}
|
51
|
+
|
52
|
+
// This method is internal and not exposed
|
53
|
+
private IRubyObject init(ThreadContext context, IRubyObject... args) {
|
54
|
+
state = new int[STATE_LENGTH];
|
55
|
+
|
56
|
+
// Set rounds
|
57
|
+
if (args.length > 0 && args[0] instanceof RubyInteger) {
|
58
|
+
numberOfRounds = ((RubyInteger) args[0]).getIntValue();
|
59
|
+
} else {
|
60
|
+
numberOfRounds = NUMBER_OF_ROUNDS;
|
61
|
+
}
|
62
|
+
|
63
|
+
return new RubyNil(context.runtime);
|
64
|
+
}
|
65
|
+
|
66
|
+
@JRubyMethod
|
67
|
+
public IRubyObject transform(ThreadContext context) {
|
68
|
+
int scratchpadIndex = 0;
|
69
|
+
int prev_scratchpadIndex = 0;
|
70
|
+
for (int round = 0; round < numberOfRounds; round++) {
|
71
|
+
System.arraycopy(state, 0, scratchpad, 0, STATE_LENGTH);
|
72
|
+
for (int stateIndex = 0; stateIndex < STATE_LENGTH; stateIndex++) {
|
73
|
+
prev_scratchpadIndex = scratchpadIndex;
|
74
|
+
if (scratchpadIndex < 365) {
|
75
|
+
scratchpadIndex += 364;
|
76
|
+
} else {
|
77
|
+
scratchpadIndex += -365;
|
78
|
+
}
|
79
|
+
state[stateIndex] = TRUTH_TABLE[scratchpad[prev_scratchpadIndex] + (scratchpad[scratchpadIndex] << 2) + 5];
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
return new RubyNil(context.runtime);
|
84
|
+
}
|
85
|
+
|
86
|
+
@JRubyMethod
|
87
|
+
public IRubyObject absorb(ThreadContext context, final IRubyObject trits) {
|
88
|
+
int offset = 0;
|
89
|
+
int length = ((RubyArray) trits).getLength();
|
90
|
+
|
91
|
+
do {
|
92
|
+
System.arraycopy(trits.toJava(int[].class), offset, state, 0, length < HASH_LENGTH ? length : HASH_LENGTH);
|
93
|
+
transform(context);
|
94
|
+
offset += HASH_LENGTH;
|
95
|
+
} while ((length -= HASH_LENGTH) > 0);
|
96
|
+
|
97
|
+
return new RubyNil(context.runtime);
|
98
|
+
}
|
99
|
+
|
100
|
+
@JRubyMethod
|
101
|
+
public RubyNil squeeze(ThreadContext context, final IRubyObject trits) {
|
102
|
+
int offset = 0;
|
103
|
+
int length = ((RubyArray) trits).getLength();
|
104
|
+
|
105
|
+
do {
|
106
|
+
for(; length < HASH_LENGTH; length++) {
|
107
|
+
((RubyArray) trits).append(context.runtime.newFixnum(0));
|
108
|
+
}
|
109
|
+
|
110
|
+
for (int i = 0; i < HASH_LENGTH; i++) {
|
111
|
+
((RubyArray) trits).store(i, context.runtime.newFixnum(state[i]));
|
112
|
+
}
|
113
|
+
|
114
|
+
transform(context);
|
115
|
+
offset += HASH_LENGTH;
|
116
|
+
} while ((length -= HASH_LENGTH) > 0);
|
117
|
+
|
118
|
+
return new RubyNil(context.runtime);
|
119
|
+
}
|
120
|
+
|
121
|
+
@JRubyMethod
|
122
|
+
public IRubyObject reset(ThreadContext context) {
|
123
|
+
Arrays.fill(state, 0);
|
124
|
+
return new RubyNil(context.runtime);
|
125
|
+
}
|
126
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
package com.vmarakana;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
|
5
|
+
import org.jruby.Ruby;
|
6
|
+
import org.jruby.RubyClass;
|
7
|
+
import org.jruby.RubyModule;
|
8
|
+
import org.jruby.runtime.ObjectAllocator;
|
9
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
10
|
+
import org.jruby.runtime.load.BasicLibraryService;
|
11
|
+
|
12
|
+
public class JCurlService implements BasicLibraryService {
|
13
|
+
private Ruby runtime;
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Basic load method of the BasicLibraryService, this method is
|
17
|
+
* invoked when the ruby code does the related require call.
|
18
|
+
* @param ruby An instance of the JRuby runtime.
|
19
|
+
* @return boolean True if everything was successful, false otherwise.
|
20
|
+
* @throws IOException is required to match the BasicLibraryService signature
|
21
|
+
*/
|
22
|
+
|
23
|
+
@Override
|
24
|
+
public boolean basicLoad(final Ruby ruby) throws IOException {
|
25
|
+
RubyModule iota = ruby.defineModule("IOTA");
|
26
|
+
RubyModule crypto = iota.defineModuleUnder("Crypto");
|
27
|
+
RubyClass jcurl = crypto.defineClassUnder("JCurl", ruby.getObject(), new ObjectAllocator() {
|
28
|
+
public IRubyObject allocate(Ruby ruby1, RubyClass rubyClass) {
|
29
|
+
return new JCurl(ruby1, rubyClass);
|
30
|
+
}
|
31
|
+
});
|
32
|
+
|
33
|
+
jcurl.defineAnnotatedMethods(JCurl.class);
|
34
|
+
return true;
|
35
|
+
}
|
36
|
+
}
|
Binary file
|
Binary file
|
Binary file
|
data/iota-ruby.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "iota/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "iota-ruby"
|
8
|
+
spec.version = IOTA::VERSION
|
9
|
+
spec.authors = ["Vivek Marakana"]
|
10
|
+
spec.email = ["vivek.marakana@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "IOTA API wrapper for Ruby"
|
13
|
+
spec.description = "Ruby gem for the IOTA core"
|
14
|
+
spec.homepage = "https://github.com/vivekmarakana/iota.lib.rb"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split("\n") - [ "lib/jcurl.jar"]
|
17
|
+
spec.test_files = `git ls-files -- test/*`.split("\n")
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
if RUBY_PLATFORM =~ /java/
|
21
|
+
spec.platform = "java"
|
22
|
+
spec.files << "lib/jcurl.jar"
|
23
|
+
else
|
24
|
+
spec.extensions = ["ext/ccurl/extconf.rb"]
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", ">= 1.15"
|
28
|
+
spec.add_development_dependency "rake", ">= 10.0"
|
29
|
+
spec.add_development_dependency "minitest", ">= 5.0"
|
30
|
+
spec.add_development_dependency "rake-compiler", ">= 1.0.4"
|
31
|
+
|
32
|
+
unless RUBY_PLATFORM =~ /java/
|
33
|
+
spec.add_runtime_dependency "digest-sha3", "~> 1.1"
|
34
|
+
end
|
35
|
+
|
36
|
+
spec.add_runtime_dependency "ffi", "~> 1.9.25"
|
37
|
+
end
|
data/lib/iota.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require "patch"
|
2
|
+
require "iota/version"
|
3
|
+
|
4
|
+
require "iota/utils/input_validator"
|
5
|
+
require "iota/utils/object_validator"
|
6
|
+
require "iota/utils/ascii"
|
7
|
+
require "iota/utils/utils"
|
8
|
+
require "iota/utils/broker"
|
9
|
+
|
10
|
+
require "iota/api/commands"
|
11
|
+
require "iota/api/wrappers"
|
12
|
+
require "iota/api/transport"
|
13
|
+
require "iota/api/api"
|
14
|
+
|
15
|
+
require "iota/crypto/pow_provider"
|
16
|
+
require "iota/crypto/curl"
|
17
|
+
require "iota/crypto/kerl"
|
18
|
+
require "iota/crypto/converter"
|
19
|
+
require "iota/crypto/bundle"
|
20
|
+
require "iota/crypto/signing"
|
21
|
+
require "iota/crypto/hmac"
|
22
|
+
require "iota/crypto/private_key"
|
23
|
+
|
24
|
+
require "iota/multisig/address"
|
25
|
+
require "iota/multisig/multisig"
|
26
|
+
|
27
|
+
require "iota/models/base"
|
28
|
+
require "iota/models/input"
|
29
|
+
require "iota/models/transfer"
|
30
|
+
require "iota/models/seed"
|
31
|
+
require "iota/models/transaction"
|
32
|
+
require "iota/models/bundle"
|
33
|
+
require "iota/models/account"
|
34
|
+
|
35
|
+
module IOTA
|
36
|
+
class Client
|
37
|
+
attr_reader :version, :host, :port, :provider, :sandbox, :token, :broker, :api, :utils, :validator, :multisig, :batch_size
|
38
|
+
|
39
|
+
def initialize(settings = {})
|
40
|
+
setSettings(settings)
|
41
|
+
@utils = IOTA::Utils::Utils.new
|
42
|
+
@validator = @utils.validator
|
43
|
+
@multisig = IOTA::Multisig::Multisig.new(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
def changeNode(settings = {})
|
47
|
+
setSettings(settings)
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def setSettings(settings)
|
53
|
+
settings = symbolize_keys(settings)
|
54
|
+
@host = settings[:host] ? settings[:host] : "http://localhost"
|
55
|
+
@port = settings[:port] ? settings[:port] : 14265
|
56
|
+
@provider = settings[:provider] || @host.gsub(/\/$/, '') + ":" + @port.to_s
|
57
|
+
@sandbox = settings[:sandbox] || false
|
58
|
+
@token = settings[:token] || false
|
59
|
+
@timeout = settings[:timeout] || 120
|
60
|
+
@batch_size = settings[:batch_size] || 500
|
61
|
+
@local_pow = settings[:local_pow] || false
|
62
|
+
|
63
|
+
if @sandbox
|
64
|
+
@sandbox = @provider.gsub(/\/$/, '')
|
65
|
+
@provider = @sandbox + '/commands'
|
66
|
+
end
|
67
|
+
|
68
|
+
@broker = IOTA::Utils::Broker.new(@provider, @token, @timeout, user: settings[:user], password: settings[:password])
|
69
|
+
@api = IOTA::API::Api.new(@broker, @sandbox, @batch_size, @local_pow)
|
70
|
+
end
|
71
|
+
|
72
|
+
def symbolize_keys(hash)
|
73
|
+
hash.inject({}){ |h,(k,v)| h[k.to_sym] = v; h }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/iota/api/api.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
module IOTA
|
2
|
+
module API
|
3
|
+
class Api
|
4
|
+
include Wrappers
|
5
|
+
include Transport
|
6
|
+
|
7
|
+
attr_reader :pow_provider
|
8
|
+
|
9
|
+
def initialize(broker, sandbox, batch_size = 500, local_pow = false)
|
10
|
+
@broker = broker
|
11
|
+
@sandbox = sandbox
|
12
|
+
@commands = Commands.new
|
13
|
+
@utils = IOTA::Utils::Utils.new
|
14
|
+
@validator = @utils.validator
|
15
|
+
@batch_size = batch_size
|
16
|
+
@pow_provider = local_pow ? IOTA::Crypto::PowProvider.new : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def findTransactions(searchValues, &callback)
|
20
|
+
if !@validator.isObject(searchValues)
|
21
|
+
return sendData(false, "You have provided an invalid key value", &callback)
|
22
|
+
end
|
23
|
+
|
24
|
+
searchKeys = searchValues.keys
|
25
|
+
validKeys = ['bundles', 'addresses', 'tags', 'approvees']
|
26
|
+
|
27
|
+
error = false
|
28
|
+
entry_count = 0
|
29
|
+
|
30
|
+
searchKeys.each do |key|
|
31
|
+
if !validKeys.include?(key.to_s)
|
32
|
+
error = "You have provided an invalid key value"
|
33
|
+
break
|
34
|
+
end
|
35
|
+
|
36
|
+
hashes = searchValues[key]
|
37
|
+
entry_count += hashes.count
|
38
|
+
|
39
|
+
if key.to_s == 'addresses'
|
40
|
+
searchValues[key] = hashes.map do |address|
|
41
|
+
@utils.noChecksum(address)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# If tags, append to 27 trytes
|
46
|
+
if key.to_s == 'tags'
|
47
|
+
searchValues[key] = hashes.map do |hash|
|
48
|
+
# Simple padding to 27 trytes
|
49
|
+
while hash.length < 27
|
50
|
+
hash += '9'
|
51
|
+
end
|
52
|
+
# validate hash
|
53
|
+
if !@validator.isTrytes(hash, 27)
|
54
|
+
error = "Invalid Trytes provided"
|
55
|
+
break
|
56
|
+
end
|
57
|
+
|
58
|
+
hash
|
59
|
+
end
|
60
|
+
else
|
61
|
+
# Check if correct array of hashes
|
62
|
+
if !@validator.isArrayOfHashes(hashes)
|
63
|
+
error = "Invalid Trytes provided"
|
64
|
+
break
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if error
|
70
|
+
return sendData(false, error, &callback)
|
71
|
+
else
|
72
|
+
if entry_count <= @batch_size || searchKeys.count > 1
|
73
|
+
return sendCommand(@commands.findTransactions(searchValues), &callback)
|
74
|
+
else
|
75
|
+
return sendBatchedCommand(@commands.findTransactions(searchValues), &callback)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def getBalances(addresses, threshold, &callback)
|
81
|
+
if !@validator.isArrayOfHashes(addresses)
|
82
|
+
return sendData(false, "Invalid Trytes provided", &callback)
|
83
|
+
end
|
84
|
+
|
85
|
+
command = @commands.getBalances(addresses.map{|address| @utils.noChecksum(address)}, threshold)
|
86
|
+
sendBatchedCommand(command, &callback)
|
87
|
+
end
|
88
|
+
|
89
|
+
def getTrytes(hashes, &callback)
|
90
|
+
if !@validator.isArrayOfHashes(hashes)
|
91
|
+
return sendData(false, "Invalid Trytes provided", &callback)
|
92
|
+
end
|
93
|
+
|
94
|
+
sendBatchedCommand(@commands.getTrytes(hashes), &callback)
|
95
|
+
end
|
96
|
+
|
97
|
+
def getInclusionStates(transactions, tips, &callback)
|
98
|
+
if !@validator.isArrayOfHashes(transactions) || !@validator.isArrayOfHashes(tips)
|
99
|
+
return sendData(false, "Invalid Trytes provided", &callback)
|
100
|
+
end
|
101
|
+
|
102
|
+
sendBatchedCommand(@commands.getInclusionStates(transactions, tips), &callback)
|
103
|
+
end
|
104
|
+
|
105
|
+
def getNodeInfo(&callback)
|
106
|
+
sendCommand(@commands.getNodeInfo, &callback)
|
107
|
+
end
|
108
|
+
|
109
|
+
def getNeighbors(&callback)
|
110
|
+
sendCommand(@commands.getNeighbors, &callback)
|
111
|
+
end
|
112
|
+
|
113
|
+
def addNeighbors(uris, &callback)
|
114
|
+
(0...uris.length).step(1) do |i|
|
115
|
+
return sendData(false, "You have provided an invalid URI for your Neighbor: " + uris[i], &callback) if !@validator.isUri(uris[i])
|
116
|
+
end
|
117
|
+
|
118
|
+
sendCommand(@commands.addNeighbors(uris), &callback)
|
119
|
+
end
|
120
|
+
|
121
|
+
def removeNeighbors(uris, &callback)
|
122
|
+
(0...uris.length).step(1) do |i|
|
123
|
+
return sendData(false, "You have provided an invalid URI for your Neighbor: " + uris[i], &callback) if !@validator.isUri(uris[i])
|
124
|
+
end
|
125
|
+
|
126
|
+
sendCommand(@commands.removeNeighbors(uris), &callback)
|
127
|
+
end
|
128
|
+
|
129
|
+
def getTips(&callback)
|
130
|
+
sendCommand(@commands.getTips, &callback)
|
131
|
+
end
|
132
|
+
|
133
|
+
def getTransactionsToApprove(depth, reference = nil, &callback)
|
134
|
+
# Check if correct depth
|
135
|
+
if !@validator.isValue(depth)
|
136
|
+
return sendData(false, "Invalid inputs provided", &callback)
|
137
|
+
end
|
138
|
+
|
139
|
+
sendCommand(@commands.getTransactionsToApprove(depth, reference), &callback)
|
140
|
+
end
|
141
|
+
|
142
|
+
def attachToTangle(trunkTransaction, branchTransaction, minWeightMagnitude, trytes, &callback)
|
143
|
+
# Check if correct trunk
|
144
|
+
if !@validator.isHash(trunkTransaction)
|
145
|
+
return sendData(false, "You have provided an invalid hash as a trunk: #{trunkTransaction}", &callback)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Check if correct branch
|
149
|
+
if !@validator.isHash(branchTransaction)
|
150
|
+
return sendData(false, "You have provided an invalid hash as a branch: #{branchTransaction}", &callback)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Check if minweight is integer
|
154
|
+
if !@validator.isValue(minWeightMagnitude)
|
155
|
+
return sendData(false, "Invalid minWeightMagnitude provided", &callback)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Check if array of trytes
|
159
|
+
if !@validator.isArrayOfTrytes(trytes)
|
160
|
+
return sendData(false, "Invalid Trytes provided", &callback)
|
161
|
+
end
|
162
|
+
|
163
|
+
if @pow_provider.nil?
|
164
|
+
command = @commands.attachToTangle(trunkTransaction, branchTransaction, minWeightMagnitude, trytes)
|
165
|
+
|
166
|
+
sendCommand(command, &callback)
|
167
|
+
else
|
168
|
+
previousTxHash = nil
|
169
|
+
finalBundleTrytes = []
|
170
|
+
|
171
|
+
trytes.each do |current_trytes|
|
172
|
+
txObject = @utils.transactionObject(current_trytes)
|
173
|
+
|
174
|
+
if !previousTxHash
|
175
|
+
if txObject.lastIndex != txObject.currentIndex
|
176
|
+
return sendData(false, "Wrong bundle order. The bundle should be ordered in descending order from currentIndex", &callback)
|
177
|
+
end
|
178
|
+
|
179
|
+
txObject.trunkTransaction = trunkTransaction
|
180
|
+
txObject.branchTransaction = branchTransaction
|
181
|
+
else
|
182
|
+
txObject.trunkTransaction = previousTxHash
|
183
|
+
txObject.branchTransaction = trunkTransaction
|
184
|
+
end
|
185
|
+
|
186
|
+
txObject.attachmentTimestamp = (Time.now.to_f * 1000).to_i
|
187
|
+
txObject.attachmentTimestampLowerBound = 0
|
188
|
+
txObject.attachmentTimestampUpperBound = (3**27 - 1) / 2
|
189
|
+
|
190
|
+
newTrytes = @utils.transactionTrytes(txObject)
|
191
|
+
|
192
|
+
begin
|
193
|
+
returnedTrytes = @pow_provider.pow(newTrytes, minWeightMagnitude)
|
194
|
+
|
195
|
+
newTxObject= @utils.transactionObject(returnedTrytes)
|
196
|
+
previousTxHash = newTxObject.hash
|
197
|
+
|
198
|
+
finalBundleTrytes << returnedTrytes
|
199
|
+
rescue => e
|
200
|
+
return sendData(false, e.message, &callback)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
sendData(true, finalBundleTrytes, &callback)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def interruptAttachingToTangle(&callback)
|
209
|
+
sendCommand(@commands.interruptAttachingToTangle, &callback)
|
210
|
+
end
|
211
|
+
|
212
|
+
def broadcastTransactions(trytes, &callback)
|
213
|
+
if !@validator.isArrayOfAttachedTrytes(trytes)
|
214
|
+
return sendData(false, "Invalid attached Trytes provided", &callback)
|
215
|
+
end
|
216
|
+
|
217
|
+
sendCommand(@commands.broadcastTransactions(trytes), &callback)
|
218
|
+
end
|
219
|
+
|
220
|
+
def storeTransactions(trytes, &callback)
|
221
|
+
if !@validator.isArrayOfAttachedTrytes(trytes)
|
222
|
+
return sendData(false, "Invalid attached Trytes provided", &callback)
|
223
|
+
end
|
224
|
+
|
225
|
+
sendCommand(@commands.storeTransactions(trytes), &callback)
|
226
|
+
end
|
227
|
+
|
228
|
+
def checkConsistency(tails, &callback)
|
229
|
+
if !@validator.isArrayOfHashes(tails)
|
230
|
+
return sendData(false, "Invalid tails provided", &callback)
|
231
|
+
end
|
232
|
+
|
233
|
+
sendCommand(@commands.checkConsistency(tails), &callback)
|
234
|
+
end
|
235
|
+
|
236
|
+
def wereAddressesSpentFrom(addresses, &callback)
|
237
|
+
if !@validator.isArrayOfHashes(addresses)
|
238
|
+
return sendData(false, "Invalid Trytes provided", &callback)
|
239
|
+
end
|
240
|
+
|
241
|
+
command = @commands.wereAddressesSpentFrom(addresses.map{|address| @utils.noChecksum(address)})
|
242
|
+
sendBatchedCommand(command, &callback)
|
243
|
+
end
|
244
|
+
|
245
|
+
private
|
246
|
+
def sendData(status, data, &callback)
|
247
|
+
callback ? callback.call(status, data) : [status, data]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|