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:
Felix Lange
2021-03-26 18:30:10 +01:00
committed by GitHub
parent 955727181b
commit cae6b5527e
11 changed files with 171 additions and 39 deletions

View File

@ -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)