// Return the number of times we have tripped an ask for this request. func (p *ProcessList) AskDBState(vmIndex int, height int) int { now := p.State.GetTimestamp().GetTimeMilli() r := p.GetRequest(now, vmIndex, height, 60) if now-r.sent >= r.wait*1000+500 { dbstate := messages.NewDBStateMissing(p.State, p.State.LLeaderHeight, p.State.LLeaderHeight+1) dbstate.SendOut(p.State, dbstate) p.State.DBStateAskCnt++ r.sent = now r.requestCnt++ } return r.requestCnt }
// When we process the directory Signature, and we are the leader for said signature, it // is then that we push it out to the rest of the network. Otherwise, if we are not the // leader for the signature, it marks the sig complete for that list func (s *State) ProcessDBSig(dbheight uint32, msg interfaces.IMsg) bool { dbs := msg.(*messages.DirectoryBlockSignature) // Don't process if syncing an EOM if s.Syncing && !s.DBSig { return false } pl := s.ProcessLists.Get(dbheight) vm := s.ProcessLists.Get(dbheight).VMs[msg.GetVMIndex()] if uint32(pl.System.Height) >= dbs.SysHeight { s.DBSigSys = true } // If we are done with DBSigs, and this message is processed, then we are done. Let everything go! if s.DBSigSys && s.DBSig && s.DBSigDone { s.DBSigProcessed-- if s.DBSigProcessed <= 0 { s.DBSig = false s.Syncing = false } vm.Signed = true //s.LeaderPL.AdminBlock return true } // Put the stuff that only executes once at the start of DBSignatures here if !s.DBSig { s.DBSigLimit = len(pl.FedServers) s.DBSigProcessed = 0 s.DBSig = true s.Syncing = true s.DBSigDone = false for _, vm := range pl.VMs { vm.Synced = false } pl.ResetDiffSigTally() } // Put the stuff that executes per DBSignature here if !dbs.Processed { if dbs.VMIndex == 0 { s.SetLeaderTimestamp(dbs.GetTimestamp()) } dbstate := s.GetDBState(dbheight - 1) if dbstate == nil || !dbs.DirectoryBlockHeader.GetBodyMR().IsSameAs(dbstate.DirectoryBlock.GetHeader().GetBodyMR()) { //fmt.Println(s.FactomNodeName, "JUST COMPARED", dbs.DirectoryBlockHeader.GetBodyMR().String()[:10], " : ", dbstate.DirectoryBlock.GetHeader().GetBodyMR().String()[:10]) pl.IncrementDiffSigTally() } // Adds DB Sig to be added to Admin block if passes sig checks allChecks := false data, err := dbs.DirectoryBlockHeader.MarshalBinary() if err != nil { fmt.Println("Debug: DBSig Signature Error, Marshal binary errored") } else { if !dbs.DBSignature.Verify(data) { fmt.Println("Debug: DBSig Signature Error, Verify errored") } else { if valid, err := s.VerifyAuthoritySignature(data, dbs.DBSignature.GetSignature(), dbs.DBHeight); err == nil && valid == 1 { allChecks = true } } } if allChecks { dbs.Matches = true s.AddDBSig(dbheight, dbs.ServerIdentityChainID, dbs.DBSignature) } dbs.Processed = true s.DBSigProcessed++ vm.Synced = true } allfaults := s.LeaderPL.System.Height >= s.LeaderPL.SysHighest // Put the stuff that executes once for set of DBSignatures (after I have them all) here if allfaults && !s.DBSigDone && s.DBSigProcessed >= s.DBSigLimit { fails := 0 for i := range pl.FedServers { vm := pl.VMs[i] tdbsig, ok := vm.List[0].(*messages.DirectoryBlockSignature) if !ok || !tdbsig.Matches { fails++ vm.List[0] = nil vm.Height = 0 s.DBSigProcessed-- } } if fails > len(pl.FedServers)/2 { //s.DoReset() return false } else if fails > 0 { return false } dbstate := s.DBStates.Get(int(dbheight - 1)) // TODO: check signatures here. Count what match and what don't. Then if a majority // disagree with us, null our entry out. Otherwise toss our DBState and ask for one from // our neighbors. if s.KeepMismatch || pl.CheckDiffSigTally() { if !dbstate.Saved { dbstate.ReadyToSave = true s.DBStates.SaveDBStateToDB(dbstate) //s.LeaderPL.AddDBSig(dbs.ServerIdentityChainID, dbs.DBSignature) } } else { s.DBSigFails++ s.Reset() msg := messages.NewDBStateMissing(s, uint32(dbheight-1), uint32(dbheight-1)) if msg != nil { s.RunLeader = false s.StartDelay = s.GetTimestamp().GetTimeMilli() s.NetworkOutMsgQueue() <- msg } } s.ReviewHolding() s.Saving = false s.DBSigDone = true } return false /* err := s.LeaderPL.AdminBlock.AddDBSig(dbs.ServerIdentityChainID, dbs.DBSignature) if err != nil { fmt.Printf("Error in adding DB sig to admin block, %s\n", err.Error()) } */ }
// Once a second at most, we check to see if we need to pull down some blocks to catch up. func (list *DBStateList) Catchup() { now := list.State.GetTimestamp() dbsHeight := list.GetHighestCompletedBlock() // We only check if we need updates once every so often. begin := -1 end := -1 // Find the first range of blocks that we don't have. for i, v := range list.DBStates { if (v == nil || v.DirectoryBlock == nil) && begin < 0 { begin = i } if v == nil { end = i } } if begin > 0 { begin += int(list.Base) end += int(list.Base) } else { plHeight := list.State.GetHighestKnownBlock() // Don't worry about the block initialization case. if plHeight < 1 { list.LastTime = nil return } if plHeight >= dbsHeight && plHeight-dbsHeight > 1 { begin = int(dbsHeight + 1) end = int(plHeight - 1) } else { list.LastTime = nil return } for list.State.ProcessLists.Get(uint32(begin)) != nil && list.State.ProcessLists.Get(uint32(begin)).Complete() { begin++ if uint32(begin) >= plHeight || begin > end { list.LastTime = nil return } } } if begin > 0 { begin-- } end++ // ask for one more, just in case. list.Lastreq = begin end2 := begin + 400 if end < end2 { end2 = end } if list.LastTime != nil && now.GetTimeMilli()-list.LastTime.GetTimeMilli() < list.State.StartDelayLimit/2 { return } if list.LastTime == nil { list.LastTime = now return } list.State.RunLeader = false list.LastTime = now msg := messages.NewDBStateMissing(list.State, uint32(begin), uint32(end2)) if msg != nil { // list.State.RunLeader = false // list.State.StartDelay = list.State.GetTimestamp().GetTimeMilli() msg.SendOut(list.State, msg) msg.SendOut(list.State, msg) msg.SendOut(list.State, msg) list.LastTime = now list.State.DBStateAskCnt++ } }