cmd/geth, consensus/ethash: add support for --miner.notify.full flag (#22558)
The PR implements the --miner.notify.full flag that enables full pending block notifications. When this flag is used, the block notifications sent to mining endpoints contain the complete block header JSON instead of a work package array. Co-authored-by: AlexSSD7 <alexandersadovskyi7@protonmail.com> Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
@ -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)
|
||||
|
Reference in New Issue
Block a user