aadcb88675
Here we add a beacon chain light client for use by geth. Geth can now be configured to run against a beacon chain API endpoint, without pointing a CL to it. To set this up, use the `--beacon.api` flag. Information provided by the beacon chain is verified, i.e. geth does not blindly trust the beacon API endpoint in this mode. The root of trust are the beacon chain 'sync committees'. The configured beacon API endpoint must provide light client data. At this time, only Lodestar and Nimbus provide the necessary APIs. There is also a standalone tool, cmd/blsync, which uses the beacon chain light client to drive any EL implementation via its engine API. --------- Co-authored-by: Felix Lange <fjl@twurst.com>
159 lines
4.9 KiB
Go
159 lines
4.9 KiB
Go
package request
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/common/mclock"
|
|
)
|
|
|
|
const (
|
|
testRequest = "Life, the Universe, and Everything"
|
|
testResponse = 42
|
|
)
|
|
|
|
var testEventType = &EventType{Name: "testEvent"}
|
|
|
|
func TestServerEvents(t *testing.T) {
|
|
rs := &testRequestServer{}
|
|
clock := &mclock.Simulated{}
|
|
srv := NewServer(rs, clock)
|
|
var lastEventType *EventType
|
|
srv.subscribe(func(event Event) { lastEventType = event.Type })
|
|
evTypeName := func(evType *EventType) string {
|
|
if evType == nil {
|
|
return "none"
|
|
}
|
|
return evType.Name
|
|
}
|
|
expEvent := func(expType *EventType) {
|
|
if lastEventType != expType {
|
|
t.Errorf("Wrong event type (expected %s, got %s)", evTypeName(expType), evTypeName(lastEventType))
|
|
}
|
|
lastEventType = nil
|
|
}
|
|
// user events should simply be passed through
|
|
rs.eventCb(Event{Type: testEventType})
|
|
expEvent(testEventType)
|
|
// send request, soft timeout, then valid response
|
|
srv.sendRequest(testRequest)
|
|
clock.WaitForTimers(1)
|
|
clock.Run(softRequestTimeout)
|
|
expEvent(EvTimeout)
|
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
|
expEvent(EvResponse)
|
|
// send request, hard timeout (response after hard timeout should be ignored)
|
|
srv.sendRequest(testRequest)
|
|
clock.WaitForTimers(1)
|
|
clock.Run(softRequestTimeout)
|
|
expEvent(EvTimeout)
|
|
clock.WaitForTimers(1)
|
|
clock.Run(hardRequestTimeout)
|
|
expEvent(EvFail)
|
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
|
expEvent(nil)
|
|
}
|
|
|
|
func TestServerParallel(t *testing.T) {
|
|
rs := &testRequestServer{}
|
|
srv := NewServer(rs, &mclock.Simulated{})
|
|
srv.subscribe(func(event Event) {})
|
|
|
|
expSend := func(expSent int) {
|
|
var sent int
|
|
for sent <= expSent {
|
|
if !srv.canRequestNow() {
|
|
break
|
|
}
|
|
sent++
|
|
srv.sendRequest(testRequest)
|
|
}
|
|
if sent != expSent {
|
|
t.Errorf("Wrong number of parallel requests accepted (expected %d, got %d)", expSent, sent)
|
|
}
|
|
}
|
|
// max out parallel allowance
|
|
expSend(defaultParallelLimit)
|
|
// 1 answered, should accept 1 more
|
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
|
expSend(1)
|
|
// 2 answered, should accept 2 more
|
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 2, Request: testRequest, Response: testResponse}})
|
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 3, Request: testRequest, Response: testResponse}})
|
|
expSend(2)
|
|
// failed request, should decrease allowance and not accept more
|
|
rs.eventCb(Event{Type: EvFail, Data: RequestResponse{ID: 4, Request: testRequest}})
|
|
expSend(0)
|
|
srv.unsubscribe()
|
|
}
|
|
|
|
func TestServerFail(t *testing.T) {
|
|
rs := &testRequestServer{}
|
|
clock := &mclock.Simulated{}
|
|
srv := NewServer(rs, clock)
|
|
srv.subscribe(func(event Event) {})
|
|
expCanRequest := func(expCanRequest bool) {
|
|
if canRequest := srv.canRequestNow(); canRequest != expCanRequest {
|
|
t.Errorf("Wrong result for canRequestNow (expected %v, got %v)", expCanRequest, canRequest)
|
|
}
|
|
}
|
|
// timed out request
|
|
expCanRequest(true)
|
|
srv.sendRequest(testRequest)
|
|
clock.WaitForTimers(1)
|
|
expCanRequest(true)
|
|
clock.Run(softRequestTimeout)
|
|
expCanRequest(false) // cannot request when there is a timed out request
|
|
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
|
expCanRequest(true)
|
|
// explicit server.Fail
|
|
srv.fail("")
|
|
clock.WaitForTimers(1)
|
|
expCanRequest(false) // cannot request for a while after a failure
|
|
clock.Run(minFailureDelay)
|
|
expCanRequest(true)
|
|
// request returned with EvFail
|
|
srv.sendRequest(testRequest)
|
|
rs.eventCb(Event{Type: EvFail, Data: RequestResponse{ID: 2, Request: testRequest}})
|
|
clock.WaitForTimers(1)
|
|
expCanRequest(false) // EvFail should also start failure delay
|
|
clock.Run(minFailureDelay)
|
|
expCanRequest(false) // second failure delay is longer, should still be disabled
|
|
clock.Run(minFailureDelay)
|
|
expCanRequest(true)
|
|
srv.unsubscribe()
|
|
}
|
|
|
|
func TestServerEventRateLimit(t *testing.T) {
|
|
rs := &testRequestServer{}
|
|
clock := &mclock.Simulated{}
|
|
srv := NewServer(rs, clock)
|
|
var eventCount int
|
|
srv.subscribe(func(event Event) {
|
|
if !event.IsRequestEvent() {
|
|
eventCount++
|
|
}
|
|
})
|
|
expEvents := func(send, expAllowed int) {
|
|
eventCount = 0
|
|
for sent := 0; sent < send; sent++ {
|
|
rs.eventCb(Event{Type: testEventType})
|
|
}
|
|
if eventCount != expAllowed {
|
|
t.Errorf("Wrong number of server events passing rate limitation (sent %d, expected %d, got %d)", send, expAllowed, eventCount)
|
|
}
|
|
}
|
|
expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
|
|
clock.Run(maxServerEventRate)
|
|
expEvents(5, 1)
|
|
clock.Run(maxServerEventRate * maxServerEventBuffer * 2)
|
|
expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
|
|
}
|
|
|
|
type testRequestServer struct {
|
|
eventCb func(Event)
|
|
}
|
|
|
|
func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb }
|
|
func (rs *testRequestServer) SendRequest(ID, Request) {}
|
|
func (rs *testRequestServer) Unsubscribe() {}
|