|
|
@@ -22,6 +22,7 @@ import (
|
|
|
"math/big"
|
|
|
"net/http"
|
|
|
"net/http/httptest"
|
|
|
+ "strconv"
|
|
|
"testing"
|
|
|
"time"
|
|
|
|
|
|
@@ -74,6 +75,50 @@ func TestRemoteNotify(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// Tests whether remote HTTP servers are correctly notified of new work. (Full pending block body / --miner.notify.full)
|
|
|
+func TestRemoteNotifyFull(t *testing.T) {
|
|
|
+ // Start a simple web server to capture notifications.
|
|
|
+ sink := make(chan map[string]interface{})
|
|
|
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
|
+ blob, err := ioutil.ReadAll(req.Body)
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("failed to read miner notification: %v", err)
|
|
|
+ }
|
|
|
+ var work map[string]interface{}
|
|
|
+ if err := json.Unmarshal(blob, &work); err != nil {
|
|
|
+ t.Errorf("failed to unmarshal miner notification: %v", err)
|
|
|
+ }
|
|
|
+ sink <- work
|
|
|
+ }))
|
|
|
+ defer server.Close()
|
|
|
+
|
|
|
+ // Create the custom ethash engine.
|
|
|
+ config := Config{
|
|
|
+ PowMode: ModeTest,
|
|
|
+ NotifyFull: true,
|
|
|
+ Log: testlog.Logger(t, log.LvlWarn),
|
|
|
+ }
|
|
|
+ ethash := New(config, []string{server.URL}, false)
|
|
|
+ defer ethash.Close()
|
|
|
+
|
|
|
+ // Stream a work task and ensure the notification bubbles out.
|
|
|
+ header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)}
|
|
|
+ block := types.NewBlockWithHeader(header)
|
|
|
+
|
|
|
+ ethash.Seal(nil, block, nil, nil)
|
|
|
+ select {
|
|
|
+ case work := <-sink:
|
|
|
+ if want := "0x" + strconv.FormatUint(header.Number.Uint64(), 16); work["number"] != want {
|
|
|
+ t.Errorf("pending block number mismatch: have %v, want %v", work["number"], want)
|
|
|
+ }
|
|
|
+ if want := "0x" + header.Difficulty.Text(16); work["difficulty"] != want {
|
|
|
+ t.Errorf("pending block difficulty mismatch: have %s, want %s", work["difficulty"], want)
|
|
|
+ }
|
|
|
+ case <-time.After(3 * time.Second):
|
|
|
+ t.Fatalf("notification timed out")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// Tests that pushing work packages fast to the miner doesn't cause any data race
|
|
|
// issues in the notifications.
|
|
|
func TestRemoteMultiNotify(t *testing.T) {
|
|
|
@@ -119,6 +164,55 @@ func TestRemoteMultiNotify(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// Tests that pushing work packages fast to the miner doesn't cause any data race
|
|
|
+// issues in the notifications. Full pending block body / --miner.notify.full)
|
|
|
+func TestRemoteMultiNotifyFull(t *testing.T) {
|
|
|
+ // Start a simple web server to capture notifications.
|
|
|
+ sink := make(chan map[string]interface{}, 64)
|
|
|
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
|
+ blob, err := ioutil.ReadAll(req.Body)
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("failed to read miner notification: %v", err)
|
|
|
+ }
|
|
|
+ var work map[string]interface{}
|
|
|
+ if err := json.Unmarshal(blob, &work); err != nil {
|
|
|
+ t.Errorf("failed to unmarshal miner notification: %v", err)
|
|
|
+ }
|
|
|
+ sink <- work
|
|
|
+ }))
|
|
|
+ defer server.Close()
|
|
|
+
|
|
|
+ // Create the custom ethash engine.
|
|
|
+ config := Config{
|
|
|
+ PowMode: ModeTest,
|
|
|
+ NotifyFull: true,
|
|
|
+ Log: testlog.Logger(t, log.LvlWarn),
|
|
|
+ }
|
|
|
+ ethash := New(config, []string{server.URL}, false)
|
|
|
+ defer ethash.Close()
|
|
|
+
|
|
|
+ // Provide a results reader.
|
|
|
+ // Otherwise the unread results will be logged asynchronously
|
|
|
+ // and this can happen after the test is finished, causing a panic.
|
|
|
+ results := make(chan *types.Block, cap(sink))
|
|
|
+
|
|
|
+ // Stream a lot of work task and ensure all the notifications bubble out.
|
|
|
+ for i := 0; i < cap(sink); i++ {
|
|
|
+ header := &types.Header{Number: big.NewInt(int64(i)), Difficulty: big.NewInt(100)}
|
|
|
+ block := types.NewBlockWithHeader(header)
|
|
|
+ ethash.Seal(nil, block, results, nil)
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 0; i < cap(sink); i++ {
|
|
|
+ select {
|
|
|
+ case <-sink:
|
|
|
+ <-results
|
|
|
+ case <-time.After(10 * time.Second):
|
|
|
+ t.Fatalf("notification %d timed out", i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// Tests whether stale solutions are correctly processed.
|
|
|
func TestStaleSubmission(t *testing.T) {
|
|
|
ethash := NewTester(nil, true)
|