gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/hostdb/update.go (about)

     1  package hostdb
     2  
     3  import (
     4  	"time"
     5  
     6  	"gitlab.com/SiaPrime/SiaPrime/build"
     7  	"gitlab.com/SiaPrime/SiaPrime/modules"
     8  	"gitlab.com/SiaPrime/SiaPrime/types"
     9  )
    10  
    11  // findHostAnnouncements returns a list of the host announcements found within
    12  // a given block. No check is made to see that the ip address found in the
    13  // announcement is actually a valid ip address.
    14  func findHostAnnouncements(b types.Block) (announcements []modules.HostDBEntry) {
    15  	for _, t := range b.Transactions {
    16  		// the HostAnnouncement must be prefaced by the standard host
    17  		// announcement string
    18  		for _, arb := range t.ArbitraryData {
    19  			addr, pubKey, err := modules.DecodeAnnouncement(arb)
    20  			if err != nil {
    21  				continue
    22  			}
    23  
    24  			// Add the announcement to the slice being returned.
    25  			var host modules.HostDBEntry
    26  			host.NetAddress = addr
    27  			host.PublicKey = pubKey
    28  			announcements = append(announcements, host)
    29  		}
    30  	}
    31  	return
    32  }
    33  
    34  // insertBlockchainHost adds a host entry to the state. The host will be inserted
    35  // into the set of all hosts, and if it is online and responding to requests it
    36  // will be put into the list of active hosts.
    37  func (hdb *HostDB) insertBlockchainHost(host modules.HostDBEntry) {
    38  	// Remove garbage hosts and local hosts (but allow local hosts in testing).
    39  	if err := host.NetAddress.IsValid(); err != nil {
    40  		hdb.log.Debugf("WARN: host '%v' has an invalid NetAddress: %v", host.NetAddress, err)
    41  		return
    42  	}
    43  	// Ignore all local hosts announced through the blockchain.
    44  	if build.Release == "standard" && host.NetAddress.IsLocal() {
    45  		return
    46  	}
    47  
    48  	// Make sure the host gets into the host tree so it does not get dropped if
    49  	// shutdown occurs before a scan can be performed.
    50  	oldEntry, exists := hdb.hostTree.Select(host.PublicKey)
    51  	if exists {
    52  		// Replace the netaddress with the most recently announced netaddress.
    53  		// Also replace the FirstSeen value with the current block height if
    54  		// the first seen value has been set to zero (no hosts actually have a
    55  		// first seen height of zero, but due to rescans hosts can end up with
    56  		// a zero-value FirstSeen field.
    57  		oldEntry.NetAddress = host.NetAddress
    58  		if oldEntry.FirstSeen == 0 {
    59  			oldEntry.FirstSeen = hdb.blockHeight
    60  		}
    61  		// Resolve the host's used subnets and update the timestamp if they
    62  		// changed. We only update the timestamp if resolving the ipNets was
    63  		// successful.
    64  		ipNets, err := hdb.managedLookupIPNets(oldEntry.NetAddress)
    65  		if err == nil && !equalIPNets(ipNets, oldEntry.IPNets) {
    66  			oldEntry.IPNets = ipNets
    67  			oldEntry.LastIPNetChange = time.Now()
    68  		}
    69  		// Modify hosttree
    70  		err = hdb.modify(oldEntry)
    71  		if err != nil {
    72  			hdb.log.Println("ERROR: unable to modify host entry of host tree after a blockchain scan:", err)
    73  		}
    74  	} else {
    75  		host.FirstSeen = hdb.blockHeight
    76  		// Insert into hosttree
    77  		err := hdb.insert(host)
    78  		if err != nil {
    79  			hdb.log.Println("ERROR: unable to insert host entry into host tree after a blockchain scan:", err)
    80  		}
    81  	}
    82  
    83  	// Add the host to the scan queue.
    84  	hdb.queueScan(host)
    85  }
    86  
    87  // ProcessConsensusChange will be called by the consensus set every time there
    88  // is a change in the blockchain. Updates will always be called in order.
    89  func (hdb *HostDB) ProcessConsensusChange(cc modules.ConsensusChange) {
    90  
    91  	hdb.mu.Lock()
    92  	defer hdb.mu.Unlock()
    93  
    94  	// Update the hostdb's understanding of the block height.
    95  	for _, block := range cc.RevertedBlocks {
    96  		// Only doing the block check if the height is above zero saves hashing
    97  		// and saves a nontrivial amount of time during IBD.
    98  		if hdb.blockHeight > 0 || block.ID() != types.GenesisID {
    99  			hdb.blockHeight--
   100  		} else if hdb.blockHeight != 0 {
   101  			// Sanity check - if the current block is the genesis block, the
   102  			// hostdb height should be set to zero.
   103  			hdb.log.Critical("Hostdb has detected a genesis block, but the height of the hostdb is set to ", hdb.blockHeight)
   104  			hdb.blockHeight = 0
   105  		}
   106  	}
   107  	for _, block := range cc.AppliedBlocks {
   108  		// Only doing the block check if the height is above zero saves hashing
   109  		// and saves a nontrivial amount of time during IBD.
   110  		if hdb.blockHeight > 0 || block.ID() != types.GenesisID {
   111  			hdb.blockHeight++
   112  		} else if hdb.blockHeight != 0 {
   113  			// Sanity check - if the current block is the genesis block, the
   114  			// hostdb height should be set to zero.
   115  			hdb.log.Critical("Hostdb has detected a genesis block, but the height of the hostdb is set to ", hdb.blockHeight)
   116  			hdb.blockHeight = 0
   117  		}
   118  	}
   119  
   120  	// Add hosts announced in blocks that were applied.
   121  	for _, block := range cc.AppliedBlocks {
   122  		for _, host := range findHostAnnouncements(block) {
   123  			hdb.log.Debugln("Found a host in a host announcement:", host.NetAddress, host.PublicKey)
   124  			hdb.insertBlockchainHost(host)
   125  		}
   126  	}
   127  
   128  	hdb.lastChange = cc.ID
   129  }