From 30381d58486a0405b6de0e610a539c52d0340db9 Mon Sep 17 00:00:00 2001 From: Mateusz Morusiewicz <11313015+Ruteri@users.noreply.github.com> Date: Thu, 25 Aug 2022 19:55:18 +0200 Subject: [PATCH] Resubmit block build job periodically (#22) --- builder/builder.go | 25 +++++++++++++---- builder/builder_test.go | 7 +++++ builder/resubmitter.go | 42 ++++++++++++++++++++++++++++ builder/resubmitter_test.go | 56 +++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 builder/resubmitter.go create mode 100644 builder/resubmitter_test.go diff --git a/builder/builder.go b/builder/builder.go index 36ac0d22612b..8a8c82ca5aa6 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -3,6 +3,7 @@ package builder import ( "errors" _ "os" + "time" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/beacon" @@ -41,6 +42,7 @@ type Builder struct { beaconClient IBeaconClient relay IRelay eth IEthereumService + resubmitter Resubmitter builderSecretKey *bls.SecretKey builderPublicKey boostTypes.PublicKey @@ -56,6 +58,7 @@ func NewBuilder(sk *bls.SecretKey, bc IBeaconClient, relay IRelay, builderSignin beaconClient: bc, relay: relay, eth: eth, + resubmitter: Resubmitter{}, builderSecretKey: sk, builderPublicKey: pk, @@ -140,13 +143,23 @@ func (b *Builder) OnPayloadAttribute(attrs *BuilderPayloadAttributes) error { return errors.New("parent block not found in blocktree") } - executableData, block := b.eth.BuildBlock(attrs) - if executableData == nil || block == nil { - log.Error("did not receive the payload") - return errors.New("could not build block") - } + firstBlockResult := b.resubmitter.newTask(12*time.Second, time.Second, func() error { + executableData, block := b.eth.BuildBlock(attrs) + if executableData == nil || block == nil { + log.Error("did not receive the payload") + return errors.New("did not receive the payload") + } + + err := b.onSealedBlock(executableData, block, proposerPubkey, vd.FeeRecipient, attrs.Slot) + if err != nil { + log.Error("could not run block hook", "err", err) + return err + } + + return nil + }) - return b.onSealedBlock(executableData, block, proposerPubkey, vd.FeeRecipient, attrs.Slot) + return firstBlockResult } func executableDataToExecutionPayload(data *beacon.ExecutableDataV1) (*boostTypes.ExecutionPayload, error) { diff --git a/builder/builder_test.go b/builder/builder_test.go index f3df52a1e430..b371a2d52b06 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -3,6 +3,7 @@ package builder import ( "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -120,4 +121,10 @@ func TestOnPayloadAttributes(t *testing.T) { require.Equal(t, expectedSignature, testRelay.submittedMsg.Signature) require.Equal(t, uint64(25), testRelay.requestedSlot) + + // Clear the submitted message and check that the job will be ran again and a new message will be submitted + testRelay.submittedMsg = nil + time.Sleep(2 * time.Second) + require.NotNil(t, testRelay.submittedMsg) + require.Equal(t, expectedMessage, *testRelay.submittedMsg.Message) } diff --git a/builder/resubmitter.go b/builder/resubmitter.go new file mode 100644 index 000000000000..e167badbab20 --- /dev/null +++ b/builder/resubmitter.go @@ -0,0 +1,42 @@ +package builder + +import ( + "context" + "sync" + "time" +) + +type Resubmitter struct { + mu sync.Mutex + cancel context.CancelFunc +} + +func (r *Resubmitter) newTask(repeatFor time.Duration, interval time.Duration, fn func() error) error { + repeatUntilCh := time.After(repeatFor) + + r.mu.Lock() + if r.cancel != nil { + r.cancel() + } + ctx, cancel := context.WithCancel(context.Background()) + r.cancel = cancel + r.mu.Unlock() + + firstRunErr := fn() + + go func() { + for ctx.Err() == nil { + select { + case <-ctx.Done(): + return + case <-repeatUntilCh: + cancel() + return + case <-time.After(interval): + fn() + } + } + }() + + return firstRunErr +} diff --git a/builder/resubmitter_test.go b/builder/resubmitter_test.go new file mode 100644 index 000000000000..516e5c731764 --- /dev/null +++ b/builder/resubmitter_test.go @@ -0,0 +1,56 @@ +package builder + +import ( + "errors" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestResubmitter(t *testing.T) { + + resubmitter := Resubmitter{} + + pingCh := make(chan error) + go func() { + res := resubmitter.newTask(time.Second, 100*time.Millisecond, func() error { + return <-pingCh + }) + require.ErrorContains(t, res, "xx") + }() + + select { + case pingCh <- errors.New("xx"): + case <-time.After(time.Second): + t.Error("timeout waiting for the function") + } + + select { + case pingCh <- nil: + t.Error("function restarted too soon") + default: + } + + time.Sleep(200 * time.Millisecond) + + select { + case pingCh <- nil: + default: + t.Error("function restarted too late") + } + + time.Sleep(800 * time.Millisecond) + + select { + case pingCh <- nil: + default: + t.Error("function restarted too late") + } + + select { + case pingCh <- nil: + t.Error("function restarted after deadline") + case <-time.After(200 * time.Millisecond): + } +}