Exemplo n.º 1
0
func NetStart(s *state.State) {
	enablenetPtr := flag.Bool("enablenet", true, "Enable or disable networking")
	listenToPtr := flag.Int("node", 0, "Node Number the simulator will set as the focus")
	cntPtr := flag.Int("count", 1, "The number of nodes to generate")
	netPtr := flag.String("net", "tree", "The default algorithm to build the network connections")
	fnetPtr := flag.String("fnet", "", "Read the given file to build the network connections")
	dropPtr := flag.Int("drop", 0, "Number of messages to drop out of every thousand")
	journalPtr := flag.String("journal", "", "Rerun a Journal of messages")
	journalingPtr := flag.Bool("journaling", false, "Write a journal of all messages recieved. Default is off.")
	followerPtr := flag.Bool("follower", false, "If true, force node to be a follower.  Only used when replaying a journal.")
	leaderPtr := flag.Bool("leader", true, "If true, force node to be a leader.  Only used when replaying a journal.")
	dbPtr := flag.String("db", "", "Override the Database in the Config file and use this Database implementation")
	cloneDBPtr := flag.String("clonedb", "", "Override the main node and use this database for the clones in a Network.")
	portOverridePtr := flag.Int("port", 0, "Address to serve WSAPI on")
	networkNamePtr := flag.String("network", "", "Network to join: MAIN, TEST or LOCAL")
	networkPortOverridePtr := flag.Int("networkPort", 0, "Address for p2p network to listen on.")
	peersPtr := flag.String("peers", "", "Array of peer addresses. ")
	blkTimePtr := flag.Int("blktime", 0, "Seconds per block.  Production is 600.")
	runtimeLogPtr := flag.Bool("runtimeLog", false, "If true, maintain runtime logs of messages passed.")
	netdebugPtr := flag.Int("netdebug", 0, "0-5: 0 = quiet, >0 = increasing levels of logging")
	exclusivePtr := flag.Bool("exclusive", false, "If true, we only dial out to special/trusted peers.")
	prefixNodePtr := flag.String("prefix", "", "Prefix the Factom Node Names with this value; used to create leaderless networks.")
	rotatePtr := flag.Bool("rotate", false, "If true, responsiblity is owned by one leader, and rotated over the leaders.")
	timeOffsetPtr := flag.Int("timedelta", 0, "Maximum timeDelta in milliseconds to offset each node.  Simulates deltas in system clocks over a network.")
	keepMismatchPtr := flag.Bool("keepmismatch", false, "If true, do not discard DBStates even when a majority of DBSignatures have a different hash")
	startDelayPtr := flag.Int("startdelay", 10, "Delay to start processing messages, in seconds")
	deadlinePtr := flag.Int("deadline", 1000, "Timeout Delay in milliseconds used on Reads and Writes to the network comm")
	customNetPtr := flag.String("customnet", "", "This string specifies a custom blockchain network ID.")
	rpcUserflag := flag.String("rpcuser", "", "Username to protect factomd local API with simple HTTP authentication")
	rpcPasswordflag := flag.String("rpcpass", "", "Password to protect factomd local API. Ignored if rpcuser is blank")
	factomdTLSflag := flag.Bool("tls", false, "Set to true to require encrypted connections to factomd API and Control Panel") //to get tls, run as "factomd -tls=true"
	factomdLocationsflag := flag.String("selfaddr", "", "comma seperated IPAddresses and DNS names of this factomd to use when creating a cert file")

	flag.Parse()

	enableNet := *enablenetPtr
	listenTo := *listenToPtr
	cnt := *cntPtr
	net := *netPtr
	fnet := *fnetPtr
	droprate := *dropPtr
	journal := *journalPtr
	journaling := *journalingPtr
	follower := *followerPtr
	leader := *leaderPtr
	db := *dbPtr
	cloneDB := *cloneDBPtr
	portOverride := *portOverridePtr
	peers := *peersPtr
	networkName := *networkNamePtr
	networkPortOverride := *networkPortOverridePtr
	blkTime := *blkTimePtr
	runtimeLog := *runtimeLogPtr
	netdebug := *netdebugPtr
	exclusive := *exclusivePtr
	prefix := *prefixNodePtr
	rotate := *rotatePtr
	timeOffset := *timeOffsetPtr
	keepMismatch := *keepMismatchPtr
	startDelay := int64(*startDelayPtr)
	deadline := *deadlinePtr
	customNet := primitives.Sha([]byte(*customNetPtr)).Bytes()[:4]
	rpcUser := *rpcUserflag
	rpcPassword := *rpcPasswordflag
	factomdTLS := *factomdTLSflag
	factomdLocations := *factomdLocationsflag

	// Must add the prefix before loading the configuration.
	s.AddPrefix(prefix)
	FactomConfigFilename := util.GetConfigFilename("m2")
	fmt.Println(fmt.Sprintf("factom config: %s", FactomConfigFilename))
	s.LoadConfig(FactomConfigFilename, networkName)
	s.OneLeader = rotate
	s.TimeOffset = primitives.NewTimestampFromMilliseconds(uint64(timeOffset))
	s.StartDelayLimit = startDelay * 1000
	s.Journaling = journaling

	if 999 < portOverride { // The command line flag exists and seems reasonable.
		s.SetPort(portOverride)
	}

	if blkTime != 0 {
		s.DirectoryBlockInSeconds = blkTime
	} else {
		blkTime = s.DirectoryBlockInSeconds
	}

	if follower {
		leader = false
	}
	if leader {
		follower = false
	}
	if !follower && !leader {
		panic("Not a leader or a follower")
	}

	if journal != "" {
		cnt = 1
	}

	if rpcUser != "" {
		s.RpcUser = rpcUser
	}

	if rpcPassword != "" {
		s.RpcPass = rpcPassword
	}

	if factomdTLS == true {
		s.FactomdTLSEnable = true
	}

	if factomdLocations != "" {
		if len(s.FactomdLocations) > 0 {
			s.FactomdLocations += ","
		}
		s.FactomdLocations += factomdLocations
	}

	fmt.Println(">>>>>>>>>>>>>>>>")
	fmt.Println(">>>>>>>>>>>>>>>> Net Sim Start!")
	fmt.Println(">>>>>>>>>>>>>>>>")
	fmt.Println(">>>>>>>>>>>>>>>> Listening to Node", listenTo)
	fmt.Println(">>>>>>>>>>>>>>>>")

	AddInterruptHandler(func() {
		fmt.Print("<Break>\n")
		fmt.Print("Gracefully shutting down the server...\n")
		for _, fnode := range fnodes {
			fmt.Print("Shutting Down: ", fnode.State.FactomNodeName, "\r\n")
			fnode.State.ShutdownChan <- 0
		}
		if enableNet {
			p2pNetwork.NetworkStop()
			// NODE_TALK_FIX
			p2pProxy.stopProxy()
		}
		fmt.Print("Waiting...\r\n")
		time.Sleep(3 * time.Second)
		os.Exit(0)
	})

	if journal != "" {
		if s.DBType != "Map" {
			fmt.Println("Journal is ALWAYS a Map database")
			s.DBType = "Map"
		}
	}
	if follower {
		s.NodeMode = "FULL"
		leadID := primitives.Sha([]byte(s.Prefix + "FNode0"))
		if s.IdentityChainID.IsSameAs(leadID) {
			s.SetIdentityChainID(primitives.Sha([]byte(time.Now().String()))) // Make sure this node is NOT a leader
		}
	}

	s.KeepMismatch = keepMismatch

	if len(db) > 0 {
		s.DBType = db
	} else {
		db = s.DBType
	}

	if len(cloneDB) > 0 {
		s.CloneDBType = cloneDB
	} else {
		s.CloneDBType = db
	}

	pnet := net
	if len(fnet) > 0 {
		pnet = fnet
		net = "file"
	}

	go StartProfiler()

	s.AddPrefix(prefix)
	s.SetOut(false)
	s.Init()
	s.SetDropRate(droprate)

	mLog.init(runtimeLog, cnt)

	setupFirstAuthority(s)

	os.Stderr.WriteString(fmt.Sprintf("%20s %s\n", "FNode 0 Salt", s.Salt.String()[:16]))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "enablenet", enableNet))
	os.Stderr.WriteString(fmt.Sprintf("%20s %d\n", "node", listenTo))
	os.Stderr.WriteString(fmt.Sprintf("%20s %s\n", "prefix", prefix))
	os.Stderr.WriteString(fmt.Sprintf("%20s %d\n", "node count", cnt))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%s\"\n", "net spec", pnet))
	os.Stderr.WriteString(fmt.Sprintf("%20s %d\n", "Msgs droped", droprate))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%s\"\n", "journal", journal))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%s\"\n", "database", db))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%s\"\n", "database for clones", cloneDB))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%d\"\n", "port", s.PortNumber))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%s\"\n", "peers", peers))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%d\"\n", "netdebug", netdebug))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%t\"\n", "exclusive", exclusive))
	os.Stderr.WriteString(fmt.Sprintf("%20s %d\n", "block time", blkTime))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "runtimeLog", runtimeLog))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "rotate", rotate))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "timeOffset", timeOffset))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "keepMismatch", keepMismatch))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "startDelay", startDelay))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "Network", s.Network))
	os.Stderr.WriteString(fmt.Sprintf("%20s %x\n", "customnet", customNet))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "deadline (ms)", deadline))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "tls", s.FactomdTLSEnable))
	os.Stderr.WriteString(fmt.Sprintf("%20s %v\n", "selfaddr", s.FactomdLocations))
	os.Stderr.WriteString(fmt.Sprintf("%20s \"%s\"\n", "rpcuser", s.RpcUser))
	if "" == s.RpcPass {
		os.Stderr.WriteString(fmt.Sprintf("%20s %s\n", "rpcpass", "is blank"))
	} else {
		os.Stderr.WriteString(fmt.Sprintf("%20s %s\n", "rpcpass", "is set"))
	}

	//************************************************
	// Actually setup the Network
	//************************************************

	// Make cnt Factom nodes
	for i := 0; i < cnt; i++ {
		makeServer(s) // We clone s to make all of our servers
	}
	// Modify Identities of new nodes
	if len(fnodes) > 1 && len(s.Prefix) == 0 {
		modifyLoadIdentities() // We clone s to make all of our servers
	}

	for i := range fnodes {
		fnodes[i].State.CreateBlankFactomIdentity(fnodes[i].State.IdentityChainID)
	}

	// Start the P2P netowork
	var networkID p2p.NetworkID
	var seedURL, networkPort, specialPeers string
	switch s.Network {
	case "MAIN", "main":
		networkID = p2p.MainNet
		seedURL = s.MainSeedURL
		networkPort = s.MainNetworkPort
		specialPeers = s.MainSpecialPeers
	case "TEST", "test":
		networkID = p2p.TestNet
		seedURL = s.TestSeedURL
		networkPort = s.TestNetworkPort
		specialPeers = s.TestSpecialPeers
	case "LOCAL", "local":
		networkID = p2p.LocalNet
		seedURL = s.LocalSeedURL
		networkPort = s.LocalNetworkPort
		specialPeers = s.LocalSpecialPeers
	case "CUSTOM", "custom":
		if bytes.Compare(customNet, []byte("\xe3\xb0\xc4\x42")) == 0 {
			panic("Please specify a custom network with -customnet=<something unique here>")
		}
		s.CustomNetworkID = customNet
		networkID = p2p.NetworkID(binary.BigEndian.Uint32(customNet))
		for i := range fnodes {
			fnodes[i].State.CustomNetworkID = customNet
		}
		seedURL = s.LocalSeedURL
		networkPort = s.LocalNetworkPort
		specialPeers = s.LocalSpecialPeers
	default:
		panic("Invalid Network choice in Config File or command line. Choose MAIN, TEST, LOCAL, or CUSTOM")
	}

	connectionMetricsChannel := make(chan interface{}, p2p.StandardChannelSize)
	p2p.NetworkDeadline = time.Duration(deadline) * time.Millisecond

	if enableNet {

		if 0 < networkPortOverride {
			networkPort = fmt.Sprintf("%d", networkPortOverride)
		}
		ci := p2p.ControllerInit{
			Port:                     networkPort,
			PeersFile:                s.PeersFile,
			Network:                  networkID,
			Exclusive:                exclusive,
			SeedURL:                  seedURL,
			SpecialPeers:             specialPeers,
			ConnectionMetricsChannel: connectionMetricsChannel,
		}
		p2pNetwork = new(p2p.Controller).Init(ci)
		p2pNetwork.StartNetwork()
		// Setup the proxy (Which translates from network parcels to factom messages, handling addressing for directed messages)
		p2pProxy = new(P2PProxy).Init(fnodes[0].State.FactomNodeName, "P2P Network").(*P2PProxy)
		p2pProxy.FromNetwork = p2pNetwork.FromNetwork
		p2pProxy.ToNetwork = p2pNetwork.ToNetwork
		fnodes[0].Peers = append(fnodes[0].Peers, p2pProxy)
		p2pProxy.SetDebugMode(netdebug)
		if 0 < netdebug {
			go p2pProxy.PeriodicStatusReport(fnodes)
			p2pNetwork.StartLogging(uint8(netdebug))
		} else {
			p2pNetwork.StartLogging(uint8(0))
		}
		p2pProxy.StartProxy()
		// Command line peers lets us manually set special peers
		p2pNetwork.DialSpecialPeersString(peers)
	}

	switch net {
	case "file":
		file, err := os.Open(fnet)
		if err != nil {
			panic(fmt.Sprintf("File network.txt failed to open: %s", err.Error()))
		} else if file == nil {
			panic(fmt.Sprint("File network.txt failed to open, and we got a file of <nil>"))
		}
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			var a, b int
			var s string
			fmt.Sscanf(scanner.Text(), "%d %s %d", &a, &s, &b)
			if s == "--" {
				AddSimPeer(fnodes, a, b)
			}
		}
	case "square":
		side := int(math.Sqrt(float64(cnt)))

		for i := 0; i < side; i++ {
			AddSimPeer(fnodes, i*side, (i+1)*side-1)
			AddSimPeer(fnodes, i, side*(side-1)+i)
			for j := 0; j < side; j++ {
				if j < side-1 {
					AddSimPeer(fnodes, i*side+j, i*side+j+1)
				}
				AddSimPeer(fnodes, i*side+j, ((i+1)*side)+j)
			}
		}
	case "long":
		fmt.Println("Using long Network")
		for i := 1; i < cnt; i++ {
			AddSimPeer(fnodes, i-1, i)
		}
		// Make long into a circle
	case "loops":
		fmt.Println("Using loops Network")
		for i := 1; i < cnt; i++ {
			AddSimPeer(fnodes, i-1, i)
		}
		for i := 0; (i+17)*2 < cnt; i += 17 {
			AddSimPeer(fnodes, i%cnt, (i+5)%cnt)
		}
		for i := 0; (i+13)*2 < cnt; i += 13 {
			AddSimPeer(fnodes, i%cnt, (i+7)%cnt)
		}
	case "alot":
		n := len(fnodes)
		for i := 0; i < n; i++ {
			AddSimPeer(fnodes, i, (i+1)%n)
			AddSimPeer(fnodes, i, (i+5)%n)
			AddSimPeer(fnodes, i, (i+7)%n)
		}

	case "alot+":
		n := len(fnodes)
		for i := 0; i < n; i++ {
			AddSimPeer(fnodes, i, (i+1)%n)
			AddSimPeer(fnodes, i, (i+5)%n)
			AddSimPeer(fnodes, i, (i+7)%n)
			AddSimPeer(fnodes, i, (i+13)%n)
		}

	case "tree":
		index := 0
		row := 1
	treeloop:
		for i := 0; true; i++ {
			for j := 0; j <= i; j++ {
				AddSimPeer(fnodes, index, row)
				AddSimPeer(fnodes, index, row+1)
				row++
				index++
				if index >= len(fnodes) {
					break treeloop
				}
			}
			row += 1
		}
	case "circles":
		circleSize := 7
		index := 0
		for {
			AddSimPeer(fnodes, index, index+circleSize-1)
			for i := index; i < index+circleSize-1; i++ {
				AddSimPeer(fnodes, i, i+1)
			}
			index += circleSize

			AddSimPeer(fnodes, index, index-circleSize/3)
			AddSimPeer(fnodes, index+2, index-circleSize-circleSize*2/3-1)
			AddSimPeer(fnodes, index+3, index-(2*circleSize)-circleSize*2/3)
			AddSimPeer(fnodes, index+5, index-(3*circleSize)-circleSize*2/3+1)

			if index >= len(fnodes) {
				break
			}
		}
	default:
		fmt.Println("Didn't understand network type. Known types: mesh, long, circles, tree, loops.  Using a Long Network")
		for i := 1; i < cnt; i++ {
			AddSimPeer(fnodes, i-1, i)
		}

	}
	if journal != "" {
		go LoadJournal(s, journal)
		startServers(false)
	} else {
		startServers(true)
	}

	// Start the webserver
	go wsapi.Start(fnodes[0].State)

	go controlPanel.ServeControlPanel(fnodes[0].State.ControlPanelChannel, fnodes[0].State, connectionMetricsChannel, p2pNetwork, Build)
	// Listen for commands:
	SimControl(listenTo)
}
Exemplo n.º 2
0
func SimControl(listenTo int) {
	var _ = time.Sleep
	var summary int
	var watchPL int
	var watchMessages int
	var rotate int
	var wsapiNode int
	var faulting bool

	for {
		l := make([]byte, 100)
		var err error
		// When running as a detatched process, this routine becomes a very tight loop and starves other goroutines.
		// So, we will sleep before letting it check to see if Stdin has been reconnected
		if _, err = os.Stdin.Read(l); err != nil {
			time.Sleep(2 * time.Second)
			continue
		}

		// This splits up the command at anycodepoint that is not a letter, number of punctuation, so usually by spaces.
		parseFunc := func(c rune) bool {
			return !unicode.IsLetter(c) && !unicode.IsNumber(c) && !unicode.IsPunct(c)
		}
		// cmd is not a list of the parameters, much like command line args show up in args[]
		cmd := strings.FieldsFunc(string(l), parseFunc)
		if 0 == len(cmd) {
			cmd = []string{"h"}
		}
		b := string(cmd[0])
		v, err := strconv.Atoi(string(b))
		if err == nil && v >= 0 && v < len(fnodes) && fnodes[listenTo].State != nil {
			listenTo = v
			os.Stderr.WriteString(fmt.Sprintf("Switching to Node %d\n", listenTo))
			// Update which node will be displayed on the controlPanel page
			connectionMetricsChannel := make(chan interface{}, p2p.StandardChannelSize)
			go controlPanel.ServeControlPanel(fnodes[listenTo].State.ControlPanelChannel, fnodes[listenTo].State, connectionMetricsChannel, p2pNetwork, Build)
		} else {
			// fmt.Printf("Parsing command, found %d elements.  The first element is: %+v / %s \n Full command: %+v\n", len(cmd), b[0], string(b), cmd)
			switch {
			case '!' == b[0]:
				if listenTo < 0 || listenTo > len(fnodes) {
					break
				}
				s := fnodes[listenTo].State
				os.Stderr.WriteString("Reset Node: " + s.FactomNodeName + "\n")
				s.Reset()

			case 'g' == b[0]:
				if len(b) > 1 {
					if b[1] == 'c' {
						copyOver(fnodes[listenTo].State)
						break
					}
				}
				if listenTo < 0 || listenTo > len(fnodes) {
					break
				}
				wsapiNode = listenTo
				wsapi.SetState(fnodes[wsapiNode].State)

				if nextAuthority == -1 {
					err := fundWallet(fnodes[wsapiNode].State, 2e7)
					if err != nil {
						os.Stderr.WriteString(fmt.Sprintf("Error in funding the wallet, %s\n", err.Error()))
						break
					}
					setUpAuthorites(fnodes[wsapiNode].State, true)
					os.Stderr.WriteString(fmt.Sprintf("%d Authorities added to the stack and funds are in wallet\n", len(authStack)))
				}
				if len(b) == 1 {
					os.Stderr.WriteString(fmt.Sprint("Authorities are ready to be made. 'gN' where N is the number to be made.\n"))
				}
				if len(b) > 1 {
					count, err := strconv.Atoi(b[1:])
					if err != nil {
						os.Stderr.WriteString(fmt.Sprintf("Error in input bN, %s\n", err.Error()))
					} else {
						if count > 100 {
							os.Stderr.WriteString(fmt.Sprint("You can only pop a max of 100 off the stack at a time."))
							count = 100
						}
						err := fundWallet(fnodes[wsapiNode].State, uint64(count*5e7))
						if err != nil {
							os.Stderr.WriteString(fmt.Sprintf("Error in funding the wallet, %s\n", err.Error()))
							break
						}
						auths, skipped, err := authorityToBlockchain(count, fnodes[wsapiNode].State)
						if err != nil {
							os.Stderr.WriteString(fmt.Sprintf("Error making authorites, %s\n", err.Error()))
						}
						os.Stderr.WriteString(fmt.Sprintf("=== %d Identities added to blockchain, %d remain in stack, %d skipped (Added by someone else) ===\n", len(auths), len(authStack), skipped))
						for _, ele := range auths {
							fmt.Println(ele.ChainID.String())
						}
					}
				}
			case '/' == b[0]:
				sortByID = !sortByID
				if sortByID {
					os.Stderr.WriteString("Sort Status by Chain IDs\n")
				} else {
					os.Stderr.WriteString("Sort Status by Node Name\n")
				}
			case 'w' == b[0]:
				if listenTo >= 0 && listenTo < len(fnodes) {
					wsapiNode = listenTo
					wsapi.SetState(fnodes[wsapiNode].State)
					os.Stderr.WriteString(fmt.Sprintf("--Listen to %s --\n", fnodes[wsapiNode].State.FactomNodeName))
				}
			case 's' == b[0]:

				if len(b) > 1 {
					ht, err := strconv.Atoi(string(b[1:]))
					if err != nil {
						os.Stderr.WriteString("type snnn where nnn is the number of status messages to print\n")
						break
					}

					if listenTo < 0 || listenTo > len(fnodes) {
						os.Stderr.WriteString("Select a node first\n")
						break
					}

					f := fnodes[listenTo]

					fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b))
					l := len(f.State.StatusStrs)
					if l < ht {
						ht = l
					}
					for i := 0; i < ht; i++ {
						os.Stderr.WriteString(f.State.StatusStrs[l-1] + "\n")
						l--
					}
					break
				}

				summary++
				if summary%2 == 1 {
					os.Stderr.WriteString("--Print Summary On--\n")
					go printSummary(&summary, summary, &listenTo, &wsapiNode)
				} else {
					os.Stderr.WriteString("--Print Summary Off--\n")
				}
			case 'p' == b[0]:
				if len(b) > 1 {
					ht, err := strconv.Atoi(string(b[1:]))
					if err != nil {
						os.Stderr.WriteString("Dump Process List with pn  where n = blockheight, i.e. 'p10'")
						break
					}

					if listenTo < 0 || listenTo > len(fnodes) {
						os.Stderr.WriteString("Select a node first")
						break
					}

					f := fnodes[listenTo]

					pl := f.State.ProcessLists.Get(uint32(ht))
					if pl == nil {
						os.Stderr.WriteString("No Process List found")
					} else {
						fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b))
						fmt.Println(pl.String())
					}

					break
				}

				watchPL++
				if watchPL%2 == 1 {
					os.Stderr.WriteString("--Print Process Lists On--\n")
					go printProcessList(&watchPL, watchPL, &listenTo)
				} else {
					os.Stderr.WriteString("--Print Process Lists Off--\n")
				}
			case 'r' == b[0]:
				rotate++
				if rotate%2 == 1 {
					os.Stderr.WriteString("--Rotate the WSAPI around the nodes--\n")
					go rotateWSAPI(&rotate, rotate, &wsapiNode)
				} else {
					os.Stderr.WriteString("--Stop Rotation of the WSAPI around the nodes.  Now --\n")
					wsapi.SetState(fnodes[wsapiNode].State)
				}
			case 'a' == b[0]:
				mLog.all = false
				for _, fnode := range fnodes {
					fnode.State.SetOut(false)
				}
				if listenTo < 0 || listenTo > len(fnodes) {
					fmt.Println("Select a node first")
					break
				}
				f := fnodes[listenTo]
				fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b[:len(b)]))
				if len(b) < 2 {
					break
				}
				ht, err := strconv.Atoi(string(b[1:]))
				if err != nil {
					fmt.Println(err, "Dump Adminblock block with an  where n = blockheight, i.e. 'a10'")
				} else {
					msg, err := f.State.LoadDBState(uint32(ht))
					if err == nil && msg != nil {
						dsmsg := msg.(*messages.DBStateMsg)
						ABlock := dsmsg.AdminBlock
						fmt.Println(ABlock.String())
					} else {
						pl := f.State.ProcessLists.Get(uint32(ht))
						if pl == nil || pl.AdminBlock == nil {
							fmt.Println("Could not find this Admin block")
						} else {
							fmt.Printf(pl.AdminBlock.String())
						}
					}
				}
			case 'e' == b[0]:
				mLog.all = false
				for _, fnode := range fnodes {
					fnode.State.SetOut(false)
				}
				if listenTo < 0 || listenTo > len(fnodes) {
					fmt.Println("Select a node first")
					break
				}
				f := fnodes[listenTo]
				fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b[:len(b)]))
				if len(b) < 2 {
					break
				}
				ht, err := strconv.Atoi(string(b[1:]))
				if err != nil {
					fmt.Println(err, "Dump Entry Credit block with fn  where n = blockheight, i.e. 'e10'")
				} else {
					msg, err := f.State.LoadDBState(uint32(ht))
					if err == nil && msg != nil {
						dsmsg := msg.(*messages.DBStateMsg)
						ECBlock := dsmsg.EntryCreditBlock
						fmt.Printf(ECBlock.String())
					} else {
						pl := f.State.ProcessLists.Get(uint32(ht))
						if pl == nil || pl.EntryCreditBlock == nil {
							fmt.Println("Could not find this Entry Credit Block")
						} else {
							fmt.Printf(pl.EntryCreditBlock.String())
						}
					}
				}
			case 'f' == b[0]:
				mLog.all = false
				for _, fnode := range fnodes {
					fnode.State.SetOut(false)
				}
				if listenTo < 0 || listenTo > len(fnodes) {
					fmt.Println("Select a node first")
					break
				}
				f := fnodes[listenTo]
				fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b[:len(b)]))
				if len(b) < 2 {
					break
				}
				ht, err := strconv.Atoi(string(b[1:]))
				if err != nil {
					fmt.Println(err, "Dump Factoid block with fn  where n = blockheight, i.e. 'f10'")
				} else {
					msg, err := f.State.LoadDBState(uint32(ht))
					if err == nil && msg != nil {
						dsmsg := msg.(*messages.DBStateMsg)
						FBlock := dsmsg.FactoidBlock
						fmt.Printf(FBlock.String())
					} else {
						dbstate := f.State.DBStates.Get(ht)
						if dbstate == nil || dbstate.FactoidBlock == nil {
							fmt.Println("Could not find this Factoid block")
						} else {
							fmt.Printf(dbstate.FactoidBlock.String())
						}
					}
				}
			case 'd' == b[0]:
				mLog.all = false
				for _, fnode := range fnodes {
					fnode.State.SetOut(false)
				}
				if listenTo < 0 || listenTo > len(fnodes) {
					fmt.Println("Select a node first")
					break
				}
				f := fnodes[listenTo]
				fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b[:len(b)]))
				if len(b) < 2 {
					break
				}
				ht, err := strconv.Atoi(string(b[1:]))
				if err != nil {
					fmt.Println(err, "Dump Directory block with dn  where n = blockheight, i.e. 'd10'")
				} else {
					msg, err := f.State.LoadDBState(uint32(ht))
					if err == nil && msg != nil {
						dsmsg := msg.(*messages.DBStateMsg)
						DBlock := dsmsg.DirectoryBlock
						fmt.Printf(DBlock.String())
					} else {
						pl := f.State.ProcessLists.Get(uint32(ht))
						if pl == nil || pl.DirectoryBlock == nil {
							fmt.Println("Could not find this directory block")
						} else {
							fmt.Printf(pl.DirectoryBlock.String())
						}
					}
				}
			case 'v' == b[0]:
				if verboseFaultOutput {
					verboseFaultOutput = false
					os.Stderr.WriteString("Vnnn          Set full fault timeout to the given number of seconds. Helps debugging.\n")
				} else {
					verboseFaultOutput = true
					os.Stderr.WriteString("--VerboseFaultOutput On--\n")
				}
			case 'V' == b[0]:
				if len(b) == 1 {
					os.Stderr.WriteString("Vnnn -- Set the timeout for faulting a server to nnn seconds\n")
					os.Stderr.WriteString("Vt   -- Start an automated Faulting Test, or stop a running Faulting Test\n")
					os.Stderr.WriteString("VL   -- Display all the authority sets in the Status update\n")
					os.Stderr.WriteString("Vr   -- Reset all nodes in the simulation\n")
					break
				}

				if b[1] == 't' {
					faulting = !faulting
					if faulting {
						os.Stderr.WriteString("Start Faulting Test\n")
						go faultTest(&faulting)
					} else {
						os.Stderr.WriteString("Stop Faulting Test\n")
					}
					break
				}

				// Reset Everything
				if b[1] == 'r' {
					os.Stderr.WriteString("Reset all nodes in the simulation!\n")
					for _, f := range fnodes {
						f.State.Reset()
					}
					break
				}

				if b[1] == 'l' || b[1] == 'L' {
					if verboseAuthoritySet {
						verboseAuthoritySet = false
						os.Stderr.WriteString("--VerboseAuthoritySet Off--\n")
					} else {
						verboseAuthoritySet = true
						os.Stderr.WriteString("--VerboseAuthoritySet On--\n")
					}
					break
				}

				if b[1] == 'd' || b[1] == 'D' {
					if verboseAuthorityDeltas {
						verboseAuthorityDeltas = false
						os.Stderr.WriteString("--VerboseAuthorityDeltas Off--\n")
					} else {
						verboseAuthorityDeltas = true
						os.Stderr.WriteString("--VerboseAuthorityDeltas On--\n")
					}
					break
				}

				nnn, err := strconv.Atoi(string(b[1:]))
				if err != nil || nnn < 0 || nnn > 99 {
					os.Stderr.WriteString("Specifiy a FaultTimeout between 0 and 100\n")
					break
				}
				for _, fn := range fnodes {
					fn.State.FaultTimeout = nnn
					os.Stderr.WriteString(fmt.Sprintf("Setting FaultTimeout of %10s to %d\n", fn.State.FactomNodeName, nnn))
				}

			case 'k' == b[0]:
				mLog.all = false
				for _, fnode := range fnodes {
					fnode.State.SetOut(false)
				}
				if listenTo < 0 || listenTo > len(fnodes) {
					fmt.Println("Select a node first")
					break
				}
				f := fnodes[listenTo]
				fmt.Println("-----------------------------", f.State.FactomNodeName, "--------------------------------------", string(b))
				if len(b) < 2 {
					fmt.Println("No Parms found.")
					break
				}

				parms := strings.Split(string(b[1:]), ".")
				if len(parms) >= 2 {
					os.Stderr.WriteString("Print Entry String with:  k<db #>.<entry #>\n")
				}
				db, err1 := strconv.Atoi(string(parms[0]))
				entry, err2 := strconv.Atoi(string(parms[1]))
				if err1 != nil || err2 != nil {
					os.Stderr.WriteString("Bad Parameters")
				} else {
					msg, err := f.State.LoadDBState(uint32(db))
					if err == nil && msg != nil {
						dsmsg := msg.(*messages.DBStateMsg)
						DBlock := dsmsg.DirectoryBlock
						entries := DBlock.GetDBEntries()
						if entry < len(entries) && entry >= 0 {
							fmt.Println(fmt.Sprintf("Looking for EB with KeyMR %x", entries[entry].GetKeyMR().Bytes()))
							eb1, _ := f.State.DB.FetchEBlockHead(entries[entry].GetChainID())
							if eb1 != nil {
								fmt.Println("Chain Head:")
								fmt.Println(eb1.String())
							}
							eb2, _ := f.State.DB.FetchEBlock(entries[entry].GetKeyMR())
							if eb2 != nil {
								fmt.Println("Entry Block:")
								fmt.Println(eb2.String())
							} else {
								fmt.Println("No Entry Block Found")
							}
						}
					} else {
						fmt.Println("Error: ", err, msg)
					}
				}

			case 'x' == b[0]:

				if listenTo >= 0 && listenTo < len(fnodes) {
					f := fnodes[listenTo]
					v := f.State.GetNetStateOff()
					if v {
						os.Stderr.WriteString("Bring " + f.State.FactomNodeName + " Back onto the network\n")
					} else {
						os.Stderr.WriteString("Take  " + f.State.FactomNodeName + " off the network\n")
					}
					f.State.SetNetStateOff(!v)
				}

			case 'y' == b[0]:
				if listenTo >= 0 && listenTo < len(fnodes) {
					f := fnodes[listenTo]
					fmt.Println("Holding:")
					for k := range f.State.Holding {
						fmt.Println(f.State.Holding[k].String())
					}
				}

			case 'm' == b[0]:
				watchMessages++
				if watchMessages%2 == 1 {
					os.Stderr.WriteString("--Print Messages On--\n")
					go printMessages(&watchMessages, watchMessages, &listenTo)
				} else {
					os.Stderr.WriteString("--Print Messages Off--\n")
				}
			case 'z' == b[0]: // Add Audit server, Remove server, and Add Leader fall through to 'n', switch to next node.
				if len(b) > 1 && b[1] == 'a' {
					msg := messages.NewRemoveServerMsg(fnodes[listenTo].State, fnodes[listenTo].State.IdentityChainID, 1)
					fnodes[listenTo].State.InMsgQueue() <- msg
					os.Stderr.WriteString(fmt.Sprintln("Attempting to remove", fnodes[listenTo].State.GetFactomNodeName(), "as a server"))
				} else {
					msg := messages.NewRemoveServerMsg(fnodes[listenTo].State, fnodes[listenTo].State.IdentityChainID, 0)
					fnodes[listenTo].State.InMsgQueue() <- msg
					os.Stderr.WriteString(fmt.Sprintln("Attempting to remove", fnodes[listenTo].State.GetFactomNodeName(), "as a server"))
				}
				fallthrough
			case 'o' == b[0]: // Add Audit server and Add Leader fall through to 'n', switch to next node.
				if b[0] == 'o' { // (Don't do anything if just passing along the remove server)
					if len(b) > 1 && b[1] == 'n' {
						index := 0
						for index < len(authKeyLibrary) {
							if authKeyLibrary[index].Taken == false {
								authKeyLibrary[index].Taken = true
								fnodes[listenTo].State.IdentityChainID = authKeyLibrary[index].ChainID
								key, pKey, _ := authKeyLookup(fnodes[listenTo].State.IdentityChainID)
								fnodes[listenTo].State.LocalServerPrivKey = key
								fnodes[listenTo].State.SimSetNewKeys(pKey)
								os.Stderr.WriteString(fmt.Sprintf("Identity of " + fnodes[listenTo].State.GetFactomNodeName() + " changed to [" + authKeyLibrary[index].ChainID.String()[:10] + "]\n"))
								break
							}
							index++
						}
					}

					msg := messages.NewAddServerMsg(fnodes[listenTo].State, 1)
					fnodes[listenTo].State.InMsgQueue() <- msg
					os.Stderr.WriteString(fmt.Sprintln("Attempting to make", fnodes[listenTo].State.GetFactomNodeName(), "a Audit Server"))
				}
				fallthrough
			case 'l' == b[0]: // Add Audit server, Remove server, and Add Leader fall through to 'n', switch to next node.
				if b[0] == 'l' { // (Don't do anything if just passing along the audit server)
					feds := fnodes[listenTo].State.LeaderPL.FedServers
					exists := false
					for _, fed := range feds {
						if fed.GetChainID().IsSameAs(fnodes[listenTo].State.IdentityChainID) {
							exists = true
						}
					}
					if len(b) > 1 && b[1] == 't' && fnodes[listenTo].State.IdentityChainID.String()[:6] != "888888" && !exists {
						index := 0
						for index < len(authKeyLibrary) {
							if authKeyLibrary[index].Taken == false {
								authKeyLibrary[index].Taken = true
								fnodes[listenTo].State.IdentityChainID = authKeyLibrary[index].ChainID
								key, pKey, _ := authKeyLookup(fnodes[listenTo].State.IdentityChainID)
								fnodes[listenTo].State.LocalServerPrivKey = key
								fnodes[listenTo].State.SimSetNewKeys(pKey)
								os.Stderr.WriteString(fmt.Sprintf("Identity of " + fnodes[listenTo].State.GetFactomNodeName() + " changed to [" + authKeyLibrary[index].ChainID.String()[:10] + "]\n"))
								break
							}
							index++
						}
						if index >= len(authKeyLibrary) {
							os.Stderr.WriteString(fmt.Sprint("Did not make a leader, ran out of identities. Type 'g1' for one more identity.\n"))
							break
						}
					}

					msg := messages.NewAddServerMsg(fnodes[listenTo].State, 0)
					fnodes[listenTo].State.InMsgQueue() <- msg
					os.Stderr.WriteString(fmt.Sprintln("Attempting to make", fnodes[listenTo].State.GetFactomNodeName(), "a Leader"))
				}
				fallthrough
			case 'n' == b[0]:
				fnodes[listenTo].State.SetOut(false)
				listenTo++
				if listenTo >= len(fnodes) {
					listenTo = 0
				}
				fnodes[listenTo].State.SetOut(true)
				os.Stderr.WriteString(fmt.Sprint("\r\nSwitching to Node ", listenTo, "\r\n"))
			case 'c' == b[0]:
				c := !fnodes[0].State.DebugConsensus
				for _, n := range fnodes {
					n.State.DebugConsensus = fnodes[0].State.DebugConsensus
				}
				if c {
					os.Stderr.WriteString(fmt.Sprint("\r\nTrace Consensus\n"))
				} else {
					os.Stderr.WriteString(fmt.Sprint("\r\nTurn off Consensus Trace \n"))
				}

				for _, f := range fnodes {
					f.State.DebugConsensus = c
				}
			case 'i' == b[0]:
				show := 0
				amt := -1
				if len(b) > 1 && (b[1] == 'H' || b[1] == 'h') {
					os.Stderr.WriteString("------------------------   Identity Commands   --------------------------------\n")
					os.Stderr.WriteString("iH           -Show this help\n")
					os.Stderr.WriteString("gN           -Adds 'N' identities to your identity pool from the identity stack. Cannot add \n")
					os.Stderr.WriteString("              identities that another instance of Factomd has added to their identity pool.\n")
					os.Stderr.WriteString("              Each Factomd instance has its own identity pool it can use (t), but everyone\n")
					os.Stderr.WriteString("              will share the identities in the identity stack. This stack is fixed and will\n")
					os.Stderr.WriteString("              be the same each time Factomd launches. It may grow in the future. Used for testing\n")
					os.Stderr.WriteString("tN           -Attaches Nth identity in pool(0 indexed) to current node. If that identity is taken, \n")
					os.Stderr.WriteString("              will grab the next available identity in the local identity pool. Can also just type \n")
					os.Stderr.WriteString("              't' and it will grab the next available identity.\n")
					os.Stderr.WriteString("tm           -Shows the current node's identity information. \n")
					os.Stderr.WriteString("tc           -Changes the current node's signing key. \n")
					os.Stderr.WriteString("t[CHAINID]   -Attaches the identity associated with the root chainID given to current node \n")
					os.Stderr.WriteString("u             Shows the authorities being monitored for change.\n")
					os.Stderr.WriteString("i             Shows the identities being monitored for change.\n")
					os.Stderr.WriteString("i[t/m/b/a][N] Shows only the Chains, Mhash, block signing key, or anchor key up to the Nth identity\n")
					os.Stderr.WriteString("isN           Shows only Nth identity\n")
					os.Stderr.WriteString("-------------------------------------------------------------------------------\n\n")

				} else {
					if len(b) > 1 {
						if b[1] == 't' {
							show = 1
						} else if b[1] == 'm' {
							show = 2
						} else if b[1] == 'b' {
							show = 3
						} else if b[1] == 'a' {
							show = 4
						}
						if len(b) > 2 {
							amt, err = strconv.Atoi(b[2:])
							if b[1] == 's' {
								show = 5
							} else if err == nil {
							} else {
								show = 0
								amt = -1
							}
						}
					}
					if amt == -1 {
						os.Stderr.WriteString(fmt.Sprintf("=== Identity List === Total: %d Displaying: All\n", len(fnodes[listenTo].State.Identities)))

					} else if show == 5 {
						os.Stderr.WriteString(fmt.Sprintf("=== Identity List === Total: %d Displaying Only: %d\n", len(fnodes[listenTo].State.Identities), amt))
					} else {
						os.Stderr.WriteString(fmt.Sprintf("=== Identity List === Total: %d Displaying: %d\n", len(fnodes[listenTo].State.Identities), amt))
					}
					for c, i := range fnodes[listenTo].State.Identities {
						if amt != -1 && c == amt+1 {
							break
						}
						stat := returnStatString(i.Status)
						if show == 5 {
							if c != amt {

							} else {
								os.Stderr.WriteString(fmt.Sprint("-----------------------------------Identity: ", amt, "---------------------------------------\n"))
							}
						} else {
							os.Stderr.WriteString(fmt.Sprint("-----------------------------------Identity: ", c, "---------------------------------------\n"))
						}
						if show == 0 || show == 5 {
							if show == 0 || c == amt {
								os.Stderr.WriteString(fmt.Sprint("Server Status: ", stat, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Identity Chain: ", i.IdentityChainID, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Management Chain: ", i.ManagementChainID, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Matryoshka Hash: ", i.MatryoshkaHash, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Key 1: ", i.Key1, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Key 2: ", i.Key2, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Key 3: ", i.Key3, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Key 4: ", i.Key4, "\n"))
								os.Stderr.WriteString(fmt.Sprint("Signing Key: ", i.SigningKey, "\n"))
								for _, a := range i.AnchorKeys {
									os.Stderr.WriteString(fmt.Sprintf("Anchor Key: {'%s' L%x T%x K:%x}\n", a.BlockChain, a.KeyLevel, a.KeyType, a.SigningKey))
								}
							}
						} else if show == 1 {
							os.Stderr.WriteString(fmt.Sprint("Server Salt:     ", fnodes[c].State.Salt.String()[:16], "\n"))
							os.Stderr.WriteString(fmt.Sprint("Server Status: ", stat, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Identity Chain: ", i.IdentityChainID, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Management Chain: ", i.ManagementChainID, "\n"))
						} else if show == 2 {
							os.Stderr.WriteString(fmt.Sprint("Server Salt:     ", fnodes[c].State.Salt.String()[:16], "\n"))
							os.Stderr.WriteString(fmt.Sprint("Server Status:   ", stat, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Identity Chain:  ", i.IdentityChainID, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Matryoshka Hash: ", i.MatryoshkaHash, "\n"))
						} else if show == 3 {
							os.Stderr.WriteString(fmt.Sprint("Server Salt:     ", fnodes[c].State.Salt.String()[:16], "\n"))
							os.Stderr.WriteString(fmt.Sprint("Server Status: ", stat, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Identity Chain: ", i.IdentityChainID, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Signing Key: ", i.SigningKey, "\n"))
						} else if show == 4 {
							os.Stderr.WriteString(fmt.Sprint("Server Salt:     ", fnodes[c].State.Salt.String()[:16], "\n"))
							os.Stderr.WriteString(fmt.Sprint("Server Status: ", stat, "\n"))
							os.Stderr.WriteString(fmt.Sprint("Identity Chain: ", i.IdentityChainID, "\n"))
							for _, a := range i.AnchorKeys {
								os.Stderr.WriteString(fmt.Sprintf("Anchor Key: {'%s' L%x T%x K:%x}\n", a.BlockChain, a.KeyLevel, a.KeyType, a.SigningKey))
							}
						}
					}
				}
			case 't' == b[0]:
				if len(b) == 2 && b[1] == 'm' {
					_, _, auth := authKeyLookup(fnodes[listenTo].State.IdentityChainID)
					if auth == nil {
						break
					}
					fullSk := []byte{0x4d, 0xb6, 0xc9}
					fullSk = append(fullSk[:], auth.Sk1[:32]...)
					shadSk := shad(fullSk)
					fullSk = append(fullSk[:], shadSk[:4]...)

					os.Stderr.WriteString(fmt.Sprint("Identity of Current Node Information\n"))
					os.Stderr.WriteString(fmt.Sprintf("Server Salt:   %s\n", fnodes[listenTo].State.Salt.String()[:16]))
					os.Stderr.WriteString(fmt.Sprintf("Root Chain ID: %s\n", fnodes[listenTo].State.IdentityChainID.String()))
					os.Stderr.WriteString(fmt.Sprintf("Sub Chain ID : %s\n", auth.ManageChain))
					os.Stderr.WriteString(fmt.Sprintf("Sk1 Key (hex): %x\n", fullSk))
					os.Stderr.WriteString(fmt.Sprintf("Signing Key (hex): %s\n", fnodes[listenTo].State.SimGetSigKey()))
					p := fnodes[listenTo].State.GetServerPrivateKey()
					str := hex.EncodeToString((p.Key)[:32])
					os.Stderr.WriteString(fmt.Sprintf("Private Key (hex): %s\n", str))

					break
				} else if len(b) == 2 && b[1] == 'c' {
					_, _, auth := authKeyLookup(fnodes[listenTo].State.IdentityChainID)
					if auth == nil {
						break
					}
					wsapiNode = listenTo
					wsapi.SetState(fnodes[wsapiNode].State)
					err := fundWallet(fnodes[listenTo].State, 1e8)
					if err != nil {
						os.Stderr.WriteString(fmt.Sprintf("Error in funding the wallet, %s\n", err.Error()))
						break
					}
					newKey, err := changeSigningKey(fnodes[listenTo].State.IdentityChainID, fnodes[listenTo].State)
					if err != nil {
						os.Stderr.WriteString(fmt.Sprintf("Error: %s\n", err.Error()))
						break
					}
					fnodes[listenTo].State.LocalServerPrivKey = newKey.PrivateKeyString()
					fnodes[listenTo].State.SetPendingSigningKey(newKey)
					os.Stderr.WriteString(fmt.Sprintf("New public key for [%s]: %s\n", fnodes[listenTo].State.IdentityChainID.String()[:8], newKey.Pub.String()))
					break
				}
				index := 0
				if len(b) == 65 {
					hash, err := fnodes[listenTo].State.IdentityChainID.HexToHash(b[1:])
					if err != nil {
						os.Stderr.WriteString(fmt.Sprintf("Error: %s\n", err.Error()))
					} else {
						fnodes[listenTo].State.IdentityChainID = hash
						key, pKey, _ := authKeyLookup(fnodes[listenTo].State.IdentityChainID)
						if len(key) == 64 {
							fnodes[listenTo].State.LocalServerPrivKey = key
							fnodes[listenTo].State.SimSetNewKeys(pKey)
						}
						os.Stderr.WriteString(fmt.Sprintf("Identity of " + fnodes[listenTo].State.GetFactomNodeName() + " changed to [" + hash.String()[:10] + "]\n"))
					}
					break
				} else if len(authKeyLibrary) == 0 {
					os.Stderr.WriteString(fmt.Sprint("There are no available identities in this node. Type 'g1' to claim another identity\n"))
					break
				} else if len(b) > 1 {
					index, err = strconv.Atoi(string(b[1:]))
					if err != nil {
						os.Stderr.WriteString(fmt.Sprint("Incorrect input. bN where N is a number\n"))
						break
					}
				}
				if index >= len(authKeyLibrary) {
					os.Stderr.WriteString(fmt.Sprintf("Identity index out of bounds, only %d in the list.\n", len(authKeyLibrary)))
					break
				}
				if authKeyLibrary[index].Taken == true {
					os.Stderr.WriteString(fmt.Sprintf("Identity %d already taken, taking next available identity in list\n", index))
				}
				for index < len(authKeyLibrary) {
					if authKeyLibrary[index].Taken == false {
						authKeyLibrary[index].Taken = true
						fnodes[listenTo].State.IdentityChainID = authKeyLibrary[index].ChainID
						key, pKey, _ := authKeyLookup(fnodes[listenTo].State.IdentityChainID)
						fnodes[listenTo].State.LocalServerPrivKey = key
						fnodes[listenTo].State.SimSetNewKeys(pKey)
						os.Stderr.WriteString(fmt.Sprintf("Identity of " + fnodes[listenTo].State.GetFactomNodeName() + " changed to [" + authKeyLibrary[index].ChainID.String()[:10] + "]\n"))
						break
					}
					index++
				}
				if index >= len(authKeyLibrary) {
					os.Stderr.WriteString(fmt.Sprint("There are no more available identities in this node. Type 'g1' to claim another identity\n"))
				}
			case 'u' == b[0]:
				os.Stderr.WriteString(fmt.Sprintf("=== Authority List ===  Total: %d Displaying: All\n", len(fnodes[listenTo].State.Authorities)))
				for _, i := range fnodes[listenTo].State.Authorities {
					os.Stderr.WriteString("-------------------------------------------------------------------------------\n")
					var stat string
					switch i.Status {
					case 0:
						stat = "Unassigned"
					case 1:
						stat = "Federated Server"
					case 2:
						stat = "Audit Server"
					case 3:
						stat = "Full"
					case 4:
						stat = "Pending Federated Server"
					case 5:
						stat = "Pending Audit Server"
					case 6:
						stat = "Pending Full"
					case 7:
						stat = "Pending"
					}
					os.Stderr.WriteString(fmt.Sprint("Server Status: ", stat, "\n"))
					os.Stderr.WriteString(fmt.Sprint("Identity Chain: ", i.AuthorityChainID, "\n"))
					os.Stderr.WriteString(fmt.Sprint("Management Chain: ", i.ManagementChainID, "\n"))
					os.Stderr.WriteString(fmt.Sprint("Matryoshka Hash: ", i.MatryoshkaHash, "\n"))
					os.Stderr.WriteString(fmt.Sprint("Signing Key: ", i.SigningKey.String(), "\n"))
					for _, a := range i.AnchorKeys {
						os.Stderr.WriteString(fmt.Sprintf("Anchor Key: {'%s' L%x T%x K:%x}\n", a.BlockChain, a.KeyLevel, a.KeyType, a.SigningKey))
					}
				}
			case 'q' == b[0]:
				eHashes := fnodes[listenTo].State.GetPendingEntries()
				os.Stderr.WriteString("Pending Entry Hash\n")
				os.Stderr.WriteString("------------------\n")
				for _, eh := range eHashes {
					os.Stderr.WriteString(fmt.Sprint(eh.String(), "\n"))
				}
			case 'j' == b[0]:

				fpl := fnodes[listenTo].State.GetPendingTransactions()
				fmt.Println(fpl)
			case 'S' == b[0]:
				nnn, err := strconv.Atoi(string(b[1:]))
				if err != nil || nnn < 0 || nnn > 999 {
					os.Stderr.WriteString("Specifiy a drop amount between 0 and 1000\n")
					break
				}
				for _, fn := range fnodes {
					fn.State.DropRate = nnn
					os.Stderr.WriteString(fmt.Sprintf("Setting drop rate of %10s to %2d.%01d\n", fn.State.FactomNodeName, nnn/10, nnn%10))
				}

			case 'O' == b[0]:
				if listenTo < 0 || listenTo > len(fnodes) {
					os.Stderr.WriteString("No Factom Node selected\n")
					break
				}
				nnn, err := strconv.Atoi(string(b[1:]))
				if err != nil || nnn < 0 || nnn > 999 {
					os.Stderr.WriteString("Specifiy a drop amount between 0 and 1000\n")
					break
				}

				fnodes[listenTo].State.DropRate = nnn
				os.Stderr.WriteString(fmt.Sprintf("Setting drop rate of %10s to %2d.%01d percent\n", fnodes[listenTo].State.FactomNodeName, nnn/10, nnn%10))

			case 'F' == b[0]:
				nn, err := strconv.Atoi(string(b[1:]))
				nnn := int64(nn)
				if err != nil || nnn < 0 || nnn > 99999 {
					os.Stderr.WriteString("Specifiy a delay amount in milliseconds less than 100 seconds\n")
					break
				}

				for _, fn := range fnodes {
					fn.State.Delay = nnn
					os.Stderr.WriteString(fmt.Sprintf("Setting Delay on communications from %10s to %2d.%03d Seconds\n", fn.State.FactomNodeName, nnn/1000, nnn%1000))
				}

				for _, f := range fnodes {
					for _, p := range f.Peers {
						sim, ok := p.(*SimPeer)
						if ok {
							sim.Delay = nnn
						}
					}
				}

			case 'D' == b[0]:
				if listenTo < 0 || listenTo > len(fnodes) {
					os.Stderr.WriteString("No Factom Node selected\n")
					break
				}
				nn, err := strconv.Atoi(string(b[1:]))
				nnn := int64(nn)
				if err != nil || nnn < 0 || nnn > 99999 {
					os.Stderr.WriteString("Specifiy a delay amount in milliseconds less than 100 seconds\n")
					break
				}

				for _, f := range fnodes {
					for _, p := range f.Peers {
						sim, ok := p.(*SimPeer)
						if ok {
							if sim.FromName == fnodes[listenTo].State.FactomNodeName {
								sim.Delay = nnn
							}
						}
					}
				}

				fnodes[listenTo].State.Delay = nnn
				os.Stderr.WriteString(fmt.Sprintf("Setting Delay on communications from %10s to %2d.%03d Seconds\n", fnodes[listenTo].State.FactomNodeName, nnn/1000, nnn%1000))

			case 'h' == b[0]:
				os.Stderr.WriteString("-------------------------------------------------------------------------------\n")
				os.Stderr.WriteString("Vtest         Run the fault test.  Faults 1 to n/2-1 servers. Waits for next block + 60 sec. Repeats.\n")
				os.Stderr.WriteString("nnn           For some number nnn < the number of nodes:  Set focus on that node\n")
				os.Stderr.WriteString("n             increment (with wrap) the node under focus.  i.e. if on 1, focus is set to 2\n")
				os.Stderr.WriteString("Vtest         Run the fault test.  Faults 1 to n/2-1 servers. Waits for next block + 60 sec. Repeats.\n")
				os.Stderr.WriteString("aN            Show Admin block    			 N. Indicate node eg:\"a5\" to shows blocks for that node.\n")
				os.Stderr.WriteString("eN            Show Entry Credit Block   N. Indicate node eg:\"f5\" to shows blocks for that node.\n")
				os.Stderr.WriteString("fN            Show Factoid block  			 N. Indicate node eg:\"f5\" to shows blocks for that node.\n")
				os.Stderr.WriteString("dN            Show Directory block			 N. Indicate node eg:\"d5\" to shows blocks for that node.\n")
				os.Stderr.WriteString("kN.M          Show Entry Block and Chain Head.  N is the directory block, and M is the Entry in that block.\n")
				os.Stderr.WriteString("                 So K3.6 gets the directory block at height 3, and prints the entry at index 6.\n")
				os.Stderr.WriteString("y             Dump what is in the Holding Map.  Can crash, but oh well.\n")
				os.Stderr.WriteString("m             Show Messages as they are passed through the simulator.\n")
				os.Stderr.WriteString("c             Trace the Consensus Process\n")
				os.Stderr.WriteString("s             Show the state of all nodes as their state changes in the simulator.\n")
				os.Stderr.WriteString("p             Show the process lists and directory block states as they change.\n")
				os.Stderr.WriteString("n             Change the focus to the next node.\n")
				os.Stderr.WriteString("l             Make focused node the Leader.\n")
				os.Stderr.WriteString("lt            Attach the next available identity to node and make focused node the Leader.\n")
				os.Stderr.WriteString("z             Attempt to remove focused node as a federated server\n")
				os.Stderr.WriteString("za            Attempt to remove focused node as a audit server\n")
				os.Stderr.WriteString("o             Make focused an audit server.\n")
				os.Stderr.WriteString("x             Take the given node out of the netork or bring an offline node back in.\n")
				os.Stderr.WriteString("w             Point the WSAPI to send API calls to the current node.\n")
				os.Stderr.WriteString("iH            To learn about identity control through simulator.\n")
				os.Stderr.WriteString("gN            Adds 'N' identities to your identity pool. (Cannot add identities already taken)\n")
				os.Stderr.WriteString("tN            Attaches Nth identity in pool to current node. Can also just press 't' to grab the next\n")
				os.Stderr.WriteString("i             Shows the identities being monitored for change.\n")
				os.Stderr.WriteString("u             Shows the current Authorities (federated or audit servers)\n")
				os.Stderr.WriteString("v             Verbose Fault Debug Output\n")
				os.Stderr.WriteString("Vnnn          Set full fault timeout to the given number of seconds. Helps debugging.\n")
				os.Stderr.WriteString("Vtest         Run the fault test.  Faults 1 to n/2-1 servers. Waits for next block + 60 sec. Repeats.\n")
				os.Stderr.WriteString("Vreset        Reset all fnodes in the simulation.\n")
				os.Stderr.WriteString("!             Reset the current node with the focus (i.e. the 'f' by it)\n")
				os.Stderr.WriteString("Snnn          Set Drop Rate to nnn on everyone\n")
				os.Stderr.WriteString("Onnn          Set Drop Rate to nnn on this node\n")
				os.Stderr.WriteString("Dnnn          Set the Delay on messages from the current node to nnn milliseconds\n")
				os.Stderr.WriteString("Fnnn          Set the Delay on messages from all nodes to nnn milliseconds\n")
				os.Stderr.WriteString("/             Toggle the sort order between ChainID and Factom Node Name\n")

				//os.Stderr.WriteString("i[m/b/a][N]   Shows only the Mhash, block signing key, or anchor key up to the Nth identity\n")
				//os.Stderr.WriteString("isN           Shows only Nth identity\n")
				os.Stderr.WriteString("h or <enter>  Show help\n")
				os.Stderr.WriteString("\n")
				os.Stderr.WriteString("Commands are case sensitive.\n")
				os.Stderr.WriteString("-------------------------------------------------------------------------------\n\n")

			default:
			}
		}
	}
}