Class: StellarCoreCommander::Transactor

Inherits:
Object
  • Object
show all
Includes:
Contracts
Defined in:
lib/stellar_core_commander/transactor.rb

Overview

A transactor plays transactions against a stellar-core test node.

Defined Under Namespace

Classes: FailedTransaction, MissingTransaction

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(commander) ⇒ Transactor

Returns a new instance of Transactor.



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/stellar_core_commander/transactor.rb', line 18

def initialize(commander)
  @commander         = commander
  @named             = {}.with_indifferent_access
  @operation_builder = OperationBuilder.new(self)
  @manual_close      = false

  network_passphrase = @commander.process_options[:network_passphrase]
  Stellar.on_network network_passphrase do
     :master, Stellar::KeyPair.master
  end
end

Instance Attribute Details

#manual_closeObject (readonly)

Returns the value of attribute manual_close.



15
16
17
# File 'lib/stellar_core_commander/transactor.rb', line 15

def manual_close
  @manual_close
end

Class Method Details

.recipe_step(name) ⇒ Object

recipe_step is a helper method to define a method that follows the common procedure of executing a recipe step:

  1. ensure all processes are running
  2. build the envelope by forwarding to the operation builder
  3. submit the envelope to the process

Parameters:

  • name (Symbol)

    the method to be defined and delegated to @operation_builder



85
86
87
88
89
90
91
# File 'lib/stellar_core_commander/transactor.rb', line 85

def self.recipe_step(name)
  define_method name do |*args|
    require_process_running
    envelope = @operation_builder.send(name, *args)
    submit_transaction envelope
  end
end

Instance Method Details

#account(name, keypair = Stellar::KeyPair.random) ⇒ Object

Registered an account for this scenario. Future calls may refer to the name provided.

Parameters:

  • name (Symbol)

    the name to register the keypair at

  • keypair=Stellar::KeyPair.random (Stellar::KeyPair)

    the keypair to use for this account



72
73
74
# File 'lib/stellar_core_commander/transactor.rb', line 72

def (name, keypair=Stellar::KeyPair.random)
  add_named name, keypair
end

#account_created(account) ⇒ Object



306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/stellar_core_commander/transactor.rb', line 306

def ()
  require_process_running
  if .is_a?(Symbol)
     = ()
  end
  begin
    @process.()
    return true
  rescue
    return false
  end
end

#balance(account) ⇒ Object



320
321
322
323
324
325
326
327
# File 'lib/stellar_core_commander/transactor.rb', line 320

def balance()
  require_process_running
  if .is_a?(Symbol)
     = ()
  end
  raise "no process!" unless @process
  @process.balance_for()
end

#catchup(ledger, mode = :minimal) ⇒ Object



197
198
199
200
# File 'lib/stellar_core_commander/transactor.rb', line 197

def catchup(ledger, mode=:minimal)
  require_process_running
  @process.catchup ledger, mode
end

#check_database_against_ledger_bucketsObject



362
363
364
365
366
367
368
369
370
# File 'lib/stellar_core_commander/transactor.rb', line 362

def check_database_against_ledger_buckets
  runs = @process.checkdb_runs
  @process.start_checkdb
  retry_until_true do
    r = @process.checkdb_runs
    $stderr.puts "checkdb runs: #{r}, checked: #{@process.objects_checked}"
    r != runs
  end
end

#check_equal_ledger_objects(processes) ⇒ Object



341
342
343
344
345
346
347
348
349
350
# File 'lib/stellar_core_commander/transactor.rb', line 341

def check_equal_ledger_objects(processes)
  raise "no process!" unless @process
  for p in processes
    if p.is_a?(Symbol)
      p = get_process(p)
    end
    @process.check_equal_ledger_objects(p)
  end
  true
end

#check_integrity_against(other) ⇒ Object



373
374
375
376
377
378
# File 'lib/stellar_core_commander/transactor.rb', line 373

def check_integrity_against(other)
  check_no_error_metrics
  check_database_against_ledger_buckets
  check_equal_ledger_objects [other]
  check_ledger_sequence_is_prefix_of other
end

#check_ledger_sequence_is_prefix_of(other) ⇒ Object



353
354
355
356
357
358
359
# File 'lib/stellar_core_commander/transactor.rb', line 353

def check_ledger_sequence_is_prefix_of(other)
  raise "no process!" unless @process
  if other.is_a?(Symbol)
    other = get_process(other)
  end
  @process.check_ledger_sequence_is_prefix_of(other)
end

#check_no_error_metricsObject



336
337
338
# File 'lib/stellar_core_commander/transactor.rb', line 336

def check_no_error_metrics
  @commander.check_no_process_error_metrics
end

#close_ledgerObject

Triggers a ledger close. Any unvalidated transaction will be validated, which will trigger an error if any fail to be validated



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/stellar_core_commander/transactor.rb', line 168

def close_ledger
  require_process_running
  @process.close_ledger

  @process.unverified.each do |eb|
    begin
      envelope, after_confirmation = *eb
      result = validate_transaction envelope
      after_confirmation.call(result) if after_confirmation
    rescue MissingTransaction
      $stderr.puts "Failed to validate tx: #{Convert.to_hex envelope.tx.hash}"
      $stderr.puts "could not be found in txhistory table on process #{@process.name}"
    rescue FailedTransaction
      $stderr.puts "Failed to validate tx: #{Convert.to_hex envelope.tx.hash}"
      $stderr.puts "failed result: #{result.to_xdr(:base64)}"
      exit 1
    end
  end

  @process.unverified.clear
end

#crashObject



203
204
205
# File 'lib/stellar_core_commander/transactor.rb', line 203

def crash
  @process.crash
end

#generate_load_and_await_completion(accounts, txs, txrate) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/stellar_core_commander/transactor.rb', line 238

def generate_load_and_await_completion(accounts, txs, txrate)
  runs = @process.load_generation_runs
  start_load_generation accounts, txs, txrate
  retry_until_true retries: accounts + txs do
    txs = @process.transactions_applied
    r = @process.load_generation_runs
    tps = @process.transactions_per_second
    ops = @process.operations_per_second
    $stderr.puts "loadgen runs: #{r}, ledger: #{ledger_num}, txs: #{txs}, actual tx/s: #{tps} op/s: #{ops}"
    r != runs
  end
end

#get_account(name) ⇒ Object



208
209
210
211
212
213
214
215
# File 'lib/stellar_core_commander/transactor.rb', line 208

def (name)
  require_process_running
  @named[name].tap do |found|
    unless found.is_a?(Stellar::KeyPair)
      raise ArgumentError, "#{name.inspect} is not account"
    end
  end
end

#get_process(name) ⇒ Object



218
219
220
221
222
223
224
# File 'lib/stellar_core_commander/transactor.rb', line 218

def get_process(name)
  @named[name].tap do |found|
    unless found.is_a?(Process)
      raise ArgumentError, "#{name.inspect} is not process"
    end
  end
end

#ledger_numObject



191
192
193
194
# File 'lib/stellar_core_commander/transactor.rb', line 191

def ledger_num
  require_process_running
  @process.ledger_num
end

#load_generation_completeObject



233
234
235
# File 'lib/stellar_core_commander/transactor.rb', line 233

def load_generation_complete
  @process.load_generation_complete
end

#metricsObject



252
253
254
# File 'lib/stellar_core_commander/transactor.rb', line 252

def metrics
  @process.metrics
end

#next_sequence(account) ⇒ Object



297
298
299
300
301
302
303
# File 'lib/stellar_core_commander/transactor.rb', line 297

def next_sequence()
  require_process_running
  base_sequence  = @process.sequence_for()
  inflight_count = @process.unverified.select{|e| e.first.tx. == .public_key}.length

  base_sequence + inflight_count + 1
end

#on(process_name) ⇒ Object



270
271
272
273
274
275
276
277
278
279
# File 'lib/stellar_core_commander/transactor.rb', line 270

def on(process_name)
  require_process_running
  tmp = @process
  p = get_process process_name
  $stderr.puts "executing steps on #{p.idname}"
  @process = p
  yield
ensure
  @process = tmp
end

#payment(*args) ⇒ Object



96
97
98
99
100
101
102
103
104
# File 'lib/stellar_core_commander/transactor.rb', line 96

def payment(*args)
  require_process_running
  envelope = @operation_builder.payment(*args)

  submit_transaction envelope do |result|
    payment_result = result.result.results!.first.tr!.value
    raise FailedTransaction unless payment_result.code.value >= 0
  end
end

#process(name, quorum = [name], options = {}) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
# File 'lib/stellar_core_commander/transactor.rb', line 257

def process(name, quorum=[name], options={})

  if @manual_close and quorum.size != 1
    raise "Cannot use `process` with multi-node quorum, this recipe has previously declared  `use_manual_close`."
  end

  $stderr.puts "creating process #{name}"
  p = @commander.make_process self, name, quorum, options
  $stderr.puts "process #{name} is #{p.idname}"
  add_named name, p
end

#require_process_runningObject



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/stellar_core_commander/transactor.rb', line 30

def require_process_running
  if @process.nil?
    @process = @commander.get_root_process self

    if not @named.has_key? @process.name
      add_named @process.name, @process
    end
  end

  @commander.start_all_processes
  @commander.require_processes_in_sync
end

#retry_until_true(**opts, &block) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/stellar_core_commander/transactor.rb', line 281

def retry_until_true(**opts, &block)
  retries = opts[:retries] || 20
  timeout = opts[:timeout] || 3
  while retries > 0
    b = begin yield block end
    if b
      return b
    end
    retries -= 1
    $stderr.puts "sleeping #{timeout} secs, #{retries} retries left"
    sleep timeout
  end
  raise "Ran out of retries while waiting for success"
end

#run_recipe(recipe_path) ⇒ Object

Runs the provided recipe against the process identified by @process

Parameters:

  • recipe_path (String)

    path to the recipe file



53
54
55
56
57
58
59
60
61
# File 'lib/stellar_core_commander/transactor.rb', line 53

def run_recipe(recipe_path)
  recipe_content = IO.read(recipe_path)
  network_passphrase = @commander.process_options[:network_passphrase]
  Stellar.on_network network_passphrase do
    instance_eval recipe_content, recipe_path, 1
  end
rescue => e
  crash_recipe e
end

#shutdown(*args) ⇒ Object



43
44
45
# File 'lib/stellar_core_commander/transactor.rb', line 43

def shutdown(*args)
  @process.shutdown *args
end

#start_load_generation(accounts = 10000000, txs = 10000000, txrate = 500) ⇒ Object



227
228
229
230
# File 'lib/stellar_core_commander/transactor.rb', line 227

def start_load_generation(accounts=10000000, txs=10000000, txrate=500)
  $stderr.puts "starting load generation: #{accounts} accounts, #{txs} txs, #{txrate} tx/s"
  @process.start_load_generation accounts, txs, txrate
end

#use_manual_closeObject



330
331
332
333
# File 'lib/stellar_core_commander/transactor.rb', line 330

def use_manual_close()
  $stderr.puts "using manual_close mode"
  @manual_close = true
end