stellar_core_commander 0.0.8 → 0.0.9

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