update deps

This commit is contained in:
Anton Kaliaev
2020-11-09 17:37:12 +04:00
parent f57961b0f5
commit c6760e7660
8 changed files with 308 additions and 332 deletions

View File

@@ -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)

View File

@@ -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)])

View File

@@ -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))

View File

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

View File

@@ -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})]

View File

@@ -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")])))

View File

@@ -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))]

View File

@@ -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)))))))