diff --git a/test/jepsen/jepsen/CHANGELOG.md b/test/jepsen/jepsen/CHANGELOG.md index 6f29fa960..9881a4c73 100644 --- a/test/jepsen/jepsen/CHANGELOG.md +++ b/test/jepsen/jepsen/CHANGELOG.md @@ -1,24 +1,6 @@ # Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). -## [Unreleased] +## 0.2.0 - 2020-11-09 ### Changed -- Add a new arity to `make-widget-async` to provide a different widget shape. - -## [0.1.1] - 2017-06-05 -### Changed -- Documentation on how to make the widgets. - -### Removed -- `make-widget-sync` - we're all async, all the time. - -### Fixed -- Fixed widget maker to keep working when daylight savings switches over. - -## 0.1.0 - 2017-06-05 -### Added -- Files from the new template. -- Widget maker public API - `make-widget-sync`. - -[Unreleased]: https://github.com/your-name/jepsen.tendermint/compare/0.1.1...HEAD -[0.1.1]: https://github.com/your-name/jepsen.tendermint/compare/0.1.0...0.1.1 +- Upgraded deps (jepsen 0.2.1) diff --git a/test/jepsen/jepsen/project.clj b/test/jepsen/jepsen/project.clj index a311c179f..0d1523982 100644 --- a/test/jepsen/jepsen/project.clj +++ b/test/jepsen/jepsen/project.clj @@ -1,14 +1,15 @@ -(defproject jepsen.tendermint "0.1.0" +(defproject jepsen.tendermint "0.2.0" :description "Jepsen tests for the Tendermint Byzantine consensus system" :url "http://github.com/jepsen-io/tendermint" :license {:name "Apache License, version 2.0" :url "https://www.apache.org/licenses/LICENSE-2.0"} - :dependencies [[org.clojure/clojure "1.8.0"] - [org.clojure/core.typed "0.4.0"] - [cheshire "5.7.1"] + :dependencies [[org.clojure/clojure "1.10.1"] + [typed.clj/runtime "1.0.12"] + [cheshire "5.10.0"] [slingshot "0.12.2"] - [clj-http "3.6.1"] - [jepsen "0.1.6"]] + [clj-http "3.10.3"] + [jepsen "0.2.1"]] + :profiles {:dev {:dependencies [[typed.clj/checker "1.0.12"]]}} :jvm-opts ["-Xmx6g" "-XX:+UseConcMarkSweepGC" "-XX:+UseParNewGC" @@ -19,6 +20,7 @@ "-XX:MaxRecursiveInlineLevel=2" "-XX:-OmitStackTraceInFastThrow" "-server"] + :plugins [[lein-cljfmt "0.7.0"]] :main jepsen.tendermint.cli :injections [(require 'clojure.core.typed) (clojure.core.typed/install)]) diff --git a/test/jepsen/jepsen/src/jepsen/tendermint/cli.clj b/test/jepsen/jepsen/src/jepsen/tendermint/cli.clj index b1ac349d4..b71f5559e 100644 --- a/test/jepsen/jepsen/src/jepsen/tendermint/cli.clj +++ b/test/jepsen/jepsen/src/jepsen/tendermint/cli.clj @@ -11,18 +11,17 @@ :default :cas-register :parse-fn keyword] [nil "--nemesis NEMESIS" "Nemesis to use; e.g. clocks" - :default :none - :parse-fn keyword] + :default :none + :parse-fn keyword] [nil "--dup-validators" "Whether to have multiple validators share the same key."] [nil "--super-byzantine-validators" "Should byzantine validators have just shy of 2/3 the voting weight?"] (jc/package-opt "tendermint-url" "https://github.com/tendermint/tendermint/releases/download/v0.33.8/tendermint_v0.33.8_linux_amd64.zip") (jc/package-opt "merkleeyes-url" "") (jc/package-opt "abci-url" "")]) - (defn -main [& args] (jc/run! (merge (jc/serve-cmd) (jc/single-test-cmd {:test-fn core/test :opt-spec opts})) - args)) + args)) diff --git a/test/jepsen/jepsen/src/jepsen/tendermint/client.clj b/test/jepsen/jepsen/src/jepsen/tendermint/client.clj index f6d202ccd..eb40e5be8 100644 --- a/test/jepsen/jepsen/src/jepsen/tendermint/client.clj +++ b/test/jepsen/jepsen/src/jepsen/tendermint/client.clj @@ -33,7 +33,7 @@ (loop [i 0] (when (< i n) (aset a i (unchecked-byte (Integer/parseInt - (subs s (* i 2) (+ (* i 2) 2)) 16))) + (subs s (* i 2) (+ (* i 2) 2)) 16))) (recur (inc i)))) (ByteBuffer/wrap a))) @@ -54,7 +54,7 @@ 0 tx 4 (throw+ {:type :unauthorized :log (:log tx)}) 111 (throw+ {:type :base-unknown-address, :log (:log tx)}) - (throw+ (assoc tx :type :unknown-tx-error)))) + (throw+ (assoc tx :type :unknown-tx-error)))) (def port "HTTP interface port" 26657) @@ -146,11 +146,11 @@ "Reads the current validator set, transactionally." [node] (-> (broadcast-tx! node (tx :validator-set-read)) - :deliver_tx - :data - hex->byte-buf - (bs/convert java.io.Reader) - (json/parse-stream true))) + :deliver_tx + :data + hex->byte-buf + (bs/convert java.io.Reader) + (json/parse-stream true))) (defn validator-set-change! "Change the weight of a validator, given by private key (a hex string), and a diff --git a/test/jepsen/jepsen/src/jepsen/tendermint/core.clj b/test/jepsen/jepsen/src/jepsen/tendermint/core.clj index 1f472d823..8633bc41a 100644 --- a/test/jepsen/jepsen/src/jepsen/tendermint/core.clj +++ b/test/jepsen/jepsen/src/jepsen/tendermint/core.clj @@ -22,10 +22,9 @@ [jepsen.os.debian :as debian] [cheshire.core :as json] [jepsen.tendermint [client :as tc] - [db :as td] - [util :refer [base-dir]] - [validator :as tv]] - )) + [db :as td] + [util :refer [base-dir]] + [validator :as tv]])) (defn r [_ _] {:type :invoke, :f :read, :value nil}) (defn w [_ _] {:type :invoke, :f :write, :value (rand-int 10)}) @@ -45,39 +44,38 @@ :fail :info)] (try+ - (case (:f op) - :read (assoc op - :type :ok - :value (independent/tuple k (tc/read node k))) - :write (do (tc/write! node k v) - (assoc op :type :ok)) - :cas (let [[v v'] v] - (tc/cas! node k v v') - (assoc op :type :ok))) + (case (:f op) + :read (assoc op + :type :ok + :value (independent/tuple k (tc/read node k))) + :write (do (tc/write! node k v) + (assoc op :type :ok)) + :cas (let [[v v'] v] + (tc/cas! node k v v') + (assoc op :type :ok))) - (catch [:type :unauthorized] e - (assoc op :type :fail, :error :precondition-failed)) + (catch [:type :unauthorized] e + (assoc op :type :fail, :error :precondition-failed)) - (catch [:type :base-unknown-address] e - (assoc op :type :fail, :error :not-found)) + (catch [:type :base-unknown-address] e + (assoc op :type :fail, :error :not-found)) - (catch org.apache.http.NoHttpResponseException e - (assoc op :type crash, :error :no-http-response)) + (catch org.apache.http.NoHttpResponseException e + (assoc op :type crash, :error :no-http-response)) - (catch java.net.ConnectException e - (condp re-find (.getMessage e) - #"Connection refused" - (assoc op :type :fail, :error :connection-refused) + (catch java.net.ConnectException e + (condp re-find (.getMessage e) + #"Connection refused" + (assoc op :type :fail, :error :connection-refused) - (assoc op :type crash, :error [:connect-exception - (.getMessage e)]))) + (assoc op :type crash, :error [:connect-exception + (.getMessage e)]))) - (catch java.net.SocketTimeoutException e - (assoc op :type crash, :error :timeout))))) + (catch java.net.SocketTimeoutException e + (assoc op :type crash, :error :timeout))))) (teardown! [_ test])))) - (defn set-client ([] (set-client nil)) @@ -92,45 +90,45 @@ :fail :info)] (try+ - (case (:f op) - :init (with-retry [tries 0] - (tc/write! node k []) - (assoc op :type :ok) - (catch Exception e - (if (<= 10 tries) - (throw e) - (do (info "Couldn't initialize key" k ":" (.getMessage e) "- retrying") - (Thread/sleep (* 50 (Math/pow 2 tries))) - (retry (inc tries)))))) - :add (let [s (or (vec (tc/read node k)) []) - s' (conj s v)] - (tc/cas! node k s s') - (assoc op :type :ok)) - :read (assoc op - :type :ok - :value (independent/tuple - k - (into (sorted-set) (tc/read node k))))) + (case (:f op) + :init (with-retry [tries 0] + (tc/write! node k []) + (assoc op :type :ok) + (catch Exception e + (if (<= 10 tries) + (throw e) + (do (info "Couldn't initialize key" k ":" (.getMessage e) "- retrying") + (Thread/sleep (* 50 (Math/pow 2 tries))) + (retry (inc tries)))))) + :add (let [s (or (vec (tc/read node k)) []) + s' (conj s v)] + (tc/cas! node k s s') + (assoc op :type :ok)) + :read (assoc op + :type :ok + :value (independent/tuple + k + (into (sorted-set) (tc/read node k))))) - (catch [:type :unauthorized] e - (assoc op :type :fail, :error :precondition-failed)) + (catch [:type :unauthorized] e + (assoc op :type :fail, :error :precondition-failed)) - (catch [:type :base-unknown-address] e - (assoc op :type :fail, :error :not-found)) + (catch [:type :base-unknown-address] e + (assoc op :type :fail, :error :not-found)) - (catch org.apache.http.NoHttpResponseException e - (assoc op :type crash, :error :no-http-response)) + (catch org.apache.http.NoHttpResponseException e + (assoc op :type crash, :error :no-http-response)) - (catch java.net.ConnectException e - (condp re-find (.getMessage e) - #"Connection refused" - (assoc op :type :fail, :error :connection-refused) + (catch java.net.ConnectException e + (condp re-find (.getMessage e) + #"Connection refused" + (assoc op :type :fail, :error :connection-refused) - (assoc op :type crash, :error [:connect-exception - (.getMessage e)]))) + (assoc op :type crash, :error [:connect-exception + (.getMessage e)]))) - (catch java.net.SocketTimeoutException e - (assoc op :type crash, :error :timeout))))) + (catch java.net.SocketTimeoutException e + (assoc op :type crash, :error :timeout))))) (teardown! [_ test])))) @@ -144,15 +142,15 @@ ; main component, and compute the remaining complement for each dup ; group. (let [{:keys [groups singles dups]} (tv/dup-groups - @(:validator-config test)) + @(:validator-config test)) chosen-ones (map (comp hash-set rand-nth vec) dups) exiles (map remove chosen-ones dups)] (nemesis/complete-grudge - (cons ; Main group - (set (concat (apply concat singles) - (apply concat chosen-ones))) + (cons ; Main group + (set (concat (apply concat singles) + (apply concat chosen-ones))) ; Exiles - exiles))))) + exiles))))) (defn split-dup-validators-grudge "Takes a test. Returns a function which takes a collection of nodes from that @@ -162,18 +160,18 @@ [test] (fn [nodes] (let [{:keys [groups singles dups]} (tv/dup-groups - @(:validator-config test)) + @(:validator-config test)) n (reduce max (map count dups))] - (->> groups - shuffle - (map shuffle) - (apply concat) - (reduce (fn [[components i] node] - [(update components (mod i n) conj node) - (inc i)]) - [[] 0]) - first - nemesis/complete-grudge)))) + (->> groups + shuffle + (map shuffle) + (apply concat) + (reduce (fn [[components i] node] + [(update components (mod i n) conj node) + (inc i)]) + [[] 0]) + first + nemesis/complete-grudge)))) (defn crash-truncate-nemesis "A nemesis which kills tendermint, kills merkleeyes, truncates the merkleeyes @@ -195,9 +193,9 @@ (td/stop-tendermint! test node) (td/stop-merkleeyes! test node) (c/su - (c/exec :truncate :-c :-s - (str "-" (rand-int 1048576)) - (str base-dir file))) + (c/exec :truncate :-c :-s + (str "-" (rand-int 1048576)) + (str base-dir file))) (td/start-merkleeyes! test node) (td/start-tendermint! test node)))) op) @@ -266,7 +264,7 @@ ; state to reflect the new state of things. (swap! (:validator-config test) #(tv/post-step % t))))) - (assoc op :value :done)) + (assoc op :value :done)) (teardown! [this test]))) @@ -278,11 +276,11 @@ :generator (gen/stagger 10 (tv/generator))} :peekaboo-dup-validators {:nemesis (nemesis/partitioner - (peekaboo-dup-validators-grudge test)) + (peekaboo-dup-validators-grudge test)) :generator (gen/start-stop 0 5)} :split-dup-validators {:nemesis (nemesis/partitioner - (split-dup-validators-grudge test)) + (split-dup-validators-grudge test)) :generator (gen/once {:type :info, :f :start})} :half-partitions {:nemesis (nemesis/partition-random-halves) @@ -301,12 +299,12 @@ :generator (gen/start-stop 15 0)} :truncate-merkleeyes {:nemesis (crash-truncate-nemesis - test 1/3 "/jepsen/jepsen.db/000001.log") + test 1/3 "/jepsen/jepsen.db/000001.log") :generator (->> {:type :info, :f :crash} (gen/delay 10))} :truncate-tendermint {:nemesis (crash-truncate-nemesis - test 1/3 "/data/cs.wal/wal") + test 1/3 "/data/cs.wal/wal") :generator (->> {:type :info, :f :crash} (gen/delay 10))} @@ -336,76 +334,75 @@ :cas-register {:client (cas-register-client) :model (model/cas-register) :generator (independent/concurrent-generator - (* 2 n) - (range) - (fn [k] - (->> (gen/mix [w cas]) - (gen/reserve n r) - (gen/stagger 1) - (gen/limit 120)))) + (* 2 n) + (range) + (fn [k] + (->> (gen/mix [w cas]) + (gen/reserve n r) + (gen/stagger 1) + (gen/limit 120)))) :final-generator nil :checker {:linear (independent/checker - (checker/linearizable))}} + (checker/linearizable))}} :set (let [keys (atom [])] {:client (set-client) :model nil :generator (independent/concurrent-generator - n - (range) - (fn [k] - (swap! keys conj k) - (gen/phases - (gen/once {:type :invoke, :f :init}) - (->> (range) - (map (fn [x] - {:type :invoke - :f :add - :value x})) - gen/seq - (gen/stagger 1/2))))) + n + (range) + (fn [k] + (swap! keys conj k) + (gen/phases + (gen/once {:type :invoke, :f :init}) + (->> (range) + (map (fn [x] + {:type :invoke + :f :add + :value x})) + gen/seq + (gen/stagger 1/2))))) :final-generator (deref-gen - (delay - (locking keys - (independent/concurrent-generator - n - @keys - (fn [k] - (gen/each (gen/once {:type :invoke - :f :read}))))))) + (delay + (locking keys + (independent/concurrent-generator + n + @keys + (fn [k] + (gen/each (gen/once {:type :invoke + :f :read}))))))) :checker {:set (independent/checker (checker/set))}})))) - (defn test [opts] (let [validator-config (atom nil) test (merge - tests/noop-test - opts - {:name (str "tendermint " (name (:workload opts)) " " - (name (:nemesis opts))) - :os debian/os - :nonserializable-keys [:validator-config] - :validator-config validator-config}) + tests/noop-test + opts + {:name (str "tendermint " (name (:workload opts)) " " + (name (:nemesis opts))) + :os debian/os + :nonserializable-keys [:validator-config] + :validator-config validator-config}) db (td/db test) nemesis (nemesis test) workload (workload test) checker (checker/compose - (merge {:timeline (independent/checker (timeline/html)) - :perf (checker/perf)} - (:checker workload))) + (merge {:timeline (independent/checker (timeline/html)) + :perf (checker/perf)} + (:checker workload))) test (merge test {:db db :client (:client workload) :generator (gen/phases - (->> (:generator workload) - (gen/nemesis (:generator nemesis)) - (gen/time-limit (:time-limit opts))) - (gen/nemesis - (gen/once {:type :info, :f :stop})) - (gen/sleep 30) - (gen/clients - (:final-generator workload))) + (->> (:generator workload) + (gen/nemesis (:generator nemesis)) + (gen/time-limit (:time-limit opts))) + (gen/nemesis + (gen/once {:type :info, :f :stop})) + (gen/sleep 30) + (gen/clients + (:final-generator workload))) :nemesis (:nemesis nemesis) :model (:model workload) :checker checker})] diff --git a/test/jepsen/jepsen/src/jepsen/tendermint/db.clj b/test/jepsen/jepsen/src/jepsen/tendermint/db.clj index 0e493e96d..0d7f9c69c 100644 --- a/test/jepsen/jepsen/src/jepsen/tendermint/db.clj +++ b/test/jepsen/jepsen/src/jepsen/tendermint/db.clj @@ -7,16 +7,16 @@ [clojure.pprint :refer [pprint]] [slingshot.slingshot :refer [try+]] [jepsen [core :as jepsen] - [control :as c] - [db :as db] - [util :as util :refer [timeout with-retry map-vals]]] + [control :as c] + [db :as db] + [util :as util :refer [timeout with-retry map-vals]]] [jepsen.control.util :as cu] [jepsen.os.debian :as debian] [jepsen.nemesis.time :as nt] [cheshire.core :as json] [jepsen.tendermint [client :as tc] - [util :refer [base-dir]] - [validator :as tv]])) + [util :refer [base-dir]] + [validator :as tv]])) (defn install-component! "Download and install a tendermint component" @@ -29,27 +29,27 @@ "Writes out the given validator structure to priv_validator.json." [validator] (c/su - (c/cd base-dir - (c/exec :echo (json/generate-string validator) - :> "priv_validator_key.json") - (info "Wrote priv_validator_key.json")))) + (c/cd base-dir + (c/exec :echo (json/generate-string validator) + :> "priv_validator_key.json") + (info "Wrote priv_validator_key.json")))) (defn write-genesis! "Writes a genesis structure to a JSON file on disk." [genesis] (c/su - (c/cd base-dir - (c/exec :echo (json/generate-string genesis) - :> "genesis.json") - (info "Wrote genesis.json")))) + (c/cd base-dir + (c/exec :echo (json/generate-string genesis) + :> "genesis.json") + (info "Wrote genesis.json")))) (defn write-config! "Writes out a config.toml file to the current node." [] (c/su - (c/cd base-dir - (c/exec :echo (slurp (io/resource "config.toml")) - :> "config.toml")))) + (c/cd base-dir + (c/exec :echo (slurp (io/resource "config.toml")) + :> "config.toml")))) (defn seeds "Constructs a --seeds command line for a test, so a tendermint node knows @@ -74,31 +74,31 @@ "Starts tendermint as a daemon." [test node] (c/su - (c/cd base-dir - (cu/start-daemon! - {:logfile tendermint-logfile - :pidfile tendermint-pidfile - :chdir base-dir} - "./tendermint" - :--home base-dir - :node - :--proxy_app socket - :--p2p.seeds (seeds test node)))) + (c/cd base-dir + (cu/start-daemon! + {:logfile tendermint-logfile + :pidfile tendermint-pidfile + :chdir base-dir} + "./tendermint" + :--home base-dir + :node + :--proxy_app socket + :--p2p.seeds (seeds test node)))) :started) (defn start-merkleeyes! "Starts merkleeyes as a daemon." [test node] (c/su - (c/cd base-dir - (cu/start-daemon! - {:logfile merkleeyes-logfile - :pidfile merkleeyes-pidfile - :chdir base-dir} - "./merkleeyes" - :start - :--dbName "jepsen" - :--address socket))) + (c/cd base-dir + (cu/start-daemon! + {:logfile merkleeyes-logfile + :pidfile merkleeyes-pidfile + :chdir base-dir} + "./merkleeyes" + :start + :--dbName "jepsen" + :--address socket))) :started) (defn stop-tendermint! [test node] @@ -146,46 +146,45 @@ (reify db/DB (setup! [_ test node] (c/su - (install-component! "tendermint" opts) - (install-component! "abci" opts) - (install-component! "merkleeyes" opts) + (install-component! "tendermint" opts) + (install-component! "abci" opts) + (install-component! "merkleeyes" opts) - (write-config!) + (write-config!) ; OK we're ready to compute the initial validator config. - (jepsen/synchronize test) - (when (= node (jepsen/primary test)) - (let [validator-config (tv/initial-config test)] - (info :initial-config (with-out-str (pprint validator-config))) - (assert (compare-and-set! (:validator-config opts) - nil - validator-config) - "Initial validator config already established!"))) + (jepsen/synchronize test) + (when (= node (jepsen/primary test)) + (let [validator-config (tv/initial-config test)] + (info :initial-config (with-out-str (pprint validator-config))) + (assert (compare-and-set! (:validator-config opts) + nil + validator-config) + "Initial validator config already established!"))) ; Now apply that config. - (jepsen/synchronize test) - (let [vc @(:validator-config opts)] - (write-genesis! (tv/genesis vc)) - (write-validator! (get (:validators vc) - (get-in vc [:nodes node])))) + (jepsen/synchronize test) + (let [vc @(:validator-config opts)] + (write-genesis! (tv/genesis vc)) + (write-validator! (get (:validators vc) + (get-in vc [:nodes node])))) - (start-merkleeyes! test node) - (start-tendermint! test node) + (start-merkleeyes! test node) + (start-tendermint! test node) - (nt/install!) + (nt/install!) - (Thread/sleep 1000))) + (Thread/sleep 1000))) (teardown! [_ test node] (stop-merkleeyes! test node) (stop-tendermint! test node) (c/su - (c/exec :rm :-rf base-dir))) + (c/exec :rm :-rf base-dir))) db/LogFiles (log-files [_ test node] [tendermint-logfile merkleeyes-logfile (str base-dir "/priv_validator.json") - (str base-dir "/genesis.json") - ]))) + (str base-dir "/genesis.json")]))) diff --git a/test/jepsen/jepsen/src/jepsen/tendermint/gowire.clj b/test/jepsen/jepsen/src/jepsen/tendermint/gowire.clj index 4b04a33a0..d42ed1bb2 100644 --- a/test/jepsen/jepsen/src/jepsen/tendermint/gowire.clj +++ b/test/jepsen/jepsen/src/jepsen/tendermint/gowire.clj @@ -32,8 +32,8 @@ Writable (byte-size [_] (.remaining x)) (write! [_ buf] - (.put buf x) - buf)) + (.put buf x) + buf)) (defn fixed-bytes [x] @@ -57,14 +57,14 @@ Long (byte-size [n] (cond (< n 0x0) (throw (IllegalArgumentException. - (str "Number " n " can't be negative"))) + (str "Number " n " can't be negative"))) (<= n 0x0) 1 (<= n 0xff) 2 (<= n 0xffff) 3 (<= n 0xffffff) 4 (<= n 0xffffffff) 5 true (throw (IllegalArgumentException. - (str "Number " n " is too large"))))) + (str "Number " n " is too large"))))) (write! [n buf] (let [int-size (dec (byte-size n))] diff --git a/test/jepsen/jepsen/src/jepsen/tendermint/validator.clj b/test/jepsen/jepsen/src/jepsen/tendermint/validator.clj index 2d1c959a3..346eba950 100644 --- a/test/jepsen/jepsen/src/jepsen/tendermint/validator.clj +++ b/test/jepsen/jepsen/src/jepsen/tendermint/validator.clj @@ -8,12 +8,12 @@ [cheshire.core :as json] [dom-top.core :as dt] [jepsen.tendermint [client :as tc] - [util :refer [base-dir]]] + [util :refer [base-dir]]] [jepsen [util :as util :refer [map-vals]] - [control :as c] - [client :as client] - [nemesis :as nemesis] - [generator :as gen]]) + [control :as c] + [client :as client] + [nemesis :as nemesis] + [generator :as gen]]) (:import (clojure.tools.logging.impl LoggerFactory Logger) (clojure.lang Namespace Symbol))) @@ -35,6 +35,7 @@ ; Domain types + (t/defalias Node "Jepsen nodes are strings." String) @@ -152,13 +153,13 @@ (t/ann ^:no-check clojure.core/update (t/All [m k v v' arg ...] (t/IFn - [m k [v arg ... arg -> v'] arg ... arg -> (t/Assoc m k v')]))) + [m k [v arg ... arg -> v'] arg ... arg -> (t/Assoc m k v')]))) (t/ann ^:no-check clojure.tools.logging/*logger-factory* LoggerFactory) (t/ann ^:no-check clojure.tools.logging.impl/get-logger [LoggerFactory (t/U clojure.lang.Symbol Namespace) - -> clojure.tools.logging.impl.Logger]) + -> clojure.tools.logging.impl.Logger]) (t/ann ^:no-check clojure.tools.logging.impl/enabled? [Logger t/Keyword -> Boolean]) @@ -177,7 +178,7 @@ [Test (t/NonEmptyColl Node) [Test Node -> res] -> (t/I (t/Map Node res) (t/NonEmptySeqable - (clojure.lang.AMapEntry Node res)))]))) + (clojure.lang.AMapEntry Node res)))]))) (t/ann ^:no-check jepsen.control/expand-path [String -> String]) @@ -234,7 +235,7 @@ (->> (:nodes config) (reduce (t/fn [m :- (t/Map Key (t/Vec Node)) [node pub-key] :- '[Node Key]] - (assoc m pub-key (conj (get m pub-key []) node))) + (assoc m pub-key (conj (get m pub-key []) node))) {}))) (t/ann ^:no-check byzantine-validators [Config -> (t/Coll Validator)]) @@ -248,7 +249,6 @@ (map key) (keep (tmfn (:validators config) Key Validator)))) - (t/ann initial-validator-votes [Config -> (t/Map Key Long)]) (defn initial-validator-votes "Takes a config. Computes a map of validator public keys to votes. When there @@ -312,9 +312,9 @@ (let [base-votes (zipmap (remove #{b} (keys (:validators config))) (repeat 2)) byz-votes {b (conform-long - (if (:super-byzantine-validators config) - (dec (* 4 (dec n))) - (- n 2)))}] + (if (:super-byzantine-validators config) + (dec (* 4 (dec n))) + (- n 2)))}] (t/ann-form base-votes (t/Map Key Long)) (merge base-votes byz-votes)))) @@ -343,9 +343,9 @@ map." [] (conform-gen-validator - (c/cd base-dir - (-> (c/exec "./tendermint" :--home base-dir :gen_validator) - (json/parse-string true))))) + (c/cd base-dir + (-> (c/exec "./tendermint" :--home base-dir :gen_validator) + (json/parse-string true))))) (t/ann augment-gen-validator [GenValidator -> Validator]) (defn augment-gen-validator @@ -360,7 +360,7 @@ :validators (t/Map Key Validator) :super-byzantine-validators Boolean :max-byzantine-vote-fraction Number}) - -> Config]) + -> Config]) (defn config "There are two pieces of state we need to handle. The first is the validator set, as known to the cluster, which maps public keys to maps like: @@ -443,8 +443,8 @@ (let [pub-key (:pub_key validator) name (->> (:nodes config) (filter - (t/fn [[_ v] :- '[t/Any Key]] - (= v pub-key))) + (t/fn [[_ v] :- '[t/Any Key]] + (= v pub-key))) first) _ (assert name) name (key name)] @@ -494,8 +494,6 @@ :nodes (map-vals compact-key (:nodes c)) :max-byzantine-vote-fraction (:max-byzantine-vote-fraction c)}) - - (t/ann vote-fractions [Config -> (t/Map Key Number)]) (defn vote-fractions "A map of validator public keys to the fraction of the vote they control." @@ -575,8 +573,8 @@ [config] (< ghost-limit (count - (set/difference (set (keys (:validators config))) - (set (vals (:nodes config))))))) + (set/difference (set (keys (:validators config))) + (set (vals (:nodes config))))))) (t/ann zombie-limit Long) (def zombie-limit @@ -591,8 +589,8 @@ [config] (< zombie-limit (count - (remove (set (keys (:validators config))) - (vals (:nodes config)))))) + (remove (set (keys (:validators config))) + (vals (:nodes config)))))) (t/ann quorum Number) (def quorum @@ -623,7 +621,6 @@ (set (ghost-validators config))))) (total-votes config)))) - (t/ann assert-valid [Config -> Config]) (defn assert-valid "Ensures that the given config is valid, and returns it. Throws @@ -659,57 +656,59 @@ state." [config transition] (assert-valid - (case (:type transition) - :create config - :destroy config - :add (let [v (:validator transition)] - (assert (not (get-in config [:validators (:pub_key v)]))) - (assoc config :prospective-validators - (assoc (:prospective-validators config) - (:pub_key v) v))) - :remove config - :alter-votes config))) + (case (:type transition) + :create config + :destroy config + :add (let [v (:validator transition)] + (assert (not (get-in config [:validators (:pub_key v)]))) + (assoc config :prospective-validators + (assoc (:prospective-validators config) + (:pub_key v) v))) + :remove config + :alter-votes config))) (t/ann post-step [Config Transition -> Config]) (defn post-step "Complete a transition once we know it's been executed." [config transition] (assert-valid - (case (:type transition) + (case (:type transition) ; Create a new validator on a node - :create (let [n (:node transition) - v (:validator transition)] - (assert (not (get-in config [:nodes n]))) - (assoc config :nodes (assoc (:nodes config) n (:pub_key v)))) + :create (let [n (:node transition) + v (:validator transition)] + (assert (not (get-in config [:nodes n]))) + (assoc config :nodes (assoc (:nodes config) n (:pub_key v)))) ; Destroy a validator on a node - :destroy (assoc config :nodes (dissoc (:nodes config) - (:node transition))) + :destroy (assoc config :nodes (dissoc (:nodes config) + (:node transition))) ; Add a validator to the validator set - :add (let [v (:validator transition)] - (assert (not (get-in config [:validators (:pub_key v)]))) - (-> config - (assoc :prospective-validators - (dissoc (:prospective-validators config) - (:pub_key v))) - (assoc :validators - (assoc (:validators config) (:pub_key v) v)))) + + + :add (let [v (:validator transition)] + (assert (not (get-in config [:validators (:pub_key v)]))) + (-> config + (assoc :prospective-validators + (dissoc (:prospective-validators config) + (:pub_key v))) + (assoc :validators + (assoc (:validators config) (:pub_key v) v)))) ; Remove a validator from the validator set - :remove (assoc config :validators - (dissoc (:validators config) (:pub_key transition))) + :remove (assoc config :validators + (dissoc (:validators config) (:pub_key transition))) ; Change the votes allocated to a validator - :alter-votes (let [k (:pub_key transition) - v (:votes transition) - validators (:validators config) - validator (get validators k) - _ (assert validator) - validator' (assoc validator :votes v) - validators' (assoc validators k validator')] - (assoc config :validators validators'))))) + :alter-votes (let [k (:pub_key transition) + v (:votes transition) + validators (:validators config) + validator (get validators k) + _ (assert validator) + validator' (assoc validator :votes v) + validators' (assoc validators k validator')] + (assoc config :validators validators'))))) (t/ann step [Config Transition -> Config]) (defn step @@ -843,9 +842,9 @@ k (or (validator-by-short-key config short-key) (prospective-validator-by-short-key config short-key) (throw (IllegalStateException. - (str "Don't recognize cluster validator " - (pr-str v) - "; where did it come from?"))))] + (str "Don't recognize cluster validator " + (pr-str v) + "; where did it come from?"))))] [(:pub_key k) (:power v)]))) (into {}))) @@ -879,8 +878,8 @@ (let [prospective (:prospective-validators config) validator (get prospective k) _ (assert validator - (str "Don't recognize validator " - k "; where did it come from?")) + (str "Don't recognize validator " + k "; where did it come from?")) validator (assoc validator :votes v) validators (assoc validators k validator) prospective (dissoc prospective k)] @@ -900,7 +899,7 @@ (let [local-config @(:validator-config test) cluster-config (tc/validator-set node) votes (tendermint-validator-set->vote-map - local-config cluster-config)] + local-config cluster-config)] (-> local-config (clear-removed-nodes votes) (update-known-nodes votes) @@ -908,39 +907,37 @@ (t/tc-ignore -(defn refresh-config! - "Attempts to update the test's config with new information from the cluster. + (defn refresh-config! + "Attempts to update the test's config with new information from the cluster. Returns our estimate of the current config. Not threadsafe." - [test] + [test] ; TODO: make this threadsafe - (or (reduce (fn [_ node] - (try - (when-let [c (current-config test node)] - (reset! (:validator-config test) c) - (reduced c)) - (catch java.io.IOException e + (or (reduce (fn [_ node] + (try + (when-let [c (current-config test node)] + (reset! (:validator-config test) c) + (reduced c)) + (catch java.io.IOException e ; (info e "unable to fetch current validator set config") - nil))) - nil - (shuffle (:nodes test))) - @(:validator-config test))) + nil))) + nil + (shuffle (:nodes test))) + @(:validator-config test))) -(defn generator - "A generator of legal state transitions on the current validator state." - [] - (reify gen/Generator - (op [this test process] - (try - (info "refreshing config") - (let [config (refresh-config! test)] - (info :config-refreshed) - (info (with-out-str (pprint config))) - (info (with-out-str (pprint (compact-config config)))) - {:type :info - :f :transition - :value (rand-legal-transition test config)}) - (catch Exception e - (warn e "error generating transition") - (throw e)))))) - -) + (defn generator + "A generator of legal state transitions on the current validator state." + [] + (reify gen/Generator + (op [this test process] + (try + (info "refreshing config") + (let [config (refresh-config! test)] + (info :config-refreshed) + (info (with-out-str (pprint config))) + (info (with-out-str (pprint (compact-config config)))) + {:type :info + :f :transition + :value (rand-legal-transition test config)}) + (catch Exception e + (warn e "error generating transition") + (throw e)))))))