// Create a new Acknowledgement. Must be called by a leader. This // call assumes all the pieces are in place to create a new acknowledgement func (s *State) NewAck(msg interfaces.IMsg) interfaces.IMsg { vmIndex := msg.GetVMIndex() msg.SetLeaderChainID(s.IdentityChainID) ack := new(messages.Ack) ack.DBHeight = s.LLeaderHeight ack.VMIndex = vmIndex ack.Minute = byte(s.ProcessLists.Get(s.LLeaderHeight).VMs[vmIndex].LeaderMinute) ack.Timestamp = s.GetTimestamp() ack.SaltNumber = s.GetSalt(ack.Timestamp) copy(ack.Salt[:8], s.Salt.Bytes()[:8]) ack.MessageHash = msg.GetMsgHash() ack.LeaderChainID = s.IdentityChainID listlen := len(s.LeaderPL.VMs[vmIndex].List) if listlen == 0 { ack.Height = 0 ack.SerialHash = ack.MessageHash } else { last := s.LeaderPL.GetAckAt(vmIndex, listlen-1) ack.Height = last.Height + 1 ack.SerialHash, _ = primitives.CreateHash(last.MessageHash, ack.MessageHash) } ack.Sign(s) return ack }
func (f *P2PProxy) Send(msg interfaces.IMsg) error { f.logMessage(msg, false) // NODE_TALK_FIX data, err := msg.MarshalBinary() if err != nil { fmt.Println("ERROR on Send: ", err) return err } hash := fmt.Sprintf("%x", msg.GetMsgHash().Bytes()) appType := fmt.Sprintf("%d", msg.Type()) message := factomMessage{message: data, peerHash: msg.GetNetworkOrigin(), appHash: hash, appType: appType} switch { case !msg.IsPeer2Peer(): message.peerHash = p2p.BroadcastFlag f.trace(message.appHash, message.appType, "P2PProxy.Send() - BroadcastFlag", "a") case msg.IsPeer2Peer() && 0 == len(message.peerHash): // directed, with no direction of who to send it to message.peerHash = p2p.RandomPeerFlag f.trace(message.appHash, message.appType, "P2PProxy.Send() - RandomPeerFlag", "a") default: f.trace(message.appHash, message.appType, "P2PProxy.Send() - Addressed by hash", "a") } if msg.IsPeer2Peer() && 1 < f.debugMode { fmt.Printf("%s Sending directed to: %s message: %+v\n", time.Now().String(), message.peerHash, msg.String()) } p2p.BlockFreeChannelSend(f.BroadcastOut, message) return nil }
func (p *P2PProxy) logMessage(msg interfaces.IMsg, received bool) { if 2 < p.debugMode { // if constants.DBSTATE_MSG == msg.Type() { // fmt.Printf("AppMsgLogging: \n Type: %s \n Network Origin: %s \n Message: %s", msg.Type(), msg.GetNetworkOrigin(), msg.String()) // } hash := fmt.Sprintf("%x", msg.GetMsgHash().Bytes()) time := time.Now().Unix() ml := messageLog{hash: hash, received: received, time: time, mtype: msg.Type(), target: msg.GetNetworkOrigin()} p2p.BlockFreeChannelSend(p.logging, ml) } }
// Messages that will go into the Process List must match an Acknowledgement. // The code for this is the same for all such messages, so we put it here. // // Returns true if it finds a match, puts the message in holding, or invalidates the message func (s *State) FollowerExecuteMsg(m interfaces.IMsg) { s.Holding[m.GetMsgHash().Fixed()] = m ack, _ := s.Acks[m.GetMsgHash().Fixed()].(*messages.Ack) if ack != nil { m.SetLeaderChainID(ack.GetLeaderChainID()) m.SetMinute(ack.Minute) pl := s.ProcessLists.Get(ack.DBHeight) pl.AddToProcessList(ack, m) } }
// Messages that will go into the Process List must match an Acknowledgement. // The code for this is the same for all such messages, so we put it here. // // Returns true if it finds a match, puts the message in holding, or invalidates the message func (s *State) FollowerExecuteEOM(m interfaces.IMsg) { if m.IsLocal() { return // This is an internal EOM message. We are not a leader so ignore. } s.Holding[m.GetMsgHash().Fixed()] = m ack, _ := s.Acks[m.GetMsgHash().Fixed()].(*messages.Ack) if ack != nil { pl := s.ProcessLists.Get(ack.DBHeight) pl.AddToProcessList(ack, m) } }
func (s *State) LeaderExecute(m interfaces.IMsg) { _, ok := s.Replay.Valid(constants.INTERNAL_REPLAY, m.GetRepeatHash().Fixed(), m.GetTimestamp(), s.GetTimestamp()) if !ok { delete(s.Holding, m.GetRepeatHash().Fixed()) delete(s.Holding, m.GetMsgHash().Fixed()) return } ack := s.NewAck(m).(*messages.Ack) m.SetLeaderChainID(ack.GetLeaderChainID()) m.SetMinute(ack.Minute) s.ProcessLists.Get(ack.DBHeight).AddToProcessList(ack, m) }
func (s *State) executeMsg(vm *VM, msg interfaces.IMsg) (ret bool) { _, ok := s.Replay.Valid(constants.INTERNAL_REPLAY, msg.GetRepeatHash().Fixed(), msg.GetTimestamp(), s.GetTimestamp()) if !ok { return } s.SetString() msg.ComputeVMIndex(s) switch msg.Validate(s) { case 1: if s.RunLeader && s.Leader && !s.Saving && vm != nil && int(vm.Height) == len(vm.List) && (!s.Syncing || !vm.Synced) && (msg.IsLocal() || msg.GetVMIndex() == s.LeaderVMIndex) && s.LeaderPL.DBHeight+1 >= s.GetHighestKnownBlock() { if len(vm.List) == 0 { s.SendDBSig(s.LLeaderHeight, s.LeaderVMIndex) s.XReview = append(s.XReview, msg) } else { msg.LeaderExecute(s) } } else { msg.FollowerExecute(s) } ret = true case 0: s.Holding[msg.GetMsgHash().Fixed()] = msg default: s.Holding[msg.GetMsgHash().Fixed()] = msg if !msg.SentInvlaid() { msg.MarkSentInvalid(true) s.networkInvalidMsgQueue <- msg } } return }
func (s *State) LeaderExecuteRevealEntry(m interfaces.IMsg) { re := m.(*messages.RevealEntryMsg) eh := re.Entry.GetHash() commit, rtn := re.ValidateRTN(s) switch rtn { case 0: m.FollowerExecute(s) case -1: return } now := s.GetTimestamp() // If we have already recorded a Reveal Entry with this hash in this period, just ignore. if _, v := s.Replay.Valid(constants.REVEAL_REPLAY, eh.Fixed(), s.GetLeaderTimestamp(), now); !v { return } ack := s.NewAck(m).(*messages.Ack) m.SetLeaderChainID(ack.GetLeaderChainID()) m.SetMinute(ack.Minute) // Put the acknowledgement in the Acks so we can tell if AddToProcessList() adds it. s.Acks[m.GetMsgHash().Fixed()] = ack s.ProcessLists.Get(ack.DBHeight).AddToProcessList(ack, m) // If it was added, then get rid of the matching Commit. if s.Acks[m.GetMsgHash().Fixed()] != nil { m.FollowerExecute(s) s.PutCommit(eh, commit) } else { // Okay the Reveal has been recorded. Record this as an entry that cannot be duplicated. s.Replay.IsTSValid_(constants.REVEAL_REPLAY, eh.Fixed(), m.GetTimestamp(), now) delete(s.Commits, eh.Fixed()) } }
func (s *State) FollowerExecuteRevealEntry(m interfaces.IMsg) { s.Holding[m.GetMsgHash().Fixed()] = m ack, _ := s.Acks[m.GetMsgHash().Fixed()].(*messages.Ack) if ack != nil { m.SetLeaderChainID(ack.GetLeaderChainID()) m.SetMinute(ack.Minute) pl := s.ProcessLists.Get(ack.DBHeight) pl.AddToProcessList(ack, m) // If we added the ack, then it will be cleared from the ack map. if s.Acks[m.GetMsgHash().Fixed()] == nil { msg := m.(*messages.RevealEntryMsg) delete(s.Commits, msg.Entry.GetHash().Fixed()) // Okay the Reveal has been recorded. Record this as an entry that cannot be duplicated. s.Replay.IsTSValid_(constants.REVEAL_REPLAY, msg.Entry.GetHash().Fixed(), msg.Timestamp, s.GetTimestamp()) } } }
func (p *ProcessList) AddToProcessList(ack *messages.Ack, m interfaces.IMsg) { if p == nil { return } // We don't check the SaltNumber if this isn't an actual message, i.e. a response from // the past. if !ack.Response && ack.LeaderChainID.IsSameAs(p.State.IdentityChainID) { num := p.State.GetSalt(ack.Timestamp) if num != ack.SaltNumber { os.Stderr.WriteString(fmt.Sprintf("This ChainID %x\n", p.State.IdentityChainID.Bytes())) os.Stderr.WriteString(fmt.Sprintf("This Salt %x\n", p.State.Salt.Bytes()[:8])) os.Stderr.WriteString(fmt.Sprintf("This SaltNumber %x\n for this ack", num)) os.Stderr.WriteString(fmt.Sprintf("Ack ChainID %x\n", ack.LeaderChainID.Bytes())) os.Stderr.WriteString(fmt.Sprintf("Ack Salt %x\n", ack.Salt)) os.Stderr.WriteString(fmt.Sprintf("Ack SaltNumber %x\n for this ack", ack.SaltNumber)) panic("There are two leaders configured with the same Identity in this network! This is a configuration problem!") } } if _, ok := m.(*messages.MissingMsg); ok { panic("This shouldn't happen") } toss := func(hint string) { fmt.Println("dddd TOSS in Process List", p.State.FactomNodeName, hint) fmt.Println("dddd TOSS in Process List", p.State.FactomNodeName, ack.String()) fmt.Println("dddd TOSS in Process List", p.State.FactomNodeName, m.String()) delete(p.State.Holding, ack.GetHash().Fixed()) delete(p.State.Acks, ack.GetHash().Fixed()) } now := p.State.GetTimestamp() vm := p.VMs[ack.VMIndex] if len(vm.List) > int(ack.Height) && vm.List[ack.Height] != nil { _, isNew2 := p.State.Replay.Valid(constants.INTERNAL_REPLAY, m.GetRepeatHash().Fixed(), m.GetTimestamp(), now) if !isNew2 { toss("seen before, or too old") return } } if ack.DBHeight != p.DBHeight { panic(fmt.Sprintf("Ack is wrong height. Expected: %d Ack: %s", p.DBHeight, ack.String())) return } if len(vm.List) > int(ack.Height) && vm.List[ack.Height] != nil { if vm.List[ack.Height].GetMsgHash().IsSameAs(m.GetMsgHash()) { fmt.Printf("dddd %-30s %10s %s\n", "xxxxxxxxx PL Duplicate ", p.State.GetFactomNodeName(), m.String()) fmt.Printf("dddd %-30s %10s %s\n", "xxxxxxxxx PL Duplicate ", p.State.GetFactomNodeName(), ack.String()) fmt.Printf("dddd %-30s %10s %s\n", "xxxxxxxxx PL Duplicate vm", p.State.GetFactomNodeName(), vm.List[ack.Height].String()) fmt.Printf("dddd %-30s %10s %s\n", "xxxxxxxxx PL Duplicate vm", p.State.GetFactomNodeName(), vm.ListAck[ack.Height].String()) toss("2") return } vm.List[ack.Height] = nil return } // From this point on, we consider the transaction recorded. If we detect it has already been // recorded, then we still treat it as if we recorded it. vm.heartBeat = 0 // We have heard from this VM // We have already tested and found m to be a new message. We now record its hashes so later, we // can detect that it has been recorded. We don't care about the results of IsTSValid_ at this point. p.State.Replay.IsTSValid_(constants.INTERNAL_REPLAY, m.GetRepeatHash().Fixed(), m.GetTimestamp(), now) p.State.Replay.IsTSValid_(constants.INTERNAL_REPLAY, m.GetMsgHash().Fixed(), m.GetTimestamp(), now) delete(p.State.Acks, ack.GetHash().Fixed()) delete(p.State.Holding, m.GetMsgHash().Fixed()) // Both the ack and the message hash to the same GetHash() m.SetLocal(false) ack.SetLocal(false) ack.SetPeer2Peer(false) m.SetPeer2Peer(false) ack.SendOut(p.State, ack) m.SendOut(p.State, m) for len(vm.List) <= int(ack.Height) { vm.List = append(vm.List, nil) vm.ListAck = append(vm.ListAck, nil) } p.VMs[ack.VMIndex].List[ack.Height] = m p.VMs[ack.VMIndex].ListAck[ack.Height] = ack p.AddOldMsgs(m) p.OldAcks[m.GetMsgHash().Fixed()] = ack }