Example #1
0
// 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
}
Example #2
0
// Create a new Acknowledgement.  This Acknowledgement
func NewAck(state interfaces.IState, hash interfaces.IHash) (iack interfaces.IMsg, err error) {
	var last *Ack
	if state.GetLastAck() != nil {
		last = state.GetLastAck().(*Ack)
	}
	ack := new(Ack)
	ack.Timestamp = state.GetTimestamp()
	ack.MessageHash = hash
	if last == nil {
		ack.Height = 0
		ack.SerialHash = ack.MessageHash
	} else {
		ack.Height = last.Height + 1
		ack.SerialHash, err = primitives.CreateHash(last.MessageHash, ack.MessageHash)
		if err != nil {
			return nil, err
		}
	}

	state.SetLastAck(ack)

	// TODO:  Add the signature.

	return ack, nil
}
Example #3
0
// Return the serial height for this Full Fault message.  Can return nil if there is
// no process list at this dbheight, or if we are missing a preceeding Full Fault message.
func (m *FullServerFault) GetSerialHash() interfaces.IHash {
	if m.SSerialHash == nil {
		sh, err := primitives.CreateHash(m.SSerialHash, m.GetCoreHash())
		if err != nil {
			panic(err.Error())
		}
		m.SSerialHash = sh
	}
	return m.SSerialHash
}
Example #4
0
// Process messages and update our state.
func (p *ProcessList) Process(state *State) (progress bool) {

	dbht := state.GetHighestCompletedBlock()
	if dbht >= p.DBHeight {
		return true
	}

	state.PLProcessHeight = p.DBHeight

	p.AskDBState(0, p.VMs[0].Height) // Look for a possible dbstate at this height.

	if len(p.System.List) > 0 {
	systemloop:
		for i, f := range p.System.List[p.System.Height:] {
			fault, ok := f.(*messages.FullServerFault)

			if ok {
				vm := p.VMs[fault.VMIndex]
				if vm.Height < int(fault.Height) {
					break systemloop
				}
				if !fault.Process(p.DBHeight, p.State) {
					return false
				}
				p.System.Height++
				progress = true
			}
			if fault == nil {
				p.Ask(-1, i, 10, 100)
			}
		}
	}

	for i := 0; i < len(p.FedServers); i++ {
		vm := p.VMs[i]

		if !p.State.Syncing {
			vm.whenFaulted = 0
			p.Unfault()
		} else {
			if !vm.Synced {
				eomFault(p, vm, i, len(vm.List), 0)
			}
		}

		if vm.Height == len(vm.List) && p.State.Syncing && !vm.Synced {
			// means that we are missing an EOM
			p.Ask(i, vm.Height, 0, 1)
		}

		// If we haven't heard anything from a VM, ask for a message at the last-known height
		if vm.Height == len(vm.List) {
			p.Ask(i, vm.Height, 20, 2)
		}

		if vm.whenFaulted > 0 && vm.Height > vm.faultHeight {
			if p.AmINegotiator && i == p.NegotiatorVMIndex {
				p.AmINegotiator = false
			}
			vm.faultHeight = -1
			vm.whenFaulted = 0

			p.Unfault()
		}

	VMListLoop:
		for j := vm.Height; j < len(vm.List); j++ {
			if vm.List[j] == nil {
				p.Ask(i, j, 0, 3)
				break VMListLoop
			}

			thisAck := vm.ListAck[j]

			var expectedSerialHash interfaces.IHash
			var err error

			if vm.Height == 0 {
				expectedSerialHash = thisAck.SerialHash
			} else {
				last := vm.ListAck[vm.Height-1]
				expectedSerialHash, err = primitives.CreateHash(last.MessageHash, thisAck.MessageHash)
				if err != nil {
					p.Ask(i, j, 3, 4)
					break VMListLoop
				}

				// compare the SerialHash of this acknowledgement with the
				// expected serialHash (generated above)
				if !expectedSerialHash.IsSameAs(thisAck.SerialHash) {
					fmt.Printf("dddd %20s %10s --- %10s %10x %10s %10x \n", "Conflict", p.State.FactomNodeName, "expected", expectedSerialHash.Bytes()[:3], "This", thisAck.Bytes()[:3])
					fmt.Printf("dddd Error detected on %s\nSerial Hash failure: Fed Server %d  Leader ID %x List Ht: %d \nDetected on: %s\n",
						state.GetFactomNodeName(),
						i,
						p.FedServers[i].GetChainID().Bytes()[:3],
						j,
						vm.List[j].String())
					fmt.Printf("dddd Last Ack: %6x  Last Serial: %6x\n", last.GetHash().Bytes()[:3], last.SerialHash.Bytes()[:3])
					fmt.Printf("dddd This Ack: %6x  This Serial: %6x\n", thisAck.GetHash().Bytes()[:3], thisAck.SerialHash.Bytes()[:3])
					fmt.Printf("dddd Expected: %6x\n", expectedSerialHash.Bytes()[:3])
					fmt.Printf("dddd The message that didn't work: %s\n\n", vm.List[j].String())
					// the SerialHash of this acknowledgment is incorrect
					// according to this node's processList

					//fault(p, i, 0, vm, 0, j, 2)
					p.State.Reset()
					return
				}
			}

			// So here is the deal.  After we have processed a block, we have to allow the DirectoryBlockSignatures a chance to save
			// to disk.  Then we can insist on having the entry blocks.
			diff := p.DBHeight - state.EntryBlockDBHeightComplete
			_, dbsig := vm.List[j].(*messages.DirectoryBlockSignature)

			// Keep in mind, the process list is processing at a height one greater than the database. 1 is caught up.  2 is one behind.
			// Until the signatures are processed, we will be 2 behind.
			if (dbsig && diff <= 2) || diff <= 1 {
				// If we can't process this entry (i.e. returns false) then we can't process any more.
				p.NextHeightToProcess[i] = j + 1
				if vm.List[j].Process(p.DBHeight, state) { // Try and Process this entry
					vm.heartBeat = 0
					vm.Height = j + 1 // Don't process it again if the process worked.

					//p.Unfault()

					progress = true
				} else {
					break VMListLoop // Don't process further in this list, go to the next.
				}
			} else {
				// If we don't have the Entry Blocks (or we haven't processed the signatures) we can't do more.
				break VMListLoop
			}
		}
	}
	return
}