diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b4539a64849297194e3ad4dcdd9cfda251614f6..2fb9133f20c416fc081d13a3c48e21eb809067c1 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,7 +4,7 @@ variables:
   REPO_DIR: gitlab.com/elixxir
   REPO_NAME: client
   DOCKER_IMAGE: elixxirlabs/cuda-go:latest
-  MIN_CODE_COVERAGE: "70"
+  MIN_CODE_COVERAGE: "35"
 
 before_script:
   ##
@@ -84,26 +84,26 @@ tag:
         - git tag $(release/client.linux64 version | grep "Elixxir Client v"| cut -d ' ' -f3) -f
         - git push origin_tags -f --tags
 
-bindings:
-  stage: build
-  except:
-    - tags
-  tags:
-    - ios
-  script:
-    - go get -u golang.org/x/mobile/cmd/gomobile
-    - go get -u golang.org/x/mobile/bind
-    - rm -rf $HOME/go/src/gitlab.com/elixxir/client/
-    - mkdir -p $HOME/go/src/gitlab.com/elixxir/client/
-    - cp -r * $HOME/go/src/gitlab.com/elixxir/client/
-    - GO111MODULE=on gomobile bind -target android -androidapi 21 gitlab.com/elixxir/client/bindings
-    - GO111MODULE=on gomobile bind -target ios gitlab.com/elixxir/client/bindings
-    - zip -r iOS.zip Bindings.framework
-  artifacts:
-    paths:
-      - iOS.zip
-      - bindings.aar
-      - bindings-sources.jar
+# bindings:
+#   stage: build
+#   except:
+#     - tags
+#   tags:
+#     - ios
+#   script:
+#     - go get -u golang.org/x/mobile/cmd/gomobile
+#     - go get -u golang.org/x/mobile/bind
+#     - rm -rf $HOME/go/src/gitlab.com/elixxir/client/
+#     - mkdir -p $HOME/go/src/gitlab.com/elixxir/client/
+#     - cp -r * $HOME/go/src/gitlab.com/elixxir/client/
+#     - GO111MODULE=on gomobile bind -target android -androidapi 21 gitlab.com/elixxir/client/bindings
+#     - GO111MODULE=on gomobile bind -target ios gitlab.com/elixxir/client/bindings
+#     - zip -r iOS.zip Bindings.framework
+#   artifacts:
+#     paths:
+#       - iOS.zip
+#       - bindings.aar
+#       - bindings-sources.jar
 
 trigger_integration:
   stage: trigger_integration
diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go
new file mode 100644
index 0000000000000000000000000000000000000000..7c53e2389b5fd1526c02a928e1c8acd9e28b4df5
--- /dev/null
+++ b/api/authenticatedChannel.go
@@ -0,0 +1,28 @@
+package api
+
+import jww "github.com/spf13/jwalterweatherman"
+
+// CreateAuthenticatedChannel creates a 1-way authenticated channel
+// so this user can send messages to the desired recipient Contact.
+// To receive confirmation from the remote user, clients must
+// register a listener to do that.
+func (c *Client) CreateAuthenticatedChannel(recipient Contact,
+	payload []byte) error {
+	jww.INFO.Printf("CreateAuthenticatedChannel(%v, %v)",
+		recipient, payload)
+	return nil
+}
+
+// RegisterAuthConfirmationCb registers a callback for channel
+// authentication confirmation events.
+func (c *Client) RegisterAuthConfirmationCb(cb func(contact Contact,
+	payload []byte)) {
+	jww.INFO.Printf("RegisterAuthConfirmationCb(...)")
+}
+
+// RegisterAuthRequestCb registers a callback for channel
+// authentication request events.
+func (c *Client) RegisterAuthRequestCb(cb func(contact Contact,
+	payload []byte)) {
+	jww.INFO.Printf("RegisterAuthRequestCb(...)")
+}
diff --git a/api/client.go b/api/client.go
index 346025c9bc5502bee5b28807ce43be23796c0730..b4748878c2150d67a60e792d7b94acd2650cfc5a 100644
--- a/api/client.go
+++ b/api/client.go
@@ -18,14 +18,13 @@ import (
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/comms/client"
-	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/crypto/csprng"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
+	"time"
 )
 
 type Client struct {
@@ -45,6 +44,10 @@ type Client struct {
 	network interfaces.NetworkManager
 	//object used to register and communicate with permissioning
 	permissioning *permissioning.Permissioning
+
+	//contains stopables for all running threads
+	runner *stoppable.Multi
+	status *statusTracker
 }
 
 // NewClient creates client storage, generates keys, connects, and registers
@@ -80,6 +83,13 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 	//store the registration code for later use
 	storageSess.SetRegCode(registrationCode)
 
+	//move the registration state to keys generated
+	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to denote state "+
+			"change in session")
+	}
+
 	//execute the rest of the loading as normal
 	return loadClient(storageSess, rngStreamGen)
 }
@@ -115,6 +125,13 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 	// Save NDF to be used in the future
 	storageSess.SetBaseNDF(def)
 
+	//move the registration state to keys generated
+	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to denote state "+
+			"change in session")
+	}
+
 	//execute the rest of the loading as normal
 	return loadClient(storageSess, rngStreamGen)
 }
@@ -146,6 +163,8 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator)
 		rng:         rngStreamGen,
 		comms:       nil,
 		network:     nil,
+		runner:      stoppable.NewMulti("client"),
+		status:      newStatusTracker(),
 	}
 
 	//get the user from session
@@ -166,6 +185,10 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator)
 
 	//initialize permissioning
 	c.permissioning, err = permissioning.Init(c.comms, def)
+	if err != nil {
+		return nil, errors.WithMessage(err, "failed to init "+
+			"permissioning handler")
+	}
 
 	// check the client version is up to date to the network
 	err = c.checkVersion()
@@ -175,10 +198,13 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator)
 
 	//register with permissioning if necessary
 	if c.storage.GetRegistrationStatus() == storage.KeyGenComplete {
+		jww.INFO.Printf("Client has not registered yet, attempting registration")
 		err = c.registerWithPermissioning()
 		if err != nil {
+			jww.ERROR.Printf("Client has failed registration: %s", err)
 			return nil, errors.WithMessage(err, "failed to load client")
 		}
+		jww.INFO.Printf("Client sucsecfully registered with the network")
 	}
 
 	// Initialize network and link it to context
@@ -202,236 +228,88 @@ func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator)
 //   	tracks the network events and hands them off to workers for handling
 //   - Historical Round Retrieval (/network/rounds/historical.go)
 //		Retrieves data about rounds which are too old to be stored by the client
-//	 - Message Retrieval Worker Group (/network/rounds/retreive.go)
+//	 - Message Retrieval Worker Group (/network/rounds/retrieve.go)
 //		Requests all messages in a given round from the gateway of the last node
-//	 - Message Handling Worker Group (/network/message/reception.go)
+//	 - Message Handling Worker Group (/network/message/handle.go)
 //		Decrypts and partitions messages when signals via the Switchboard
 //	 - Health Tracker (/network/health)
-func (c *Client) StartNetworkFollower() (stoppable.Stoppable, error) {
+//		Via the network instance tracks the state of the network
+//	 - Garbled Messages (/network/message/garbled.go)
+//		Can be signaled to check all recent messages which could be be decoded
+//		Uses a message store on disk for persistence
+//	 - Critical Messages (/network/message/critical.go)
+//		Ensures all protocol layer mandatory messages are sent
+//		Uses a message store on disk for persistence
+//	 - KeyExchange Trigger (/keyExchange/trigger.go)
+//		Responds to sent rekeys and executes them
+//   - KeyExchange Confirm (/keyExchange/confirm.go)
+//		Responds to confirmations of successful rekey operations
+func (c *Client) StartNetworkFollower() error {
 	jww.INFO.Printf("StartNetworkFollower()")
-	multi := stoppable.NewMulti("client")
+
+	err := c.status.toStarting()
+	if err != nil {
+		return errors.WithMessage(err, "Failed to Start the Network Follower")
+	}
 
 	stopFollow, err := c.network.Follow()
 	if err != nil {
-		return nil, errors.WithMessage(err, "Failed to start following "+
+		return errors.WithMessage(err, "Failed to start following "+
 			"the network")
 	}
-	multi.Add(stopFollow)
+	c.runner.Add(stopFollow)
 	// Key exchange
-	multi.Add(keyExchange.Start(c.switchboard, c.storage, c.network))
-	return multi, nil
-}
-
-
+	c.runner.Add(keyExchange.Start(c.switchboard, c.storage, c.network))
 
-// SendE2E sends an end-to-end payload to the provided recipient with
-// the provided msgType. Returns the list of rounds in which parts of
-// the message were sent or an error if it fails.
-func (c *Client) SendE2E(payload []byte, recipient id.ID, msgType int) (
-	[]int, error) {
-	jww.INFO.Printf("SendE2E(%s, %s, %d)", payload, recipient,
-		msgType)
-	return nil, nil
-}
-
-// SendUnsafe sends an unencrypted payload to the provided recipient
-// with the provided msgType. Returns the list of rounds in which parts
-// of the message were sent or an error if it fails.
-// NOTE: Do not use this function unless you know what you are doing.
-// This function always produces an error message in client logging.
-func (c *Client) SendUnsafe(payload []byte, recipient id.ID, msgType int) ([]int,
-	error) {
-	jww.INFO.Printf("SendUnsafe(%s, %s, %d)", payload, recipient,
-		msgType)
-	return nil, nil
-}
-
-// SendCMIX sends a "raw" CMIX message payload to the provided
-// recipient. Note that both SendE2E and SendUnsafe call SendCMIX.
-// Returns the round ID of the round the payload was sent or an error
-// if it fails.
-func (c *Client) SendCMIX(payload []byte, recipient id.ID) (int, error) {
-	jww.INFO.Printf("SendCMIX(%s, %s)", payload, recipient)
-	return 0, nil
-}
-
-// RegisterListener registers a listener callback function that is called
-// every time a new message matches the specified parameters.
-func (c *Client) RegisterListenerCb(uid id.ID, msgType int, username string,
-	listenerCb func(msg Message)) {
-	jww.INFO.Printf("RegisterListener(%s, %d, %s, func())", uid, msgType,
-		username)
-}
-
-// RegisterForNotifications allows a client to register for push
-// notifications.
-// Note that clients are not required to register for push notifications
-// especially as these rely on third parties (i.e., Firebase *cough*
-// *cough* google's palantir *cough*) that may represent a security
-// risk to the user.
-func (c *Client) RegisterForNotifications(token []byte) error {
-	jww.INFO.Printf("RegisterForNotifications(%s)", token)
-	// // Pull the host from the manage
-	// notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
-	// if !ok {
-	// 	return errors.New("Failed to retrieve host for notification bot")
-	// }
-
-	// // Send the register message
-	// _, err := cl.receptionManager.Comms.RegisterForNotifications(notificationBotHost,
-	// 	&mixmessages.NotificationToken{
-	// 		Token: notificationToken,
-	// 	})
-	// if err != nil {
-	// 	err := errors.Errorf(
-	// 		"RegisterForNotifications: Unable to register for notifications! %s", err)
-	// 	return err
-	// }
-
-	return nil
-}
-
-// UnregisterForNotifications turns of notifications for this client
-func (c *Client) UnregisterForNotifications() error {
-	jww.INFO.Printf("UnregisterForNotifications()")
-	// // Pull the host from the manage
-	// notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
-	// if !ok {
-	// 	return errors.New("Failed to retrieve host for notification bot")
-	// }
-
-	// // Send the unregister message
-	// _, err := cl.receptionManager.Comms.UnregisterForNotifications(notificationBotHost)
-	// if err != nil {
-	// 	err := errors.Errorf(
-	// 		"RegisterForNotifications: Unable to register for notifications! %s", err)
-	// 	return err
-	// }
-
-	return nil
-}
-
-// Returns true if the cryptographic identity has been registered with
-// the CMIX user discovery agent.
-// Note that clients do not need to perform this step if they use
-// out of band methods to exchange cryptographic identities
-// (e.g., QR codes), but failing to be registered precludes usage
-// of the user discovery mechanism (this may be preferred by user).
-func (c *Client) IsRegistered() bool {
-	jww.INFO.Printf("IsRegistered()")
-	return false
-}
-
-// RegisterIdentity registers an arbitrary username with the user
-// discovery protocol. Returns an error when it cannot connect or
-// the username is already registered.
-func (c *Client) RegisterIdentity(username string) error {
-	jww.INFO.Printf("RegisterIdentity(%s)", username)
-	return nil
-}
-
-// RegisterEmail makes the users email searchable after confirmation.
-// It returns a registration confirmation token to be used with
-// ConfirmRegistration or an error on failure.
-func (c *Client) RegisterEmail(email string) ([]byte, error) {
-	jww.INFO.Printf("RegisterEmail(%s)", email)
-	return nil, nil
-}
-
-// RegisterPhone makes the users phone searchable after confirmation.
-// It returns a registration confirmation token to be used with
-// ConfirmRegistration or an error on failure.
-func (c *Client) RegisterPhone(phone string) ([]byte, error) {
-	jww.INFO.Printf("RegisterPhone(%s)", phone)
-	return nil, nil
-}
+	err = c.status.toRunning()
+	if err != nil {
+		return errors.WithMessage(err, "Failed to Start the Network Follower")
+	}
 
-// ConfirmRegistration sends the user discovery agent a confirmation
-// token (from register Email/Phone) and code (string sent via Email
-// or SMS to confirm ownership) to confirm ownership.
-func (c *Client) ConfirmRegistration(token, code []byte) error {
-	jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code)
 	return nil
 }
 
-// GetUser returns the current user Identity for this client. This
-// can be serialized into a byte stream for out-of-band sharing.
-func (c *Client) GetUser() (Contact, error) {
-	jww.INFO.Printf("GetUser()")
-	return Contact{}, nil
-}
-
-// MakeContact creates a contact from a byte stream (i.e., unmarshal's a
-// Contact object), allowing out-of-band import of identities.
-func (c *Client) MakeContact(contactBytes []byte) (Contact, error) {
-	jww.INFO.Printf("MakeContact(%s)", contactBytes)
-	return Contact{}, nil
-}
-
-// GetContact returns a Contact object for the given user id, or
-// an error
-func (c *Client) GetContact(uid []byte) (Contact, error) {
-	jww.INFO.Printf("GetContact(%s)", uid)
-	return Contact{}, nil
-}
-
-// Search accepts a "separator" separated list of search elements with
-// an associated list of searchTypes. It returns a ContactList which
-// allows you to iterate over the found contact objects.
-func (c *Client) Search(data, separator string, searchTypes []byte) []Contact {
-	jww.INFO.Printf("Search(%s, %s, %s)", data, separator, searchTypes)
+// StopNetworkFollower stops the network follower if it is running.
+// It returns errors if the Follower is in the wrong status to stop or if it
+// fails to stop it.
+// if the network follower is running and this fails, the client object will
+// most likely be in an unrecoverable state and need to be trashed.
+func (c *Client) StopNetworkFollower(timeout time.Duration) error {
+	err := c.status.toStopping()
+	if err != nil {
+		return errors.WithMessage(err, "Failed to Stop the Network Follower")
+	}
+	err = c.runner.Close(timeout)
+	if err != nil {
+		return errors.WithMessage(err, "Failed to Stop the Network Follower")
+	}
+	c.runner = stoppable.NewMulti("client")
+	err = c.status.toStopped()
+	if err != nil {
+		return errors.WithMessage(err, "Failed to Stop the Network Follower")
+	}
 	return nil
 }
 
-// SearchWithHandler is a non-blocking search that also registers
-// a callback interface for user disovery events.
-func (c *Client) SearchWithCallback(data, separator string, searchTypes []byte,
-	cb func(results []Contact)) {
-	resultCh := make(chan []Contact, 1)
-	go func(out chan []Contact, data, separator string, srchTypes []byte) {
-		out <- c.Search(data, separator, srchTypes)
-		close(out)
-	}(resultCh, data, separator, searchTypes)
-
-	go func(in chan []Contact, cb func(results []Contact)) {
-		select {
-		case contacts := <-in:
-			cb(contacts)
-			//TODO: Timer
-		}
-	}(resultCh, cb)
-}
-
-// CreateAuthenticatedChannel creates a 1-way authenticated channel
-// so this user can send messages to the desired recipient Contact.
-// To receive confirmation from the remote user, clients must
-// register a listener to do that.
-func (c *Client) CreateAuthenticatedChannel(recipient Contact,
-	payload []byte) error {
-	jww.INFO.Printf("CreateAuthenticatedChannel(%v, %v)",
-		recipient, payload)
-	return nil
+//gets the state of the network follower
+func (c *Client) NetworkFollowerStatus() Status {
+	return c.status.get()
 }
 
-// RegisterAuthConfirmationCb registers a callback for channel
-// authentication confirmation events.
-func (c *Client) RegisterAuthConfirmationCb(cb func(contact Contact,
-	payload []byte)) {
-	jww.INFO.Printf("RegisterAuthConfirmationCb(...)")
+// Returns the switchboard for Registration
+func (c *Client) GetSwitchboard() interfaces.Switchboard {
+	return c.switchboard
 }
 
-// RegisterAuthRequestCb registers a callback for channel
-// authentication request events.
-func (c *Client) RegisterAuthRequestCb(cb func(contact Contact,
-	payload []byte)) {
-	jww.INFO.Printf("RegisterAuthRequestCb(...)")
+// Returns the health tracker for registration and polling
+func (c *Client) GetHealth() interfaces.HealthTracker {
+	return c.network.GetHealthTracker()
 }
 
 // RegisterRoundEventsCb registers a callback for round
 // events.
-func (c *Client) RegisterRoundEventsCb(
-	cb func(re *pb.RoundInfo, timedOut bool)) {
-	jww.INFO.Printf("RegisterRoundEventsCb(...)")
+func (c *Client) GetRoundEvents() interfaces.RoundEvents {
+	return c.network.GetInstance().GetRoundEvents()
 }
 
 // ----- Utility Functions -----
diff --git a/api/contact.go b/api/contact.go
index 07f3e6ec0463e08d738cfceb8ce6881b66264d2f..151245d5f2c350505872957d756e9148586f9b19 100644
--- a/api/contact.go
+++ b/api/contact.go
@@ -6,11 +6,35 @@
 
 package api
 
+import jww "github.com/spf13/jwalterweatherman"
+
 import (
 	"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
 )
 
+// GetUser returns the current user Identity for this client. This
+// can be serialized into a byte stream for out-of-band sharing.
+func (c *Client) GetUser() (Contact, error) {
+	jww.INFO.Printf("GetUser()")
+	return Contact{}, nil
+}
+
+// MakeContact creates a contact from a byte stream (i.e., unmarshal's a
+// Contact object), allowing out-of-band import of identities.
+func (c *Client) MakeContact(contactBytes []byte) (Contact, error) {
+	jww.INFO.Printf("MakeContact(%s)", contactBytes)
+	return Contact{}, nil
+}
+
+// GetContact returns a Contact object for the given user id, or
+// an error
+func (c *Client) GetContact(uid []byte) (Contact, error) {
+	jww.INFO.Printf("GetContact(%s)", uid)
+	return Contact{}, nil
+}
+
+
 // Contact implements the Contact interface defined in bindings/interfaces.go,
 type Contact struct {
 	ID            id.ID
diff --git a/api/interfaces.go b/api/interfaces.go
deleted file mode 100644
index 5d8c04419cde6972ac3e253bcce8924a7f6d6e68..0000000000000000000000000000000000000000
--- a/api/interfaces.go
+++ /dev/null
@@ -1,45 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////
-// Copyright © 2020 Privategrity Corporation                                   /
-//                                                                             /
-// All rights reserved.                                                        /
-////////////////////////////////////////////////////////////////////////////////
-
-package api
-
-import (
-	"gitlab.com/xx_network/primitives/id"
-)
-
-// Message is a message received from the cMix network in the clear
-// or that has been decrypted using established E2E keys.
-type Message interface {
-	// Returns the message's sender ID, if available
-	GetSender() id.ID
-	GetSenderBytes() []byte
-
-	// Returns the message payload/contents
-	// Parse this with protobuf/whatever according to the message type
-	GetPayload() []byte
-
-	// Returns the message's recipient ID
-	// This is usually your userID but could be an ephemeral/group ID
-	GetRecipient() id.ID
-	GetRecipientBytes() []byte
-
-	// Returns the message's type
-	GetMessageType() int32
-
-	// Returns the message's timestamp in seconds since unix epoc
-	GetTimestamp() int64
-	// Returns the message's timestamp in ns since unix epoc
-	GetTimestampNano() int64
-}
-
-// RoundEvent contains event information for a given round.
-// TODO: This is a half-baked interface and will be filled out later.
-type RoundEvent interface {
-	// GetID returns the round ID for this round.
-	GetID() int
-	// GetStatus returns the status of this round.
-	GetStatus() int
-}
diff --git a/api/notifications.go b/api/notifications.go
new file mode 100644
index 0000000000000000000000000000000000000000..119b675f86ffc0e6f76e39d2dc06d5d77f4a9612
--- /dev/null
+++ b/api/notifications.go
@@ -0,0 +1,51 @@
+package api
+
+import jww "github.com/spf13/jwalterweatherman"
+
+// RegisterForNotifications allows a client to register for push
+// notifications.
+// Note that clients are not required to register for push notifications
+// especially as these rely on third parties (i.e., Firebase *cough*
+// *cough* google's palantir *cough*) that may represent a security
+// risk to the user.
+func (c *Client) RegisterForNotifications(token []byte) error {
+	jww.INFO.Printf("RegisterForNotifications(%s)", token)
+	// // Pull the host from the manage
+	// notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
+	// if !ok {
+	// 	return errors.New("Failed to retrieve host for notification bot")
+	// }
+
+	// // Send the register message
+	// _, err := cl.receptionManager.Comms.RegisterForNotifications(notificationBotHost,
+	// 	&mixmessages.NotificationToken{
+	// 		Token: notificationToken,
+	// 	})
+	// if err != nil {
+	// 	err := errors.Errorf(
+	// 		"RegisterForNotifications: Unable to register for notifications! %s", err)
+	// 	return err
+	// }
+
+	return nil
+}
+
+// UnregisterForNotifications turns of notifications for this client
+func (c *Client) UnregisterForNotifications() error {
+	jww.INFO.Printf("UnregisterForNotifications()")
+	// // Pull the host from the manage
+	// notificationBotHost, ok := cl.receptionManager.Comms.GetHost(&id.NotificationBot)
+	// if !ok {
+	// 	return errors.New("Failed to retrieve host for notification bot")
+	// }
+
+	// // Send the unregister message
+	// _, err := cl.receptionManager.Comms.UnregisterForNotifications(notificationBotHost)
+	// if err != nil {
+	// 	err := errors.Errorf(
+	// 		"RegisterForNotifications: Unable to register for notifications! %s", err)
+	// 	return err
+	// }
+
+	return nil
+}
diff --git a/api/send.go b/api/send.go
new file mode 100644
index 0000000000000000000000000000000000000000..ee11f6da2b32656ee5ff96bc0ca9095d38459a5f
--- /dev/null
+++ b/api/send.go
@@ -0,0 +1,42 @@
+package api
+
+import (
+	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/interfaces/params"
+	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/id"
+	jww "github.com/spf13/jwalterweatherman"
+)
+
+//This holds all functions to send messages over the network
+
+// SendE2E sends an end-to-end payload to the provided recipient with
+// the provided msgType. Returns the list of rounds in which parts of
+// the message were sent or an error if it fails.
+func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, error) {
+	jww.INFO.Printf("SendE2E(%s, %d. %v)", m.Recipient,
+		m.MessageType, m.Payload)
+	return c.network.SendE2E(m, param)
+}
+
+// SendUnsafe sends an unencrypted payload to the provided recipient
+// with the provided msgType. Returns the list of rounds in which parts
+// of the message were sent or an error if it fails.
+// NOTE: Do not use this function unless you know what you are doing.
+// This function always produces an error message in client logging.
+func (c *Client) SendUnsafe(m message.Send, param params.Unsafe) ([]id.Round,
+	error) {
+	jww.INFO.Printf("SendUnsafe(%s, %d. %v)", m.Recipient,
+		m.MessageType, m.Payload)
+	return c.network.SendUnsafe(m, param)
+}
+
+// SendCMIX sends a "raw" CMIX message payload to the provided
+// recipient. Note that both SendE2E and SendUnsafe call SendCMIX.
+// Returns the round ID of the round the payload was sent or an error
+// if it fails.
+func (c *Client) SendCMIX(msg format.Message, param params.CMIX) (id.Round,
+	error) {
+	jww.INFO.Printf("SendCMIX(%v)", msg)
+	return c.network.SendCMIX(msg, param)
+}
diff --git a/api/status.go b/api/status.go
new file mode 100644
index 0000000000000000000000000000000000000000..cebfac0f4a9d9958955198a95dad5e81eb7923b9
--- /dev/null
+++ b/api/status.go
@@ -0,0 +1,80 @@
+package api
+
+import (
+	"fmt"
+	"github.com/pkg/errors"
+	"sync/atomic"
+)
+
+type Status int
+
+const (
+	Stopped  Status = 0
+	Starting Status = 1000
+	Running  Status = 2000
+	Stopping Status = 3000
+)
+
+func (s Status) String() string {
+	switch s {
+	case Stopped:
+		return "Stopped"
+	case Starting:
+		return "Starting"
+	case Running:
+		return "Running"
+	case Stopping:
+		return "Stopping"
+	default:
+		return fmt.Sprintf("Unknown status %d", s)
+	}
+}
+
+type statusTracker struct {
+	s *uint32
+}
+
+func newStatusTracker() *statusTracker {
+	s := uint32(Stopped)
+	return &statusTracker{s: &s}
+}
+
+func (s *statusTracker) toStarting() error {
+	if !atomic.CompareAndSwapUint32(s.s, uint32(Stopped), uint32(Starting)) {
+		return errors.Errorf("Failed to move to '%s' status, at '%s', "+
+			"must be at '%s' for transition", Starting,
+			Status(atomic.LoadUint32(s.s)), Stopped)
+	}
+	return nil
+}
+
+func (s *statusTracker) toRunning() error {
+	if !atomic.CompareAndSwapUint32(s.s, uint32(Starting), uint32(Running)) {
+		return errors.Errorf("Failed to move to '%s' status, at '%s', "+
+			"must be at '%s' for transition",
+			Running, Status(atomic.LoadUint32(s.s)), Starting)
+	}
+	return nil
+}
+
+func (s *statusTracker) toStopping() error {
+	if !atomic.CompareAndSwapUint32(s.s, uint32(Running), uint32(Stopping)) {
+		return errors.Errorf("Failed to move to '%s' status, at '%s',"+
+			" must be at '%s' for transition", Stopping,
+			Status(atomic.LoadUint32(s.s)), Running)
+	}
+	return nil
+}
+
+func (s *statusTracker) toStopped() error {
+	if !atomic.CompareAndSwapUint32(s.s, uint32(Stopping), uint32(Stopped)) {
+		return errors.Errorf("Failed to move to '%s' status, at '%s',"+
+			" must be at '%s' for transition", Stopped,
+			Status(atomic.LoadUint32(s.s)), Stopping)
+	}
+	return nil
+}
+
+func (s *statusTracker) get() Status {
+	return Status(atomic.LoadUint32(s.s))
+}
diff --git a/api/userDiscovery.go b/api/userDiscovery.go
new file mode 100644
index 0000000000000000000000000000000000000000..3da6d21fd9aa3f7d59ff2154c9a901cdff2e86a2
--- /dev/null
+++ b/api/userDiscovery.go
@@ -0,0 +1,73 @@
+package api
+
+import jww "github.com/spf13/jwalterweatherman"
+
+// Returns true if the cryptographic identity has been registered with
+// the CMIX user discovery agent.
+// Note that clients do not need to perform this step if they use
+// out of band methods to exchange cryptographic identities
+// (e.g., QR codes), but failing to be registered precludes usage
+// of the user discovery mechanism (this may be preferred by user).
+func (c *Client) IsRegistered() bool {
+	jww.INFO.Printf("IsRegistered()")
+	return false
+}
+
+// RegisterIdentity registers an arbitrary username with the user
+// discovery protocol. Returns an error when it cannot connect or
+// the username is already registered.
+func (c *Client) RegisterIdentity(username string) error {
+	jww.INFO.Printf("RegisterIdentity(%s)", username)
+	return nil
+}
+
+// RegisterEmail makes the users email searchable after confirmation.
+// It returns a registration confirmation token to be used with
+// ConfirmRegistration or an error on failure.
+func (c *Client) RegisterEmail(email string) ([]byte, error) {
+	jww.INFO.Printf("RegisterEmail(%s)", email)
+	return nil, nil
+}
+
+// RegisterPhone makes the users phone searchable after confirmation.
+// It returns a registration confirmation token to be used with
+// ConfirmRegistration or an error on failure.
+func (c *Client) RegisterPhone(phone string) ([]byte, error) {
+	jww.INFO.Printf("RegisterPhone(%s)", phone)
+	return nil, nil
+}
+
+// ConfirmRegistration sends the user discovery agent a confirmation
+// token (from register Email/Phone) and code (string sent via Email
+// or SMS to confirm ownership) to confirm ownership.
+func (c *Client) ConfirmRegistration(token, code []byte) error {
+	jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code)
+	return nil
+}
+
+// Search accepts a "separator" separated list of search elements with
+// an associated list of searchTypes. It returns a ContactList which
+// allows you to iterate over the found contact objects.
+func (c *Client) Search(data, separator string, searchTypes []byte) []Contact {
+	jww.INFO.Printf("Search(%s, %s, %s)", data, separator, searchTypes)
+	return nil
+}
+
+// SearchWithHandler is a non-blocking search that also registers
+// a callback interface for user disovery events.
+func (c *Client) SearchWithCallback(data, separator string, searchTypes []byte,
+	cb func(results []Contact)) {
+	resultCh := make(chan []Contact, 1)
+	go func(out chan []Contact, data, separator string, srchTypes []byte) {
+		out <- c.Search(data, separator, srchTypes)
+		close(out)
+	}(resultCh, data, separator, searchTypes)
+
+	go func(in chan []Contact, cb func(results []Contact)) {
+		select {
+		case contacts := <-in:
+			cb(contacts)
+			//TODO: Timer
+		}
+	}(resultCh, cb)
+}
diff --git a/api/version.go b/api/version.go
index 639329b21a87149ebf22ab49b0a5853e928db782..d8a8e2a056308b8a6f02f3b20f37bf68fa37d339 100644
--- a/api/version.go
+++ b/api/version.go
@@ -16,7 +16,7 @@ func (c *Client) Version() version.Version {
 
 func (c *Client) checkVersion() error {
 	clientVersion := c.Version()
-	jww.INFO.Printf("Client Version: %s", clientVersion)
+	jww.INFO.Printf("Client Version: %s", clientVersion.String())
 
 	has, netVersion, err := c.permissioning.GetNetworkVersion()
 	if err != nil {
@@ -29,7 +29,7 @@ func (c *Client) checkVersion() error {
 			return errors.Errorf("Client and Minimum Network Version are "+
 				"incompatible\n"+
 				"\tMinimum Network: %s\n"+
-				"\tClient: %s", netVersion, clientVersion)
+				"\tClient: %s", netVersion.String(), clientVersion.String())
 		}
 	} else {
 		jww.WARN.Printf("Network requires no minnimim version")
diff --git a/bindings/api.go b/bindings/api.go
index b8351406a78d4b37e6b10553e7bf30384fbfe553..3195423f109913a399747e46fc2ba985dc4fc461 100644
--- a/bindings/api.go
+++ b/bindings/api.go
@@ -35,7 +35,7 @@ type BindingsClient struct {
 // Users of this function should delete the storage directory on error.
 func NewClient(network, storageDir string, password []byte) (Client, error) {
 	// TODO: This should wrap the bindings ClientImpl, when available.
-	client, err := api.NewClient(network, storageDir, password)
+	client, err := api.NewClient(network, storageDir, password, "")
 	if err != nil {
 		return nil, err
 	}
diff --git a/bindings/interfaces.go b/bindings/interfaces.go
index e7d3f4e272fe86cfb59a4fcce1f5d79300875889..a4fd23c45cff5af5f4d3597afd8f233828e2faeb 100644
--- a/bindings/interfaces.go
+++ b/bindings/interfaces.go
@@ -8,7 +8,7 @@ package bindings
 
 import (
 	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/stoppable"
+	"gitlab.com/xx_network/primitives/id"
 )
 
 // Client is defined inside the api package. At minimum, it implements all of
@@ -121,7 +121,7 @@ type Client interface {
 	// and returns an object for checking state and stopping those threads.
 	// Call this when returning from sleep and close when going back to
 	// sleep.
-	StartNetworkRunner() stoppable.Stoppable
+	StartNetworkFollower() error
 
 	// RegisterRoundEventsHandler registers a callback interface for round
 	// events.
@@ -140,11 +140,11 @@ type ContactList interface {
 
 // Listener provides a callback to hear a message
 // An object implementing this interface can be called back when the client
-// gets a message of the type that the registerer specified at registration
+// gets a message of the type that the regi    sterer specified at registration
 // time.
 type Listener interface {
 	// Hear is called to receive a message in the UI
-	Hear(msg api.Message)
+	Hear(msg Message)
 }
 
 // AuthEventHandler handles authentication requests initiated by
@@ -189,3 +189,28 @@ type RoundEventHandler interface {
 type UserDiscoveryHandler interface {
 	HandleSearchResults(results ContactList)
 }
+
+// Message is a message received from the cMix network in the clear
+// or that has been decrypted using established E2E keys.
+type Message interface {
+	// Returns the message's sender ID, if available
+	GetSender() id.ID
+	GetSenderBytes() []byte
+
+	// Returns the message payload/contents
+	// Parse this with protobuf/whatever according to the message type
+	GetPayload() []byte
+
+	// Returns the message's recipient ID
+	// This is usually your userID but could be an ephemeral/group ID
+	GetRecipient() id.ID
+	GetRecipientBytes() []byte
+
+	// Returns the message's type
+	GetMessageType() int32
+
+	// Returns the message's timestamp in seconds since unix epoc
+	GetTimestamp() int64
+	// Returns the message's timestamp in ns since unix epoc
+	GetTimestampNano() int64
+}
diff --git a/cmd/root.go b/cmd/root.go
index fb328b155b826d8433cc0b990927041aa0ab6a7d..480077b6289e8b88c8bd6d2f48d58a33f1d1a049 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -13,6 +13,7 @@ import (
 	"github.com/spf13/cobra"
 	jww "github.com/spf13/jwalterweatherman"
 	"github.com/spf13/viper"
+	"gitlab.com/elixxir/client/api"
 	"gitlab.com/xx_network/primitives/id"
 	"io/ioutil"
 	"os"
@@ -172,12 +173,45 @@ var rootCmd = &cobra.Command{
 	Short: "Runs a client for cMix anonymous communication platform",
 	Args:  cobra.NoArgs,
 	Run: func(cmd *cobra.Command, args []string) {
-		if !verbose && viper.Get("verbose") != nil {
-			verbose = viper.GetBool("verbose")
+		initLog(viper.GetBool("verbose"), viper.GetString("log"))
+		jww.INFO.Printf(Version())
+
+		pass := viper.GetString("password")
+		storeDir := viper.GetString("session")
+		regCode := viper.GetString("regcode")
+
+		var client *api.Client
+		if _, err := os.Stat(storeDir); os.IsNotExist(err) {
+			// Load NDF
+			ndfPath := viper.GetString("ndf")
+			ndfJSON, err := ioutil.ReadFile(ndfPath)
+			if err != nil {
+				jww.FATAL.Panicf(err.Error())
+			}
+
+			client, err = api.NewClient(string(ndfJSON), storeDir,
+				[]byte(pass), regCode)
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+		} else {
+			client, err = api.LoadClient(storeDir, []byte(pass))
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
 		}
-		if logPath == "" && viper.Get("logPath") != nil {
-			logPath = viper.GetString("logPath")
+
+		user, err := client.GetUser()
+		if err != nil {
+			jww.FATAL.Panicf("%+v", err)
 		}
+		jww.INFO.Printf("%v", user.ID)
+
+	},
+}
+
+func initLog(verbose bool, logPath string) {
+	if logPath != "-" && logPath != "" {
 		// Disable stdout output
 		jww.SetStdoutOutput(ioutil.Discard)
 		// Use log file
@@ -187,10 +221,16 @@ var rootCmd = &cobra.Command{
 			panic(err.Error())
 		}
 		jww.SetLogOutput(logOutput)
-		if verbose {
-			jww.SetLogThreshold(jww.LevelTrace)
-		}
-	},
+	}
+
+	if verbose {
+		jww.SetStdoutThreshold(jww.LevelTrace)
+		jww.SetLogThreshold(jww.LevelTrace)
+	} else {
+		jww.SetStdoutThreshold(jww.LevelInfo)
+		jww.SetLogThreshold(jww.LevelInfo)
+	}
+
 }
 
 func isValidUser(usr []byte) (bool, *id.ID) {
@@ -222,60 +262,30 @@ func init() {
 	// Here you will define your flags and configuration settings.
 	// Cobra supports persistent flags, which, if defined here,
 	// will be global for your application.
-	rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false,
+	rootCmd.Flags().BoolP("verbose", "v", false,
 		"Verbose mode for debugging")
+	viper.BindPFlag("verbose", rootCmd.Flags().Lookup("verbose"))
+
+	rootCmd.Flags().StringP("session", "s",
+		"", "Sets the initial username and the directory for "+
+			"client storage")
+	viper.BindPFlag("session", rootCmd.Flags().Lookup("session"))
+
+	rootCmd.Flags().StringP("password", "p", "",
+		"Password to the session file")
+	viper.BindPFlag("password", rootCmd.Flags().Lookup("password"))
 
-	rootCmd.PersistentFlags().BoolVarP(&noBlockingTransmission, "noBlockingTransmission",
-		"", false, "Sets if transmitting messages blocks or not.  "+
-			"Defaults to true if unset.")
-	rootCmd.PersistentFlags().Uint32VarP(&rateLimiting, "rateLimiting", "",
-		1000, "Sets the amount of time, in ms, "+
-			"that the client waits between sending messages.  "+
-			"set to zero to disable.  "+
-			"Automatically disabled if 'blockingTransmission' is false")
-
-	rootCmd.PersistentFlags().Uint64VarP(&userId, "userid", "i", 0,
-		"ID to sign in as. Does not register, must be an available precanned user")
-
-	rootCmd.PersistentFlags().StringVarP(&registrationCode,
-		"regcode", "r",
-		"",
-		"Registration Code with the registration server")
-
-	rootCmd.PersistentFlags().StringVarP(&username,
-		"username", "E",
-		"",
-		"Username to register for User Discovery")
-
-	rootCmd.PersistentFlags().StringVarP(&sessionFile, "sessionfile", "f",
-		"", "Passes a file path for loading a session.  "+
-			"If the file doesn't exist the code will register the user and"+
-			" store it there.  If not passed the session will be stored"+
-			" to ram and lost when the cli finishes")
-
-	rootCmd.PersistentFlags().StringVarP(&ndfPubKey,
-		"ndfPubKeyCertPath",
-		"p",
-		"",
-		"Path to the certificated containing the public key for the "+
-			" network definition JSON file")
-
-	rootCmd.PersistentFlags().StringVarP(&ndfPath,
-		"ndf",
-		"n",
-		"ndf.json",
+	rootCmd.Flags().StringP("ndf", "n", "ndf.json",
 		"Path to the network definition JSON file")
+	viper.BindPFlag("ndf", rootCmd.Flags().Lookup("ndf"))
 
-	rootCmd.PersistentFlags().BoolVar(&skipNDFVerification,
-		"skipNDFVerification",
-		false,
-		"Specifies if the NDF should be loaded without the signature")
+	rootCmd.Flags().StringP("log", "l", "-",
+		"Path to the log output path (- is stdout)")
+	viper.BindPFlag("log", rootCmd.Flags().Lookup("log"))
 
-	rootCmd.PersistentFlags().StringVarP(&sessFilePassword,
-		"password",
-		"P",
-		"",
-		"Password to the session file")
+	rootCmd.Flags().StringP("regcode", "r", "",
+		"Registration code (optional)")
+	viper.BindPFlag("regcode", rootCmd.Flags().Lookup("regcode"))
 
 	// Cobra also supports local flags, which will only run
 	// when this action is called directly.
@@ -307,11 +317,8 @@ func init() {
 		"w", 1, "Denotes the number of messages the "+
 			"client should receive before closing")
 
-	rootCmd.Flags().StringVarP(&searchForUser, "SearchForUser", "s", "",
-		"Sets the email to search for to find a user with user discovery")
-
-	rootCmd.Flags().StringVarP(&logPath, "log", "l", "",
-		"Print logs to specified log file, not stdout")
+	// rootCmd.Flags().StringVarP(&searchForUser, "SearchForUser", "s", "",
+	// 	"Sets the email to search for to find a user with user discovery")
 
 	rootCmd.Flags().UintVarP(&messageTimeout, "messageTimeout",
 		"t", 45, "The number of seconds to wait for "+
diff --git a/cmd/version.go b/cmd/version.go
index c231ec50626563ba99e39fbc3b63ab50975bd7c9..309fbf6f72d85325ad547b2c1e70b3299d822e33 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -18,9 +18,11 @@ import (
 // Change this value to set the version for this build
 const currentVersion = "1.4.0"
 
-func printVersion() {
-	fmt.Printf("Elixxir Client v%s -- %s\n\n", api.SEMVER, api.GITVERSION)
-	fmt.Printf("Dependencies:\n\n%s\n", api.DEPENDENCIES)
+func Version() string {
+	out := fmt.Sprintf("Elixxir Client v%s -- %s\n\n", api.SEMVER,
+		api.GITVERSION)
+	out += fmt.Sprintf("Dependencies:\n\n%s\n", api.DEPENDENCIES)
+	return out
 }
 
 func init() {
@@ -33,7 +35,7 @@ var versionCmd = &cobra.Command{
 	Short: "Print the version and dependency information for the Elixxir binary",
 	Long:  `Print the version and dependency information for the Elixxir binary`,
 	Run: func(cmd *cobra.Command, args []string) {
-		printVersion()
+		fmt.Printf(Version())
 	},
 }
 
diff --git a/go.mod b/go.mod
index e5c7c5d3eab3f89ad9682624dce8c0f41f9975e9..364100667bc4b0c9a455eac2f765e256f551042a 100644
--- a/go.mod
+++ b/go.mod
@@ -6,26 +6,27 @@ require (
 	github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
 	github.com/golang/protobuf v1.4.2
 	github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
-	github.com/pelletier/go-toml v1.6.0 // indirect
+	github.com/magiconair/properties v1.8.4 // indirect
+	github.com/mitchellh/mapstructure v1.3.3 // indirect
+	github.com/pelletier/go-toml v1.8.1 // indirect
 	github.com/pkg/errors v0.9.1
 	github.com/smartystreets/assertions v1.0.1 // indirect
-	github.com/spf13/afero v1.2.2 // indirect
+	github.com/spf13/afero v1.4.0 // indirect
 	github.com/spf13/cast v1.3.1 // indirect
 	github.com/spf13/cobra v1.0.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/pflag v1.0.5 // indirect
-	github.com/spf13/viper v1.6.2
-	gitlab.com/elixxir/comms v0.0.0-20200923155248-2dd684128da1
+	github.com/spf13/viper v1.7.1
+	gitlab.com/elixxir/comms v0.0.0-20200924210331-d7903c023fa6
 	gitlab.com/elixxir/crypto v0.0.0-20200921195205-bca0178268ec
-	gitlab.com/elixxir/ekv v0.1.1
-	gitlab.com/elixxir/primitives v0.0.0-20200916172343-37503735c7a1
-	gitlab.com/xx_network/comms v0.0.0-20200923154925-b8a96380f180
+	gitlab.com/elixxir/ekv v0.1.3
+	gitlab.com/elixxir/primitives v0.0.0-20200915190719-f4586ec93f50
+	gitlab.com/xx_network/comms v0.0.0-20200924172734-1124191b69ee
 	gitlab.com/xx_network/crypto v0.0.0-20200812183430-c77a5281c686
 	gitlab.com/xx_network/primitives v0.0.0-20200915204206-eb0287ed0031
-	golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
-	golang.org/x/sys v0.0.0-20200828194041-157a740278f4 // indirect
+	golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
 	google.golang.org/protobuf v1.25.0
-	gopkg.in/ini.v1 v1.52.0 // indirect
+	gopkg.in/ini.v1 v1.61.0 // indirect
 )
 
 replace google.golang.org/grpc => github.com/grpc/grpc-go v1.27.1
diff --git a/go.sum b/go.sum
index fbc8028b449a6520568fd35118ff1a97514ddc1d..4fa2f61b06bad217a57129bbe30eddb99db834c3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,18 +1,39 @@
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -22,11 +43,13 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -39,6 +62,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekf
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -52,6 +77,7 @@ github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -60,26 +86,55 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc/grpc-go v1.27.1 h1:EluyjU5nlbuNJSEktNl600PIpzbO2OcvZWfWV1jFvKM=
 github.com/grpc/grpc-go v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -89,23 +144,44 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
+github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
+github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
 github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
+github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
+github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -117,7 +193,11 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -130,9 +210,17 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/afero v1.4.0 h1:jsLTaI1zwYO3vjrzHalkVcIHXTNmdQFepW4OI8H3+x8=
+github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
 github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
+github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
@@ -141,12 +229,19 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I=
+github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
+github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
 github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
+github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
+github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
@@ -188,12 +283,16 @@ gitlab.com/elixxir/comms v0.0.0-20200916212207-60e7bd5b0913 h1:p4TLPPaMysV//lOJU
 gitlab.com/elixxir/comms v0.0.0-20200916212207-60e7bd5b0913/go.mod h1:yBEsOZSPyJQJvDbtlQ5L8ydy1JRgVlRoNgMDy9koQcE=
 gitlab.com/elixxir/comms v0.0.0-20200917172539-929fc227eb0c h1:go7/RknV7646Ie+nmQXZAa/aJ5wZBn5bpAYRB+tPens=
 gitlab.com/elixxir/comms v0.0.0-20200917172539-929fc227eb0c/go.mod h1:yBEsOZSPyJQJvDbtlQ5L8ydy1JRgVlRoNgMDy9koQcE=
+gitlab.com/elixxir/comms v0.0.0-20200921200427-5955a0a798b9 h1:skzHNWCMh+T7Cn58/88Mikg2R8KnSWfzLV0w7SnerOs=
+gitlab.com/elixxir/comms v0.0.0-20200921200427-5955a0a798b9/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0=
 gitlab.com/elixxir/comms v0.0.0-20200922163657-3e723b7170f6 h1:dFgfdATZuiPybonCBh0s4HeLB8Qw3Zm9EoLDRh2Eaaw=
 gitlab.com/elixxir/comms v0.0.0-20200922163657-3e723b7170f6/go.mod h1:yBEsOZSPyJQJvDbtlQ5L8ydy1JRgVlRoNgMDy9koQcE=
-gitlab.com/elixxir/comms v0.0.0-20200922182918-25d056c28b3a h1:aBBz0LOfUulcQojWFg2sawdI0EkdRNTKU5qlPsmn+Ow=
-gitlab.com/elixxir/comms v0.0.0-20200922182918-25d056c28b3a/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0=
-gitlab.com/elixxir/comms v0.0.0-20200923155248-2dd684128da1 h1:bYdJzis8XR/TNBY3BWlhlRrHPIffVrFZp66gX99nH0Q=
-gitlab.com/elixxir/comms v0.0.0-20200923155248-2dd684128da1/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0=
+gitlab.com/elixxir/comms v0.0.0-20200924072138-2e2709483d89 h1:PQalM7pnCRzZRKvdzJ6Jwz6e8bPR9H4CURzAwqYnJPE=
+gitlab.com/elixxir/comms v0.0.0-20200924072138-2e2709483d89/go.mod h1:uRr8j6yTjCslxZxbRe6k4ixACu9gAeF61JZH36OFFa0=
+gitlab.com/elixxir/comms v0.0.0-20200924172854-724244a10032 h1:0RLZM1fBzp7IRrjoCQANQfXMBDr1Hmjbynme564zXG8=
+gitlab.com/elixxir/comms v0.0.0-20200924172854-724244a10032/go.mod h1:9+Jj7K8HOTgBjPuiP69VtTKTv7GvAK6bWlh4lgMAqrk=
+gitlab.com/elixxir/comms v0.0.0-20200924210331-d7903c023fa6 h1:ctVsHyiabgRls3esApbBemDwmQ/a0CramEmZt9RCQb8=
+gitlab.com/elixxir/comms v0.0.0-20200924210331-d7903c023fa6/go.mod h1:9+Jj7K8HOTgBjPuiP69VtTKTv7GvAK6bWlh4lgMAqrk=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c=
 gitlab.com/elixxir/crypto v0.0.0-20200805174804-bdf909f2a16d/go.mod h1:cu6uNoANVLV0J6HyTL6KqVtVyh9SHU1RjJhytYlsbVQ=
@@ -225,25 +324,27 @@ gitlab.com/elixxir/crypto v0.0.0-20200915211245-8a519dfcc38d h1:6D2r42dFuUm96Kje
 gitlab.com/elixxir/crypto v0.0.0-20200915211245-8a519dfcc38d/go.mod h1:zUczcFuZGqLchDX1sjgBo189soeDK2p5Mx+GNNrkTLI=
 gitlab.com/elixxir/crypto v0.0.0-20200917184612-bb2ad1c493ce h1:g8/MABMbpVUJOn2BMhZJo8Pkee4YVSriFoV5po0TDkY=
 gitlab.com/elixxir/crypto v0.0.0-20200917184612-bb2ad1c493ce/go.mod h1:zUczcFuZGqLchDX1sjgBo189soeDK2p5Mx+GNNrkTLI=
+gitlab.com/elixxir/crypto v0.0.0-20200921191117-583f263ab715 h1:1eMAfJ1uyOVU8O3JXQSBrVYt1CLMRUBSjYYzVPI+uO0=
+gitlab.com/elixxir/crypto v0.0.0-20200921191117-583f263ab715/go.mod h1:1P3IMJ6i3L+5si0PiMvoo/qQXMsEhNVjn0yMUrm3eiA=
 gitlab.com/elixxir/crypto v0.0.0-20200921195205-bca0178268ec h1:8dnRUCSNz7knf+K5OvmEwY181aPp5ErseJogEwgS6dY=
 gitlab.com/elixxir/crypto v0.0.0-20200921195205-bca0178268ec/go.mod h1:1P3IMJ6i3L+5si0PiMvoo/qQXMsEhNVjn0yMUrm3eiA=
 gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842 h1:m1zDQ6UadpuMnV7nvnyR+DUXE3AisRnVjajTb1xZE4c=
 gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842/go.mod h1:bXY0kgbV5BHYda4YY5/hiG5bjimGK+R3PYub5yM9C/s=
 gitlab.com/elixxir/ekv v0.1.1 h1:Em3rF8sv+tNbQGXbcpYzAS2blWRAP708JGhYlkN74Kg=
 gitlab.com/elixxir/ekv v0.1.1/go.mod h1:bXY0kgbV5BHYda4YY5/hiG5bjimGK+R3PYub5yM9C/s=
+gitlab.com/elixxir/ekv v0.1.3 h1:OE+LBMIhjGUMwc6hHJzYvEPNJQV7t1vMnJyIgxUMUo8=
+gitlab.com/elixxir/ekv v0.1.3/go.mod h1:e6WPUt97taFZe5PFLPb1Dupk7tqmDCTQu1kkstqJvw4=
 gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg=
 gitlab.com/elixxir/primitives v0.0.0-20200804170709-a1896d262cd9/go.mod h1:p0VelQda72OzoUckr1O+vPW0AiFe0nyKQ6gYcmFSuF8=
 gitlab.com/elixxir/primitives v0.0.0-20200804182913-788f47bded40/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc=
 gitlab.com/elixxir/primitives v0.0.0-20200804231232-ad79a9e8f113/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc=
 gitlab.com/elixxir/primitives v0.0.0-20200805174810-86b366d1dd2d/go.mod h1:tzdFFvb1ESmuTCOl1z6+yf6oAICDxH2NPUemVgoNLxc=
 gitlab.com/elixxir/primitives v0.0.0-20200812191102-31c01f08b4dc/go.mod h1:pJx2DZk9s8vVMnLN7x0hIPngDjbNSdOP6kk3RLlRxHg=
-gitlab.com/elixxir/primitives v0.0.0-20200907165319-16ed0124890b h1:d1ttSIOWxWytnTpjO9hyr4KFtv/dmDBYuK59EP0sjAQ=
 gitlab.com/elixxir/primitives v0.0.0-20200907165319-16ed0124890b/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
 gitlab.com/elixxir/primitives v0.0.0-20200915190719-f4586ec93f50 h1:J0A2JsYlb0He1lTGDy+6KX3s/87uklk/pLv9FKv9yp8=
 gitlab.com/elixxir/primitives v0.0.0-20200915190719-f4586ec93f50/go.mod h1:kNp47yPqja2lHSiS4DddTvFpB/4D9dB2YKnw5c+LJCE=
 gitlab.com/elixxir/primitives v0.0.0-20200916172343-37503735c7a1 h1:51FDjTwXKVadID7xRxQxMKequpEjoKAIxaMpAn/YCP0=
 gitlab.com/elixxir/primitives v0.0.0-20200916172343-37503735c7a1/go.mod h1:pJx2DZk9s8vVMnLN7x0hIPngDjbNSdOP6kk3RLlRxHg=
-gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023 h1:fQPaxyuXyH3vl8qFlFDBEx8rlEzBnXBNy74K8ItFRM4=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
 gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba h1:7nozLSNBX0CfP53DDiDNLJx9obhYGfGf5na0/c9rMso=
 gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba/go.mod h1:idLzPGYig57XE7xuU93OlIF9s6NgSJj7OArQvsd5DjY=
@@ -258,10 +359,9 @@ gitlab.com/xx_network/comms v0.0.0-20200910173932-bd179f5fee4f h1:ExTCqEoro7VuS1
 gitlab.com/xx_network/comms v0.0.0-20200910173932-bd179f5fee4f/go.mod h1:+jEkDQKoK51WLl2ZZuxfAZkz6YFbUQ+oZfH0dt2wIF0=
 gitlab.com/xx_network/comms v0.0.0-20200915154643-d533291041b7 h1:lPx1wpkjNpwLaZ0pyd7/iCcdITjT+eCMmb0HXCVoIkk=
 gitlab.com/xx_network/comms v0.0.0-20200915154643-d533291041b7/go.mod h1:+jEkDQKoK51WLl2ZZuxfAZkz6YFbUQ+oZfH0dt2wIF0=
-gitlab.com/xx_network/comms v0.0.0-20200922173551-45ad1fa27175 h1:HDmgh2Skbgv/fW1selsLDRr+hvQaK24nsthxv9nAHRM=
-gitlab.com/xx_network/comms v0.0.0-20200922173551-45ad1fa27175/go.mod h1:wDPZABTOhqz+uFM75CzpGplQBRIsCQcS1EYXwker6nw=
-gitlab.com/xx_network/comms v0.0.0-20200923154925-b8a96380f180 h1:TGamVmJrBj7AvLi6okQ7PQoutaBptCXMAiUqTwoiXRc=
-gitlab.com/xx_network/comms v0.0.0-20200923154925-b8a96380f180/go.mod h1:wDPZABTOhqz+uFM75CzpGplQBRIsCQcS1EYXwker6nw=
+gitlab.com/xx_network/comms v0.0.0-20200924172734-1124191b69ee h1:dPRaW0OxcoBlWALd5H6VUYnL/ALvT7j14kWJNBi0K7A=
+gitlab.com/xx_network/comms v0.0.0-20200924172734-1124191b69ee/go.mod h1:jECvMkoYKZFooCudoZxxaf2bo1DzpWP0gCahXHdlqUM=
+gitlab.com/xx_network/crypto v0.0.0-20200805231039-4aa0e350ed0a h1:BlfWGPokU6yU69O+PGGsgc5iA/P9gERbHzYUvjoYbgM=
 gitlab.com/xx_network/crypto v0.0.0-20200806202113-978fa1984bbf/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw=
 gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce h1:gypNBUl2guESEv4MDgH+miwYqR4jPoWM8dLt2Zs5gIs=
 gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce/go.mod h1:i0df/q6dDCBiscgD51fMoS2U2TBrm6LcyN822JmB5Tw=
@@ -279,11 +379,17 @@ gitlab.com/xx_network/primitives v0.0.0-20200915204206-eb0287ed0031/go.mod h1:wt
 gitlab.com/xx_network/ring v0.0.2 h1:TlPjlbFdhtJrwvRgIg4ScdngMTaynx/ByHBRZiXCoL0=
 gitlab.com/xx_network/ring v0.0.2/go.mod h1:aLzpP2TiZTQut/PVHR40EJAomzugDdHXetbieRClXIM=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -296,26 +402,57 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
 golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -327,21 +464,53 @@ golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirS
 golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200828194041-157a740278f4 h1:kCCpuwSAoYJPkNc6x0xT9yTtV4oKtARo4RGBQWOfg9E=
 golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73IhgqJ71c9s80WsQnh0Es=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/genproto v0.0.0-20200709005830-7a2ca40e9dc3 h1:JwLN1jVnmIsfE4HkDVe2AblFAbo0Z+4cjteDSOnv6oE=
 google.golang.org/genproto v0.0.0-20200709005830-7a2ca40e9dc3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -364,9 +533,12 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
 gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.61.0 h1:LBCdW4FmFYL4s/vDZD1RQYX7oAR6IjujCYgMdbHBR10=
+gopkg.in/ini.v1 v1.61.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -378,4 +550,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/interfaces/roundEvents.go b/interfaces/roundEvents.go
new file mode 100644
index 0000000000000000000000000000000000000000..a3f27f76331dec24b73cea6af6bd3c99d1a54514
--- /dev/null
+++ b/interfaces/roundEvents.go
@@ -0,0 +1,32 @@
+package interfaces
+
+import (
+	ds "gitlab.com/elixxir/comms/network/dataStructures"
+	"gitlab.com/elixxir/primitives/states"
+	"gitlab.com/xx_network/primitives/id"
+	"time"
+)
+
+// The round events interface allows the registration of an event which triggers
+// when a round reaches one or more states
+
+type RoundEvents interface {
+	// designates a callback to call on the specified event
+	// rid is the id of the round the event occurs on
+	// callback is the callback the event is triggered on
+	// timeout is the amount of time before an error event is returned
+	// valid states are the states which the event should trigger on
+	AddRoundEvent(rid id.Round, callback ds.RoundEventCallback,
+		timeout time.Duration, validStates ...states.Round) *ds.EventCallback
+
+	// designates a go channel to signal the specified event
+	// rid is the id of the round the event occurs on
+	// eventChan is the channel the event is triggered on
+	// timeout is the amount of time before an error event is returned
+	// valid states are the states which the event should trigger on
+	AddRoundEventChan(rid id.Round, eventChan chan ds.EventReturn,
+		timeout time.Duration, validStates ...states.Round) *ds.EventCallback
+
+	//Allows the un-registration of a round event before it triggers
+	Remove(rid id.Round, e *ds.EventCallback)
+}
diff --git a/interfaces/switchboard.go b/interfaces/switchboard.go
new file mode 100644
index 0000000000000000000000000000000000000000..3ebb9d8b23779c0d8d024d330e078dc1748c6b01
--- /dev/null
+++ b/interfaces/switchboard.go
@@ -0,0 +1,68 @@
+package interfaces
+
+import (
+	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/switchboard"
+	"gitlab.com/xx_network/primitives/id"
+)
+
+// public switchboard interface which only allows registration and does not
+// allow speaking messages
+type Switchboard interface {
+	// Registers a new listener. Returns the ID of the new listener.
+	// Keep this around if you want to be able to delete the listener later.
+	//
+	// name is used for debug printing and not checked for uniqueness
+	//
+	// user: 0 for all, or any user ID to listen for messages from a particular
+	// user. 0 can be id.ZeroUser or id.ZeroID
+	// messageType: 0 for all, or any message type to listen for messages of
+	// that type. 0 can be switchboard.AnyType
+	// newListener: something implementing the Listener interface. Do not
+	// pass nil to this.
+	//
+	// If a message matches multiple listeners, all of them will hear the
+	// message.
+	RegisterListener(user *id.ID, messageType message.Type,
+		newListener switchboard.Listener) switchboard.ListenerID
+
+	// Registers a new listener built around the passed function.
+	// Returns the ID of the new listener.
+	// Keep this around if you want to be able to delete the listener later.
+	//
+	// name is used for debug printing and not checked for uniqueness
+	//
+	// user: 0 for all, or any user ID to listen for messages from a particular
+	// user. 0 can be id.ZeroUser or id.ZeroID
+	// messageType: 0 for all, or any message type to listen for messages of
+	// that type. 0 can be switchboard.AnyType
+	// newListener: a function implementing the ListenerFunc function type.
+	// Do not pass nil to this.
+	//
+	// If a message matches multiple listeners, all of them will hear the
+	// message.
+	RegisterFunc(name string, user *id.ID, messageType message.Type,
+		newListener switchboard.ListenerFunc) switchboard.ListenerID
+
+	// Registers a new listener built around the passed channel.
+	// Returns the ID of the new listener.
+	// Keep this around if you want to be able to delete the listener later.
+	//
+	// name is used for debug printing and not checked for uniqueness
+	//
+	// user: 0 for all, or any user ID to listen for messages from a particular
+	// user. 0 can be id.ZeroUser or id.ZeroID
+	// messageType: 0 for all, or any message type to listen for messages of
+	// that type. 0 can be switchboard.AnyType
+	// newListener: an item channel.
+	// Do not pass nil to this.
+	//
+	// If a message matches multiple listeners, all of them will hear the
+	// message.
+	RegisterChannel(name string, user *id.ID, messageType message.Type,
+		newListener chan message.Receive) switchboard.ListenerID
+
+	// Unregister removes the listener with the specified ID so it will no
+	// longer get called
+	Unregister(listenerID switchboard.ListenerID)
+}
diff --git a/network/follow.go b/network/follow.go
index 0a99f3d7e6bfbc26bd3916e558700bf5f04d6eb6..40892dc565c33ddb1f30fc0318351b37f30fa052 100644
--- a/network/follow.go
+++ b/network/follow.go
@@ -17,7 +17,7 @@ package network
 //   - /node/register.go for add/remove node events
 //   - /rounds/historical.go for old round retrieval
 //   - /rounds/retrieve.go for message retrieval
-//   - /message/reception.go decryption, partitioning, and signaling of messages
+//   - /message/handle.go decryption, partitioning, and signaling of messages
 //   - /health/tracker.go - tracks the state of the network through the network
 //		instance
 
@@ -33,6 +33,7 @@ import (
 	"time"
 )
 
+//comms interface makes testing easier
 type followNetworkComms interface {
 	GetHost(hostId *id.ID) (*connect.Host, bool)
 	SendPoll(host *connect.Host, message *pb.GatewayPoll) (*pb.GatewayPollResponse, error)
@@ -55,6 +56,7 @@ func (m *manager) followNetwork(quitCh <-chan struct{}) {
 	}
 }
 
+// executes each iteration of the follower
 func (m *manager) follow(rng csprng.Source, comms followNetworkComms) {
 
 	//randomly select a gateway to poll
@@ -109,14 +111,21 @@ func (m *manager) follow(rng csprng.Source, comms followNetworkComms) {
 	}
 
 	// ---- Round Processing -----
-	//build the round checker
+	// check rounds using the round checker function which determines if there
+	// are messages waiting in rounds and then sends signals to the appropriate
+	// handling threads
 	roundChecker := func(rid id.Round) bool {
 		return m.round.Checker(rid)
 	}
 
-	//check rounds
+	// get the bit vector of rounds that have been checked
 	checkedRounds := m.Session.GetCheckedRounds()
+	// cleave off old state in the bit vector which is deprecated from the
+	// network
 	checkedRounds.Forward(lastTrackedRound)
+	// loop through all rounds the client does not know about and the gateway
+	// does, checking the bloom filter for the user to see if there are
+	// messages for the user (bloom not implemented yet)
 	checkedRounds.RangeUncheckedMasked(gwRoundsState, roundChecker,
 		int(m.param.MaxCheckedRounds))
 }
diff --git a/network/health/tracker.go b/network/health/tracker.go
index 88a194a250967a65119e404174d06867240662d9..3a297ba9bb26a68f8e570d4762b840cac491684e 100644
--- a/network/health/tracker.go
+++ b/network/health/tracker.go
@@ -9,6 +9,7 @@
 package health
 
 import (
+	"errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/stoppable"
 	"gitlab.com/elixxir/comms/network"
@@ -24,7 +25,7 @@ type Tracker struct {
 	channels []chan bool
 	funcs    []func(isHealthy bool)
 
-	*stoppable.Single
+	running bool
 
 	isHealthy bool
 	mux       sync.RWMutex
@@ -46,7 +47,7 @@ func newTracker(timeout time.Duration) *Tracker {
 		channels:  make([]chan bool, 0),
 		heartbeat: make(chan network.Heartbeat, 100),
 		isHealthy: false,
-		Single:    stoppable.NewSingle("Health Tracker"),
+		running:   false,
 	}
 }
 
@@ -75,13 +76,30 @@ func (t *Tracker) setHealth(h bool) {
 	t.transmit(h)
 }
 
-func (t *Tracker) Start() {
-	if t.Single.IsRunning() {
-		jww.FATAL.Panicf("Cannot start the health tracker when it " +
-			"is already running")
+func (t *Tracker) Start() (stoppable.Stoppable, error) {
+	t.mux.Lock()
+	defer t.mux.Unlock()
+	if t.running {
+		return nil, errors.New("cannot start Health tracker threads, " +
+			"they are already running")
 	}
+	t.running = true
+
+	t.isHealthy = false
+
+	stop := stoppable.NewSingle("Health Tracker")
+	stopCleanup := stoppable.NewCleanup(stop, func(duration time.Duration) error {
+		t.mux.Lock()
+		defer t.mux.Unlock()
+		t.isHealthy = false
+		t.transmit(false)
+		t.running = false
+		return nil
+	})
+
+	go t.start(stop.Quit())
 
-	//go t.start(t.Quit())
+	return stopCleanup, nil
 }
 
 // Long-running thread used to monitor and report on network health
diff --git a/network/manager.go b/network/manager.go
index 1482b1dba7fadc4f2cd8f07c490e0912b2cc1929..75f263b67051ad54275e8d3daab42d0cb90a2af1 100644
--- a/network/manager.go
+++ b/network/manager.go
@@ -87,6 +87,14 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard,
 }
 
 // StartRunners kicks off all network reception goroutines ("threads").
+// Started Threads are:
+//   - Network Follower (/network/follow.go)
+//   - Historical Round Retrieval (/network/rounds/historical.go)
+//	 - Message Retrieval Worker Group (/network/rounds/retrieve.go)
+//	 - Message Handling Worker Group (/network/message/handle.go)
+//	 - Health Tracker (/network/health)
+//	 - Garbled Messages (/network/message/garbled.go)
+//	 - Critical Messages (/network/message/critical.go)
 func (m *manager) Follow() (stoppable.Stoppable, error) {
 
 	if !atomic.CompareAndSwapUint32(m.running, 0, 1) {
@@ -96,8 +104,11 @@ func (m *manager) Follow() (stoppable.Stoppable, error) {
 	multi := stoppable.NewMulti("networkManager")
 
 	// health tracker
-	m.Health.Start()
-	multi.Add(m.Health)
+	healthStop, err := m.Health.Start()
+	if err != nil {
+		return nil, errors.Errorf("failed to follow")
+	}
+	multi.Add(healthStop)
 
 	// Node Updates
 	multi.Add(node.StartRegistration(m.Instance, m.Session, m.Rng,
diff --git a/network/message/critical.go b/network/message/critical.go
index 164dcf52d65749a86c3845c638b6faa1482b2ab0..238d94c90549ba1c3344f62debe2e819a6c275ba 100644
--- a/network/message/critical.go
+++ b/network/message/critical.go
@@ -10,6 +10,14 @@ import (
 	"time"
 )
 
+// Critical Messages are protocol layer communications that must succeed. These
+// are added to the persistent critical messages store.  This thread waits for
+// network access to move from unhealthy to healthy and the sends all critical
+// messages.
+// Health is tracked by registering with the Health
+// Tracker (/network/Health/Tracker.g0)
+
+//Thread loop for processing critical messages
 func (m *Manager) processCriticalMessages(quitCh <-chan struct{}) {
 	done := false
 	for !done {
@@ -24,6 +32,7 @@ func (m *Manager) processCriticalMessages(quitCh <-chan struct{}) {
 	}
 }
 
+// processes all critical messages
 func (m *Manager) criticalMessages() {
 	critMsgs := m.Session.GetCriticalMessages()
 	//try to send every message in the critical messages buffer in paralell
diff --git a/network/message/garbled.go b/network/message/garbled.go
index c4fe424b9ccda33a5e9b72c36bde9f86b509e136..169d0281c098513675635b7d60791cd0061e7fc8 100644
--- a/network/message/garbled.go
+++ b/network/message/garbled.go
@@ -5,6 +5,23 @@ import (
 	"time"
 )
 
+// Messages can arrive in the network out of order. When message handling fails
+// to decrypt a message, it is added to the garbled message buffer (which is
+// stored on disk) and the message decryption is retried here whenever triggered.
+
+// This can be triggered through the CheckGarbledMessages on the network manager
+// and is used in the /keyExchange package on successful rekey triggering
+
+// Triggers Garbled message checking if the queue is not full
+// Exposed on the network manager
+func (m *Manager) CheckGarbledMessages() {
+	select {
+	case m.triggerGarbled <- struct{}{}:
+	default:
+	}
+}
+
+//long running thread which processes garbled messages
 func (m *Manager) processGarbledMessages(quitCh <-chan struct{}) {
 	done := false
 	for !done {
@@ -17,6 +34,7 @@ func (m *Manager) processGarbledMessages(quitCh <-chan struct{}) {
 	}
 }
 
+//handler for a single run of garbled messages
 func (m *Manager) handleGarbledMessages() {
 	garbledMsgs := m.Session.GetGarbledMessages()
 	e2eKv := m.Session.E2e()
@@ -34,7 +52,8 @@ func (m *Manager) handleGarbledMessages() {
 				//remove from the buffer if decryption is successful
 				garbledMsgs.Remove(grbldMsg)
 				//handle the successfully decrypted message
-				xxMsg, ok := m.partitioner.HandlePartition(sender, message.E2E, msg.GetContents())
+				xxMsg, ok := m.partitioner.HandlePartition(sender, message.E2E,
+					msg.GetContents())
 				if ok {
 					m.Switchboard.Speak(xxMsg)
 					continue
@@ -42,8 +61,8 @@ func (m *Manager) handleGarbledMessages() {
 			}
 		}
 		// fail the message if any part of the decryption fails,
-		// unless it is our of attempts and has been in the buffer long enough,
-		// then remove it
+		// unless it is the last attempts and has been in the buffer long
+		// enough, in which case remove it
 		if count == m.param.MaxChecksGarbledMessage &&
 			time.Since(timestamp) > m.param.GarbledMessageWait {
 			garbledMsgs.Remove(grbldMsg)
diff --git a/network/message/reception.go b/network/message/handler.go
similarity index 93%
rename from network/message/reception.go
rename to network/message/handler.go
index 74b60b7d79aaba2f3a03a7ade4829baa715aca33..66eb7ad268a7791dfa8e1ef0f66d4413d64381eb 100644
--- a/network/message/reception.go
+++ b/network/message/handler.go
@@ -9,7 +9,7 @@ import (
 	"time"
 )
 
-func (m *Manager) processMessages(quitCh <-chan struct{}) {
+func (m *Manager) handleMessages(quitCh <-chan struct{}) {
 	done := false
 	for !done {
 		select {
@@ -17,7 +17,7 @@ func (m *Manager) processMessages(quitCh <-chan struct{}) {
 			done = true
 		case bundle := <-m.messageReception:
 			for _, msg := range bundle.Messages {
-				m.receiveMessage(msg)
+				m.handleMessage(msg)
 			}
 			bundle.Finish()
 		}
@@ -25,7 +25,7 @@ func (m *Manager) processMessages(quitCh <-chan struct{}) {
 
 }
 
-func (m *Manager) receiveMessage(ecrMsg format.Message) {
+func (m *Manager) handleMessage(ecrMsg format.Message) {
 	// We've done all the networking, now process the message
 	fingerprint := ecrMsg.GetKeyFP()
 
diff --git a/network/message/manager.go b/network/message/manager.go
index 3d95ef04099fe5bf997d601b0a9b4205c9385281..daa398a6cfe033f7ac0d6462306617e1d5b79e5f 100644
--- a/network/message/manager.go
+++ b/network/message/manager.go
@@ -41,22 +41,14 @@ func (m *Manager) GetMessageReceptionChannel() chan<- Bundle {
 	return m.messageReception
 }
 
-//Gets the channel to send received messages on
-func (m *Manager) CheckGarbledMessages() {
-	select {
-	case m.triggerGarbled <- struct{}{}:
-	default:
-	}
-}
-
 //Starts all worker pool
 func (m *Manager) StartProcessies() stoppable.Stoppable {
 	multi := stoppable.NewMulti("MessageReception")
 
-	//create the message reception workers
+	//create the message handler workers
 	for i := uint(0); i < m.param.MessageReceptionWorkerPoolSize; i++ {
 		stop := stoppable.NewSingle(fmt.Sprintf("MessageReception Worker %v", i))
-		go m.processMessages(stop.Quit())
+		go m.handleMessages(stop.Quit())
 		multi.Add(stop)
 	}
 
diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go
index 83e76e3cec2f0048e5fd1ed5144c29f18ad854ac..c60cab6aa257d7a11d6a01666d2f0c31c2b22f4a 100644
--- a/network/message/sendCmix.go
+++ b/network/message/sendCmix.go
@@ -13,8 +13,15 @@ import (
 	"time"
 )
 
-// Internal send e2e which bypasses the network check, for use in SendE2E and
-// SendUnsafe which do their own network checks
+// WARNING: Potentially Unsafe
+// Payloads send are not End to End encrypted, MetaData is NOT protected with
+// this call, see SendE2E for End to End encryption and full privacy protection
+// Internal SendCmix which bypasses the network check, will attempt to send to
+// the network without checking state. It has a built in retry system which can
+// be configured through the params object.
+// If the message is successfully sent, the id of the round sent it is returned,
+// which can be registered with the network instance to get a callback on
+// its status
 func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, error) {
 
 	timeStart := time.Now()
@@ -29,11 +36,14 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err
 
 		//find the best round to send to, excluding roudn which have been attempted
 		bestRound, _ := m.Instance.GetWaitingRounds().GetUpcomingRealtime(remainingTime, attempted)
-		topology, err := buildToplogy(bestRound.Topology)
+
+		//build the topology
+		idList, err := id.NewIDListFromBytes(bestRound.Topology)
 		if err == nil {
 			jww.ERROR.Printf("Failed to use topology for round %v: %s", bestRound.ID, err)
 			continue
 		}
+		topology := connect.NewCircuit(idList)
 
 		//get they keys for the round, reject if any nodes do not have
 		//keying relationships
@@ -101,22 +111,11 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err
 	return 0, errors.New("failed to send the message")
 }
 
-func buildToplogy(nodes [][]byte) (*connect.Circuit, error) {
-	idList := make([]*id.ID, len(nodes))
-	for i, n := range nodes {
-		nid, err := id.Unmarshal(n)
-		if err != nil {
-			return nil, errors.WithMessagef(err, "Failed to "+
-				"convert topology on node %v/%v {raw id: %v}", i, len(nodes), n)
-		}
-		idList[i] = nid
-	}
-	topology := connect.NewCircuit(idList)
-	return topology, nil
-
-}
-
-func handleMissingNodeKeys(instance *network.Instance, newNodeChan chan network.NodeGateway, nodes []*id.ID) {
+// Signals to the node registration thread to register a node if keys are
+// missing. Registration is triggered automatically when the node is first seen,
+// so this should on trigger on rare events.
+func handleMissingNodeKeys(instance *network.Instance,
+	newNodeChan chan network.NodeGateway, nodes []*id.ID) {
 	for _, n := range nodes {
 		ng, err := instance.GetNodeAndGateway(n)
 		if err != nil {
diff --git a/network/message/sendUnsafe.go b/network/message/sendUnsafe.go
index 2cabff6fcc194bffe01fc05648af666029d079f0..92c3fbbf29f9cff68aaf585c4eca268184733d60 100644
--- a/network/message/sendUnsafe.go
+++ b/network/message/sendUnsafe.go
@@ -11,6 +11,15 @@ import (
 	"time"
 )
 
+// WARNING: Unsafe
+// Payloads are not End to End encrypted, MetaData is NOT protected with
+// this call, see SendE2E for End to End encryption and full privacy protection
+// Internal SendUnsafe which bypasses the network check, will attempt to send to
+// the network without checking state.
+// This partitions payloads into multi-part messages but does NOT end to encrypt
+// them
+// Sends using SendCMIX and returns a list of rounds the messages are in. Will
+// return an error if a single part of the message fails to send.
 func (m *Manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, error) {
 
 	//timestamp the message
diff --git a/network/node/register_test.go b/network/node/register_test.go
index a005733131a134e68c600edd57e8eb8b3fa07f27..38c9ef1603f225f424e4d6ca1af2b6ade7c05ea6 100644
--- a/network/node/register_test.go
+++ b/network/node/register_test.go
@@ -1,19 +1,19 @@
 package node
 
 import (
-	"crypto/rand"
-	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/client/storage"
+	//"crypto/rand"
+	//"gitlab.com/elixxir/client/stoppable"
+	//"gitlab.com/elixxir/client/storage"
 	pb "gitlab.com/elixxir/comms/mixmessages"
-	"gitlab.com/elixxir/comms/network"
-	"gitlab.com/elixxir/crypto/csprng"
-	"gitlab.com/elixxir/crypto/fastRNG"
+	//"gitlab.com/elixxir/comms/network"
+	//"gitlab.com/elixxir/crypto/csprng"
+	//"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/comms/connect"
-	"gitlab.com/xx_network/crypto/signature/rsa"
+	//"gitlab.com/xx_network/crypto/signature/rsa"
 	"gitlab.com/xx_network/primitives/id"
-	"gitlab.com/xx_network/primitives/ndf"
-	"testing"
-	"time"
+	//"gitlab.com/xx_network/primitives/ndf"
+	//"testing"
+	//"time"
 )
 
 // Mock client comms object
@@ -52,64 +52,65 @@ func (mcc *MockClientComms) SendConfirmNonceMessage(host *connect.Host,
 	}, nil
 }
 
-func TestRegisterNodes(t *testing.T) {
-	privKey, err := rsa.LoadPrivateKeyFromPem([]byte("-----BEGIN PRIVATE KEY-----\nMIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC7Dkb6VXFn4cdp\nU0xh6ji0nTDQUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZr\ntzujFPBRFp9O14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfI\nTVCv8CLE0t1ibiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGes\nkWEFa2VttHqF910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq\n6/OAXCU1JLi3kW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzf\nrarmsGM0LZh6JY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYI\nCqldpt79gaET9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8V\nMKbrCaOkzD5zgnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4S\no9AppDQB41SH3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenP\nel2ApMXp+LVRdDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/u\nSALsU2v9UHBzprdrLSZk2YpozJb+CQIDAQABAoICAARjDFUYpeU6zVNyCauOM7BA\ns4FfQdHReg+zApTfWHosDQ04NIc9CGbM6e5E9IFlb3byORzyevkllf5WuMZVWmF8\nd1YBBeTftKYBn2Gwa42Ql9dl3eD0wQ1gUWBBeEoOVZQ0qskr9ynpr0o6TfciWZ5m\nF50UWmUmvc4ppDKhoNwogNU/pKEwwF3xOv2CW2hB8jyLQnk3gBZlELViX3UiFKni\n/rCfoYYvDFXt+ABCvx/qFNAsQUmerurQ3Ob9igjXRaC34D7F9xQ3CMEesYJEJvc9\nGjvr5DbnKnjx152HS56TKhK8gp6vGHJz17xtWECXD3dIUS/1iG8bqXuhdg2c+2aW\nm3MFpa5jgpAawUWc7c32UnqbKKf+HI7/x8J1yqJyNeU5SySyYSB5qtwTShYzlBW/\nyCYD41edeJcmIp693nUcXzU+UAdtpt0hkXS59WSWlTrB/huWXy6kYXLNocNk9L7g\niyx0cOmkuxREMHAvK0fovXdVyflQtJYC7OjJxkzj2rWO+QtHaOySXUyinkuTb5ev\nxNhs+ROWI/HAIE9buMqXQIpHx6MSgdKOL6P6AEbBan4RAktkYA6y5EtH/7x+9V5E\nQTIz4LrtI6abaKb4GUlZkEsc8pxrkNwCqOAE/aqEMNh91Na1TOj3f0/a6ckGYxYH\npyrvwfP2Ouu6e5FhDcCBAoIBAQDcN8mK99jtrH3q3Q8vZAWFXHsOrVvnJXyHLz9V\n1Rx/7TnMUxvDX1PIVxhuJ/tmHtxrNIXOlps80FCZXGgxfET/YFrbf4H/BaMNJZNP\nag1wBV5VQSnTPdTR+Ijice+/ak37S2NKHt8+ut6yoZjD7sf28qiO8bzNua/OYHkk\nV+RkRkk68Uk2tFMluQOSyEjdsrDNGbESvT+R1Eotupr0Vy/9JRY/TFMc4MwJwOoy\ns7wYr9SUCq/cYn7FIOBTI+PRaTx1WtpfkaErDc5O+nLLEp1yOrfktl4LhU/r61i7\nfdtafUACTKrXG2qxTd3w++mHwTwVl2MwhiMZfxvKDkx0L2gxAoIBAQDZcxKwyZOy\ns6Aw7igw1ftLny/dpjPaG0p6myaNpeJISjTOU7HKwLXmlTGLKAbeRFJpOHTTs63y\ngcmcuE+vGCpdBHQkaCev8cve1urpJRcxurura6+bYaENO6ua5VzF9BQlDYve0YwY\nlbJiRKmEWEAyULjbIebZW41Z4UqVG3MQI750PRWPW4WJ2kDhksFXN1gwSnaM46KR\nPmVA0SL+RCPcAp/VkImCv0eqv9exsglY0K/QiJfLy3zZ8QvAn0wYgZ3AvH3lr9rJ\nT7pg9WDb+OkfeEQ7INubqSthhaqCLd4zwbMRlpyvg1cMSq0zRvrFpwVlSY85lW4F\ng/tgjJ99W9VZAoIBAH3OYRVDAmrFYCoMn+AzA/RsIOEBqL8kaz/Pfh9K4D01CQ/x\naqryiqqpFwvXS4fLmaClIMwkvgq/90ulvuCGXeSG52D+NwW58qxQCxgTPhoA9yM9\nVueXKz3I/mpfLNftox8sskxl1qO/nfnu15cXkqVBe4ouD+53ZjhAZPSeQZwHi05h\nCbJ20gl66M+yG+6LZvXE96P8+ZQV80qskFmGdaPozAzdTZ3xzp7D1wegJpTz3j20\n3ULKAiIb5guZNU0tEZz5ikeOqsQt3u6/pVTeDZR0dxnyFUf/oOjmSorSG75WT3sA\n0ZiR0SH5mhFR2Nf1TJ4JHmFaQDMQqo+EG6lEbAECggEAA7kGnuQ0lSCiI3RQV9Wy\nAa9uAFtyE8/XzJWPaWlnoFk04jtoldIKyzHOsVU0GOYOiyKeTWmMFtTGANre8l51\nizYiTuVBmK+JD/2Z8/fgl8dcoyiqzvwy56kX3QUEO5dcKO48cMohneIiNbB7PnrM\nTpA3OfkwnJQGrX0/66GWrLYP8qmBDv1AIgYMilAa40VdSyZbNTpIdDgfP6bU9Ily\nG7gnyF47HHPt5Cx4ouArbMvV1rof7ytCrfCEhP21Lc46Ryxy81W5ZyzoQfSxfdKb\nGyDR+jkryVRyG69QJf5nCXfNewWbFR4ohVtZ78DNVkjvvLYvr4qxYYLK8PI3YMwL\nsQKCAQB9lo7JadzKVio+C18EfNikOzoriQOaIYowNaaGDw3/9KwIhRsKgoTs+K5O\ngt/gUoPRGd3M2z4hn5j4wgeuFi7HC1MdMWwvgat93h7R1YxiyaOoCTxH1klbB/3K\n4fskdQRxuM8McUebebrp0qT5E0xs2l+ABmt30Dtd3iRrQ5BBjnRc4V//sQiwS1aC\nYi5eNYCQ96BSAEo1dxJh5RI/QxF2HEPUuoPM8iXrIJhyg9TEEpbrEJcxeagWk02y\nOMEoUbWbX07OzFVvu+aJaN/GlgiogMQhb6IiNTyMlryFUleF+9OBA8xGHqGWA6nR\nOaRA5ZbdE7g7vxKRV36jT3wvD7W+\n-----END PRIVATE KEY-----\n"))
-	if err != nil || privKey == nil {
-		t.Error("Failed to load privKey\n")
-	}
-	pub := "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n"
+// func TestRegisterNodes(t *testing.T) {
+// 	privKey, err := rsa.LoadPrivateKeyFromPem([]byte("-----BEGIN PRIVATE KEY-----\n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\nOaRA5ZbdE7g7vxKRV36jT3wvD7W+\n-----END PRIVATE KEY-----\n"))
+// 	if err != nil || privKey == nil {
+// 		t.Error("Failed to load privKey\n")
+// 	}
+// 	pub := "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n"
 
-	salt := make([]byte, 32)
-	_, err = rand.Read(salt)
-	if err != nil {
-		t.Errorf("Failed to generate salt: %+v", err)
-	}
-	//uid := id.NewIdFromString("zezima", id.User, t)
-	comms := NewMockClientComms()
+// 	salt := make([]byte, 32)
+// 	_, err = rand.Read(salt)
+// 	if err != nil {
+// 		t.Errorf("Failed to generate salt: %+v", err)
+// 	}
+// 	//uid := id.NewIdFromString("zezima", id.User, t)
+// 	comms := NewMockClientComms()
 
-	instanceComms := &connect.ProtoComms{}
-	_, err = instanceComms.AddHost(&id.Permissioning, "0.0.0.0:420", []byte(pub), false, false)
-	if err != nil {
-		t.Errorf("Faield to add perm host: %+v", err)
-	}
+// 	instanceComms := &connect.ProtoComms{}
+// 	_, err = instanceComms.AddHost(&id.Permissioning, "0.0.0.0:420", []byte(pub),
+// 		connect.GetDefaultHostParams())
+// 	if err != nil {
+// 		t.Errorf("Faield to add perm host: %+v", err)
+// 	}
 
-	sess := storage.InitTestingSession(t)
+// 	sess := storage.InitTestingSession(t)
 
-	rng := fastRNG.NewStreamGenerator(7, 3, csprng.NewSystemRNG)
+// 	rng := fastRNG.NewStreamGenerator(7, 3, csprng.NewSystemRNG)
 
-	stop := stoppable.NewSingle("test")
-	c := make(chan network.NodeGateway, 100)
-	go registerNodes(sess, rng, comms, stop, c)
+// 	stop := stoppable.NewSingle("test")
+// 	c := make(chan network.NodeGateway, 100)
+// 	go registerNodes(sess, rng, comms, stop, c)
 
-	c <- network.NodeGateway{
-		Node: ndf.Node{
-			ID:             id.NewIdFromString("zezima", id.Node, t).Bytes(),
-			Address:        "0.0.0.0:420",
-			TlsCertificate: pub,
-		},
-		Gateway: ndf.Gateway{
-			ID:             id.NewIdFromString("zezima", id.Gateway, t).Bytes(),
-			Address:        "0.0.0.0:421",
-			TlsCertificate: pub,
-		},
-	}
+// 	c <- network.NodeGateway{
+// 		Node: ndf.Node{
+// 			ID:             id.NewIdFromString("zezima", id.Node, t).Bytes(),
+// 			Address:        "0.0.0.0:420",
+// 			TlsCertificate: pub,
+// 		},
+// 		Gateway: ndf.Gateway{
+// 			ID:             id.NewIdFromString("zezima", id.Gateway, t).Bytes(),
+// 			Address:        "0.0.0.0:421",
+// 			TlsCertificate: pub,
+// 		},
+// 	}
 
-	timeout := time.NewTimer(time.Second * 5)
-	select {
-	case <-timeout.C:
-		t.Errorf("Timed out waiting for request nonce channel signal")
-	case <-comms.request:
-	}
+// 	timeout := time.NewTimer(time.Second * 5)
+// 	select {
+// 	case <-timeout.C:
+// 		t.Errorf("Timed out waiting for request nonce channel signal")
+// 	case <-comms.request:
+// 	}
 
-	timeout.Reset(5 * time.Second)
-	select {
-	case <-timeout.C:
-		t.Errorf("Timed out waiting for confirm nonce channel signal")
-	case <-comms.confirm:
-	}
+// 	timeout.Reset(5 * time.Second)
+// 	select {
+// 	case <-timeout.C:
+// 		t.Errorf("Timed out waiting for confirm nonce channel signal")
+// 	case <-comms.confirm:
+// 	}
 
-	err = stop.Close(5 * time.Second)
-	if err != nil {
-		t.Errorf("Failed to stop registration thread: %+v", err)
-	}
-}
\ No newline at end of file
+// 	err = stop.Close(5 * time.Second)
+// 	if err != nil {
+// 		t.Errorf("Failed to stop registration thread: %+v", err)
+// 	}
+// }
diff --git a/network/rounds/check.go b/network/rounds/check.go
index 5ac70543d0f9221742818e89764736c0a27cc1e0..74d8f0b3361fd4a569f7d347d23be856467e3b76 100644
--- a/network/rounds/check.go
+++ b/network/rounds/check.go
@@ -1,40 +1,47 @@
 package rounds
 
 import (
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/xx_network/primitives/id"
 )
 
-// getRoundChecker passes a context and the round infos received by the
-// gateway to the funky round checker api to update round state.
-// The returned function passes round event objects over the context
-// to the rest of the message handlers for getting messages.
+// the round checker is a single use function which is meant to be wrapped
+// and adhere to the knownRounds checker interface. it receives a round ID and
+// looks up the state of that round to determine if the client has a message
+// waiting in it.
+// It will return true if it can conclusively determine no message exists,
+// returning false and set the round to processing if it needs further
+// investigation.
+// Once it determines messages might be waiting in a round, it determines
+// if the information about that round is already present, if it is the data is
+// sent to Message Retrieval Workers, otherwise it is sent to Historical Round
+// Retrieval
 func (m *Manager) Checker(roundID id.Round) bool {
 	// Set round to processing, if we can
 	processing, count := m.p.Process(roundID)
 	if !processing {
+		// if is already processing, ignore
 		return false
 	}
+
+	//if the number of times the round has been checked has hit the max, drop it
 	if count == m.params.MaxAttemptsCheckingARound {
+		jww.ERROR.Printf("Round %v failed the maximum number of times "+
+			"(%v), stopping retrval attempt", roundID,
+			m.params.MaxAttemptsCheckingARound)
 		m.p.Done(roundID)
 		return true
 	}
-	// FIXME: Spec has us SETTING processing, but not REMOVING it
-	// until the get messages thread completes the lookup, this
-	// is smell that needs refining. It seems as if there should be
-	// a state that lives with the round info as soon as we know
-	// about it that gets updated at different parts...not clear
-	// needs to be thought through.
-	//defer processing.Done(roundID)
 
 	// TODO: Bloom filter lookup -- return true when we don't have
-	// Go get the round from the round infos, if it exists
 
+	// Go get the round from the round infos, if it exists
 	ri, err := m.Instance.GetRound(roundID)
 	if err != nil {
-		// If we didn't find it, send to historical
-		// rounds processor
+		// If we didn't find it, send to Historical Rounds Retrieval
 		m.historicalRounds <- roundID
 	} else {
+		// IF found, send to Message Retrieval Workers
 		m.lookupRoundMessages <- ri
 	}
 
diff --git a/network/rounds/historical.go b/network/rounds/historical.go
index c1a488555f44a825609c8670e12081e75f851042..d582ba20476126567c7cb656089031668ed806ef 100644
--- a/network/rounds/historical.go
+++ b/network/rounds/historical.go
@@ -15,17 +15,27 @@ import (
 	"time"
 )
 
+// Historical Rounds looks up the round history via random gateways.
+// It batches these quests but never waits longer than
+// params.HistoricalRoundsPeriod to do a lookup.
+// Historical rounds receives input from:
+//   - Network Follower (/network/follow.go)
+// Historical Rounds sends the output to:
+//	 - Message Retrieval Workers (/network/round/retrieve.go)
+
+//interface to increase east of testing of historical rounds
 type historicalRoundsComms interface {
 	GetHost(hostId *id.ID) (*connect.Host, bool)
 	RequestHistoricalRounds(host *connect.Host,
 		message *pb.HistoricalRounds) (*pb.HistoricalRoundsResponse, error)
 }
 
-// ProcessHistoricalRounds analyzes round history to see if this Client
-// needs to check for messages at any of the gateways which completed
-// those rounds.
+// Long running thread which process historical rounds
+// Can be killed by sending a signal to the quit channel
+// takes a comms interface to aid in testing
 func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-chan struct{}) {
-	ticker := time.NewTicker(m.params.HistoricalRoundsPeriod)
+
+	timerCh := make(<-chan time.Time)
 
 	rng := m.Rng.GetStream()
 	var rounds []uint64
@@ -33,30 +43,48 @@ func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-c
 	done := false
 	for !done {
 		shouldProcess := false
+		// wait for a quit or new round to check
 		select {
 		case <-quitCh:
 			rng.Close()
+			// return all rounds in the queue to the input channel so they can
+			// be checked in the future. If the queue is full, disable them as
+			// processing so they are picked up from the beginning
+			for _, rid := range rounds {
+				select {
+				case m.historicalRounds <- id.Round(rid):
+				default:
+					m.p.NotProcessing(id.Round(rid))
+				}
+			}
 			done = true
-		case <-ticker.C:
+		// if the timer elapses process rounds to ensure the delay isn't too long
+		case <-timerCh:
 			if len(rounds) > 0 {
 				shouldProcess = true
 			}
+		// get new round to lookup and force a lookup if
 		case rid := <-m.historicalRounds:
 			rounds = append(rounds, uint64(rid))
 			if len(rounds) > int(m.params.MaxHistoricalRounds) {
 				shouldProcess = true
+			} else if len(rounds) == 1 {
+				//if this is the first round, start the timeout
+				timerCh = time.NewTimer(m.params.HistoricalRoundsPeriod).C
 			}
 		}
 		if !shouldProcess {
 			continue
 		}
 
+		//find a gateway to request about the rounds
 		gwHost, err := gateway.Get(m.Instance.GetPartialNdf().Get(), comm, rng)
 		if err != nil {
 			jww.FATAL.Panicf("Failed to track network, NDF has corrupt "+
 				"data: %s", err)
 		}
 
+		//send the historical rounds request
 		hr := &pb.HistoricalRounds{
 			Rounds: rounds,
 		}
@@ -65,17 +93,25 @@ func (m *Manager) processHistoricalRounds(comm historicalRoundsComms, quitCh <-c
 		if err != nil {
 			jww.ERROR.Printf("Failed to request historical rounds "+
 				"data: %s", response)
-			// if the check fails to resolve, break the loop so they will be
+			// if the check fails to resolve, break the loop and so they will be
 			// checked again
-			break
+			timerCh = time.NewTimer(m.params.HistoricalRoundsPeriod).C
+			continue
 		}
+
+		// process the returned historical rounds.
 		for i, roundInfo := range response.Rounds {
+			// The interface has missing returns returned as nil, such rounds
+			// need be be removes as processing so the network follower will
+			// pick them up in the future.
 			if roundInfo == nil {
 				jww.ERROR.Printf("could not retreive "+
 					"historical round %d", rounds[i])
+				m.p.Fail(id.Round(rounds[i]))
 				continue
 			}
-			m.p.Done(id.Round(rounds[i]))
+			// Successfully retrieved rounds are sent to the Message
+			// Retrieval Workers
 			m.lookupRoundMessages <- roundInfo
 		}
 	}
diff --git a/network/rounds/processingRounds.go b/network/rounds/processingRounds.go
index 5a9442ba16cd80fc842d600f9c95475fdb6f6364..585a7656c692cdf8e21719ffd30c4960c7cb3ebf 100644
--- a/network/rounds/processingRounds.go
+++ b/network/rounds/processingRounds.go
@@ -8,7 +8,7 @@ import (
 )
 
 type status struct {
-	count      uint
+	failCount  uint
 	processing bool
 }
 
@@ -34,16 +34,15 @@ func (pr *processing) Process(id id.Round) (bool, uint) {
 
 	if rs, ok := pr.rounds[id]; ok {
 		if rs.processing {
-			return false, rs.count
+			return false, rs.failCount
 		}
-		rs.count++
 		rs.processing = true
 
-		return true, rs.count
+		return true, rs.failCount
 	}
 
 	pr.rounds[id] = &status{
-		count:      0,
+		failCount:  0,
 		processing: true,
 	}
 
@@ -62,12 +61,14 @@ func (pr *processing) IsProcessing(id id.Round) bool {
 	return false
 }
 
-// Fail sets a round's processing status to failed so that it can be retried.
+// Fail sets a round's processing status to failed and increments its fail
+// counter so that it can be retried.
 func (pr *processing) Fail(id id.Round) {
 	pr.Lock()
 	defer pr.Unlock()
 	if rs, ok := pr.rounds[id]; ok {
 		rs.processing = false
+		rs.failCount++
 	}
 }
 
@@ -77,3 +78,13 @@ func (pr *processing) Done(id id.Round) {
 	defer pr.Unlock()
 	delete(pr.rounds, id)
 }
+
+// NotProcessing sets a round's processing status to failed so that it can be
+// retried but does not increment its fail counter.
+func (pr *processing) NotProcessing(id id.Round) {
+	pr.Lock()
+	defer pr.Unlock()
+	if rs, ok := pr.rounds[id]; ok {
+		rs.processing = false
+	}
+}
\ No newline at end of file
diff --git a/network/rounds/processingRounds_test.go b/network/rounds/processingRounds_test.go
index e57fe05e4d9ba437b5b21af052c92dd719e8bfcf..8b61ad6d76a050134a03246df47c6e7996af4ed8 100644
--- a/network/rounds/processingRounds_test.go
+++ b/network/rounds/processingRounds_test.go
@@ -33,10 +33,10 @@ func TestProcessing_Process(t *testing.T) {
 	}{
 		{10, true, true, 0},
 		{10, true, false, 0},
-		{10, false, true, 1},
+		{10, false, true, 0},
 		{100, true, true, 0},
 		{100, true, false, 0},
-		{100, false, true, 1},
+		{100, false, true, 0},
 	}
 
 	for i, d := range testData {
@@ -86,6 +86,9 @@ func TestProcessing_Fail(t *testing.T) {
 	if pr.rounds[rid].processing {
 		t.Errorf("Fail() did not mark processing as false for round id %d.", rid)
 	}
+	if pr.rounds[rid].failCount != 1 {
+		t.Errorf("Fail() did not increment the fail count of round id %d.", rid)
+	}
 }
 
 // Tests happy path of Done.
diff --git a/network/rounds/retrieve.go b/network/rounds/retrieve.go
index b6b45e7a35383e9f3dabe116733c77de12887db4..7378332ad289aa21ef45a0e2844b29428ea06235 100644
--- a/network/rounds/retrieve.go
+++ b/network/rounds/retrieve.go
@@ -1,7 +1,6 @@
 package rounds
 
 import (
-	"encoding/binary"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/network/gateway"
@@ -40,12 +39,6 @@ func (m *Manager) processMessageRetrieval(comms messageRetrievalComms,
 	}
 }
 
-// TODO: remove me when api fixed
-func uint64ToBytes(i uint64) []byte {
-	bs := make([]byte, 8)
-	binary.LittleEndian.PutUint64(bs, 31415926)
-	return bs
-}
 
 func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo,
 	comms messageRetrievalComms) (message.Bundle, error) {
@@ -62,8 +55,7 @@ func (m *Manager) getMessagesFromGateway(roundInfo *pb.RoundInfo,
 	// send the request
 	msgReq := &pb.GetMessages{
 		ClientID: m.Uid.Marshal(),
-		//TODO: fix this, should not be a byte slice
-		RoundID: uint64ToBytes(uint64(rid)),
+		RoundID:  uint64(rid),
 	}
 	msgResp, err := comms.RequestMessages(gwHost, msgReq)
 	// Fail the round if an error occurs so it can be tried again later
diff --git a/network/send.go b/network/send.go
index 7e6aeb84e73ca0a30a1ff660aee3855dea4196a8..904776c9dceca9af15e6814ce16ccd0162e66382 100644
--- a/network/send.go
+++ b/network/send.go
@@ -14,7 +14,7 @@ import (
 // Returns the round ID of the round the payload was sent or an error
 // if it fails.
 func (m *manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, error) {
-	if !m.Health.IsRunning() {
+	if !m.Health.IsHealthy() {
 		return 0, errors.New("Cannot send cmix message when the " +
 			"network is not healthy")
 	}
@@ -28,7 +28,7 @@ func (m *manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err
 // NOTE: Do not use this function unless you know what you are doing.
 // This function always produces an error message in client logging.
 func (m *manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, error) {
-	if !m.Health.IsRunning() {
+	if !m.Health.IsHealthy() {
 		return nil, errors.New("cannot send unsafe message when the " +
 			"network is not healthy")
 	}
@@ -46,7 +46,7 @@ func (m *manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round,
 func (m *manager) SendE2E(msg message.Send, e2eP params.E2E) (
 	[]id.Round, error) {
 
-	if !m.Health.IsRunning() {
+	if !m.Health.IsHealthy() {
 		return nil, errors.New("Cannot send e2e message when the " +
 			"network is not healthy")
 	}
diff --git a/permissioning/permissioning.go b/permissioning/permissioning.go
index 7ebb8ac90691fe57d8d089f086554fc586b38d70..3d28dca1b7da5cd75548b463e52f6e8127fe0b03 100644
--- a/permissioning/permissioning.go
+++ b/permissioning/permissioning.go
@@ -23,8 +23,8 @@ func Init(comms *client.Comms, def *ndf.NetworkDefinition) (*Permissioning, erro
 	var err error
 	//add the permissioning host to comms
 	perm.host, err = comms.AddHost(&id.Permissioning, def.Registration.Address,
-		[]byte(def.Registration.TlsCertificate), false,
-		false)
+		[]byte(def.Registration.TlsCertificate),
+		connect.GetDefaultHostParams())
 
 	if err != nil {
 		return nil, errors.WithMessage(err, "failed to create permissioning")
diff --git a/permissioning/register_test.go b/permissioning/register_test.go
index bdf96a3bc0a30da7f6e42b9e01982a9b2bd2bc97..3ef1040e3fc186bd4e5f800fadb1d848a6ae1488 100644
--- a/permissioning/register_test.go
+++ b/permissioning/register_test.go
@@ -50,7 +50,8 @@ func TestRegisterWithPermissioning(t *testing.T) {
 
 	var sender MockRegistrationSender
 	sender.succeedGetHost = true
-	sender.getHost, err = connect.NewHost(&id.Permissioning, "address", nil, false, false)
+	sender.getHost, err = connect.NewHost(&id.Permissioning, "address", nil,
+		connect.GetDefaultHostParams())
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/stoppable/cleanup.go b/stoppable/cleanup.go
index ffe3cdae60b6c14ca081e18dce3aa0a44b21380d..a733d74bc175d09403d2a681c8108b528a31d9f2 100644
--- a/stoppable/cleanup.go
+++ b/stoppable/cleanup.go
@@ -37,7 +37,7 @@ func (c *Cleanup) IsRunning() bool {
 
 // Name returns the name of the stoppable denoting it has cleanup.
 func (c *Cleanup) Name() string {
-	return Name() + " with cleanup"
+	return c.stop.Name() + " with cleanup"
 }
 
 // Close stops the contained stoppable and runs the cleanup function after. The
@@ -51,9 +51,9 @@ func (c *Cleanup) Close(timeout time.Duration) error {
 			start := time.Now()
 
 			// Run the stoppable
-			if err := Close(timeout); err != nil {
+			if err := c.stop.Close(timeout); err != nil {
 				err = errors.WithMessagef(err, "Cleanup for %s not executed",
-					Name())
+					c.stop.Name())
 				return
 			}
 
@@ -71,10 +71,10 @@ func (c *Cleanup) Close(timeout time.Duration) error {
 			case err := <-complete:
 				if err != nil {
 					err = errors.WithMessagef(err, "Cleanup for %s failed",
-						Name())
+						c.stop.Name())
 				}
 			case <-timer.C:
-				err = errors.Errorf("Clean up for %s timeout", Name())
+				err = errors.Errorf("Clean up for %s timeout", c.stop.Name())
 			}
 		})
 
diff --git a/stoppable/multi.go b/stoppable/multi.go
index a0f947d02d7a81d359435c8a53597a7bbf3fd714..061be492dd4efd2d6c618d7f9772a18fb8cc7ab7 100644
--- a/stoppable/multi.go
+++ b/stoppable/multi.go
@@ -43,7 +43,7 @@ func (m *Multi) Name() string {
 	m.mux.RLock()
 	names := m.name + ": {"
 	for _, s := range m.stoppables {
-		names += Name() + ", "
+		names += s.Name() + ", "
 	}
 	if len(m.stoppables) > 0 {
 		names = names[:len(names)-2]
@@ -69,7 +69,7 @@ func (m *Multi) Close(timeout time.Duration) error {
 			for _, stoppable := range m.stoppables {
 				wg.Add(1)
 				go func(stoppable Stoppable) {
-					if Close(timeout) != nil {
+					if stoppable.Close(timeout) != nil {
 						atomic.AddUint32(&numErrors, 1)
 					}
 					wg.Done()
diff --git a/storage/cmix/store_test.go b/storage/cmix/store_test.go
index df305ebb3dd092b03a0e74ae01661a135a9faf3b..1605abe94784920bc319dbb79641571b85c6d332 100644
--- a/storage/cmix/store_test.go
+++ b/storage/cmix/store_test.go
@@ -14,34 +14,13 @@ import (
 	"gitlab.com/elixxir/ekv"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/primitives/id"
-	"os"
 	"testing"
 )
 
-// Most of these tests use the same Store
-// So keep that in mind when designing tests
-var testStore *Store
-
-// Main testing function
-func TestMain(m *testing.M) {
-
-	kv := make(ekv.Memstore)
-	vkv := versioned.NewKV(kv)
-
-	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
-	priv := grp.NewInt(2)
-
-	testStore, _ = NewStore(grp, vkv, priv)
-
-	runFunc := func() int {
-		return m.Run()
-	}
-
-	os.Exit(runFunc())
-}
-
 // Happy path Add/Done test
 func TestStore_AddRemove(t *testing.T) {
+	testStore, _ := makeTestStore()
+
 	nodeId := id.NewIdFromString("test", id.Node, t)
 	key := testStore.grp.NewInt(5)
 
@@ -60,13 +39,16 @@ func TestStore_AddRemove(t *testing.T) {
 
 // Happy path
 func TestLoadStore(t *testing.T) {
+	testStore, kv := makeTestStore()
+
 	// Add a test node key
 	nodeId := id.NewIdFromString("test", id.Node, t)
 	key := testStore.grp.NewInt(5)
+
 	testStore.Add(nodeId, key)
 
 	// Load the store and check its attributes
-	store, err := LoadStore(testStore.kv)
+	store, err := LoadStore(kv)
 	if err != nil {
 		t.Errorf("Unable to load store: %+v", err)
 	}
@@ -83,6 +65,7 @@ func TestLoadStore(t *testing.T) {
 
 // Happy path
 func TestStore_GetRoundKeys(t *testing.T) {
+	testStore, _ := makeTestStore()
 	// Set up the circuit
 	numIds := 10
 	nodeIds := make([]*id.ID, numIds)
@@ -107,6 +90,7 @@ func TestStore_GetRoundKeys(t *testing.T) {
 
 // Missing keys path
 func TestStore_GetRoundKeys_Missing(t *testing.T) {
+	testStore, _ := makeTestStore()
 	// Set up the circuit
 	numIds := 10
 	nodeIds := make([]*id.ID, numIds)
@@ -165,3 +149,17 @@ func TestNewStore(t *testing.T) {
 		t.Errorf("Failed to set store.kv")
 	}
 }
+
+// Main testing function
+func makeTestStore() (*Store, *versioned.KV) {
+
+	kv := make(ekv.Memstore)
+	vkv := versioned.NewKV(kv)
+
+	grp := cyclic.NewGroup(large.NewInt(173), large.NewInt(2))
+	priv := grp.NewInt(2)
+
+	testStore, _ := NewStore(grp, vkv, priv)
+
+	return testStore, vkv
+}
\ No newline at end of file
diff --git a/storage/regCode.go b/storage/regCode.go
index c2d7c2fadf5b5556b75d6569294735e9917a833f..acc03a36051e824e40f693ab96837debe1d129fe 100644
--- a/storage/regCode.go
+++ b/storage/regCode.go
@@ -1,10 +1,10 @@
 package storage
 
 import (
-	"gitlab.com/elixxir/client/storage/versioned"
 	"github.com/pkg/errors"
-	"time"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"time"
 )
 
 const regCodeKey = "regCode"
diff --git a/switchboard/switchboard_test.go b/switchboard/switchboard_test.go
index 27a7635c2ad301099a854a1945fd6d2bf54761b0..5c097cdfa05a2686fd571258c290765d62cc8741 100644
--- a/switchboard/switchboard_test.go
+++ b/switchboard/switchboard_test.go
@@ -155,7 +155,7 @@ func TestSwitchboard_RegisterFunc(t *testing.T) {
 		t.Errorf("Listener is not registered by Message Type")
 	}
 
-	Hear(message.Receive{})
+	lid.listener.Hear(message.Receive{})
 	if !heard {
 		t.Errorf("Func listener not registered correctly")
 	}
@@ -224,7 +224,7 @@ func TestSwitchboard_RegisterChan(t *testing.T) {
 		t.Errorf("Listener is not registered by Message Type")
 	}
 
-	Hear(message.Receive{})
+	lid.listener.Hear(message.Receive{})
 	select {
 	case <-ch:
 	case <-time.After(5 * time.Millisecond):