stellar_core_commander 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ec23f9e827ebf793af1412a68847a9f37ff9278
4
- data.tar.gz: 9e2d0a36edb3093e4384067225d95c03341cca8f
3
+ metadata.gz: fd2f67696affdaab450d32a5f0af66983a30c4bf
4
+ data.tar.gz: a1c96602fc57defdc5bc288ee2e1d3edcbb05ca2
5
5
  SHA512:
6
- metadata.gz: 2cd2365fb8291e0307c29b5283eb0537950e6bab08ed69999cb4fc9c5f66c14b17d0758aabf37b5467eef99778afb3b8915e0bb6bcef533e6611ca376cdf78ab
7
- data.tar.gz: f1c4810b80c622b188c7f936a45dc2db4ecd98e2a1e71103f6cd525293720144481ef49198bda1c0ebe42a3f6f5152d6784960c0a22558d1a5d11b4015ccd0c4
6
+ metadata.gz: 754f6d203d4d406fc446ff8975ef964c2cfc14cea19824f4d8773d92a468dc1a01f5930f1ba091556187f0ffa2f8d35f038c50edb2bc661b1365c20453bb5b8b
7
+ data.tar.gz: 78f2b8bf586722d6fa1f882c638b627c1b0ba9569a8a1dca823b22ab8b716e5bc4a1fc701a9894e61d1c5f9bf7d9a929d6675c1beb6f83cd24629a6416ef481b
data/Gemfile CHANGED
@@ -2,4 +2,4 @@ source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
4
  # gem 'stellar-base', path: "~/src/stellar/ruby-stellar-base"
5
- # gem 'xdr', path: "~/src/stellar/ruby-xdr"#
5
+ # gem 'xdr', path: "~/src/stellar/ruby-xdr"#
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', 'a path to a stellar-core executable (defaults to `which stellar-core`)', argument: true
11
-
12
- on 'r', 'recipe', 'a recipe file', argument: true #, required: true
13
- on 'p', 'process', 'method for running stellar-core', argument: true, default: 'local'
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.get_process(:process))
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
 
@@ -2,9 +2,9 @@ account :usd_gateway
2
2
  account :scott
3
3
  account :andrew
4
4
 
5
- payment :master, :usd_gateway, [:native, 1000 * Stellar::ONE]
6
- payment :master, :scott, [:native, 1000 * Stellar::ONE]
7
- payment :master, :andrew, [:native, 1000 * Stellar::ONE]
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,7 @@
1
+ account :scott
2
+
3
+ create_account :scott, :master
4
+
5
+ close_ledger
6
+
7
+ merge_account :scott, :master
@@ -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
@@ -1,3 +1,5 @@
1
+ use_manual_close #use_manual_close causes scc to run a process with MANUAL_CLOSE=true
2
+
1
3
  account :usd_gateway
2
4
  account :eur_gateway
3
5
  account :scott
@@ -18,15 +18,23 @@ module StellarCoreCommander
18
18
  @processes = []
19
19
  end
20
20
 
21
- Contract None => Process
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 and
25
- def make_process
24
+ # tmpdir
25
+ def make_process(transactor, name, quorum, thresh, options={})
26
26
  tmpdir = Dir.mktmpdir("scc")
27
27
 
28
- identity = Stellar::KeyPair.random
29
- base_port = 39132 + @processes.map(&:required_ports).sum
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(tmpdir, base_port, identity, @process_options).tap do |p|
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
- run_cmd "docker", %W(run --name #{state_container_name} -p #{postgres_port}:5432 --env-file stellar-core.env -d stellar/stellar-core-state)
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
- run_cmd "docker", %W(rm -f -v #{state_container_name})
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
- run_cmd "docker", %W(inspect #{container_name})
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
- run_cmd "docker", %W(rm -f #{container_name})
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
- `docker exec #{state_container_name} pg_dump -U #{database_user} --clean --no-owner #{database_name}`
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
- "c#{base_port}"
107
+ "scc-#{idname}"
100
108
  end
101
109
 
102
110
  Contract None => String
103
111
  def state_container_name
104
- "db#{container_name}"
112
+ "scc-state-#{idname}"
105
113
  end
106
114
 
107
115
  Contract None => String
108
116
  def docker_host
109
- docker_uri = URI.parse(ENV['DOCKER_HOST'])
110
- if docker_uri.scheme == "tcp"
111
- docker_uri.host
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 http_host
123
+ def hostname
119
124
  docker_host
120
125
  end
121
126
 
122
127
  private
123
128
  def launch_stellar_core
124
- run_cmd "docker", %W(run
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=1
154
+ QUORUM_THRESHOLD=#{threshold}
149
155
 
150
- PREFERRED_PEERS=["127.0.0.1:#{peer_port}"]
151
- QUORUM_SET=["#{identity.address}"]
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(working_dir, base_port, identity, opts)
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_#{basename}"
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=1
160
- VALIDATORS=["#{@identity.address}"]
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: true,
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
- def initialize(working_dir, base_port, identity, opts)
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
- break if body["info"]["state"] == "Synced!"
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 "whoa! we jumped two ledgers, from #{prev_ledger} to #{current_ledger}"
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 http_host
115
- "127.0.0.1"
193
+ def hostname
194
+ host || DEFAULT_HOST
116
195
  end
117
196
 
118
197
  Contract None => Num
119
198
  def close_timeout
120
- 5.0
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 "couldn't find result for #{hex_hash}" if base64_result.blank?
267
+ raise MissingTransaction if base64_result.blank?
195
268
 
196
269
  raw_result = Convert.from_base64(base64_result)
197
270
 
@@ -1,3 +1,3 @@
1
1
  module StellarCoreCommander
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -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.10"
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.9
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-01 00:00:00.000000000 Z
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.10
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.10
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