// 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 }
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) }
// 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 }
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 }
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 }
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) }
// 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 }
// 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 }
//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 }
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 }
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 }