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 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