diff --git a/cmd/root.go b/cmd/root.go index 41cd73e10c7b68e224776771c31e8cfb1323fbe7..c09275041992074413fa95f5b2a9701cfc74dedb 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -248,6 +248,8 @@ var rootCmd = &cobra.Command{ } fmt.Printf("Received %d\n", receiveCnt) + jww.DEBUG.Printf("Verbose round information: \n%s", + client.GetNetworkInterface().GetVerboseRounds()) err = client.StopNetworkFollower() if err != nil { jww.WARN.Printf( @@ -340,7 +342,8 @@ func printRoundResults(allRoundsSucceeded, timedOut bool, } func createClient() *api.Client { - initLog(viper.GetUint("logLevel"), viper.GetString("log")) + logLevel := viper.GetUint("logLevel") + initLog(logLevel, viper.GetString("log")) jww.INFO.Printf(Version()) pass := viper.GetString("password") @@ -383,6 +386,7 @@ func createClient() *api.Client { netParams.ForceHistoricalRounds = viper.GetBool("forceHistoricalRounds") netParams.FastPolling = !viper.GetBool("slowPolling") netParams.ForceMessagePickupRetry = viper.GetBool("forceMessagePickupRetry") + netParams.VerboseRoundTracking = logLevel > 0 client, err := api.OpenClient(storeDir, []byte(pass), netParams) if err != nil { diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go index 072306fddc18f53c7f07299dcffb52e64cdce853..b0d5351b70e290ec024d5d4d36e72c2eed2f4f1b 100644 --- a/interfaces/networkManager.go +++ b/interfaces/networkManager.go @@ -38,6 +38,9 @@ type NetworkManager interface { // address size is known. GetAddressSize() uint8 + // GetVerboseRounds returns stringification of verbose round info + GetVerboseRounds() string + // RegisterAddressSizeNotification returns a channel that will trigger for // every address space size update. The provided tag is the unique ID for // the channel. Returns an error if the tag is already used. diff --git a/keyExchange/utils_test.go b/keyExchange/utils_test.go index 0a1b0206bc8e72bf3ca25b4dd17e4ce02a5937d1..6acb4a73a6224a0230a32ec3a4b3ccabe3738814 100644 --- a/keyExchange/utils_test.go +++ b/keyExchange/utils_test.go @@ -79,6 +79,8 @@ func (t *testNetworkManagerGeneric) SendUnsafe(m message.Send, p params.Unsafe) return nil, nil } +func (t *testNetworkManagerGeneric) GetVerboseRounds() string { return "" } + func (t *testNetworkManagerGeneric) SendCMIX(message format.Message, rid *id.ID, p params.CMIX) (id.Round, ephemeral.Id, error) { return id.Round(0), ephemeral.Id{}, nil @@ -177,6 +179,8 @@ func (t *testNetworkManagerFullExchange) CheckGarbledMessages() { return } +func (t *testNetworkManagerFullExchange) GetVerboseRounds() string { return "" } + // Intended for alice to send to bob. Trigger's Bob's confirmation, chaining the operation // together func (t *testNetworkManagerFullExchange) SendE2E(message.Send, params.E2E, *stoppable.Single) ( diff --git a/network/ephemeral/testutil.go b/network/ephemeral/testutil.go index 1051e9c297d84a22436a08429f8f023deb953698..634518a1a6ba255fc55b47b092e1ed6b42efe1a7 100644 --- a/network/ephemeral/testutil.go +++ b/network/ephemeral/testutil.go @@ -96,7 +96,8 @@ func (t *testNetworkManager) GetSender() *gateway.Sender { return nil } -func (t *testNetworkManager) GetAddressSize() uint8 { return 15 } +func (t *testNetworkManager) GetAddressSize() uint8 { return 15 } +func (t *testNetworkManager) GetVerboseRounds() string { return "" } func (t *testNetworkManager) RegisterAddressSizeNotification(string) (chan uint8, error) { return nil, nil } diff --git a/network/follow.go b/network/follow.go index 6d3093f4a633df60f5bdbb2cacb2d5ffd9898022..8c8404b88df79c5c5d5e1adf80159f3077a9b737 100644 --- a/network/follow.go +++ b/network/follow.go @@ -56,6 +56,13 @@ func (m *manager) followNetwork(report interfaces.ClientErrorReport, TrackTicker := time.NewTicker(debugTrackPeriod) rng := m.Rng.GetStream() + abandon := func(round id.Round) { return } + if m.verboseRounds != nil { + abandon = func(round id.Round) { + m.verboseRounds.denote(round, Abandoned) + } + } + for { select { case <-stop.Quit(): @@ -63,7 +70,7 @@ func (m *manager) followNetwork(report interfaces.ClientErrorReport, stop.ToStopped() return case <-ticker.C: - m.follow(report, rng, m.Comms, stop) + m.follow(report, rng, m.Comms, stop, abandon) case <-TrackTicker.C: numPolls := atomic.SwapUint64(m.tracker, 0) if m.numLatencies != 0 { @@ -94,7 +101,7 @@ func (m *manager) followNetwork(report interfaces.ClientErrorReport, // executes each iteration of the follower func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, - comms followNetworkComms, stop *stoppable.Single) { + comms followNetworkComms, stop *stoppable.Single, abandon func(round id.Round)) { //Get the identity we will poll for identity, err := m.Session.Reception().GetIdentity(rng, m.addrSpace.GetWithoutWait()) @@ -307,13 +314,12 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, jww.DEBUG.Printf("New Earliest Remaining: %d", earliestRemaining) } -bo roundsWithMessages2 := identity.UR.Iterate(func(rid id.Round) bool { if gwRoundsState.Checked(rid) { return rounds.Checker(rid, filterList, identity.CR) } return false - }, roundsUnknown) + }, roundsUnknown, abandon) for _, rid := range roundsWithMessages { if identity.CR.Check(rid) { @@ -331,4 +337,27 @@ bo for _, rid := range roundsWithMessages2 { m.round.GetMessagesFromRound(rid, identity) } + + if m.verboseRounds != nil { + for i := earliestTrackedRound; i <= earliestRemaining; i++ { + state := Unchecked + for _, rid := range roundsWithMessages { + if rid == i { + state = Checked + } + } + for _, rid := range roundsWithMessages2 { + if rid == i { + state = Checked + } + } + for _, rid := range roundsUnknown { + if rid == i { + state = Unknown + } + } + m.verboseRounds.denote(i, RoundState(state)) + } + } + } diff --git a/network/gateway/hostPool.go b/network/gateway/hostPool.go index e97dd5dd5be2a0b2c2e08737512595b22c71f49d..18122389d048141dbc71fd8d56de62cfbebd1253 100644 --- a/network/gateway/hostPool.go +++ b/network/gateway/hostPool.go @@ -374,7 +374,7 @@ func (h *HostPool) replaceHostNoStore(newId *id.ID, oldPoolIndex uint32) error { go oldHost.Disconnect() } - jww.DEBUG.Printf("Replaced Host at %d [%s] with new Host %s", oldPoolIndex,oldHostIDStr, + jww.DEBUG.Printf("Replaced Host at %d [%s] with new Host %s", oldPoolIndex, oldHostIDStr, newId.String()) return nil diff --git a/network/manager.go b/network/manager.go index e26c455b39c25b594780ef7695f84bf207414b9b..2e53a7a0f12c2a6c73abd42e6ed65e5dce88c0c1 100644 --- a/network/manager.go +++ b/network/manager.go @@ -34,7 +34,7 @@ import ( ) // Manager implements the NetworkManager interface inside context. It -// controls access to network resources and implements all of the communications +// controls access to network resources and implements all the communications // functions used by the client. type manager struct { // parameters of the network @@ -50,9 +50,10 @@ type manager struct { message *message.Manager //number of polls done in a period of time - tracker *uint64 - latencySum uint64 - numLatencies uint64 + tracker *uint64 + latencySum uint64 + numLatencies uint64 + verboseRounds *RoundTracker // Address space size addrSpace *ephemeral.AddressSpace @@ -89,6 +90,10 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard, events: events, } + if params.VerboseRoundTracking { + m.verboseRounds = NewRoundTracker() + } + m.Internal = internal.Internal{ Session: session, Switchboard: switchboard, @@ -223,3 +228,8 @@ func (m *manager) UnregisterAddressSizeNotification(tag string) { func (m *manager) SetPoolFilter(f gateway.Filter) { m.sender.SetFilter(f) } + +// GetVerboseRounds returns verbose round information +func (m *manager) GetVerboseRounds() string { + return m.verboseRounds.String() +} diff --git a/network/roundTracking.go b/network/roundTracking.go new file mode 100644 index 0000000000000000000000000000000000000000..eeeeff42c9b68e76f98a03f48939b3b2331d711e --- /dev/null +++ b/network/roundTracking.go @@ -0,0 +1,73 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2021 Privategrity Corporation / +// / +// All rights reserved. / +//////////////////////////////////////////////////////////////////////////////// + +package network + +import ( + "fmt" + "gitlab.com/xx_network/primitives/id" + "sort" + "sync" +) + +type RoundState uint8 + +const ( + Unchecked = iota + Unknown + Checked + Abandoned +) + +func (rs RoundState) String() string { + switch rs { + case Unchecked: + return "Unchecked" + case Unknown: + return "Unknown" + case Checked: + return "Checked" + case Abandoned: + return "Abandoned" + default: + return fmt.Sprintf("Unregistered Round State: %d", rs) + } +} + +type RoundTracker struct { + state map[id.Round]RoundState + mux sync.Mutex +} + +func NewRoundTracker() *RoundTracker { + return &RoundTracker{ + state: make(map[id.Round]RoundState), + } +} + +func (rt *RoundTracker) denote(rid id.Round, state RoundState) { + rt.mux.Lock() + defer rt.mux.Unlock() + rt.state[rid] = state +} + +func (rt *RoundTracker) String() string { + rt.mux.Lock() + defer rt.mux.Unlock() + keys := make([]int, 0, len(rt.state)) + for key := range rt.state { + keys = append(keys, int(key)) + } + + sort.Ints(keys) + + stringification := "" + for _, key := range keys { + stringification += fmt.Sprintf("Round: %d, state:%s \n", key, rt.state[id.Round(key)]) + } + + return stringification +} diff --git a/storage/rounds/unknownRounds.go b/storage/rounds/unknownRounds.go index 4e061a3c64bfb32f94e674fbf903361dc2bf752b..6fe15191e9eb3cbf535314092046b85f4de7fc86 100644 --- a/storage/rounds/unknownRounds.go +++ b/storage/rounds/unknownRounds.go @@ -198,13 +198,13 @@ func (urs *UnknownRounds) unmarshal(b []byte) error { return json.Unmarshal(b, &urs.rounds) } -func (urs *UnknownRounds) Get(round id.Round)(present bool, numchecked uint64){ +func (urs *UnknownRounds) Get(round id.Round) (present bool, numchecked uint64) { urs.mux.Lock() defer urs.mux.Unlock() numcheck, exist := urs.rounds[round] - if !exist{ + if !exist { return false, 0 } return exist, *numcheck -} \ No newline at end of file +}