stellar_core_commander 0.0.9 → 0.0.10
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 +4 -4
- data/Gemfile +1 -1
- data/bin/scc +22 -6
- data/examples/allow_trust.rb +3 -3
- data/examples/cross_host_simple_payment.rb +19 -0
- data/examples/merge_account.rb +7 -0
- data/examples/multi_host_simple_payment.rb +19 -0
- data/examples/trade.rb +2 -0
- data/lib/stellar_core_commander/commander.rb +33 -7
- data/lib/stellar_core_commander/docker_process.rb +48 -22
- data/lib/stellar_core_commander/local_process.rb +27 -20
- data/lib/stellar_core_commander/operation_builder.rb +66 -3
- data/lib/stellar_core_commander/process.rb +97 -24
- data/lib/stellar_core_commander/transactor.rb +90 -17
- data/lib/stellar_core_commander/version.rb +1 -1
- data/stellar_core_commander.gemspec +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd2f67696affdaab450d32a5f0af66983a30c4bf
|
4
|
+
data.tar.gz: a1c96602fc57defdc5bc288ee2e1d3edcbb05ca2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 754f6d203d4d406fc446ff8975ef964c2cfc14cea19824f4d8773d92a468dc1a01f5930f1ba091556187f0ffa2f8d35f038c50edb2bc661b1365c20453bb5b8b
|
7
|
+
data.tar.gz: 78f2b8bf586722d6fa1f882c638b627c1b0ba9569a8a1dca823b22ab8b716e5bc4a1fc701a9894e61d1c5f9bf7d9a929d6675c1beb6f83cd24629a6416ef481b
|
data/Gemfile
CHANGED
data/bin/scc
CHANGED
@@ -4,13 +4,23 @@ require 'stellar_core_commander'
|
|
4
4
|
require 'slop'
|
5
5
|
|
6
6
|
def run
|
7
|
-
$opts = Slop.parse do
|
7
|
+
$opts = Slop.parse(ARGV, :help => true) do
|
8
8
|
banner 'Usage: scc -r RECIPE'
|
9
9
|
|
10
|
-
on 'stellar-core-bin',
|
11
|
-
|
12
|
-
|
13
|
-
on '
|
10
|
+
on 'stellar-core-bin',
|
11
|
+
'a path to a stellar-core executable (defaults to `which stellar-core`)',
|
12
|
+
argument: true
|
13
|
+
on 'r', 'recipe',
|
14
|
+
'a recipe file',
|
15
|
+
argument: true
|
16
|
+
on 'p', 'process',
|
17
|
+
'method for running stellar-core',
|
18
|
+
argument: true,
|
19
|
+
default: 'local'
|
20
|
+
on 'w', 'wait',
|
21
|
+
'wait for TERM signal before shutting down and cleaning up',
|
22
|
+
argument: false,
|
23
|
+
default: false
|
14
24
|
end
|
15
25
|
|
16
26
|
recipe = load_recipe
|
@@ -23,7 +33,13 @@ def run
|
|
23
33
|
transactor.run_recipe recipe
|
24
34
|
transactor.close_ledger
|
25
35
|
|
26
|
-
output_results(transactor
|
36
|
+
output_results(commander.get_root_process transactor)
|
37
|
+
|
38
|
+
if $opts[:wait]
|
39
|
+
puts "Waiting for INT signal..."
|
40
|
+
Signal.trap("INT"){ exit }
|
41
|
+
sleep
|
42
|
+
end
|
27
43
|
end
|
28
44
|
|
29
45
|
|
data/examples/allow_trust.rb
CHANGED
@@ -2,9 +2,9 @@ account :usd_gateway
|
|
2
2
|
account :scott
|
3
3
|
account :andrew
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
create_account :usd_gateway
|
6
|
+
create_account :scott
|
7
|
+
create_account :andrew
|
8
8
|
|
9
9
|
close_ledger
|
10
10
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
process :node1, [:node1, :node2, :node3], 2, host: '192.168.99.105'
|
2
|
+
process :node2, [:node1, :node2, :node3], 2, host: '192.168.99.104'
|
3
|
+
process :node3, [:node1, :node2, :node3], 2, host: '192.168.99.103'
|
4
|
+
|
5
|
+
account :alice
|
6
|
+
account :bob
|
7
|
+
|
8
|
+
puts "Running txs on node1"
|
9
|
+
|
10
|
+
on :node1 do
|
11
|
+
create_account :alice, :master
|
12
|
+
create_account :bob, :master
|
13
|
+
close_ledger
|
14
|
+
payment :master, :bob, [:native, 1000_000000]
|
15
|
+
close_ledger
|
16
|
+
end
|
17
|
+
|
18
|
+
payment :master, :alice, [:native, 1000_000000]
|
19
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
process :node1, [:node1, :node2, :node3], 2
|
2
|
+
process :node2, [:node1, :node2, :node3], 2
|
3
|
+
process :node3, [:node1, :node2, :node3], 2
|
4
|
+
|
5
|
+
account :alice
|
6
|
+
account :bob
|
7
|
+
|
8
|
+
puts "Running txs on node1"
|
9
|
+
|
10
|
+
on :node1 do
|
11
|
+
create_account :alice, :master
|
12
|
+
create_account :bob, :master
|
13
|
+
close_ledger
|
14
|
+
payment :master, :bob, [:native, 1000_000000]
|
15
|
+
close_ledger
|
16
|
+
end
|
17
|
+
|
18
|
+
payment :master, :alice, [:native, 1000_000000]
|
19
|
+
|
data/examples/trade.rb
CHANGED
@@ -18,15 +18,23 @@ module StellarCoreCommander
|
|
18
18
|
@processes = []
|
19
19
|
end
|
20
20
|
|
21
|
-
Contract
|
21
|
+
Contract Transactor, Symbol, ArrayOf[Symbol], Num, Hash => Process
|
22
22
|
#
|
23
23
|
# make_process returns a new, unlaunched Process object, bound to a new
|
24
|
-
# tmpdir
|
25
|
-
def make_process
|
24
|
+
# tmpdir
|
25
|
+
def make_process(transactor, name, quorum, thresh, options={})
|
26
26
|
tmpdir = Dir.mktmpdir("scc")
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
process_options = @process_options.merge({
|
29
|
+
transactor: transactor,
|
30
|
+
working_dir: tmpdir,
|
31
|
+
name: name,
|
32
|
+
base_port: 39132 + @processes.map(&:required_ports).sum,
|
33
|
+
identity: Stellar::KeyPair.random,
|
34
|
+
quorum: quorum,
|
35
|
+
threshold: thresh,
|
36
|
+
manual_close: false
|
37
|
+
}).merge(options)
|
30
38
|
|
31
39
|
process_class = case @process_type
|
32
40
|
when 'local'
|
@@ -37,12 +45,30 @@ module StellarCoreCommander
|
|
37
45
|
raise "Unknown process type: #{@process_type}"
|
38
46
|
end
|
39
47
|
|
40
|
-
process_class.new(
|
41
|
-
p.setup
|
48
|
+
process_class.new(process_options).tap do |p|
|
42
49
|
@processes << p
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
53
|
+
Contract Transactor => Process
|
54
|
+
def get_root_process(transactor)
|
55
|
+
if @processes.size == 0
|
56
|
+
make_process transactor, :node0, [:node0], 1, { manual_close: transactor.manual_close }
|
57
|
+
end
|
58
|
+
@processes[0]
|
59
|
+
end
|
60
|
+
|
61
|
+
Contract None => ArrayOf[Process]
|
62
|
+
def start_all_processes
|
63
|
+
@processes.each do |p|
|
64
|
+
if not p.running?
|
65
|
+
$stderr.puts "running #{p.idname} (dir:#{p.working_dir})"
|
66
|
+
p.run
|
67
|
+
p.wait_for_ready
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
46
72
|
def cleanup
|
47
73
|
@processes.each(&:cleanup)
|
48
74
|
end
|
@@ -13,45 +13,52 @@ module StellarCoreCommander
|
|
13
13
|
|
14
14
|
Contract None => Any
|
15
15
|
def launch_state_container
|
16
|
-
|
16
|
+
$stderr.puts "launching state container #{state_container_name}"
|
17
|
+
docker %W(run --name #{state_container_name} -p #{postgres_port}:5432 --env-file stellar-core.env -d stellar/stellar-core-state)
|
17
18
|
raise "Could not create state container" unless $?.success?
|
18
19
|
end
|
19
20
|
|
20
21
|
Contract None => Any
|
21
22
|
def shutdown_state_container
|
22
|
-
|
23
|
+
return true unless state_container_running?
|
24
|
+
docker %W(rm -f -v #{state_container_name})
|
23
25
|
raise "Could not drop db: #{database_name}" unless $?.success?
|
24
26
|
end
|
25
27
|
|
26
28
|
Contract None => Any
|
27
29
|
def write_config
|
28
|
-
IO.write("#{working_dir}/.pgpass", "#{docker_host}:#{postgres_port}:*:#{database_user}:#{database_password}")
|
29
|
-
FileUtils.chmod(0600, "#{working_dir}/.pgpass")
|
30
30
|
IO.write("#{working_dir}/stellar-core.env", config)
|
31
31
|
end
|
32
32
|
|
33
33
|
Contract None => Any
|
34
34
|
def setup
|
35
35
|
write_config
|
36
|
-
launch_state_container
|
37
36
|
end
|
38
37
|
|
39
38
|
Contract None => nil
|
40
39
|
def run
|
41
40
|
raise "already running!" if running?
|
41
|
+
setup
|
42
|
+
launch_state_container
|
42
43
|
launch_stellar_core
|
43
44
|
end
|
44
45
|
|
45
46
|
Contract None => Bool
|
46
47
|
def running?
|
47
|
-
|
48
|
+
docker %W(inspect #{container_name})
|
49
|
+
$?.success?
|
50
|
+
end
|
51
|
+
|
52
|
+
Contract None => Bool
|
53
|
+
def state_container_running?
|
54
|
+
docker %W(inspect #{state_container_name})
|
48
55
|
$?.success?
|
49
56
|
end
|
50
57
|
|
51
58
|
Contract None => Any
|
52
59
|
def shutdown
|
53
60
|
return true unless running?
|
54
|
-
|
61
|
+
docker %W(rm -f #{container_name})
|
55
62
|
end
|
56
63
|
|
57
64
|
Contract None => Any
|
@@ -65,7 +72,8 @@ module StellarCoreCommander
|
|
65
72
|
Contract None => Any
|
66
73
|
def dump_database
|
67
74
|
Dir.chdir(working_dir) do
|
68
|
-
|
75
|
+
host_args = "-H tcp://#{docker_host}:#{docker_port}" if host
|
76
|
+
`docker #{host_args} exec #{state_container_name} pg_dump -U #{database_user} --clean --no-owner #{database_name}`
|
69
77
|
end
|
70
78
|
end
|
71
79
|
|
@@ -96,32 +104,30 @@ module StellarCoreCommander
|
|
96
104
|
|
97
105
|
Contract None => String
|
98
106
|
def container_name
|
99
|
-
"
|
107
|
+
"scc-#{idname}"
|
100
108
|
end
|
101
109
|
|
102
110
|
Contract None => String
|
103
111
|
def state_container_name
|
104
|
-
"
|
112
|
+
"scc-state-#{idname}"
|
105
113
|
end
|
106
114
|
|
107
115
|
Contract None => String
|
108
116
|
def docker_host
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
else
|
113
|
-
"127.0.0.1"
|
114
|
-
end
|
117
|
+
return host if host
|
118
|
+
return URI.parse(ENV['DOCKER_HOST']).host if ENV['DOCKER_HOST']
|
119
|
+
DEFAULT_HOST
|
115
120
|
end
|
116
121
|
|
117
122
|
Contract None => String
|
118
|
-
def
|
123
|
+
def hostname
|
119
124
|
docker_host
|
120
125
|
end
|
121
126
|
|
122
127
|
private
|
123
128
|
def launch_stellar_core
|
124
|
-
|
129
|
+
$stderr.puts "launching stellar-core container #{container_name}"
|
130
|
+
docker %W(run
|
125
131
|
--name #{container_name}
|
126
132
|
--net host
|
127
133
|
--volumes-from #{state_container_name}
|
@@ -143,12 +149,12 @@ module StellarCoreCommander
|
|
143
149
|
main_PEER_SEED=#{identity.seed}
|
144
150
|
main_VALIDATION_SEED=#{identity.seed}
|
145
151
|
|
146
|
-
MANUAL_CLOSE=true
|
152
|
+
#{"MANUAL_CLOSE=true" if manual_close?}
|
147
153
|
|
148
|
-
QUORUM_THRESHOLD
|
154
|
+
QUORUM_THRESHOLD=#{threshold}
|
149
155
|
|
150
|
-
PREFERRED_PEERS
|
151
|
-
QUORUM_SET
|
156
|
+
PREFERRED_PEERS=#{peers}
|
157
|
+
QUORUM_SET=#{quorum}
|
152
158
|
|
153
159
|
HISTORY_PEERS=["main"]
|
154
160
|
|
@@ -157,5 +163,25 @@ module StellarCoreCommander
|
|
157
163
|
HISTORY_MKDIR=mkdir -p history/%s/{0}
|
158
164
|
EOS
|
159
165
|
end
|
166
|
+
|
167
|
+
def docker_port
|
168
|
+
if ENV['DOCKER_HOST']
|
169
|
+
URI.parse(ENV['DOCKER_HOST']).port
|
170
|
+
else
|
171
|
+
2376
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def docker_args
|
176
|
+
if host
|
177
|
+
["-H", "tcp://#{docker_host}:#{docker_port}"]
|
178
|
+
else
|
179
|
+
[]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def docker(args)
|
184
|
+
run_cmd "docker", docker_args + args
|
185
|
+
end
|
160
186
|
end
|
161
187
|
end
|
@@ -6,21 +6,11 @@ module StellarCoreCommander
|
|
6
6
|
attr_reader :pid
|
7
7
|
attr_reader :wait
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
stellar_core_bin = opts[:stellar_core_bin]
|
11
|
-
if stellar_core_bin.blank?
|
12
|
-
search = `which stellar-core`.strip
|
13
|
-
|
14
|
-
if $?.success?
|
15
|
-
stellar_core_bin = search
|
16
|
-
else
|
17
|
-
$stderr.puts "Could not find a `stellar-core` binary, please use --stellar-core-bin to specify"
|
18
|
-
exit 1
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
FileUtils.cp(stellar_core_bin, "#{working_dir}/stellar-core")
|
9
|
+
def initialize(params)
|
23
10
|
super
|
11
|
+
@stellar_core_bin = params[:stellar_core_bin]
|
12
|
+
raise "`host` param is unsupported on LocalProcess, please use `-p docker` for this recipe." if params[:host]
|
13
|
+
setup_working_dir
|
24
14
|
end
|
25
15
|
|
26
16
|
Contract None => Any
|
@@ -69,7 +59,7 @@ module StellarCoreCommander
|
|
69
59
|
Contract None => Num
|
70
60
|
def run
|
71
61
|
raise "already running!" if running?
|
72
|
-
|
62
|
+
setup
|
73
63
|
forcescp
|
74
64
|
launch_stellar_core
|
75
65
|
end
|
@@ -120,7 +110,7 @@ module StellarCoreCommander
|
|
120
110
|
|
121
111
|
Contract None => String
|
122
112
|
def database_name
|
123
|
-
"stellar_core_tmp_#{
|
113
|
+
"stellar_core_tmp_#{idname}"
|
124
114
|
end
|
125
115
|
|
126
116
|
Contract None => String
|
@@ -145,7 +135,6 @@ module StellarCoreCommander
|
|
145
135
|
Contract None => String
|
146
136
|
def config
|
147
137
|
<<-EOS.strip_heredoc
|
148
|
-
MANUAL_CLOSE=true
|
149
138
|
PEER_PORT=#{peer_port}
|
150
139
|
RUN_STANDALONE=false
|
151
140
|
HTTP_PORT=#{http_port}
|
@@ -154,10 +143,13 @@ module StellarCoreCommander
|
|
154
143
|
VALIDATION_SEED="#{@identity.seed}"
|
155
144
|
|
156
145
|
DATABASE="#{dsn}"
|
146
|
+
PREFERRED_PEERS=#{peers}
|
147
|
+
|
148
|
+
#{"MANUAL_CLOSE=true" if manual_close?}
|
157
149
|
|
158
150
|
[QUORUM_SET]
|
159
|
-
THRESHOLD
|
160
|
-
VALIDATORS
|
151
|
+
THRESHOLD=#{threshold}
|
152
|
+
VALIDATORS=#{quorum}
|
161
153
|
|
162
154
|
[HISTORY.main]
|
163
155
|
get="cp history/main/{0} {1}"
|
@@ -166,5 +158,20 @@ module StellarCoreCommander
|
|
166
158
|
EOS
|
167
159
|
end
|
168
160
|
|
161
|
+
def setup_working_dir
|
162
|
+
if @stellar_core_bin.blank?
|
163
|
+
search = `which stellar-core`.strip
|
164
|
+
|
165
|
+
if $?.success?
|
166
|
+
@stellar_core_bin = search
|
167
|
+
else
|
168
|
+
$stderr.puts "Could not find a `stellar-core` binary, please use --stellar-core-bin to specify"
|
169
|
+
exit 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
FileUtils.cp(@stellar_core_bin, "#{working_dir}/stellar-core")
|
174
|
+
end
|
175
|
+
|
169
176
|
end
|
170
|
-
end
|
177
|
+
end
|
@@ -17,6 +17,15 @@ module StellarCoreCommander
|
|
17
17
|
{buy:Currency, with: Currency},
|
18
18
|
]
|
19
19
|
|
20
|
+
ThresholdByte = And[Num, lambda{|n| (0..255).include? n}]
|
21
|
+
|
22
|
+
Thresholds = {
|
23
|
+
low: ThresholdByte,
|
24
|
+
medium: ThresholdByte,
|
25
|
+
high: ThresholdByte,
|
26
|
+
master_weight: ThresholdByte
|
27
|
+
}
|
28
|
+
|
20
29
|
Contract Transactor => Any
|
21
30
|
def initialize(transactor)
|
22
31
|
@transactor = transactor
|
@@ -75,8 +84,8 @@ module StellarCoreCommander
|
|
75
84
|
}).to_envelope(account)
|
76
85
|
end
|
77
86
|
|
78
|
-
Contract Symbol, Symbol, String, Num => Any
|
79
|
-
def allow_trust(account, trustor, code)
|
87
|
+
Contract Symbol, Symbol, String, Num, Bool => Any
|
88
|
+
def allow_trust(account, trustor, code, authorize=true)
|
80
89
|
currency = make_currency([code, account])
|
81
90
|
account = get_account account
|
82
91
|
trustor = get_account trustor
|
@@ -87,10 +96,15 @@ module StellarCoreCommander
|
|
87
96
|
sequence: next_sequence(account),
|
88
97
|
currency: currency,
|
89
98
|
trustor: trustor,
|
90
|
-
authorize:
|
99
|
+
authorize: authorize,
|
91
100
|
}).to_envelope(account)
|
92
101
|
end
|
93
102
|
|
103
|
+
Contract Symbol, Symbol, String, Num => Any
|
104
|
+
def revoke_trust(account, trustor, code)
|
105
|
+
allow_trust(account, trustor, code, false)
|
106
|
+
end
|
107
|
+
|
94
108
|
Contract Symbol, OfferCurrencies, Num, Num => Any
|
95
109
|
def offer(account, currencies, amount, price)
|
96
110
|
account = get_account account
|
@@ -134,6 +148,50 @@ module StellarCoreCommander
|
|
134
148
|
tx.to_envelope(account)
|
135
149
|
end
|
136
150
|
|
151
|
+
|
152
|
+
Contract Symbol, Stellar::KeyPair, Num => Any
|
153
|
+
def add_signer(account, key, weight)
|
154
|
+
account = get_account account
|
155
|
+
|
156
|
+
tx = Stellar::Transaction.set_options({
|
157
|
+
account: account,
|
158
|
+
sequence: next_sequence(account),
|
159
|
+
signer: Stellar::Signer.new({
|
160
|
+
pub_key: key.public_key,
|
161
|
+
weight: weight
|
162
|
+
}),
|
163
|
+
})
|
164
|
+
|
165
|
+
tx.to_envelope(account)
|
166
|
+
end
|
167
|
+
|
168
|
+
Contract(Symbol, Thresholds => Any)
|
169
|
+
def set_thresholds(account, thresholds)
|
170
|
+
account = get_account account
|
171
|
+
|
172
|
+
tx = Stellar::Transaction.set_options({
|
173
|
+
account: account,
|
174
|
+
sequence: next_sequence(account),
|
175
|
+
thresholds: make_thresholds_word(thresholds),
|
176
|
+
})
|
177
|
+
|
178
|
+
tx.to_envelope(account)
|
179
|
+
end
|
180
|
+
|
181
|
+
Contract Symbol, Symbol => Any
|
182
|
+
def merge_account(account, into)
|
183
|
+
account = get_account account
|
184
|
+
into = get_account into
|
185
|
+
|
186
|
+
tx = Stellar::Transaction.account_merge({
|
187
|
+
account: account,
|
188
|
+
sequence: next_sequence(account),
|
189
|
+
destination: into,
|
190
|
+
})
|
191
|
+
|
192
|
+
tx.to_envelope(account)
|
193
|
+
end
|
194
|
+
|
137
195
|
private
|
138
196
|
|
139
197
|
delegate :get_account, to: :@transactor
|
@@ -156,6 +214,11 @@ module StellarCoreCommander
|
|
156
214
|
flags.map{|f| Stellar::AccountFlags.send(f)}
|
157
215
|
end
|
158
216
|
|
217
|
+
Contract Thresholds => String
|
218
|
+
def make_thresholds_word(thresholds)
|
219
|
+
thresholds.values_at(:master_weight, :low, :medium, :high).pack("C*")
|
220
|
+
end
|
221
|
+
|
159
222
|
Contract Amount => Any
|
160
223
|
def normalize_amount(amount)
|
161
224
|
return amount if amount.first == :native
|
@@ -3,22 +3,70 @@ module StellarCoreCommander
|
|
3
3
|
class Process
|
4
4
|
include Contracts
|
5
5
|
|
6
|
+
attr_reader :transactor
|
6
7
|
attr_reader :working_dir
|
8
|
+
attr_reader :name
|
7
9
|
attr_reader :base_port
|
8
10
|
attr_reader :identity
|
9
11
|
attr_reader :server
|
12
|
+
attr_accessor :unverified
|
13
|
+
attr_reader :threshold
|
14
|
+
attr_reader :host
|
15
|
+
|
16
|
+
DEFAULT_HOST = '127.0.0.1'
|
17
|
+
|
18
|
+
Contract({
|
19
|
+
transactor: Transactor,
|
20
|
+
working_dir: String,
|
21
|
+
name: Symbol,
|
22
|
+
base_port: Num,
|
23
|
+
identity: Stellar::KeyPair,
|
24
|
+
quorum: ArrayOf[Symbol],
|
25
|
+
threshold: Num,
|
26
|
+
manual_close: Or[Bool, nil],
|
27
|
+
host: Or[String, nil]
|
28
|
+
} => Any)
|
29
|
+
def initialize(params)
|
30
|
+
#config
|
31
|
+
@transactor = params[:transactor]
|
32
|
+
@working_dir = params[:working_dir]
|
33
|
+
@name = params[:name]
|
34
|
+
@base_port = params[:base_port]
|
35
|
+
@identity = params[:identity]
|
36
|
+
@quorum = params[:quorum]
|
37
|
+
@threshold = params[:threshold]
|
38
|
+
@manual_close = params[:manual_close] || false
|
39
|
+
@host = params[:host]
|
40
|
+
|
41
|
+
# state
|
42
|
+
@unverified = []
|
43
|
+
|
44
|
+
|
45
|
+
if not @quorum.include? @name
|
46
|
+
@quorum << @name
|
47
|
+
end
|
10
48
|
|
11
|
-
|
12
|
-
@working_dir = working_dir
|
13
|
-
@base_port = base_port
|
14
|
-
@identity = identity
|
15
|
-
|
16
|
-
@server = Faraday.new(url: "http://#{http_host}:#{http_port}") do |conn|
|
49
|
+
@server = Faraday.new(url: "http://#{hostname}:#{http_port}") do |conn|
|
17
50
|
conn.request :url_encoded
|
18
51
|
conn.adapter Faraday.default_adapter
|
19
52
|
end
|
20
53
|
end
|
21
54
|
|
55
|
+
Contract None => ArrayOf[String]
|
56
|
+
def quorum
|
57
|
+
@quorum.map do |q|
|
58
|
+
@transactor.get_process(q).identity.address
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Contract None => ArrayOf[String]
|
63
|
+
def peers
|
64
|
+
@quorum.map do |q|
|
65
|
+
p = @transactor.get_process(q)
|
66
|
+
"#{p.hostname}:#{p.peer_port}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
22
70
|
Contract None => Num
|
23
71
|
def required_ports
|
24
72
|
2
|
@@ -29,6 +77,11 @@ module StellarCoreCommander
|
|
29
77
|
FileUtils.rm_rf working_dir
|
30
78
|
end
|
31
79
|
|
80
|
+
Contract None => String
|
81
|
+
def idname
|
82
|
+
"#{@name}-#{@base_port}-#{@identity.address[0..5]}"
|
83
|
+
end
|
84
|
+
|
32
85
|
Contract None => Any
|
33
86
|
def wait_for_ready
|
34
87
|
loop do
|
@@ -38,22 +91,30 @@ module StellarCoreCommander
|
|
38
91
|
if response
|
39
92
|
body = ActiveSupport::JSON.decode(response.body)
|
40
93
|
|
41
|
-
|
94
|
+
state = body["info"]["state"]
|
95
|
+
$stderr.puts "state: #{state}"
|
96
|
+
break if state == "Synced!"
|
42
97
|
end
|
43
98
|
|
44
|
-
$stderr.puts "waiting until stellar-core is synced"
|
99
|
+
$stderr.puts "waiting until stellar-core #{idname} is synced"
|
45
100
|
sleep 1
|
46
101
|
end
|
47
102
|
end
|
48
103
|
|
104
|
+
Contract None => Bool
|
105
|
+
def manual_close?
|
106
|
+
@manual_close
|
107
|
+
end
|
108
|
+
|
49
109
|
Contract None => Bool
|
50
110
|
def close_ledger
|
51
111
|
prev_ledger = latest_ledger
|
52
112
|
next_ledger = prev_ledger + 1
|
53
113
|
|
54
|
-
server.get("manualclose")
|
55
|
-
|
56
114
|
Timeout.timeout(close_timeout) do
|
115
|
+
|
116
|
+
server.get("manualclose") if manual_close?
|
117
|
+
|
57
118
|
loop do
|
58
119
|
current_ledger = latest_ledger
|
59
120
|
|
@@ -61,17 +122,34 @@ module StellarCoreCommander
|
|
61
122
|
when current_ledger == next_ledger
|
62
123
|
break
|
63
124
|
when current_ledger > next_ledger
|
64
|
-
raise "
|
125
|
+
raise "#{idname} jumped two ledgers, from #{prev_ledger} to #{current_ledger}"
|
65
126
|
else
|
66
|
-
$stderr.puts "waiting for ledger #{next_ledger}"
|
127
|
+
$stderr.puts "#{idname} waiting for ledger #{next_ledger} (current: #{current_ledger}, ballots prepared: #{scp_ballots_prepared})"
|
67
128
|
sleep 0.5
|
68
129
|
end
|
69
130
|
end
|
70
131
|
end
|
132
|
+
$stderr.puts "#{idname} closed #{latest_ledger}"
|
71
133
|
|
72
134
|
true
|
73
135
|
end
|
74
136
|
|
137
|
+
Contract None => Hash
|
138
|
+
def metrics
|
139
|
+
response = server.get("/metrics")
|
140
|
+
body = ActiveSupport::JSON.decode(response.body)
|
141
|
+
body["metrics"]
|
142
|
+
rescue
|
143
|
+
{}
|
144
|
+
end
|
145
|
+
|
146
|
+
Contract None => Num
|
147
|
+
def scp_ballots_prepared
|
148
|
+
metrics["scp.ballot.prepare"]["count"]
|
149
|
+
rescue
|
150
|
+
0
|
151
|
+
end
|
152
|
+
|
75
153
|
Contract None => Num
|
76
154
|
def http_port
|
77
155
|
base_port
|
@@ -88,7 +166,7 @@ module StellarCoreCommander
|
|
88
166
|
body = ActiveSupport::JSON.decode(response.body)
|
89
167
|
|
90
168
|
if body["status"] == "ERROR"
|
91
|
-
raise "transaction failed: #{body.inspect}"
|
169
|
+
raise "transaction on #{idname} failed: #{body.inspect}"
|
92
170
|
end
|
93
171
|
|
94
172
|
end
|
@@ -104,26 +182,21 @@ module StellarCoreCommander
|
|
104
182
|
database[:ledgerheaders].max(:ledgerseq)
|
105
183
|
end
|
106
184
|
|
107
|
-
Contract String => String
|
185
|
+
Contract String => Maybe[String]
|
108
186
|
def transaction_result(hex_hash)
|
109
187
|
row = database[:txhistory].where(txid:hex_hash).first
|
188
|
+
return if row.blank?
|
110
189
|
row[:txresult]
|
111
190
|
end
|
112
191
|
|
113
192
|
Contract None => String
|
114
|
-
def
|
115
|
-
|
193
|
+
def hostname
|
194
|
+
host || DEFAULT_HOST
|
116
195
|
end
|
117
196
|
|
118
197
|
Contract None => Num
|
119
198
|
def close_timeout
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
Contract None => String
|
125
|
-
def basename
|
126
|
-
File.basename(working_dir)
|
199
|
+
15.0
|
127
200
|
end
|
128
201
|
|
129
202
|
Contract String, ArrayOf[String] => Maybe[Bool]
|
@@ -139,4 +212,4 @@ module StellarCoreCommander
|
|
139
212
|
end
|
140
213
|
|
141
214
|
end
|
142
|
-
end
|
215
|
+
end
|
@@ -10,17 +10,30 @@ module StellarCoreCommander
|
|
10
10
|
include Contracts
|
11
11
|
|
12
12
|
class FailedTransaction < StandardError ; end
|
13
|
+
class MissingTransaction < StandardError ; end
|
14
|
+
|
15
|
+
attr_reader :manual_close
|
13
16
|
|
14
17
|
Contract Commander => Any
|
15
18
|
def initialize(commander)
|
16
19
|
@commander = commander
|
17
20
|
@named = {}.with_indifferent_access
|
18
|
-
@unverified = []
|
19
21
|
@operation_builder = OperationBuilder.new(self)
|
22
|
+
@manual_close = false
|
20
23
|
|
21
24
|
account :master, Stellar::KeyPair.from_raw_seed("allmylifemyhearthasbeensearching")
|
22
25
|
end
|
23
26
|
|
27
|
+
def require_process_running
|
28
|
+
if @process == nil
|
29
|
+
@process = @commander.get_root_process self
|
30
|
+
if not @named.has_key? @process.name
|
31
|
+
add_named @process.name, @process
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@commander.start_all_processes
|
35
|
+
end
|
36
|
+
|
24
37
|
Contract String => Any
|
25
38
|
#
|
26
39
|
# Runs the provided recipe against the process identified by @process
|
@@ -28,12 +41,6 @@ module StellarCoreCommander
|
|
28
41
|
# @param recipe_path [String] path to the recipe file
|
29
42
|
#
|
30
43
|
def run_recipe(recipe_path)
|
31
|
-
@process = @commander.make_process
|
32
|
-
@process.run
|
33
|
-
@process.wait_for_ready
|
34
|
-
|
35
|
-
add_named :process, @process
|
36
|
-
|
37
44
|
recipe_content = IO.read(recipe_path)
|
38
45
|
instance_eval recipe_content
|
39
46
|
end
|
@@ -48,10 +55,6 @@ module StellarCoreCommander
|
|
48
55
|
# @param keypair=Stellar::KeyPair.random [Stellar::KeyPair] the keypair to use for this account
|
49
56
|
#
|
50
57
|
def account(name, keypair=Stellar::KeyPair.random)
|
51
|
-
unless keypair.is_a?(Stellar::KeyPair)
|
52
|
-
raise ArgumentError, "`#{keypair.class.name}` is not `Stellar::KeyPair`"
|
53
|
-
end
|
54
|
-
|
55
58
|
add_named name, keypair
|
56
59
|
end
|
57
60
|
|
@@ -59,8 +62,8 @@ module StellarCoreCommander
|
|
59
62
|
#
|
60
63
|
# @see StellarCoreCommander::OperationBuilder#payment
|
61
64
|
def payment(*args)
|
65
|
+
require_process_running
|
62
66
|
envelope = @operation_builder.payment(*args)
|
63
|
-
|
64
67
|
submit_transaction envelope do |result|
|
65
68
|
payment_result = result.result.results!.first.tr!.value
|
66
69
|
raise FailedTransaction unless payment_result.code.value >= 0
|
@@ -70,6 +73,7 @@ module StellarCoreCommander
|
|
70
73
|
#
|
71
74
|
# @see StellarCoreCommander::OperationBuilder#create_account
|
72
75
|
def create_account(*args)
|
76
|
+
require_process_running
|
73
77
|
envelope = @operation_builder.create_account(*args)
|
74
78
|
submit_transaction envelope
|
75
79
|
end
|
@@ -77,6 +81,7 @@ module StellarCoreCommander
|
|
77
81
|
#
|
78
82
|
# @see StellarCoreCommander::OperationBuilder#trust
|
79
83
|
def trust(*args)
|
84
|
+
require_process_running
|
80
85
|
envelope = @operation_builder.trust(*args)
|
81
86
|
submit_transaction envelope
|
82
87
|
end
|
@@ -84,6 +89,7 @@ module StellarCoreCommander
|
|
84
89
|
#
|
85
90
|
# @see StellarCoreCommander::OperationBuilder#change_trust
|
86
91
|
def change_trust(*args)
|
92
|
+
require_process_running
|
87
93
|
envelope = @operation_builder.change_trust(*args)
|
88
94
|
submit_transaction envelope
|
89
95
|
end
|
@@ -91,6 +97,7 @@ module StellarCoreCommander
|
|
91
97
|
#
|
92
98
|
# @see StellarCoreCommander::OperationBuilder#offer
|
93
99
|
def offer(*args)
|
100
|
+
require_process_running
|
94
101
|
envelope = @operation_builder.offer(*args)
|
95
102
|
submit_transaction envelope
|
96
103
|
end
|
@@ -98,6 +105,7 @@ module StellarCoreCommander
|
|
98
105
|
#
|
99
106
|
# @see StellarCoreCommander::OperationBuilder#require_trust_auth
|
100
107
|
def require_trust_auth(*args)
|
108
|
+
require_process_running
|
101
109
|
envelope = @operation_builder.require_trust_auth(*args)
|
102
110
|
submit_transaction envelope
|
103
111
|
end
|
@@ -105,30 +113,61 @@ module StellarCoreCommander
|
|
105
113
|
#
|
106
114
|
# @see StellarCoreCommander::OperationBuilder#set_flags
|
107
115
|
def set_flags(*args)
|
116
|
+
require_process_running
|
108
117
|
envelope = @operation_builder.set_flags(*args)
|
109
118
|
submit_transaction envelope
|
110
119
|
end
|
111
120
|
|
121
|
+
#
|
122
|
+
# @see StellarCoreCommander::OperationBuilder#add_signer
|
123
|
+
def add_signer(*args)
|
124
|
+
require_process_running
|
125
|
+
envelope = @operation_builder.add_signer(*args)
|
126
|
+
submit_transaction envelope
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# @see StellarCoreCommander::OperationBuilder#set_thresholds
|
131
|
+
def set_thresholds(*args)
|
132
|
+
require_process_running
|
133
|
+
envelope = @operation_builder.set_thresholds(*args)
|
134
|
+
submit_transaction envelope
|
135
|
+
end
|
136
|
+
|
112
137
|
#
|
113
138
|
# @see StellarCoreCommander::OperationBuilder#allow_trust
|
114
139
|
def allow_trust(*args)
|
140
|
+
require_process_running
|
115
141
|
envelope = @operation_builder.allow_trust(*args)
|
116
142
|
submit_transaction envelope
|
117
143
|
end
|
118
144
|
|
145
|
+
|
146
|
+
#
|
147
|
+
# @see StellarCoreCommander::OperationBuilder#merge_account
|
148
|
+
def merge_account(*args)
|
149
|
+
require_process_running
|
150
|
+
envelope = @operation_builder.merge_account(*args)
|
151
|
+
submit_transaction envelope
|
152
|
+
end
|
153
|
+
|
119
154
|
Contract None => Any
|
120
155
|
#
|
121
156
|
# Triggers a ledger close. Any unvalidated transaction will
|
122
157
|
# be validated, which will trigger an error if any fail to be validated
|
123
158
|
#
|
124
159
|
def close_ledger
|
160
|
+
require_process_running
|
125
161
|
@process.close_ledger
|
126
162
|
|
127
|
-
@unverified.each do |eb|
|
163
|
+
@process.unverified.each do |eb|
|
128
164
|
begin
|
129
165
|
envelope, after_confirmation = *eb
|
130
166
|
result = validate_transaction envelope
|
131
167
|
after_confirmation.call(result) if after_confirmation
|
168
|
+
rescue MissingTransaction
|
169
|
+
$stderr.puts "Failed to validate tx: #{Convert.to_hex envelope.tx.hash}"
|
170
|
+
$stderr.puts "could not be found in txhistory table on process #{@process.name}"
|
132
171
|
rescue FailedTransaction
|
133
172
|
$stderr.puts "Failed to validate tx: #{Convert.to_hex envelope.tx.hash}"
|
134
173
|
$stderr.puts "failed result: #{result.to_xdr(:hex)}"
|
@@ -136,11 +175,12 @@ module StellarCoreCommander
|
|
136
175
|
end
|
137
176
|
end
|
138
177
|
|
139
|
-
@unverified.clear
|
178
|
+
@process.unverified.clear
|
140
179
|
end
|
141
180
|
|
142
181
|
Contract Symbol => Stellar::KeyPair
|
143
182
|
def get_account(name)
|
183
|
+
require_process_running
|
144
184
|
@named[name].tap do |found|
|
145
185
|
unless found.is_a?(Stellar::KeyPair)
|
146
186
|
raise ArgumentError, "#{name.inspect} is not account"
|
@@ -157,14 +197,46 @@ module StellarCoreCommander
|
|
157
197
|
end
|
158
198
|
end
|
159
199
|
|
200
|
+
Contract Symbol, ArrayOf[Symbol], Num, Hash => Process
|
201
|
+
def process(name, quorum=[name], thresh=quorum.length, options={})
|
202
|
+
|
203
|
+
if @manual_close
|
204
|
+
raise "Cannot use `process`, this recipe has previously declared `use_manual_close`."
|
205
|
+
end
|
206
|
+
|
207
|
+
$stderr.puts "creating process #{name}"
|
208
|
+
p = @commander.make_process self, name, quorum, thresh, options
|
209
|
+
$stderr.puts "process #{name} is #{p.idname}"
|
210
|
+
add_named name, p
|
211
|
+
end
|
212
|
+
|
213
|
+
Contract Symbol, Proc => Any
|
214
|
+
def on(process_name)
|
215
|
+
require_process_running
|
216
|
+
tmp = @process
|
217
|
+
p = get_process process_name
|
218
|
+
$stderr.puts "executing steps on #{p.idname}"
|
219
|
+
@process = p
|
220
|
+
yield
|
221
|
+
ensure
|
222
|
+
@process = tmp
|
223
|
+
end
|
224
|
+
|
160
225
|
Contract Stellar::KeyPair => Num
|
161
226
|
def next_sequence(account)
|
227
|
+
require_process_running
|
162
228
|
base_sequence = @process.sequence_for(account)
|
163
|
-
inflight_count = @unverified.select{|e| e.first.tx.source_account == account.public_key}.length
|
229
|
+
inflight_count = @process.unverified.select{|e| e.first.tx.source_account == account.public_key}.length
|
164
230
|
|
165
231
|
base_sequence + inflight_count + 1
|
166
232
|
end
|
167
233
|
|
234
|
+
Contract None => Any
|
235
|
+
def use_manual_close()
|
236
|
+
$stderr.puts "using manual_close mode"
|
237
|
+
@manual_close = true
|
238
|
+
end
|
239
|
+
|
168
240
|
private
|
169
241
|
Contract Symbol, Any => Any
|
170
242
|
def add_named(name, object)
|
@@ -177,11 +249,12 @@ module StellarCoreCommander
|
|
177
249
|
|
178
250
|
Contract Stellar::TransactionEnvelope, Or[nil, Proc] => Any
|
179
251
|
def submit_transaction(envelope, &after_confirmation)
|
252
|
+
require_process_running
|
180
253
|
hex = envelope.to_xdr(:hex)
|
181
254
|
@process.submit_transaction hex
|
182
255
|
|
183
256
|
# submit to process
|
184
|
-
@unverified << [envelope, after_confirmation]
|
257
|
+
@process.unverified << [envelope, after_confirmation]
|
185
258
|
end
|
186
259
|
|
187
260
|
Contract Stellar::TransactionEnvelope => Stellar::TransactionResult
|
@@ -191,7 +264,7 @@ module StellarCoreCommander
|
|
191
264
|
|
192
265
|
base64_result = @process.transaction_result(hex_hash)
|
193
266
|
|
194
|
-
raise
|
267
|
+
raise MissingTransaction if base64_result.blank?
|
195
268
|
|
196
269
|
raw_result = Convert.from_base64(base64_result)
|
197
270
|
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_dependency "stellar-base", "= 0.0.
|
20
|
+
spec.add_dependency "stellar-base", "= 0.0.12"
|
21
21
|
spec.add_dependency "slop", "~> 3.6.0"
|
22
22
|
spec.add_dependency "faraday", "~> 0.9.1"
|
23
23
|
spec.add_dependency "faraday_middleware", "~> 0.9.1"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stellar_core_commander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Fleckenstein
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: stellar-base
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.
|
19
|
+
version: 0.0.12
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.0.
|
26
|
+
version: 0.0.12
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: slop
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,6 +179,9 @@ files:
|
|
179
179
|
- Rakefile
|
180
180
|
- bin/scc
|
181
181
|
- examples/allow_trust.rb
|
182
|
+
- examples/cross_host_simple_payment.rb
|
183
|
+
- examples/merge_account.rb
|
184
|
+
- examples/multi_host_simple_payment.rb
|
182
185
|
- examples/non_native_payment.rb
|
183
186
|
- examples/pathed_payment.rb
|
184
187
|
- examples/simple_payment.rb
|