예제 #1
0
// Validate the message, given the state.  Three possible results:
//  < 0 -- Message is invalid.  Discard
//  0   -- Cannot tell if message is Valid
//  1   -- Message is valid
func (m *DataResponse) Validate(state interfaces.IState) int {
	var dataHash interfaces.IHash
	var err error
	switch m.DataType {
	case 0: // DataType = entry
		dataObject, ok := m.DataObject.(interfaces.IEBEntry)
		if !ok {
			return -1
		}
		dataHash = dataObject.GetHash()
	case 1: // DataType = eblock
		dataObject, ok := m.DataObject.(interfaces.IEntryBlock)
		if !ok {
			return -1
		}
		dataHash, err = dataObject.KeyMR()
		if err != nil {
			return -1
		}
	default:
		// DataType currently not supported, treat as invalid
		return -1
	}

	if dataHash.IsSameAs(m.DataHash) {
		return 1
	}

	return -1
}
예제 #2
0
func (s *State) FetchPaidFor(hash interfaces.IHash) (interfaces.IHash, error) {
	//TODO: expand to search data from outside database
	if hash == nil {
		return nil, nil
	}

	ecBlock := s.ProcessLists.LastList().EntryCreditBlock
	for _, tx := range ecBlock.GetEntries() {
		switch tx.ECID() {
		case entryCreditBlock.ECIDEntryCommit:
			if hash.IsSameAs(tx.(*entryCreditBlock.CommitEntry).EntryHash) {
				return tx.GetSigHash(), nil
			}
			break
		case entryCreditBlock.ECIDChainCommit:
			if hash.IsSameAs(tx.(*entryCreditBlock.CommitChain).EntryHash) {
				return tx.GetSigHash(), nil
			}
			break
		}
	}

	dbase := s.GetAndLockDB()
	defer s.UnlockDB()

	return dbase.FetchPaidFor(hash)
}
예제 #3
0
// Gets the authority matching the identity ChainID.
// Returns the authority and the int of its type:
//		1  ->  Federated
//		0  ->  Audit
// 		-1 ->  Not fed or audit
//		-2 -> Not found
func (st *State) GetAuthority(serverID interfaces.IHash) (*Authority, int) {
	for _, auth := range st.Authorities {
		if serverID.IsSameAs(auth.AuthorityChainID) {
			return auth, auth.Type()
		}
	}
	return nil, -2
}
예제 #4
0
func (c *ECBlock) GetEntryByHash(hash interfaces.IHash) interfaces.IECBlockEntry {
	if hash == nil {
		return nil
	}

	txs := c.GetEntries()
	for _, tx := range txs {
		if hash.IsSameAs(tx.Hash()) {
			return tx
		}
		if hash.IsSameAs(tx.GetSigHash()) {
			return tx
		}
	}
	return nil
}
예제 #5
0
func (c *FBlock) GetTransactionByHash(hash interfaces.IHash) interfaces.ITransaction {
	if hash == nil {
		return nil
	}

	txs := c.GetTransactions()
	for _, tx := range txs {
		if hash.IsSameAs(tx.GetHash()) {
			return tx
		}
		if hash.IsSameAs(tx.GetSigHash()) {
			return tx
		}
	}
	return nil
}
예제 #6
0
func (s *State) FetchEntryByHash(hash interfaces.IHash) (interfaces.IEBEntry, error) {
	//TODO: expand to search data from outside database
	if hash == nil {
		return nil, nil
	}

	pl := s.ProcessLists.LastList()
	keys := pl.GetKeysNewEntries()

	for _, key := range keys {
		tx := pl.GetNewEntry(key)
		if hash.IsSameAs(tx.GetHash()) {
			return tx, nil
		}
	}

	dbase := s.GetAndLockDB()
	defer s.UnlockDB()

	return dbase.FetchEntry(hash)
}
예제 #7
0
// Creates a blank identity
func (st *State) CreateBlankFactomIdentity(chainID interfaces.IHash) int {
	if index := st.isIdentityChain(chainID); index != -1 {
		return index
	}
	var idnew []*Identity
	idnew = make([]*Identity, len(st.Identities)+1)

	var oneID Identity

	for i := 0; i < len(st.Identities); i++ {
		idnew[i] = st.Identities[i]
	}
	oneID.IdentityChainID = chainID

	oneID.Status = constants.IDENTITY_UNASSIGNED
	if chainID.IsSameAs(st.IdentityChainID) {
		oneID.Status = constants.IDENTITY_SELF
	}
	oneID.IdentityRegistered = 0
	oneID.IdentityCreated = 0
	oneID.ManagementRegistered = 0
	oneID.ManagementCreated = 0

	oneID.ManagementChainID = primitives.NewZeroHash()
	oneID.Key1 = primitives.NewZeroHash()
	oneID.Key2 = primitives.NewZeroHash()
	oneID.Key3 = primitives.NewZeroHash()
	oneID.Key4 = primitives.NewZeroHash()
	oneID.MatryoshkaHash = primitives.NewZeroHash()
	oneID.SigningKey = primitives.NewZeroHash()

	idnew[len(st.Identities)] = &oneID

	st.Identities = idnew
	return len(st.Identities) - 1
}
예제 #8
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
}
예제 #9
0
//returns status, proper transaction ID, transaction timestamp, block timestamp, and an error
func (s *State) GetACKStatus(hash interfaces.IHash) (int, interfaces.IHash, interfaces.Timestamp, interfaces.Timestamp, error) {
	pl := s.ProcessLists.LastList()
	m := pl.GetOldMsgs(hash)
	if m != nil || pl.DirectoryBlock == nil {
		return constants.AckStatusACK, hash, m.GetTimestamp(), nil, nil
	}

	ts := pl.DirectoryBlock.GetHeader().GetTimestamp()

	keys := pl.GetKeysNewEntries()
	for _, k := range keys {
		tx := pl.GetNewEntry(k)
		if hash.IsSameAs(tx.GetHash()) {
			return constants.AckStatusACK, hash, nil, ts, nil
		}
	}
	ecBlock := pl.EntryCreditBlock
	if ecBlock != nil {
		tx := ecBlock.GetEntryByHash(hash)
		if tx != nil {
			return constants.AckStatusACK, tx.GetSigHash(), tx.GetTimestamp(), ts, nil
		}
	}
	fBlock := s.FactoidState.GetCurrentBlock()
	if fBlock != nil {
		tx := fBlock.GetTransactionByHash(hash)
		if tx != nil {
			return constants.AckStatusACK, tx.GetSigHash(), tx.GetTimestamp(), ts, nil
		}
	}

	msg := s.GetInvalidMsg(hash)
	if msg != nil {
		return constants.AckStatusInvalid, hash, nil, nil, nil
	}

	in, err := s.DB.FetchIncludedIn(hash)
	if err != nil {
		return 0, hash, nil, nil, err
	}

	if in == nil {
		if s.IsStateFullySynced() {
			return constants.AckStatusNotConfirmed, hash, nil, nil, nil
		} else {
			return constants.AckStatusUnknown, hash, nil, nil, nil
		}
	}

	in2, err := s.DB.FetchIncludedIn(in)
	if err != nil {
		return 0, hash, nil, nil, err
	}

	dBlock, err := s.DB.FetchDBlock(in2)
	if err != nil {
		return 0, hash, nil, nil, err
	}

	fBlock, err = s.DB.FetchFBlock(in)
	if err != nil {
		return 0, hash, nil, nil, err
	}
	if fBlock != nil {
		tx := fBlock.GetTransactionByHash(hash)
		if tx == nil {
			return 0, hash, nil, nil, fmt.Errorf("Transaction not found in a block we were expecting")
		}
		return constants.AckStatusDBlockConfirmed, tx.GetSigHash(), tx.GetTimestamp(), dBlock.GetHeader().GetTimestamp(), nil
	}

	ecBlock, err = s.DB.FetchECBlock(in)
	if err != nil {
		return 0, hash, nil, nil, err
	}
	if ecBlock != nil {
		tx := ecBlock.GetEntryByHash(hash)
		if tx == nil {
			return 0, hash, nil, nil, fmt.Errorf("Transaction not found in a block we were expecting")
		}
		return constants.AckStatusDBlockConfirmed, tx.GetSigHash(), tx.GetTimestamp(), dBlock.GetHeader().GetTimestamp(), nil
	}

	//entries have no timestamp of their own, so return nil

	return constants.AckStatusDBlockConfirmed, hash, nil, dBlock.GetHeader().GetTimestamp(), nil
}
예제 #10
0
func (e *Receipt) Validate() error {
	if e == nil {
		return fmt.Errorf("No receipt provided")
	}
	if e.Entry == nil {
		return fmt.Errorf("Receipt has no entry")
	}
	if e.MerkleBranch == nil {
		return fmt.Errorf("Receipt has no MerkleBranch")
	}
	if e.EntryBlockKeyMR == nil {
		return fmt.Errorf("Receipt has no EntryBlockKeyMR")
	}
	if e.DirectoryBlockKeyMR == nil {
		return fmt.Errorf("Receipt has no DirectoryBlockKeyMR")
	}
	entryHash, err := primitives.NewShaHashFromStr(e.Entry.Key)
	//TODO: validate entry hashes into EntryHash

	if err != nil {
		return err
	}
	var left interfaces.IHash
	var right interfaces.IHash
	var currentEntry interfaces.IHash
	currentEntry = entryHash
	eBlockFound := false
	dBlockFound := false
	for i, node := range e.MerkleBranch {
		if node.Left == nil {
			if node.Right == nil {
				return fmt.Errorf("Node %v/%v has two nil sides", i, len(e.MerkleBranch))
			}
			left = currentEntry
			right = node.Right
		} else {
			left = node.Left
			if node.Right == nil {
				right = currentEntry
			} else {
				right = node.Right
			}
		}
		if left.IsSameAs(currentEntry) == false && left.IsSameAs(currentEntry) {
			return fmt.Errorf("Entry %v not found in node %v/%v", currentEntry, i, len(e.MerkleBranch))
		}
		top := primitives.HashMerkleBranches(left, right)
		if node.Top != nil {
			if top.IsSameAs(node.Top) == false {
				return fmt.Errorf("Derived top %v is not the same as saved top in node %v/%v", top, i, len(e.MerkleBranch))
			}
		}
		if top.IsSameAs(e.EntryBlockKeyMR) == true {
			eBlockFound = true
		}
		if top.IsSameAs(e.DirectoryBlockKeyMR) == true {
			dBlockFound = true
		}
		currentEntry = top
	}

	if eBlockFound == false {
		return fmt.Errorf("EntryBlockKeyMR not found in branch")
	}

	if dBlockFound == false {
		return fmt.Errorf("DirectoryBlockKeyMR not found in branch")
	}

	return nil
}
예제 #11
0
func (st *State) AddIdentityFromChainID(cid interfaces.IHash) error {
	if cid.String() == st.GetNetworkBootStrapIdentity().String() { // Ignore Bootstrap Identity
		return nil
	}

	index := st.isIdentityChain(cid)
	if index == -1 {
		index = st.CreateBlankFactomIdentity(cid)
	}

	managementChain, _ := primitives.HexToHash(MAIN_FACTOM_IDENTITY_LIST)
	dbase := st.GetAndLockDB()
	ents, err := dbase.FetchAllEntriesByChainID(managementChain)
	st.UnlockDB()
	if err != nil {
		return err
	}
	if len(ents) == 0 {
		st.removeIdentity(index)
		return errors.New("Identity Error: No main Main Factom Identity Chain chain created")
	}

	// Check Identity chain
	eblkStackRoot := make([]interfaces.IEntryBlock, 0)
	mr, err := st.DB.FetchHeadIndexByChainID(cid)
	if err != nil {
		return err
	} else if mr == nil {
		st.removeIdentity(index)
		return errors.New("Identity Error: Identity Chain not found")
	}
	for !mr.IsSameAs(primitives.NewZeroHash()) {
		eblk, err := st.DB.FetchEBlock(mr)
		if err != nil || eblk == nil {
			break
		}
		eblkStackRoot = append(eblkStackRoot, eblk)
		mr = eblk.GetHeader().GetPrevKeyMR()
	}

	for i := len(eblkStackRoot) - 1; i >= 0; i-- {
		LoadIdentityByEntryBlock(eblkStackRoot[i], st)
	}

	mr, err = st.DB.FetchHeadIndexByChainID(managementChain)
	if err != nil {
		return err
	}
	// Check Factom Main Identity List
	for !mr.IsSameAs(primitives.NewZeroHash()) {
		eblk, err := st.DB.FetchEBlock(mr)
		if err != nil {
			return err
		}
		if eblk == nil {
			break
		}
		entries := eblk.GetEntryHashes()
		height := eblk.GetDatabaseHeight()
		for _, eHash := range entries {
			hs := eHash.String()
			if hs[0:10] != "0000000000" { //ignore minute markers
				ent, err := st.DB.FetchEntry(eHash)
				if err != nil || ent == nil {
					continue
				}
				if len(ent.ExternalIDs()) > 3 {
					// This is the Register Factom Identity Message
					if len(ent.ExternalIDs()[2]) == 32 {
						idChain := primitives.NewHash(ent.ExternalIDs()[2][:32])
						if string(ent.ExternalIDs()[1]) == "Register Factom Identity" && cid.IsSameAs(idChain) {
							registerFactomIdentity(ent, cid, height, st)
							break // Found the registration
						}
					}
				}
			}
		}
		mr = eblk.GetHeader().GetPrevKeyMR()
	}

	eblkStackSub := make([]interfaces.IEntryBlock, 0)
	if st.Identities[index].ManagementChainID == nil {
		st.removeIdentity(index)
		return errors.New("Identity Error: No management chain found")
	}
	mr, err = st.DB.FetchHeadIndexByChainID(st.Identities[index].ManagementChainID)
	if err != nil {
		return err
	} else if mr == nil {
		st.removeIdentity(index)
		return nil
	}
	for !mr.IsSameAs(primitives.NewZeroHash()) {
		eblk, err := st.DB.FetchEBlock(mr)
		if err != nil {
			break
		}
		eblkStackSub = append(eblkStackSub, eblk)
		mr = eblk.GetHeader().GetPrevKeyMR()
	}
	for i := len(eblkStackSub) - 1; i >= 0; i-- {
		LoadIdentityByEntryBlock(eblkStackSub[i], st)
	}
	err = checkIdentityForFull(index, st)
	if err != nil {
		st.removeIdentity(index)
		return errors.New("Error: Identity not full - " + err.Error())
	}

	return nil
}