stellar_core_commander 0.0.8 → 0.0.9

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: 2d1cd8f2aeaf80f4c957fa062d63449ff0d36dfd
4
- data.tar.gz: 257c977e5fa0b37615448040ebcb42fd77cae408
3
+ metadata.gz: 6ec23f9e827ebf793af1412a68847a9f37ff9278
4
+ data.tar.gz: 9e2d0a36edb3093e4384067225d95c03341cca8f
5
5
  SHA512:
6
- metadata.gz: 690851008b629b2ece84d06e27cac23a4f794b66383686335983491858e35f3d1634f60f25452dc4a50a483ceba2f14ca7206db291c3ca890013362cefec53e5
7
- data.tar.gz: 8321aaa93507ce629edc802adbbc203a5b69248b610fe223144910a267c6edc12db9c5c2d373acb24e9d02928223ab56d76ffd8554c42d9f4a7dca0d53de078e
6
+ metadata.gz: 2cd2365fb8291e0307c29b5283eb0537950e6bab08ed69999cb4fc9c5f66c14b17d0758aabf37b5467eef99778afb3b8915e0bb6bcef533e6611ca376cdf78ab
7
+ data.tar.gz: f1c4810b80c622b188c7f936a45dc2db4ecd98e2a1e71103f6cd525293720144481ef49198bda1c0ebe42a3f6f5152d6784960c0a22558d1a5d11b4015ccd0c4
data/bin/scc CHANGED
@@ -6,41 +6,33 @@ require 'slop'
6
6
  def run
7
7
  $opts = Slop.parse do
8
8
  banner 'Usage: scc -r RECIPE'
9
-
10
- on 'stellar-core-bin', 'a path to a stellar-core executable (default to `which stellar-core`)', argument: true
9
+
10
+ on 'stellar-core-bin', 'a path to a stellar-core executable (defaults to `which stellar-core`)', argument: true
11
+
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'
12
14
  end
13
15
 
14
16
  recipe = load_recipe
15
17
  commander = make_commander
16
- process = commander.make_process
17
18
 
18
19
  #run recipe
19
- transactor = StellarCoreCommander::Transactor.new(process)
20
- process.run
21
- process.wait_for_ready
20
+ transactor = StellarCoreCommander::Transactor.new(commander)
21
+
22
+
22
23
  transactor.run_recipe recipe
23
24
  transactor.close_ledger
24
25
 
25
- output_results(process)
26
+ output_results(transactor.get_process(:process))
26
27
  end
27
28
 
28
29
 
29
30
  def make_commander
30
- stellar_core_bin = $opts[:"stellar-core-bin"]
31
+ opts = {
32
+ stellar_core_bin: $opts[:"stellar-core-bin"],
33
+ }
31
34
 
32
- if stellar_core_bin.blank?
33
- search = `which stellar-core`.strip
34
-
35
- if $?.success?
36
- stellar_core_bin = search
37
- else
38
- $stderr.puts "Could not find a `stellar-core` binary, please use --stellar-core-bin to specify"
39
- exit 1
40
- end
41
- end
42
-
43
- StellarCoreCommander::Commander.new(stellar_core_bin).tap do |c|
35
+ StellarCoreCommander::Commander.new($opts[:"process"], opts).tap do |c|
44
36
  c.cleanup_at_exit!
45
37
  end
46
38
  end
@@ -66,5 +58,3 @@ def output_results(process)
66
58
  end
67
59
 
68
60
  run
69
-
70
-
@@ -2,9 +2,9 @@ account :usd_gateway
2
2
  account :scott
3
3
  account :andrew
4
4
 
5
- payment :master, :usd_gateway, [:native, 1000_000000]
6
- payment :master, :scott, [:native, 1000_000000]
7
- payment :master, :andrew, [:native, 1000_000000]
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]
8
8
 
9
9
  close_ledger
10
10
 
@@ -18,7 +18,3 @@ trust :andrew, :usd_gateway, "USD"
18
18
  close_ledger
19
19
 
20
20
  allow_trust :usd_gateway, :scott, "USD"
21
-
22
- # close_ledger
23
-
24
- # payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000_000000]
@@ -13,8 +13,8 @@ trust :andrew, :usd_gateway, "USD"
13
13
 
14
14
  close_ledger
15
15
 
16
- payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000_000000]
16
+ payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000 * Stellar::ONE]
17
17
 
18
18
  close_ledger
19
19
 
20
- payment :scott, :andrew, ["USD", :usd_gateway, 500_000000]
20
+ payment :scott, :andrew, ["USD", :usd_gateway, 500 * Stellar::ONE]
@@ -1,17 +1,14 @@
1
- # DOES NOT YET WORK WITH LATEST TRANSACTION TYPES
2
-
3
1
  account :usd_gateway
4
2
  account :eur_gateway
5
3
  account :scott
6
4
  account :bartek
7
5
  account :andrew
8
6
 
9
- payment :master, :usd_gateway, [:native, 1000_000000]
10
- payment :master, :eur_gateway, [:native, 1000_000000]
11
-
12
- payment :master, :scott, [:native, 1000_000000]
13
- payment :master, :bartek, [:native, 1000_000000]
14
- payment :master, :andrew, [:native, 1000_000000]
7
+ create_account :usd_gateway, :master
8
+ create_account :eur_gateway, :master
9
+ create_account :scott, :master
10
+ create_account :bartek, :master
11
+ create_account :andrew, :master
15
12
 
16
13
  close_ledger
17
14
 
@@ -22,15 +19,15 @@ trust :andrew, :eur_gateway, "EUR"
22
19
 
23
20
  close_ledger
24
21
 
25
- payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000_000000]
26
- payment :usd_gateway, :andrew, ["USD", :usd_gateway, 200_000000]
27
- payment :eur_gateway, :andrew, ["EUR", :eur_gateway, 200_000000]
28
- payment :eur_gateway, :bartek, ["EUR", :eur_gateway, 1000_000000]
22
+ payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000 * Stellar::ONE]
23
+ payment :usd_gateway, :andrew, ["USD", :usd_gateway, 200 * Stellar::ONE]
24
+ payment :eur_gateway, :andrew, ["EUR", :eur_gateway, 200 * Stellar::ONE]
25
+ payment :eur_gateway, :bartek, ["EUR", :eur_gateway, 1000 * Stellar::ONE]
29
26
 
30
27
  close_ledger
31
28
 
32
- offer :andrew, {buy:["USD", :usd_gateway], with:["EUR", :eur_gateway]}, 200_000000, 1.0
29
+ offer :andrew, {buy:["USD", :usd_gateway], with:["EUR", :eur_gateway]}, 200 * Stellar::ONE, 1.0
33
30
 
34
31
  close_ledger
35
32
 
36
- payment :scott, :bartek, ["EUR", :eur_gateway, 10], path: [["USD", :usd_gateway]]
33
+ payment :scott, :bartek, ["EUR", :eur_gateway, 10], with: ["USD", :usd_gateway, 10], path: []
@@ -2,6 +2,6 @@ account :scott
2
2
 
3
3
  create_account :scott, :master
4
4
 
5
- close_ledger
5
+ close_ledger
6
6
 
7
- payment :master, :scott, [:native, 1000_000000]
7
+ payment :master, :scott, [:native, 1000 * Stellar::ONE]
@@ -3,10 +3,10 @@ account :eur_gateway
3
3
  account :scott
4
4
  account :bartek
5
5
 
6
- create_account :usd_gateway, :master, 1000_000000
7
- create_account :eur_gateway, :master, 1000_000000
8
- create_account :scott, :master, 1000_000000
9
- create_account :bartek, :master, 1000_000000
6
+ create_account :usd_gateway, :master, 1000 * Stellar::ONE
7
+ create_account :eur_gateway, :master, 1000 * Stellar::ONE
8
+ create_account :scott, :master, 1000 * Stellar::ONE
9
+ create_account :bartek, :master, 1000 * Stellar::ONE
10
10
 
11
11
  close_ledger
12
12
 
@@ -17,15 +17,15 @@ trust :bartek, :eur_gateway, "EUR"
17
17
 
18
18
  close_ledger
19
19
 
20
- payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000_000000]
21
- payment :eur_gateway, :bartek, ["EUR", :eur_gateway, 1000_000000]
20
+ payment :usd_gateway, :scott, ["USD", :usd_gateway, 1000 * Stellar::ONE]
21
+ payment :eur_gateway, :bartek, ["EUR", :eur_gateway, 1000 * Stellar::ONE]
22
22
 
23
23
  close_ledger
24
24
 
25
- offer :bartek, {buy:["USD", :usd_gateway], with:["EUR", :eur_gateway]}, 1000_000000, 1.0
25
+ offer :bartek, {buy:["USD", :usd_gateway], with:["EUR", :eur_gateway]}, 1000 * Stellar::ONE, 1.0
26
26
 
27
27
  close_ledger
28
28
 
29
- offer :scott, {sell:["USD", :usd_gateway], for:["EUR", :eur_gateway]}, 500_000000, 1.0
29
+ offer :scott, {sell:["USD", :usd_gateway], for:["EUR", :eur_gateway]}, 500 * Stellar::ONE, 1.0
30
30
 
31
- offer :scott, {sell:["USD", :usd_gateway], for: :native}, 500_000000, 1.0
31
+ offer :scott, {sell:["USD", :usd_gateway], for: :native}, 500 * Stellar::ONE, 1.0
@@ -13,7 +13,11 @@ module StellarCoreCommander
13
13
  extend ActiveSupport::Autoload
14
14
 
15
15
  autoload :Commander
16
+
16
17
  autoload :Process
18
+ autoload :LocalProcess
19
+ autoload :DockerProcess
20
+
17
21
  autoload :Transactor
18
22
  autoload :OperationBuilder
19
23
 
@@ -1,28 +1,43 @@
1
1
  require 'fileutils'
2
2
  module StellarCoreCommander
3
+
4
+ #
5
+ # Commander is the object that manages running stellar-core processes. It is
6
+ # responsible for creating and cleaning Process objects
7
+ #
3
8
  class Commander
4
9
  include Contracts
5
10
 
6
- #
11
+ #
7
12
  # Creates a new core commander
8
- #
9
- Contract String => Any
10
- def initialize(stellar_core_bin)
11
- @stellar_core_bin = stellar_core_bin
12
- raise "no file at #{stellar_core_bin}" unless File.exist?(stellar_core_bin)
13
-
13
+ #
14
+ Contract Or["local", "docker"], Hash => Any
15
+ def initialize(process_type, process_options={})
16
+ @process_type = process_type
17
+ @process_options = process_options
14
18
  @processes = []
15
19
  end
16
20
 
17
21
  Contract None => Process
22
+ #
23
+ # make_process returns a new, unlaunched Process object, bound to a new
24
+ # tmpdir and
18
25
  def make_process
19
26
  tmpdir = Dir.mktmpdir("scc")
20
27
 
21
28
  identity = Stellar::KeyPair.random
22
- base_port = 39132 + (@processes.length * 2)
23
-
24
- FileUtils.cp(@stellar_core_bin, "#{tmpdir}/stellar-core")
25
- Process.new(tmpdir, base_port, identity).tap do |p|
29
+ base_port = 39132 + @processes.map(&:required_ports).sum
30
+
31
+ process_class = case @process_type
32
+ when 'local'
33
+ LocalProcess
34
+ when 'docker'
35
+ DockerProcess
36
+ else
37
+ raise "Unknown process type: #{@process_type}"
38
+ end
39
+
40
+ process_class.new(tmpdir, base_port, identity, @process_options).tap do |p|
26
41
  p.setup
27
42
  @processes << p
28
43
  end
@@ -40,4 +55,4 @@ module StellarCoreCommander
40
55
  end
41
56
 
42
57
  end
43
- end
58
+ end
@@ -0,0 +1,161 @@
1
+ require 'uri'
2
+ require 'securerandom'
3
+
4
+ module StellarCoreCommander
5
+
6
+ class DockerProcess < Process
7
+ include Contracts
8
+
9
+ Contract None => Num
10
+ def required_ports
11
+ 3
12
+ end
13
+
14
+ Contract None => Any
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)
17
+ raise "Could not create state container" unless $?.success?
18
+ end
19
+
20
+ Contract None => Any
21
+ def shutdown_state_container
22
+ run_cmd "docker", %W(rm -f -v #{state_container_name})
23
+ raise "Could not drop db: #{database_name}" unless $?.success?
24
+ end
25
+
26
+ Contract None => Any
27
+ 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
+ IO.write("#{working_dir}/stellar-core.env", config)
31
+ end
32
+
33
+ Contract None => Any
34
+ def setup
35
+ write_config
36
+ launch_state_container
37
+ end
38
+
39
+ Contract None => nil
40
+ def run
41
+ raise "already running!" if running?
42
+ launch_stellar_core
43
+ end
44
+
45
+ Contract None => Bool
46
+ def running?
47
+ run_cmd "docker", %W(inspect #{container_name})
48
+ $?.success?
49
+ end
50
+
51
+ Contract None => Any
52
+ def shutdown
53
+ return true unless running?
54
+ run_cmd "docker", %W(rm -f #{container_name})
55
+ end
56
+
57
+ Contract None => Any
58
+ def cleanup
59
+ database.disconnect
60
+ shutdown
61
+ shutdown_state_container
62
+ rm_working_dir
63
+ end
64
+
65
+ Contract None => Any
66
+ def dump_database
67
+ Dir.chdir(working_dir) do
68
+ `docker exec #{state_container_name} pg_dump -U #{database_user} --clean --no-owner #{database_name}`
69
+ end
70
+ end
71
+
72
+ Contract None => Sequel::Database
73
+ def database
74
+ @database ||= Sequel.postgres(database_name, host: docker_host, port: postgres_port, user: database_user, password: database_password)
75
+ end
76
+
77
+ Contract None => String
78
+ def database_name
79
+ "stellar"
80
+ end
81
+
82
+ Contract None => String
83
+ def database_user
84
+ "postgres"
85
+ end
86
+
87
+ Contract None => String
88
+ def database_password
89
+ @database_password ||= SecureRandom.hex
90
+ end
91
+
92
+ Contract None => Num
93
+ def postgres_port
94
+ base_port + 2
95
+ end
96
+
97
+ Contract None => String
98
+ def container_name
99
+ "c#{base_port}"
100
+ end
101
+
102
+ Contract None => String
103
+ def state_container_name
104
+ "db#{container_name}"
105
+ end
106
+
107
+ Contract None => String
108
+ 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
115
+ end
116
+
117
+ Contract None => String
118
+ def http_host
119
+ docker_host
120
+ end
121
+
122
+ private
123
+ def launch_stellar_core
124
+ run_cmd "docker", %W(run
125
+ --name #{container_name}
126
+ --net host
127
+ --volumes-from #{state_container_name}
128
+ --env-file stellar-core.env
129
+ -d stellar/stellar-core
130
+ /run main fresh forcescp
131
+ )
132
+ raise "Could not create stellar-core container" unless $?.success?
133
+ end
134
+
135
+ Contract None => String
136
+ def config
137
+ <<-EOS.strip_heredoc
138
+ POSTGRES_PASSWORD=#{database_password}
139
+
140
+ main_POSTGRES_PORT=#{postgres_port}
141
+ main_PEER_PORT=#{peer_port}
142
+ main_HTTP_PORT=#{http_port}
143
+ main_PEER_SEED=#{identity.seed}
144
+ main_VALIDATION_SEED=#{identity.seed}
145
+
146
+ MANUAL_CLOSE=true
147
+
148
+ QUORUM_THRESHOLD=1
149
+
150
+ PREFERRED_PEERS=["127.0.0.1:#{peer_port}"]
151
+ QUORUM_SET=["#{identity.address}"]
152
+
153
+ HISTORY_PEERS=["main"]
154
+
155
+ HISTORY_GET=cp history/%s/{0} {1}
156
+ HISTORY_PUT=cp {0} history/%s/{1}
157
+ HISTORY_MKDIR=mkdir -p history/%s/{0}
158
+ EOS
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,170 @@
1
+ module StellarCoreCommander
2
+
3
+ class LocalProcess < Process
4
+ include Contracts
5
+
6
+ attr_reader :pid
7
+ attr_reader :wait
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")
23
+ super
24
+ end
25
+
26
+ Contract None => Any
27
+ def forcescp
28
+ run_cmd "./stellar-core", ["--forcescp"]
29
+ raise "Could not set --forcescp" unless $?.success?
30
+ end
31
+
32
+ Contract None => Any
33
+ def initialize_history
34
+ run_cmd "./stellar-core", ["--newhist", "main"]
35
+ raise "Could not initialize history" unless $?.success?
36
+ end
37
+
38
+ Contract None => Any
39
+ def initialize_database
40
+ run_cmd "./stellar-core", ["--newdb"]
41
+ raise "Could not initialize db" unless $?.success?
42
+ end
43
+
44
+ Contract None => Any
45
+ def create_database
46
+ run_cmd "createdb", [database_name]
47
+ raise "Could not create db: #{database_name}" unless $?.success?
48
+ end
49
+
50
+ Contract None => Any
51
+ def drop_database
52
+ run_cmd "dropdb", [database_name]
53
+ raise "Could not drop db: #{database_name}" unless $?.success?
54
+ end
55
+
56
+ Contract None => Any
57
+ def write_config
58
+ IO.write("#{@working_dir}/stellar-core.cfg", config)
59
+ end
60
+
61
+ Contract None => Any
62
+ def setup
63
+ write_config
64
+ create_database
65
+ initialize_history
66
+ initialize_database
67
+ end
68
+
69
+ Contract None => Num
70
+ def run
71
+ raise "already running!" if running?
72
+
73
+ forcescp
74
+ launch_stellar_core
75
+ end
76
+
77
+
78
+ Contract None => Bool
79
+ def running?
80
+ return false unless @pid
81
+ ::Process.kill 0, @pid
82
+ true
83
+ rescue Errno::ESRCH
84
+ false
85
+ end
86
+
87
+ Contract Bool => Bool
88
+ def shutdown(graceful=true)
89
+ return true if !running?
90
+
91
+ if graceful
92
+ ::Process.kill "INT", @pid
93
+ else
94
+ ::Process.kill "KILL", @pid
95
+ end
96
+
97
+ @wait.value.success?
98
+ end
99
+
100
+ Contract None => Any
101
+ def cleanup
102
+ database.disconnect
103
+ shutdown
104
+ drop_database
105
+ rm_working_dir
106
+ end
107
+
108
+ Contract None => Any
109
+ def dump_database
110
+ Dir.chdir(@working_dir) do
111
+ `pg_dump #{database_name} --clean --no-owner`
112
+ end
113
+ end
114
+
115
+
116
+ Contract None => Sequel::Database
117
+ def database
118
+ @database ||= Sequel.postgres(database_name)
119
+ end
120
+
121
+ Contract None => String
122
+ def database_name
123
+ "stellar_core_tmp_#{basename}"
124
+ end
125
+
126
+ Contract None => String
127
+ def dsn
128
+ "postgresql://dbname=#{database_name}"
129
+ end
130
+
131
+ private
132
+ def launch_stellar_core
133
+ Dir.chdir @working_dir do
134
+ sin, sout, serr, wait = Open3.popen3("./stellar-core")
135
+
136
+ # throwaway stdout, stderr (the logs will record any output)
137
+ Thread.new{ until (line = sout.gets).nil? ; end }
138
+ Thread.new{ until (line = serr.gets).nil? ; end }
139
+
140
+ @wait = wait
141
+ @pid = wait.pid
142
+ end
143
+ end
144
+
145
+ Contract None => String
146
+ def config
147
+ <<-EOS.strip_heredoc
148
+ MANUAL_CLOSE=true
149
+ PEER_PORT=#{peer_port}
150
+ RUN_STANDALONE=false
151
+ HTTP_PORT=#{http_port}
152
+ PUBLIC_HTTP_PORT=false
153
+ PEER_SEED="#{@identity.seed}"
154
+ VALIDATION_SEED="#{@identity.seed}"
155
+
156
+ DATABASE="#{dsn}"
157
+
158
+ [QUORUM_SET]
159
+ THRESHOLD=1
160
+ VALIDATORS=["#{@identity.address}"]
161
+
162
+ [HISTORY.main]
163
+ get="cp history/main/{0} {1}"
164
+ put="cp {0} history/main/{1}"
165
+ mkdir="mkdir -p history/main/{0}"
166
+ EOS
167
+ end
168
+
169
+ end
170
+ end
@@ -5,9 +5,12 @@ module StellarCoreCommander
5
5
 
6
6
  Currency = Or[
7
7
  [String, Symbol],
8
- :native
8
+ :native,
9
+ ]
10
+ Amount = Or[
11
+ [String, Symbol, Num],
12
+ [:native, Num],
9
13
  ]
10
- Amount = Any #TODO
11
14
 
12
15
  OfferCurrencies = Or[
13
16
  {sell:Currency, for: Currency},
@@ -19,30 +22,27 @@ module StellarCoreCommander
19
22
  @transactor = transactor
20
23
  end
21
24
 
22
- Contract Symbol, Symbol, Amount, Or[{}, {path: Any}] => Any
25
+ Contract Symbol, Symbol, Amount, Or[{}, {path: ArrayOf[Currency], with:Amount}] => Any
23
26
  def payment(from, to, amount, options={})
24
27
  from = get_account from
25
28
  to = get_account to
26
29
 
27
- if amount.first != :native
28
- amount = [:iso4217] + amount
29
- amount[2] = get_account(amount[2])
30
- amount[1] = amount[1].ljust(4, "\x00")
31
- end
32
-
33
30
  attrs = {
34
31
  account: from,
35
32
  destination: to,
36
33
  sequence: next_sequence(from),
37
- amount: amount,
34
+ amount: normalize_amount(amount),
38
35
  }
39
36
 
40
- # TODO: Fix pathed payments
41
- # if options[:path]
42
- # attrs[:path] = options[:path].map{|p| make_currency p}
43
- # end
37
+ tx = if options[:with]
38
+ attrs[:with] = normalize_amount(options[:with])
39
+ attrs[:path] = options[:path].map{|p| make_currency p}
40
+ Stellar::Transaction.path_payment(attrs)
41
+ else
42
+ Stellar::Transaction.payment(attrs)
43
+ end
44
44
 
45
- Stellar::Transaction.payment(attrs).to_envelope(from)
45
+ tx.to_envelope(from)
46
46
  end
47
47
 
48
48
  Contract Symbol, Symbol, Num => Any
@@ -146,10 +146,9 @@ module StellarCoreCommander
146
146
  end
147
147
 
148
148
  code, issuer = *input
149
- code = code.ljust(4, "\x00")
150
149
  issuer = get_account issuer
151
150
 
152
- [:iso4217, code, issuer]
151
+ [:alphanum, code, issuer]
153
152
  end
154
153
 
155
154
  def make_account_flags(flags=nil)
@@ -157,5 +156,15 @@ module StellarCoreCommander
157
156
  flags.map{|f| Stellar::AccountFlags.send(f)}
158
157
  end
159
158
 
159
+ Contract Amount => Any
160
+ def normalize_amount(amount)
161
+ return amount if amount.first == :native
162
+
163
+ amount = [:alphanum] + amount
164
+ amount[2] = get_account(amount[2]) # translate issuer to account
165
+
166
+ amount
167
+ end
168
+
160
169
  end
161
170
  end
@@ -6,82 +6,34 @@ module StellarCoreCommander
6
6
  attr_reader :working_dir
7
7
  attr_reader :base_port
8
8
  attr_reader :identity
9
- attr_reader :pid
10
- attr_reader :wait
9
+ attr_reader :server
11
10
 
12
- def initialize(working_dir, base_port, identity)
11
+ def initialize(working_dir, base_port, identity, opts)
13
12
  @working_dir = working_dir
14
13
  @base_port = base_port
15
14
  @identity = identity
16
15
 
17
- @server = Faraday.new(url: "http://127.0.0.1:#{http_port}") do |conn|
16
+ @server = Faraday.new(url: "http://#{http_host}:#{http_port}") do |conn|
18
17
  conn.request :url_encoded
19
18
  conn.adapter Faraday.default_adapter
20
19
  end
21
20
  end
22
21
 
23
- Contract None => Any
24
- def forcescp
25
- run_cmd "./stellar-core", ["--forcescp"]
26
- raise "Could not set --forcescp" unless $?.success?
27
- end
28
-
29
- Contract None => Any
30
- def initialize_history
31
- run_cmd "./stellar-core", ["--newhist", "main"]
32
- raise "Could not initialize history" unless $?.success?
33
- end
34
-
35
- Contract None => Any
36
- def initialize_database
37
- run_cmd "./stellar-core", ["--newdb"]
38
- raise "Could not initialize db" unless $?.success?
39
- end
40
-
41
- Contract None => Any
42
- def create_database
43
- run_cmd "createdb", [database_name]
44
- raise "Could not create db: #{database_name}" unless $?.success?
45
- end
46
-
47
- Contract None => Any
48
- def drop_database
49
- run_cmd "dropdb", [database_name]
50
- raise "Could not drop db: #{database_name}" unless $?.success?
51
- end
52
-
53
- Contract None => Any
54
- def write_config
55
- IO.write("#{@working_dir}/stellar-core.cfg", config)
22
+ Contract None => Num
23
+ def required_ports
24
+ 2
56
25
  end
57
26
 
58
27
  Contract None => Any
59
28
  def rm_working_dir
60
- FileUtils.rm_rf @working_dir
61
- end
62
-
63
- Contract None => Any
64
- def setup
65
- write_config
66
- create_database
67
- initialize_history
68
- initialize_database
29
+ FileUtils.rm_rf working_dir
69
30
  end
70
31
 
71
- Contract None => Num
72
- def run
73
- raise "already running!" if running?
74
-
75
- forcescp
76
- launch_stellar_core
77
- end
78
-
79
-
80
32
  Contract None => Any
81
33
  def wait_for_ready
82
34
  loop do
83
35
 
84
- response = @server.get("/info") rescue false
36
+ response = server.get("/info") rescue false
85
37
 
86
38
  if response
87
39
  body = ActiveSupport::JSON.decode(response.body)
@@ -94,36 +46,14 @@ module StellarCoreCommander
94
46
  end
95
47
  end
96
48
 
97
- Contract None => Bool
98
- def running?
99
- return false unless @pid
100
- ::Process.kill 0, @pid
101
- true
102
- rescue Errno::ESRCH
103
- false
104
- end
105
-
106
- Contract Bool => Bool
107
- def shutdown(graceful=true)
108
- return true if !running?
109
-
110
- if graceful
111
- ::Process.kill "INT", @pid
112
- else
113
- ::Process.kill "KILL", @pid
114
- end
115
-
116
- @wait.value.success?
117
- end
118
-
119
49
  Contract None => Bool
120
50
  def close_ledger
121
51
  prev_ledger = latest_ledger
122
52
  next_ledger = prev_ledger + 1
123
53
 
124
- @server.get("manualclose")
54
+ server.get("manualclose")
125
55
 
126
- Timeout.timeout(5.0) do
56
+ Timeout.timeout(close_timeout) do
127
57
  loop do
128
58
  current_ledger = latest_ledger
129
59
 
@@ -142,9 +72,19 @@ module StellarCoreCommander
142
72
  true
143
73
  end
144
74
 
75
+ Contract None => Num
76
+ def http_port
77
+ base_port
78
+ end
79
+
80
+ Contract None => Num
81
+ def peer_port
82
+ base_port + 1
83
+ end
84
+
145
85
  Contract String => Any
146
86
  def submit_transaction(envelope_hex)
147
- response = @server.get("tx", blob: envelope_hex)
87
+ response = server.get("tx", blob: envelope_hex)
148
88
  body = ActiveSupport::JSON.decode(response.body)
149
89
 
150
90
  if body["status"] == "ERROR"
@@ -153,14 +93,12 @@ module StellarCoreCommander
153
93
 
154
94
  end
155
95
 
156
-
157
96
  Contract Stellar::KeyPair => Num
158
97
  def sequence_for(account)
159
98
  row = database[:accounts].where(:accountid => account.address).first
160
99
  row[:seqnum]
161
100
  end
162
101
 
163
-
164
102
  Contract None => Num
165
103
  def latest_ledger
166
104
  database[:ledgerheaders].max(:ledgerseq)
@@ -172,98 +110,33 @@ module StellarCoreCommander
172
110
  row[:txresult]
173
111
  end
174
112
 
175
- Contract None => Any
176
- def cleanup
177
- database.disconnect
178
- shutdown
179
- drop_database
180
- rm_working_dir
181
- end
182
-
183
- Contract None => Any
184
- def dump_database
185
- Dir.chdir(@working_dir) do
186
- `pg_dump #{database_name} --clean --no-owner`
187
- end
188
- end
189
-
190
-
191
- Contract None => Sequel::Database
192
- def database
193
- @database ||= Sequel.postgres(database_name)
194
- end
195
-
196
113
  Contract None => String
197
- def database_name
198
- "stellar_core_tmp_#{basename}"
199
- end
200
-
201
- Contract None => String
202
- def dsn
203
- "postgresql://dbname=#{database_name}"
114
+ def http_host
115
+ "127.0.0.1"
204
116
  end
205
117
 
206
118
  Contract None => Num
207
- def http_port
208
- @base_port
209
- end
210
-
211
- Contract None => Num
212
- def peer_port
213
- @base_port + 1
119
+ def close_timeout
120
+ 5.0
214
121
  end
215
122
 
216
123
  private
217
124
  Contract None => String
218
125
  def basename
219
- File.basename(@working_dir)
126
+ File.basename(working_dir)
220
127
  end
221
128
 
222
129
  Contract String, ArrayOf[String] => Maybe[Bool]
223
130
  def run_cmd(cmd, args)
224
131
  args += [{
225
- out: "stellar-core.log",
132
+ out: "stellar-core.log",
226
133
  err: "stellar-core.log",
227
134
  }]
228
135
 
229
- Dir.chdir @working_dir do
136
+ Dir.chdir working_dir do
230
137
  system(cmd, *args)
231
138
  end
232
139
  end
233
140
 
234
- def launch_stellar_core
235
- Dir.chdir @working_dir do
236
- sin, sout, serr, wait = Open3.popen3("./stellar-core")
237
-
238
- # throwaway stdout, stderr (the logs will record any output)
239
- Thread.new{ until (line = sout.gets).nil? ; end }
240
- Thread.new{ until (line = serr.gets).nil? ; end }
241
-
242
- @wait = wait
243
- @pid = wait.pid
244
- end
245
- end
246
-
247
- Contract None => String
248
- def config
249
- <<-EOS.strip_heredoc
250
- MANUAL_CLOSE=true
251
- PEER_PORT=#{peer_port}
252
- RUN_STANDALONE=false
253
- HTTP_PORT=#{http_port}
254
- PUBLIC_HTTP_PORT=false
255
- PEER_SEED="#{@identity.seed}"
256
- VALIDATION_SEED="#{@identity.seed}"
257
- QUORUM_THRESHOLD=1
258
- QUORUM_SET=["#{@identity.address}"]
259
- DATABASE="#{dsn}"
260
-
261
- [HISTORY.main]
262
- get="cp history/main/{0} {1}"
263
- put="cp {0} history/main/{1}"
264
- mkdir="mkdir -p history/main/{0}"
265
- EOS
266
- end
267
-
268
141
  end
269
142
  end
@@ -2,32 +2,37 @@ require 'fileutils'
2
2
  module StellarCoreCommander
3
3
 
4
4
 
5
- #
5
+ #
6
6
  # A transactor plays transactions against a stellar-core test node.
7
- #
8
- #
7
+ #
8
+ #
9
9
  class Transactor
10
10
  include Contracts
11
11
 
12
12
  class FailedTransaction < StandardError ; end
13
13
 
14
- Contract Process => Any
15
- def initialize(process)
16
- @process = process
17
- @named = {}.with_indifferent_access
18
- @unverified = []
14
+ Contract Commander => Any
15
+ def initialize(commander)
16
+ @commander = commander
17
+ @named = {}.with_indifferent_access
18
+ @unverified = []
19
19
  @operation_builder = OperationBuilder.new(self)
20
+
20
21
  account :master, Stellar::KeyPair.from_raw_seed("allmylifemyhearthasbeensearching")
21
22
  end
22
23
 
23
24
  Contract String => Any
24
- #
25
+ #
25
26
  # Runs the provided recipe against the process identified by @process
26
- #
27
+ #
27
28
  # @param recipe_path [String] path to the recipe file
28
- #
29
+ #
29
30
  def run_recipe(recipe_path)
30
- raise "stellar-core not running" unless @process.running?
31
+ @process = @commander.make_process
32
+ @process.run
33
+ @process.wait_for_ready
34
+
35
+ add_named :process, @process
31
36
 
32
37
  recipe_content = IO.read(recipe_path)
33
38
  instance_eval recipe_content
@@ -35,13 +40,13 @@ module StellarCoreCommander
35
40
 
36
41
 
37
42
  Contract Symbol, Stellar::KeyPair => Any
38
- #
43
+ #
39
44
  # Registered an account for this scenario. Future calls may refer to
40
45
  # the name provided.
41
- #
46
+ #
42
47
  # @param name [Symbol] the name to register the keypair at
43
48
  # @param keypair=Stellar::KeyPair.random [Stellar::KeyPair] the keypair to use for this account
44
- #
49
+ #
45
50
  def account(name, keypair=Stellar::KeyPair.random)
46
51
  unless keypair.is_a?(Stellar::KeyPair)
47
52
  raise ArgumentError, "`#{keypair.class.name}` is not `Stellar::KeyPair`"
@@ -51,71 +56,71 @@ module StellarCoreCommander
51
56
  end
52
57
 
53
58
 
54
- #
59
+ #
55
60
  # @see StellarCoreCommander::OperationBuilder#payment
56
61
  def payment(*args)
57
62
  envelope = @operation_builder.payment(*args)
58
63
 
59
64
  submit_transaction envelope do |result|
60
- payment_result = result.result.results!.first.tr!.payment_result!
65
+ payment_result = result.result.results!.first.tr!.value
61
66
  raise FailedTransaction unless payment_result.code.value >= 0
62
67
  end
63
68
  end
64
69
 
65
- #
70
+ #
66
71
  # @see StellarCoreCommander::OperationBuilder#create_account
67
72
  def create_account(*args)
68
73
  envelope = @operation_builder.create_account(*args)
69
74
  submit_transaction envelope
70
- end
75
+ end
71
76
 
72
- #
77
+ #
73
78
  # @see StellarCoreCommander::OperationBuilder#trust
74
79
  def trust(*args)
75
80
  envelope = @operation_builder.trust(*args)
76
81
  submit_transaction envelope
77
- end
82
+ end
78
83
 
79
- #
84
+ #
80
85
  # @see StellarCoreCommander::OperationBuilder#change_trust
81
86
  def change_trust(*args)
82
87
  envelope = @operation_builder.change_trust(*args)
83
88
  submit_transaction envelope
84
89
  end
85
90
 
86
- #
91
+ #
87
92
  # @see StellarCoreCommander::OperationBuilder#offer
88
93
  def offer(*args)
89
94
  envelope = @operation_builder.offer(*args)
90
95
  submit_transaction envelope
91
96
  end
92
97
 
93
- #
98
+ #
94
99
  # @see StellarCoreCommander::OperationBuilder#require_trust_auth
95
100
  def require_trust_auth(*args)
96
101
  envelope = @operation_builder.require_trust_auth(*args)
97
102
  submit_transaction envelope
98
- end
103
+ end
99
104
 
100
- #
105
+ #
101
106
  # @see StellarCoreCommander::OperationBuilder#set_flags
102
107
  def set_flags(*args)
103
108
  envelope = @operation_builder.set_flags(*args)
104
109
  submit_transaction envelope
105
110
  end
106
-
107
- #
111
+
112
+ #
108
113
  # @see StellarCoreCommander::OperationBuilder#allow_trust
109
114
  def allow_trust(*args)
110
115
  envelope = @operation_builder.allow_trust(*args)
111
116
  submit_transaction envelope
112
- end
117
+ end
113
118
 
114
119
  Contract None => Any
115
- #
120
+ #
116
121
  # Triggers a ledger close. Any unvalidated transaction will
117
122
  # be validated, which will trigger an error if any fail to be validated
118
- #
123
+ #
119
124
  def close_ledger
120
125
  @process.close_ledger
121
126
 
@@ -131,7 +136,6 @@ module StellarCoreCommander
131
136
  end
132
137
  end
133
138
 
134
- # TODO: validate in-flight transactions
135
139
  @unverified.clear
136
140
  end
137
141
 
@@ -144,6 +148,15 @@ module StellarCoreCommander
144
148
  end
145
149
  end
146
150
 
151
+ Contract Symbol => Process
152
+ def get_process(name)
153
+ @named[name].tap do |found|
154
+ unless found.is_a?(Process)
155
+ raise ArgumentError, "#{name.inspect} is not process"
156
+ end
157
+ end
158
+ end
159
+
147
160
  Contract Stellar::KeyPair => Num
148
161
  def next_sequence(account)
149
162
  base_sequence = @process.sequence_for(account)
@@ -177,9 +190,9 @@ module StellarCoreCommander
177
190
  hex_hash = Convert.to_hex(raw_hash)
178
191
 
179
192
  base64_result = @process.transaction_result(hex_hash)
180
-
193
+
181
194
  raise "couldn't find result for #{hex_hash}" if base64_result.blank?
182
-
195
+
183
196
  raw_result = Convert.from_base64(base64_result)
184
197
 
185
198
  pair = Stellar::TransactionResultPair.from_xdr(raw_result)
@@ -194,4 +207,4 @@ module StellarCoreCommander
194
207
  end
195
208
 
196
209
  end
197
- end
210
+ end
@@ -1,3 +1,3 @@
1
1
  module StellarCoreCommander
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
@@ -17,11 +17,11 @@ 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.9"
20
+ spec.add_dependency "stellar-base", "= 0.0.10"
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"
24
- spec.add_dependency "pg", "~> 0.18.1"
24
+ spec.add_dependency "pg", "~> 0.18.1"
25
25
  spec.add_dependency "sequel", "~> 4.21.0"
26
26
  spec.add_dependency "activesupport", ">= 4.0.0"
27
27
  spec.add_dependency "contracts", "~> 0.9"
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.8
4
+ version: 0.0.9
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-05-21 00:00:00.000000000 Z
11
+ date: 2015-06-01 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.9
19
+ version: 0.0.10
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.9
26
+ version: 0.0.10
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: slop
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -186,6 +186,8 @@ files:
186
186
  - lib/stellar_core_commander.rb
187
187
  - lib/stellar_core_commander/commander.rb
188
188
  - lib/stellar_core_commander/convert.rb
189
+ - lib/stellar_core_commander/docker_process.rb
190
+ - lib/stellar_core_commander/local_process.rb
189
191
  - lib/stellar_core_commander/operation_builder.rb
190
192
  - lib/stellar_core_commander/process.rb
191
193
  - lib/stellar_core_commander/transactor.rb