#!/usr/bin/env ruby # frozen_string_literal: true # Copyright (c) 2018 Yegor Bugayenko # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the 'Software'), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. STDOUT.sync = true require 'slop' require 'rainbow' require 'zold/log' require 'zold/age' require 'zold/wallet' require 'zold/wallets' require 'zold/sync_wallets' require 'zold/cached_wallets' require 'zold/remotes' require 'zold/commands/list' require_relative '../lib/zold/stress/round' require_relative '../lib/zold/stress/stats' require_relative '../lib/zold/stress/summary' require_relative '../lib/zold/stress/air' Thread.current.name = 'main' Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = Encoding::UTF_8 log = Zold::Log::Regular.new vlog = Zold::Log::Quiet.new begin opts = Slop.parse(ARGV, strict: false, suppress_errors: true) do |o| o.banner = "Usage: zold-stress [options] Available options:" o.integer '-r', '--rounds', 'Total amount of paying rounds to complete (default: 16)', default: 16 o.integer '-w', '--wait', 'For how to long to wait for all payments to arrive (default: 600 seconds)', default: 600 o.integer '-p', '--pool', 'From how many wallets to send payments (default: 8)', default: 8 o.integer '-t', '--threads', "How many threads to use for each operation (default: #{Concurrent.processor_count * 8})", default: Concurrent.processor_count * 8 o.integer '-b', '--batch', 'How many transactions to send in each round (default: 64)', default: 64 o.string '--private-key', 'The location of RSA private key (default: ~/.ssh/id_rsa)', require: true, default: File.expand_path('~/.ssh/id_rsa') o.string '--home', "Home directory (default: #{Dir.pwd})", default: Dir.pwd o.string '--network', "The name of the network we work in (default: #{Zold::Wallet::MAIN_NETWORK}", required: true, default: Zold::Wallet::MAIN_NETWORK o.bool '-h', '--help', 'Show these instructions' o.on '--verbose', 'Enable extra logging information' do log = Zold::Log::Verbose.new vlog = Zold::Log::Regular.new end o.on '--no-colors', 'Disable colors in the ouput' do Rainbow.enabled = false end end log = Zold::Log::Sync.new(log) vlog = Zold::Log::Sync.new(vlog) if opts.help? log.info(opts.to_s) exit end home = File.expand_path(opts[:home]) FileUtils.mkdir_p(home) Dir.chdir(home) zoldata = File.join(home, '.zoldata') wallets = Zold::SyncWallets.new( Zold::CachedWallets.new(Zold::Wallets.new(home)), log: log ) remotes = Zold::Remotes.new(file: File.join(zoldata, 'remotes'), network: opts['network']) if remotes.all.empty? remotes.defaults log.info("The list of remotes has got default nodes, there are #{remotes.all.count} total") end copies = File.join(zoldata, 'copies') stats = Zold::Stress::Stats.new summary = Zold::Stress::Summary.new(stats, opts['batch']) air = Zold::Stress::Air.new round = Zold::Stress::Round.new( pvt: Zold::Key.new(file: opts['private-key']), wallets: wallets, remotes: remotes, copies: copies, stats: stats, air: air, log: log, vlog: vlog, opts: opts ) start = Time.now round.update round.prepare opts['rounds'].times do |r| round.send round.pull round.match log.info(summary) Zold::List.new(wallets: wallets, log: log).run(['list'] + opts.arguments) if (r % 10).zero? end s = Time.now loop do break if Time.now > s + opts['wait'] break if air.fetch.empty? round.pull round.match log.info(summary) end unless air.fetch.empty? raise "#{air.fetch.count} payments out of #{stats.total('paid')} are still somewhere, we lost them :(" end log.info("Successfully sent and received #{Rainbow(stats.total('arrived')).green} transactions \ in #{Zold::Age.new(start)}") rescue StandardError => ex log.error(Backtrace.new(ex)) exit(-1) end