github.com/nebulouslabs/sia@v1.3.7/modules/host/announce.go (about)

     1  package host
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/NebulousLabs/Sia/build"
     7  	"github.com/NebulousLabs/Sia/modules"
     8  )
     9  
    10  var (
    11  	// errAnnWalletLocked is returned during a host announcement if the wallet
    12  	// is locked.
    13  	errAnnWalletLocked = errors.New("cannot announce the host while the wallet is locked")
    14  
    15  	// errUnknownAddress is returned if the host is unable to determine a
    16  	// public address for itself to use in the announcement.
    17  	errUnknownAddress = errors.New("host cannot announce, does not seem to have a valid address")
    18  )
    19  
    20  // managedAnnounce creates an announcement transaction and submits it to the network.
    21  func (h *Host) managedAnnounce(addr modules.NetAddress) (err error) {
    22  	// The wallet needs to be unlocked to add fees to the transaction, and the
    23  	// host needs to have an active unlock hash that renters can make payment
    24  	// to.
    25  	unlocked, err := h.wallet.Unlocked()
    26  	if err != nil {
    27  		return err
    28  	}
    29  	if !unlocked {
    30  		return errAnnWalletLocked
    31  	}
    32  
    33  	h.mu.Lock()
    34  	pubKey := h.publicKey
    35  	secKey := h.secretKey
    36  	err = h.checkUnlockHash()
    37  	h.mu.Unlock()
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	// Create the announcement that's going to be added to the arbitrary data
    43  	// field of the transaction.
    44  	signedAnnouncement, err := modules.CreateAnnouncement(addr, pubKey, secKey)
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	// Create a transaction, with a fee, that contains the full announcement.
    50  	txnBuilder, err := h.wallet.StartTransaction()
    51  	if err != nil {
    52  		return err
    53  	}
    54  	defer func() {
    55  		if err != nil {
    56  			txnBuilder.Drop()
    57  		}
    58  	}()
    59  	_, fee := h.tpool.FeeEstimation()
    60  	fee = fee.Mul64(600) // Estimated txn size (in bytes) of a host announcement.
    61  	err = txnBuilder.FundSiacoins(fee)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	_ = txnBuilder.AddMinerFee(fee)
    66  	_ = txnBuilder.AddArbitraryData(signedAnnouncement)
    67  	txnSet, err := txnBuilder.Sign(true)
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	// Add the transactions to the transaction pool.
    73  	err = h.tpool.AcceptTransactionSet(txnSet)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	h.mu.Lock()
    79  	h.announced = true
    80  	h.mu.Unlock()
    81  	h.log.Printf("INFO: Successfully announced as %v", addr)
    82  	return nil
    83  }
    84  
    85  // Announce creates a host announcement transaction.
    86  func (h *Host) Announce() error {
    87  	err := h.tg.Add()
    88  	if err != nil {
    89  		return err
    90  	}
    91  	defer h.tg.Done()
    92  
    93  	// Grab the internal net address and internal auto address, and compare
    94  	// them.
    95  	h.mu.RLock()
    96  	userSet := h.settings.NetAddress
    97  	autoSet := h.autoAddress
    98  	h.mu.RUnlock()
    99  
   100  	// Check that we have at least one address to work with.
   101  	if userSet == "" && autoSet == "" {
   102  		return build.ExtendErr("cannot announce because address could not be determined", err)
   103  	}
   104  
   105  	// Prefer using the userSet address, otherwise use the automatic address.
   106  	var annAddr modules.NetAddress
   107  	if userSet != "" {
   108  		annAddr = userSet
   109  	} else {
   110  		annAddr = autoSet
   111  	}
   112  
   113  	// Check that the address is sane, and that the address is also not local.
   114  	err = annAddr.IsStdValid()
   115  	if err != nil {
   116  		return build.ExtendErr("announcement requested with bad net address", err)
   117  	}
   118  	if annAddr.IsLocal() && build.Release != "testing" {
   119  		return errors.New("announcement requested with local net address")
   120  	}
   121  
   122  	// Address has cleared inspection, perform the announcement.
   123  	return h.managedAnnounce(annAddr)
   124  }
   125  
   126  // AnnounceAddress submits a host announcement to the blockchain to announce a
   127  // specific address. If there is no error, the host's address will be updated
   128  // to the supplied address.
   129  func (h *Host) AnnounceAddress(addr modules.NetAddress) error {
   130  	err := h.tg.Add()
   131  	if err != nil {
   132  		return err
   133  	}
   134  	defer h.tg.Done()
   135  
   136  	// Check that the address is sane, and that the address is also not local.
   137  	err = addr.IsStdValid()
   138  	if err != nil {
   139  		return build.ExtendErr("announcement requested with bad net address", err)
   140  	}
   141  	if addr.IsLocal() {
   142  		return errors.New("announcement requested with local net address")
   143  	}
   144  
   145  	// Attempt the actual announcement.
   146  	err = h.managedAnnounce(addr)
   147  	if err != nil {
   148  		return build.ExtendErr("unable to perform manual host announcement", err)
   149  	}
   150  
   151  	// Address is valid, update the host's internal net address to match the
   152  	// specified addr.
   153  	h.mu.Lock()
   154  	h.settings.NetAddress = addr
   155  	h.mu.Unlock()
   156  	return nil
   157  }