github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/host/announce_test.go (about)

     1  package host
     2  
     3  import (
     4  	"bytes"
     5  	"net"
     6  	"testing"
     7  
     8  	"SiaPrime/modules"
     9  	"SiaPrime/types"
    10  )
    11  
    12  // announcementFinder is a quick module that parses the blockchain for host
    13  // announcements, keeping a record of all the announcements that get found.
    14  type announcementFinder struct {
    15  	cs modules.ConsensusSet
    16  
    17  	// Announcements that have been seen. The two slices are wedded.
    18  	netAddresses []modules.NetAddress
    19  	publicKeys   []types.SiaPublicKey
    20  }
    21  
    22  // ProcessConsensusChange receives consensus changes from the consensus set and
    23  // parses them for valid host announcements.
    24  func (af *announcementFinder) ProcessConsensusChange(cc modules.ConsensusChange) {
    25  	for _, block := range cc.AppliedBlocks {
    26  		for _, txn := range block.Transactions {
    27  			for _, arb := range txn.ArbitraryData {
    28  				addr, pubKey, err := modules.DecodeAnnouncement(arb)
    29  				if err == nil {
    30  					af.netAddresses = append(af.netAddresses, addr)
    31  					af.publicKeys = append(af.publicKeys, pubKey)
    32  				}
    33  			}
    34  		}
    35  	}
    36  }
    37  
    38  // Close will shut down the announcement finder.
    39  func (af *announcementFinder) Close() error {
    40  	af.cs.Unsubscribe(af)
    41  	return nil
    42  }
    43  
    44  // newAnnouncementFinder will create and return an announcement finder.
    45  func newAnnouncementFinder(cs modules.ConsensusSet) (*announcementFinder, error) {
    46  	af := &announcementFinder{
    47  		cs: cs,
    48  	}
    49  	err := cs.ConsensusSetSubscribe(af, modules.ConsensusChangeBeginning, nil)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return af, nil
    54  }
    55  
    56  // TestHostAnnounce checks that the host announce function is operating
    57  // correctly.
    58  func TestHostAnnounce(t *testing.T) {
    59  	if testing.Short() {
    60  		t.SkipNow()
    61  	}
    62  	t.Parallel()
    63  	ht, err := newHostTester("TestHostAnnounce")
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	defer ht.Close()
    68  
    69  	// Create an announcement finder to scan the blockchain for host
    70  	// announcements.
    71  	af, err := newAnnouncementFinder(ht.cs)
    72  	if err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	defer af.Close()
    76  
    77  	// Create an announcement, then use the address finding module to scan the
    78  	// blockchain for the host's address.
    79  	err = ht.host.Announce()
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	_, err = ht.miner.AddBlock()
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	if len(af.publicKeys) != 1 {
    88  		t.Fatal("could not find host announcement in blockchain")
    89  	}
    90  	if af.netAddresses[0] != ht.host.autoAddress {
    91  		t.Error("announcement has wrong address")
    92  	}
    93  	if !bytes.Equal(af.publicKeys[0].Key, ht.host.publicKey.Key) {
    94  		t.Error("announcement has wrong host key")
    95  	}
    96  }
    97  
    98  // TestHostAnnounceAddress checks that the host announce address function is
    99  // operating correctly.
   100  func TestHostAnnounceAddress(t *testing.T) {
   101  	if testing.Short() {
   102  		t.SkipNow()
   103  	}
   104  	t.Parallel()
   105  	ht, err := newHostTester("TestHostAnnounceAddress")
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	defer ht.Close()
   110  
   111  	// Create an announcement finder to scan the blockchain for host
   112  	// announcements.
   113  	af, err := newAnnouncementFinder(ht.cs)
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  	defer af.Close()
   118  
   119  	// Create an announcement, then use the address finding module to scan the
   120  	// blockchain for the host's address.
   121  	addr := modules.NetAddress("foo.com:1234")
   122  	err = ht.host.AnnounceAddress(addr)
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	_, err = ht.miner.AddBlock()
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	if len(af.netAddresses) != 1 {
   131  		t.Fatal("could not find host announcement in blockchain")
   132  	}
   133  	if af.netAddresses[0] != addr {
   134  		t.Error("announcement has wrong address")
   135  	}
   136  	if !bytes.Equal(af.publicKeys[0].Key, ht.host.publicKey.Key) {
   137  		t.Error("announcement has wrong host key")
   138  	}
   139  }
   140  
   141  // TestHostAnnounceCheckUnlockHash verifies that the host's unlock hash is
   142  // checked when an announcement is performed.
   143  func TestHostAnnounceCheckUnlockHash(t *testing.T) {
   144  	if testing.Short() {
   145  		t.SkipNow()
   146  	}
   147  	t.Parallel()
   148  	ht, err := newHostTester(t.Name())
   149  	if err != nil {
   150  		t.Fatal(err)
   151  	}
   152  	defer ht.Close()
   153  
   154  	ht.host.mu.RLock()
   155  	oldUnlockHash := ht.host.unlockHash
   156  	ht.host.mu.RUnlock()
   157  
   158  	err = ht.wallet.Reset()
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	err = ht.initWallet()
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  	for i := types.BlockHeight(0); i <= types.MaturityDelay; i++ {
   167  		_, err = ht.miner.AddBlock()
   168  		if err != nil {
   169  			t.Fatal(err)
   170  		}
   171  	}
   172  	err = ht.host.Announce()
   173  	if err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	_, err = ht.miner.AddBlock()
   177  	if err != nil {
   178  		t.Fatal(err)
   179  	}
   180  	ht.host.mu.RLock()
   181  	newUnlockHash := ht.host.unlockHash
   182  	ht.host.mu.RUnlock()
   183  	if newUnlockHash == oldUnlockHash {
   184  		t.Fatal("host did not set a new unlock hash after announce with reset wallet")
   185  	}
   186  	hasAddr := false
   187  	addrs, err := ht.wallet.AllAddresses()
   188  	if err != nil {
   189  		t.Fatal(err)
   190  	}
   191  	for _, addr := range addrs {
   192  		if addr == newUnlockHash {
   193  			hasAddr = true
   194  			break
   195  		}
   196  	}
   197  	if !hasAddr {
   198  		t.Fatal("host unlock has did not exist in wallet")
   199  	}
   200  }
   201  
   202  // TestHostVerifyAnnouncementAddress tests various edge cases of the
   203  // staticVerifyAnnouncementAddress function.
   204  func TestHostVerifyAnnouncementAddress(t *testing.T) {
   205  	ipv4loopback := net.IPv4(127, 0, 0, 1)
   206  	if testing.Short() {
   207  		t.SkipNow()
   208  	}
   209  	// Create custom dependency to test edge cases for various hostnames.
   210  	deps := NewDependencyCustomLookupIP(func(host string) ([]net.IP, error) {
   211  		switch host {
   212  		case "TwoIPv4Loopback.com":
   213  			return []net.IP{ipv4loopback, ipv4loopback}, nil
   214  		case "TwoIPv6Loopback.com":
   215  			return []net.IP{net.IPv6loopback, net.IPv6loopback}, nil
   216  		case "DifferentLoopback.com":
   217  			return []net.IP{ipv4loopback, net.IPv6loopback}, nil
   218  		case "MoreThanTwo.com":
   219  			return []net.IP{{}, {}, {}}, nil
   220  		case "LessThanOne.com":
   221  			return []net.IP{}, nil
   222  		case "OneValidIP.com":
   223  			return []net.IP{{1, 2, 3, 4}}, nil
   224  		case "TwoValidIP.com":
   225  			return []net.IP{{1, 2, 3, 4}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}}, nil
   226  		case "TwoIPSameType.com":
   227  			return []net.IP{{1, 2, 3, 4}, {4, 3, 2, 1}}, nil
   228  		default:
   229  			t.Fatal("shouldn't happen")
   230  		}
   231  		return nil, nil
   232  	})
   233  	// Create host from dependency.
   234  	ht, err := newMockHostTester(deps, t.Name())
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	// Create host addresses.
   239  	host1 := modules.NetAddress("TwoIPv4Loopback.com:1234")
   240  	host2 := modules.NetAddress("TwoIPv6Loopback.com:1234")
   241  	host3 := modules.NetAddress("DifferentLoopback.com:1234")
   242  	host4 := modules.NetAddress("MoreThanTwo.com:1234")
   243  	host5 := modules.NetAddress("LessThanOne.com:1234")
   244  	host6 := modules.NetAddress("OneValidIP.com:1234")
   245  	host7 := modules.NetAddress("TwoValidIP.com:1234")
   246  	host8 := modules.NetAddress("TwoIPSameType.com:1234")
   247  
   248  	// Test individual hosts.
   249  	if err := ht.host.staticVerifyAnnouncementAddress(host1); err == nil {
   250  		t.Error("Announcing host1 should have failed but didn't")
   251  	}
   252  	if err := ht.host.staticVerifyAnnouncementAddress(host2); err == nil {
   253  		t.Error("Announcing host2 should have failed but didn't")
   254  	}
   255  	if err := ht.host.staticVerifyAnnouncementAddress(host3); err != nil {
   256  		t.Error("Announcing host3 shouldn't have failed but did", err)
   257  	}
   258  	if err := ht.host.staticVerifyAnnouncementAddress(host4); err == nil {
   259  		t.Error("Announcing host4 should have failed but didn't")
   260  	}
   261  	if err := ht.host.staticVerifyAnnouncementAddress(host5); err == nil {
   262  		t.Error("Announcing host5 should have failed but didn't")
   263  	}
   264  	if err := ht.host.staticVerifyAnnouncementAddress(host6); err != nil {
   265  		t.Error("Announcing host6 shouldn't have failed but did", err)
   266  	}
   267  	if err := ht.host.staticVerifyAnnouncementAddress(host7); err != nil {
   268  		t.Error("Announcing host7 shouldn't have failed but did", err)
   269  	}
   270  	if err := ht.host.staticVerifyAnnouncementAddress(host8); err == nil {
   271  		t.Error("Announcing host8 should have failed but didn't")
   272  	}
   273  }