github.com/luckypickle/go-ethereum-vet@v1.14.2/consensus/ethash/sealer_test.go (about)

     1  package ethash
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  	"math/big"
     7  	"net"
     8  	"net/http"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/luckypickle/go-ethereum-vet/common"
    13  	"github.com/luckypickle/go-ethereum-vet/core/types"
    14  )
    15  
    16  // Tests whether remote HTTP servers are correctly notified of new work.
    17  func TestRemoteNotify(t *testing.T) {
    18  	// Start a simple webserver to capture notifications
    19  	sink := make(chan [3]string)
    20  
    21  	server := &http.Server{
    22  		Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    23  			blob, err := ioutil.ReadAll(req.Body)
    24  			if err != nil {
    25  				t.Fatalf("failed to read miner notification: %v", err)
    26  			}
    27  			var work [3]string
    28  			if err := json.Unmarshal(blob, &work); err != nil {
    29  				t.Fatalf("failed to unmarshal miner notification: %v", err)
    30  			}
    31  			sink <- work
    32  		}),
    33  	}
    34  	// Open a custom listener to extract its local address
    35  	listener, err := net.Listen("tcp", "localhost:0")
    36  	if err != nil {
    37  		t.Fatalf("failed to open notification server: %v", err)
    38  	}
    39  	defer listener.Close()
    40  
    41  	go server.Serve(listener)
    42  
    43  	// Create the custom ethash engine
    44  	ethash := NewTester([]string{"http://" + listener.Addr().String()})
    45  	defer ethash.Close()
    46  
    47  	// Stream a work task and ensure the notification bubbles out
    48  	header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)}
    49  	block := types.NewBlockWithHeader(header)
    50  
    51  	ethash.Seal(nil, block, nil)
    52  	select {
    53  	case work := <-sink:
    54  		if want := header.HashNoNonce().Hex(); work[0] != want {
    55  			t.Errorf("work packet hash mismatch: have %s, want %s", work[0], want)
    56  		}
    57  		if want := common.BytesToHash(SeedHash(header.Number.Uint64())).Hex(); work[1] != want {
    58  			t.Errorf("work packet seed mismatch: have %s, want %s", work[1], want)
    59  		}
    60  		target := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), 256), header.Difficulty)
    61  		if want := common.BytesToHash(target.Bytes()).Hex(); work[2] != want {
    62  			t.Errorf("work packet target mismatch: have %s, want %s", work[2], want)
    63  		}
    64  	case <-time.After(time.Second):
    65  		t.Fatalf("notification timed out")
    66  	}
    67  }
    68  
    69  // Tests that pushing work packages fast to the miner doesn't cause any daa race
    70  // issues in the notifications.
    71  func TestRemoteMultiNotify(t *testing.T) {
    72  	// Start a simple webserver to capture notifications
    73  	sink := make(chan [3]string, 64)
    74  
    75  	server := &http.Server{
    76  		Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
    77  			blob, err := ioutil.ReadAll(req.Body)
    78  			if err != nil {
    79  				t.Fatalf("failed to read miner notification: %v", err)
    80  			}
    81  			var work [3]string
    82  			if err := json.Unmarshal(blob, &work); err != nil {
    83  				t.Fatalf("failed to unmarshal miner notification: %v", err)
    84  			}
    85  			sink <- work
    86  		}),
    87  	}
    88  	// Open a custom listener to extract its local address
    89  	listener, err := net.Listen("tcp", "localhost:0")
    90  	if err != nil {
    91  		t.Fatalf("failed to open notification server: %v", err)
    92  	}
    93  	defer listener.Close()
    94  
    95  	go server.Serve(listener)
    96  
    97  	// Create the custom ethash engine
    98  	ethash := NewTester([]string{"http://" + listener.Addr().String()})
    99  	defer ethash.Close()
   100  
   101  	// Stream a lot of work task and ensure all the notifications bubble out
   102  	for i := 0; i < cap(sink); i++ {
   103  		header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)}
   104  		block := types.NewBlockWithHeader(header)
   105  
   106  		ethash.Seal(nil, block, nil)
   107  	}
   108  	for i := 0; i < cap(sink); i++ {
   109  		select {
   110  		case <-sink:
   111  		case <-time.After(250 * time.Millisecond):
   112  			t.Fatalf("notification %d timed out", i)
   113  		}
   114  	}
   115  }