diff --git a/builder/builder.go b/builder/builder.go index 8a8c82ca5aa6..c4c415c1fe72 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -2,7 +2,9 @@ package builder import ( "errors" + "math/big" _ "os" + "sync" "time" "github.com/ethereum/go-ethereum/common/hexutil" @@ -47,6 +49,10 @@ type Builder struct { builderSecretKey *bls.SecretKey builderPublicKey boostTypes.PublicKey builderSigningDomain boostTypes.Domain + + bestMu sync.Mutex + bestAttrs BuilderPayloadAttributes + bestBlockProfit *big.Int } func NewBuilder(sk *bls.SecretKey, bc IBeaconClient, relay IRelay, builderSigningDomain boostTypes.Domain, eth IEthereumService) *Builder { @@ -63,10 +69,25 @@ func NewBuilder(sk *bls.SecretKey, bc IBeaconClient, relay IRelay, builderSignin builderPublicKey: pk, builderSigningDomain: builderSigningDomain, + bestBlockProfit: big.NewInt(0), } } -func (b *Builder) onSealedBlock(executableData *beacon.ExecutableDataV1, block *types.Block, proposerPubkey boostTypes.PublicKey, proposerFeeRecipient boostTypes.Address, slot uint64) error { +func (b *Builder) onSealedBlock(executableData *beacon.ExecutableDataV1, block *types.Block, proposerPubkey boostTypes.PublicKey, proposerFeeRecipient boostTypes.Address, attrs *BuilderPayloadAttributes) error { + b.bestMu.Lock() + defer b.bestMu.Unlock() + + // Do not submit blocks that don't improve the profit + if b.bestAttrs != *attrs { + b.bestAttrs = *attrs + b.bestBlockProfit.SetInt64(0) + } else { + if block.Profit.Cmp(b.bestBlockProfit) <= 0 { + log.Info("Ignoring block that is not improving the profit") + return nil + } + } + payload, err := executableDataToExecutionPayload(executableData) if err != nil { log.Error("could not format execution payload", "err", err) @@ -81,7 +102,7 @@ func (b *Builder) onSealedBlock(executableData *beacon.ExecutableDataV1, block * } blockBidMsg := boostTypes.BidTrace{ - Slot: slot, + Slot: attrs.Slot, ParentHash: payload.ParentHash, BlockHash: payload.BlockHash, BuilderPubkey: b.builderPublicKey, @@ -110,6 +131,8 @@ func (b *Builder) onSealedBlock(executableData *beacon.ExecutableDataV1, block * return err } + b.bestBlockProfit.Set(block.Profit) + return nil } @@ -150,7 +173,7 @@ func (b *Builder) OnPayloadAttribute(attrs *BuilderPayloadAttributes) error { return errors.New("did not receive the payload") } - err := b.onSealedBlock(executableData, block, proposerPubkey, vd.FeeRecipient, attrs.Slot) + err := b.onSealedBlock(executableData, block, proposerPubkey, vd.FeeRecipient, attrs) if err != nil { log.Error("could not run block hook", "err", err) return err diff --git a/builder/builder_test.go b/builder/builder_test.go index b371a2d52b06..599352ee5222 100644 --- a/builder/builder_test.go +++ b/builder/builder_test.go @@ -122,9 +122,13 @@ func TestOnPayloadAttributes(t *testing.T) { 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 + // Clear the submitted message and check that the job will be ran again and but a new message will not be submitted since the profit is the same testRelay.submittedMsg = nil - time.Sleep(2 * time.Second) + time.Sleep(1200 * time.Millisecond) + require.Nil(t, testRelay.submittedMsg) + + // Up the profit, expect to get the block + testEthService.testBlock.Profit.SetInt64(11) + time.Sleep(1200 * time.Millisecond) require.NotNil(t, testRelay.submittedMsg) - require.Equal(t, expectedMessage, *testRelay.submittedMsg.Message) }