// dbheight is the height of the process list, and vmIndex is the vm // that is missing the DBSig. If the DBSig isn't our responsiblity, then // this call will do nothing. Assumes the state for the leader is set properly func (s *State) SendDBSig(dbheight uint32, vmIndex int) { ht := s.GetHighestCompletedBlock() if dbheight <= ht || s.EOM { return } pl := s.ProcessLists.Get(dbheight) vm := pl.VMs[vmIndex] if vm.Height > 0 { return } leader, lvm := pl.GetVirtualServers(vm.LeaderMinute, s.IdentityChainID) if !leader || lvm != vmIndex { return } if !vm.Signed { dbstate := s.DBStates.Get(int(dbheight - 1)) if dbstate == nil && dbheight > 0 { s.SendDBSig(dbheight-1, vmIndex) return } if lvm == vmIndex { if !pl.DBSigAlreadySent { dbs := new(messages.DirectoryBlockSignature) dbs.DirectoryBlockHeader = dbstate.DirectoryBlock.GetHeader() //dbs.DirectoryBlockKeyMR = dbstate.DirectoryBlock.GetKeyMR() dbs.ServerIdentityChainID = s.GetIdentityChainID() dbs.DBHeight = dbheight dbs.Timestamp = s.GetTimestamp() dbs.SetVMHash(nil) dbs.SetVMIndex(vmIndex) dbs.SetLocal(true) dbs.Sign(s) err := dbs.Sign(s) if err != nil { panic(err) } dbs.LeaderExecute(s) vm.Signed = true pl.DBSigAlreadySent = true } else { pl.Ask(vmIndex, 0, 0, 5) } } } }
// TODO: Should fault the server if we don't have the proper sequence of EOM messages. func (s *State) ProcessEOM(dbheight uint32, msg interfaces.IMsg) bool { e := msg.(*messages.EOM) if s.Syncing && !s.EOM { return false } if s.EOM && int(e.Minute) > s.EOMMinute { return false } pl := s.ProcessLists.Get(dbheight) vm := s.ProcessLists.Get(dbheight).VMs[msg.GetVMIndex()] if uint32(pl.System.Height) >= e.SysHeight { s.EOMSys = true } // If I have done everything for all EOMs for all VMs, then and only then do I // let processing continue. if s.EOMDone && s.EOMSys { s.EOMProcessed-- if s.EOMProcessed <= 0 { s.EOM = false s.EOMDone = false s.ReviewHolding() s.Syncing = false } s.SendHeartBeat() return true } // What I do once for all VMs at the beginning of processing a particular EOM if !s.EOM { s.EOMSys = false s.Syncing = true s.EOM = true s.EOMLimit = len(s.LeaderPL.FedServers) s.EOMMinute = int(e.Minute) s.EOMsyncing = true s.EOMProcessed = 0 s.Newblk = false for _, vm := range pl.VMs { vm.Synced = false } s.AddStatus("EOM Syncing") return false } // What I do for each EOM if !e.Processed { vm.LeaderMinute++ s.EOMProcessed++ e.Processed = true vm.Synced = true if s.LeaderPL.SysHighest < int(e.SysHeight) { s.LeaderPL.SysHighest = int(e.SysHeight) } s.AddStatus("EOM Processed") return false } allfaults := s.LeaderPL.System.Height >= s.LeaderPL.SysHighest // After all EOM markers are processed, Claim we are done. Now we can unwind if allfaults && s.EOMProcessed == s.EOMLimit && !s.EOMDone { s.AddStatus("EOM All Done") s.EOMDone = true for _, eb := range pl.NewEBlocks { eb.AddEndOfMinuteMarker(byte(e.Minute + 1)) } s.FactoidState.EndOfPeriod(int(e.Minute)) ecblk := pl.EntryCreditBlock ecbody := ecblk.GetBody() mn := entryCreditBlock.NewMinuteNumber(e.Minute + 1) ecbody.AddEntry(mn) if !s.Leader { s.CurrentMinute = int(e.Minute) } s.CurrentMinute++ switch { case s.CurrentMinute < 10: s.LeaderPL = s.ProcessLists.Get(s.LLeaderHeight) s.Leader, s.LeaderVMIndex = s.LeaderPL.GetVirtualServers(s.CurrentMinute, s.IdentityChainID) case s.CurrentMinute == 10: eBlocks := []interfaces.IEntryBlock{} entries := []interfaces.IEBEntry{} for _, v := range pl.NewEBlocks { eBlocks = append(eBlocks, v) } for _, v := range pl.NewEntries { entries = append(entries, v) } dbstate := s.AddDBState(true, s.LeaderPL.DirectoryBlock, s.LeaderPL.AdminBlock, s.GetFactoidState().GetCurrentBlock(), s.LeaderPL.EntryCreditBlock, eBlocks, entries) if dbstate == nil { dbstate = s.DBStates.Get(int(s.LeaderPL.DirectoryBlock.GetHeader().GetDBHeight())) } dbht := int(dbstate.DirectoryBlock.GetHeader().GetDBHeight()) if dbht > 0 { prev := s.DBStates.Get(dbht - 1) s.DBStates.FixupLinks(prev, dbstate) } s.DBStates.ProcessBlocks(dbstate) s.CurrentMinute = 0 s.LLeaderHeight++ s.LeaderPL = s.ProcessLists.Get(s.LLeaderHeight) s.Leader, s.LeaderVMIndex = s.LeaderPL.GetVirtualServers(0, s.IdentityChainID) s.DBSigProcessed = 0 // Note about dbsigs.... If we processed the previous minute, then we generate the DBSig for the next block. // But if we didn't process the preivious block, like we start from scratch, or we had to reset the entire // network, then no dbsig exists. This code doesn't execute, and so we have no dbsig. In that case, on // the next EOM, we see the block hasn't been signed, and we sign the block (Thats the call to SendDBSig() // above). if s.Leader { dbstate := s.DBStates.Get(int(s.LLeaderHeight - 1)) dbs := new(messages.DirectoryBlockSignature) db := dbstate.DirectoryBlock dbs.DirectoryBlockHeader = db.GetHeader() //dbs.DirectoryBlockKeyMR = dbstate.DirectoryBlock.GetKeyMR() dbs.ServerIdentityChainID = s.GetIdentityChainID() dbs.DBHeight = s.LLeaderHeight dbs.Timestamp = s.GetTimestamp() dbs.SetVMHash(nil) dbs.SetVMIndex(s.LeaderVMIndex) dbs.SetLocal(true) dbs.Sign(s) err := dbs.Sign(s) if err != nil { panic(err) } dbs.LeaderExecute(s) } s.Saving = true } for k := range s.Commits { vs := s.Commits[k] if len(vs) == 0 { delete(s.Commits, k) continue } v, ok := vs[0].(interfaces.IMsg) if ok { _, ok := s.Replay.Valid(constants.TIME_TEST, v.GetRepeatHash().Fixed(), v.GetTimestamp(), s.GetTimestamp()) if !ok { copy(vs, vs[1:]) vs[len(vs)-1] = nil s.Commits[k] = vs[:len(vs)-1] } } } for k := range s.Acks { v := s.Acks[k].(*messages.Ack) if v.DBHeight < s.LLeaderHeight { delete(s.Acks, k) } } } return false }