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

     1  package pool
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net"
     8  	"testing"
     9  	"time"
    10  
    11  	"SiaPrime/build"
    12  	"SiaPrime/types"
    13  	"gitlab.com/NebulousLabs/errors"
    14  )
    15  
    16  // TestStratumServer would test before and after a connections is made to the server
    17  func TestStratumServer(t *testing.T) {
    18  	//t.Log("TestStratumServer")
    19  	if !build.POOL {
    20  		return
    21  	}
    22  	pt, err := newPoolTester(t.Name(), 0)
    23  	defer pt.Close()
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	if len(pt.mpool.dispatcher.handlers) != 0 {
    29  		t.Fatal(errors.New(fmt.Sprintf("wrong handler number %d", len(pt.mpool.dispatcher.handlers))))
    30  	}
    31  
    32  	time.Sleep(time.Millisecond * 2)
    33  
    34  	//t.Logf("listening on port: %v\n", pt.mpool.InternalSettings().PoolNetworkPort)
    35  	socket, err := net.Dial("tcp", fmt.Sprintf(":%d", pt.mpool.InternalSettings().PoolNetworkPort))
    36  	if err != nil {
    37  		t.Fatal(err)
    38  	}
    39  
    40  	time.Sleep(time.Millisecond * 2)
    41  
    42  	if len(pt.mpool.dispatcher.handlers) != 1 {
    43  		t.Fatal(errors.New(fmt.Sprintf("wrong handler number %d", len(pt.mpool.dispatcher.handlers))))
    44  	}
    45  
    46  	socket.Close()
    47  
    48  	time.Sleep(time.Millisecond * 2)
    49  	// after connection close, handler should be deleted
    50  	if len(pt.mpool.dispatcher.handlers) != 0 {
    51  		t.Fatal(errors.New(fmt.Sprintf("wrong handler number %d", len(pt.mpool.dispatcher.handlers))))
    52  	}
    53  }
    54  
    55  func createAuthorizeRequest(t *testing.T, port int, waitchan chan int, tID uint64, autoclose bool) net.Conn {
    56  	//fmt.Printf("listening on port: %v\n", pt.mpool.InternalSettings().PoolNetworkPort)
    57  	socket, err := net.DialTimeout("tcp", fmt.Sprintf(":%d", port), 3*time.Second)
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	defer func() {
    62  		if autoclose {
    63  			socket.Close()
    64  		}
    65  		//fmt.Println("Closed socket: ", tID)
    66  	}()
    67  	//fmt.Println("listening successfully")
    68  
    69  	args := []string{fmt.Sprintf("%s.%s", tAddress, tUser), ""}
    70  	params := make([]interface{}, len(args))
    71  	for i, v := range args {
    72  		params[i] = v
    73  	}
    74  	req := types.StratumRequest{Method: "mining.authorize", Params: params, ID: tID}
    75  	rawmsg, err := json.Marshal(req)
    76  	if err != nil {
    77  		t.Fatal(err)
    78  		return nil
    79  	}
    80  	rawmsg = append(rawmsg, []byte("\n")...)
    81  	socket.SetWriteDeadline(time.Now().Add(1 * time.Second))
    82  	if waitchan != nil {
    83  		waitchan <- 2
    84  	}
    85  	_, err = socket.Write(rawmsg)
    86  	if err != nil {
    87  		t.Fatal(err)
    88  		return nil
    89  	} else if waitchan != nil {
    90  		waitchan <- 0
    91  	}
    92  	for {
    93  		//fmt.Printf("Creating NewReader for socket\n")
    94  		reader := bufio.NewReader(socket)
    95  
    96  		//fmt.Printf("Reading from socket\n")
    97  		rawmessage, err := reader.ReadString('\n')
    98  		if err != nil {
    99  			t.Fatal(err)
   100  		}
   101  
   102  		r := types.StratumResponse{}
   103  		err = json.Unmarshal([]byte(rawmessage), &r)
   104  		if err != nil {
   105  			//fmt.Println(string(rawmessage))
   106  			t.Fatal(err)
   107  		}
   108  
   109  		if r.ID == tID {
   110  			break
   111  		} else {
   112  			t.Fatal("got a wrong message: ", rawmessage)
   113  		}
   114  	}
   115  	if waitchan != nil {
   116  		waitchan <- 1
   117  	}
   118  	return socket
   119  }
   120  
   121  func TestStratumAuthorize(t *testing.T) {
   122  	if !build.POOL {
   123  		return
   124  	}
   125  	pt, err := newPoolTester(t.Name(), 0)
   126  	defer pt.Close()
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	time.Sleep(time.Millisecond * 2)
   131  	port := pt.mpool.InternalSettings().PoolNetworkPort
   132  	createAuthorizeRequest(t, port, nil, 123, true)
   133  }
   134  
   135  func TestStratumAuthorizeHeavyLoad(t *testing.T) {
   136  	if !build.POOL {
   137  		return
   138  	}
   139  	pt, err := newPoolTester(t.Name(), 0)
   140  	defer pt.Close()
   141  	if err != nil {
   142  		t.Fatal(err)
   143  	}
   144  	time.Sleep(time.Millisecond * 2)
   145  	port := pt.mpool.InternalSettings().PoolNetworkPort
   146  	// we start getting socket issues when we get into
   147  	// 1000+ - not sure why, but I think the socket buffers
   148  	// may get filled up before we can read them
   149  	num := 100
   150  	numPrepWritten := 0
   151  	numWritten := 0
   152  	numAuthed := 0
   153  	waitchan := make(chan int, num*3)
   154  	for i := 1; i < num+1; i++ {
   155  		go createAuthorizeRequest(t, port, waitchan, uint64(i), true)
   156  		// If we don't sleep for a ms here, we get a deadlock.
   157  		// I'm not sure why.
   158  		time.Sleep(2 * time.Millisecond)
   159  	}
   160  	for {
   161  		select {
   162  		case info := <-waitchan:
   163  			if info == 0 {
   164  				numWritten += 1
   165  			} else if info == 1 {
   166  				numAuthed += 1
   167  			} else if info == 2 {
   168  				numPrepWritten += 1
   169  			}
   170  			//fmt.Printf("Prep Written: %d, Written: %d, Authed: %d, Remaining Connections:  %d, Total Connections Opened: %d\n", numPrepWritten, numWritten, numAuthed, pt.mpool.NumConnections(), pt.mpool.NumConnectionsOpened())
   171  			if numAuthed == num {
   172  				return
   173  			}
   174  		default:
   175  		}
   176  		time.Sleep(2 * time.Millisecond)
   177  	}
   178  }
   179  
   180  func createSubscribeRequest(t *testing.T, socket net.Conn, waitchan chan int, tID uint64, autoclose bool) net.Conn {
   181  	defer func() {
   182  		if autoclose {
   183  			socket.Close()
   184  		}
   185  	}()
   186  
   187  	args := []string{"testminer"}
   188  	params := make([]interface{}, len(args))
   189  	for i, v := range args {
   190  		params[i] = v
   191  	}
   192  	req := types.StratumRequest{Method: "mining.subscribe", Params: params, ID: tID}
   193  	rawmsg, err := json.Marshal(req)
   194  	if err != nil {
   195  		return nil
   196  	}
   197  
   198  	rawmsg = append(rawmsg, []byte("\n")...)
   199  	_, err = socket.Write(rawmsg)
   200  	//fmt.Println("Subscribe write completed: ", tID)
   201  	if err != nil {
   202  		return nil
   203  	}
   204  
   205  	for {
   206  		reader := bufio.NewReader(socket)
   207  
   208  		rawmessage, err := reader.ReadString('\n')
   209  		// fmt.Println(rawmessage)
   210  		if err != nil {
   211  			t.Fatal(err)
   212  		}
   213  
   214  		r := types.StratumResponse{}
   215  		err = json.Unmarshal([]byte(rawmessage), &r)
   216  		if err != nil {
   217  			t.Fatal(err)
   218  		}
   219  		if r.ID == tID {
   220  			//fmt.Printf("MATCH %d: %s\n", r.ID, rawmessage)
   221  			if r.Error != nil {
   222  				rErr := r.Error
   223  				t.Fatal(errors.New(rErr[0].(string)))
   224  			}
   225  			resp := r.Result.([]interface{})
   226  			if len(resp) != 3 {
   227  				t.Fatal(errors.New(fmt.Sprintf("wrong response number %d", len(resp))))
   228  			}
   229  
   230  			break
   231  		} else {
   232  			//fmt.Printf("%d: %s\n", r.ID, rawmessage)
   233  		}
   234  	}
   235  	//fmt.Println("Subscribe completed: ", tID)
   236  	if waitchan != nil {
   237  		waitchan <- 1
   238  	} else {
   239  		//fmt.Println("NOT sending waitchan: ", tID)
   240  	}
   241  	//fmt.Println("waitchan sent: ", tID)
   242  	return socket
   243  	//fmt.Println("exited TestStratumSubscribe")
   244  }
   245  
   246  func TestStratumSubscribe(t *testing.T) {
   247  	//fmt.Println("TestStratumSubscribe")
   248  	if !build.POOL {
   249  		return
   250  	}
   251  	pt, err := newPoolTester(t.Name(), 0)
   252  	defer pt.Close()
   253  	if err != nil {
   254  		t.Fatal(err)
   255  	}
   256  	time.Sleep(time.Millisecond * 2)
   257  	port := pt.mpool.InternalSettings().PoolNetworkPort
   258  	socket := createAuthorizeRequest(t, port, nil, 123, false)
   259  	createSubscribeRequest(t, socket, nil, 123, true)
   260  }
   261  
   262  func TestStratumSubscribeHeavyLoad(t *testing.T) {
   263  	if !build.POOL {
   264  		return
   265  	}
   266  	pt, err := newPoolTester(t.Name(), 0)
   267  	defer pt.Close()
   268  	if err != nil {
   269  		t.Fatal(err)
   270  	}
   271  	time.Sleep(time.Millisecond * 2)
   272  	port := pt.mpool.InternalSettings().PoolNetworkPort
   273  	num := 10
   274  	//numPrepWritten := 0
   275  	//numWritten := 0
   276  	numSubscribed := 0
   277  	waitchan := make(chan int, num*3)
   278  	for i := 1; i < num+1; i++ {
   279  		socket := createAuthorizeRequest(t, port, nil, uint64(i), false)
   280  		go createSubscribeRequest(t, socket, waitchan, uint64(i), true)
   281  		// If we don't sleep for a ms here, we get a deadlock.
   282  		// I'm not sure why.
   283  		time.Sleep(2 * time.Millisecond)
   284  	}
   285  	for {
   286  		select {
   287  		case info := <-waitchan:
   288  			if info == 1 {
   289  				numSubscribed += 1
   290  			}
   291  			//fmt.Printf("Subscribed: %d, Remaining Connections:  %d, Total Connections Opened: %d\n", numSubscribed, pt.mpool.NumConnections(), pt.mpool.NumConnectionsOpened())
   292  			if numSubscribed == num {
   293  				return
   294  			}
   295  		default:
   296  		}
   297  		time.Sleep(2 * time.Millisecond)
   298  	}
   299  }