Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for a minimum amount of time since parent assertion was created to post a new assertion #714

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
30 changes: 22 additions & 8 deletions assertions/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,19 @@
)

type timings struct {
pollInterval time.Duration
confInterval time.Duration
postInterval time.Duration
avgBlockTime time.Duration
pollInterval time.Duration
confInterval time.Duration
postInterval time.Duration
avgBlockTime time.Duration
minGapToParent time.Duration
}

var defaultTimings = timings{
pollInterval: time.Minute,
confInterval: time.Second * 10,
postInterval: time.Hour,
avgBlockTime: time.Second * 12,
pollInterval: time.Minute,
confInterval: time.Second * 10,
postInterval: time.Hour,
avgBlockTime: time.Second * 12,
minGapToParent: time.Minute * 15

Check failure on line 54 in assertions/manager.go

View workflow job for this annotation

GitHub Actions / Build and Test

syntax error: unexpected newline in composite literal; possibly missing comma or }

Check failure on line 54 in assertions/manager.go

View workflow job for this annotation

GitHub Actions / Gosec scan

syntax error: unexpected newline in composite literal; possibly missing comma or }

Check failure on line 54 in assertions/manager.go

View workflow job for this annotation

GitHub Actions / Lint

syntax error: unexpected newline in composite literal; possibly missing comma or } (typecheck)

Check failure on line 54 in assertions/manager.go

View workflow job for this annotation

GitHub Actions / Lint

missing ',' before newline in composite literal (typecheck)

Check failure on line 54 in assertions/manager.go

View workflow job for this annotation

GitHub Actions / Lint

syntax error: unexpected newline in composite literal; possibly missing comma or }) (typecheck)

Check failure on line 54 in assertions/manager.go

View workflow job for this annotation

GitHub Actions / Lint

syntax error: unexpected newline in composite literal; possibly missing comma or }) (typecheck)
rauljordan marked this conversation as resolved.
Show resolved Hide resolved
}

// The Manager struct is responsible for several tasks related to the assertion
Expand Down Expand Up @@ -167,6 +169,18 @@
}
}

// WithMinimumGapToParentAssertion overrides the default minimum gap (in duration)
// to parent assertion creation time.
//
// The minimum gap to parent assertion is used by the assertion manager to wait
// until this much amount of duration is passed since the parent assertion was created
// before posting a new assertion.
func WithMinimumGapToParentAssertion(t time.Duration) Opt {
return func(m *Manager) {
m.times.minGapToParent = t
}
}

// NewManager creates a manager from the required dependencies.
func NewManager(
chain protocol.AssertionChain,
Expand Down
5 changes: 5 additions & 0 deletions assertions/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"

"github.com/offchainlabs/bold/assertions"

Check failure on line 20 in assertions/manager_test.go

View workflow job for this annotation

GitHub Actions / Lint

could not import github.com/offchainlabs/bold/assertions (-: # github.com/offchainlabs/bold/assertions [github.com/offchainlabs/bold/assertions.test]
protocol "github.com/offchainlabs/bold/chain-abstraction"
cm "github.com/offchainlabs/bold/challenge-manager"
"github.com/offchainlabs/bold/challenge-manager/types"
Expand Down Expand Up @@ -123,6 +123,7 @@
types.DefensiveMode,
assertions.WithPollingInterval(time.Millisecond*200),
assertions.WithAverageBlockCreationTime(time.Second),
assertions.WithMinimumGapToParentAssertion(0),
assertions.WithPostingDisabled(),
)
require.NoError(t, err)
Expand Down Expand Up @@ -305,6 +306,7 @@
types.DefensiveMode,
assertions.WithPollingInterval(time.Millisecond*200),
assertions.WithAverageBlockCreationTime(time.Second),
assertions.WithMinimumGapToParentAssertion(0),
assertions.WithPostingDisabled(),
)
require.NoError(t, err)
Expand Down Expand Up @@ -376,6 +378,7 @@
types.ResolveMode,
assertions.WithPollingInterval(time.Millisecond*200),
assertions.WithAverageBlockCreationTime(time.Second),
assertions.WithMinimumGapToParentAssertion(0),
assertions.WithFastConfirmation(),
)
require.NoError(t, err)
Expand Down Expand Up @@ -448,6 +451,7 @@
types.ResolveMode,
assertions.WithPollingInterval(time.Millisecond*200),
assertions.WithAverageBlockCreationTime(time.Second),
assertions.WithMinimumGapToParentAssertion(0),
assertions.WithDangerousReadyToPost(),
assertions.WithPostingDisabled(),
assertions.WithFastConfirmation(),
Expand Down Expand Up @@ -489,6 +493,7 @@
types.ResolveMode,
assertions.WithPollingInterval(time.Millisecond*200),
assertions.WithAverageBlockCreationTime(time.Second),
assertions.WithMinimumGapToParentAssertion(0),
assertions.WithDangerousReadyToPost(),
assertions.WithPostingDisabled(),
assertions.WithFastConfirmation(),
Expand Down
61 changes: 36 additions & 25 deletions assertions/poster.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ package assertions
import (
"context"
"fmt"
"math/big"
"time"

"github.com/ccoveille/go-safecast"
"github.com/pkg/errors"

"github.com/ethereum/go-ethereum/log"
Expand Down Expand Up @@ -37,36 +39,33 @@ func (m *Manager) postAssertionRoutine(ctx context.Context) {
exceedsMaxMempoolSizeEphemeralErrorHandler := ephemeral.NewEphemeralErrorHandler(10*time.Minute, "posting this transaction will exceed max mempool size", 0)

log.Info("Ready to post")
if _, err := m.PostAssertion(ctx); err != nil {
if !errors.Is(err, solimpl.ErrAlreadyExists) {
logLevel := log.Error
logLevel = exceedsMaxMempoolSizeEphemeralErrorHandler.LogLevel(err, logLevel)

logLevel("Could not submit latest assertion to L1", "err", err)
errorPostingAssertionCounter.Inc(1)
}
}
ticker := time.NewTicker(m.times.postInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
_, err := m.PostAssertion(ctx)
if err != nil {
switch {
case errors.Is(err, solimpl.ErrAlreadyExists):
case errors.Is(err, solimpl.ErrBatchNotYetFound):
log.Info("Waiting for more batches to post assertions about them onchain")
default:
logLevel := log.Error
logLevel = exceedsMaxMempoolSizeEphemeralErrorHandler.LogLevel(err, logLevel)

logLevel("Could not submit latest assertion", "err", err, "validatorName", m.validatorName)
errorPostingAssertionCounter.Inc(1)
_, err := m.PostAssertion(ctx)
if err != nil {
switch {
case errors.Is(err, solimpl.ErrAlreadyExists):
case errors.Is(err, solimpl.ErrBatchNotYetFound):
log.Info("Waiting for more batches to post assertions about them onchain")
default:
logLevel := log.Error
logLevel = exceedsMaxMempoolSizeEphemeralErrorHandler.LogLevel(err, logLevel)

logLevel("Could not submit latest assertion", "err", err, "validatorName", m.validatorName)
errorPostingAssertionCounter.Inc(1)

if ctx.Err() != nil {
return
}
} else {
exceedsMaxMempoolSizeEphemeralErrorHandler.Reset()
continue // We retry again in case of a non ctx error
}
} else {
exceedsMaxMempoolSizeEphemeralErrorHandler.Reset()
}

select {
case <-ticker.C:
case <-ctx.Done():
return
}
Expand Down Expand Up @@ -140,6 +139,18 @@ func (m *Manager) PostAssertionBasedOnParent(
) (protocol.Assertion, error),
) (option.Option[*protocol.AssertionCreatedInfo], error) {
none := option.None[*protocol.AssertionCreatedInfo]()
if m.times.minGapToParent != 0 {
ganeshvanahalli marked this conversation as resolved.
Show resolved Hide resolved
parentCreationBlock, err := m.backend.HeaderByNumber(ctx, new(big.Int).SetUint64(parentCreationInfo.CreationBlock))
if err != nil {
return none, fmt.Errorf("error getting parent assertion creation block header: %w", err)
}
parentCreationTime, err := safecast.ToInt64(parentCreationBlock.Time)
if err != nil {
return none, fmt.Errorf("error casting parent assertion creation time to int64: %w", err)
}
targetTime := time.Unix(parentCreationTime, 0).Add(m.times.minGapToParent)
time.Sleep(time.Until(targetTime))
}
if !parentCreationInfo.InboxMaxCount.IsUint64() {
return none, errors.New("inbox max count not a uint64")
}
Expand Down
4 changes: 4 additions & 0 deletions assertions/poster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,17 @@ func TestPostAssertion(t *testing.T) {
stateManager, err := statemanager.NewForSimpleMachine(t, stateManagerOpts...)
require.NoError(t, err)

// Set MinimumGapToBlockCreationTime as 1 second to verify that a new assertion is only posted after 1 sec has passed
// from parent assertion creation. This will make the test run for ~19 seconds as the parent assertion time is
// ~18 seconds in the future
assertionManager, err := assertions.NewManager(
aliceChain,
stateManager,
"alice",
types.DefensiveMode,
assertions.WithPollingInterval(time.Millisecond*200),
assertions.WithAverageBlockCreationTime(time.Second),
assertions.WithMinimumGapToParentAssertion(time.Second),
)
require.NoError(t, err)

Expand Down
11 changes: 11 additions & 0 deletions challenge-manager/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"github.com/offchainlabs/bold/api/backend"
"github.com/offchainlabs/bold/api/db"
"github.com/offchainlabs/bold/api/server"
"github.com/offchainlabs/bold/assertions"

Check failure on line 17 in challenge-manager/stack.go

View workflow job for this annotation

GitHub Actions / Lint

could not import github.com/offchainlabs/bold/assertions (-: # github.com/offchainlabs/bold/assertions
protocol "github.com/offchainlabs/bold/chain-abstraction"
watcher "github.com/offchainlabs/bold/challenge-manager/chain-watcher"
"github.com/offchainlabs/bold/challenge-manager/types"
Expand All @@ -28,6 +28,7 @@
postInterval time.Duration
confInterval time.Duration
avgBlockTime time.Duration
minGapToParent time.Duration
trackChallengeParentAssertionHashes []protocol.AssertionHash
apiAddr string
apiDBPath string
Expand All @@ -44,6 +45,7 @@
postInterval: time.Hour,
confInterval: time.Second * 10,
avgBlockTime: time.Second * 12,
minGapToParent: time.Minute * 10,
trackChallengeParentAssertionHashes: nil,
apiAddr: "",
apiDBPath: "",
Expand Down Expand Up @@ -100,6 +102,14 @@
}
}

// StackWithMinimumGapToParentAssertion sets the minimum gap to parent assertion creation time
// of the challenge manager.
func StackWithMinimumGapToParentAssertion(interval time.Duration) StackOpt {
return func(p *stackParams) {
p.minGapToParent = interval
}
}

// WithTrackChallengeParentAssertionHashes sets the track challenge parent
// assertion hashes of the challenge manager.
func StackWithTrackChallengeParentAssertionHashes(hashes []string) StackOpt {
Expand Down Expand Up @@ -211,6 +221,7 @@
assertions.WithConfirmationInterval(params.confInterval),
assertions.WithPollingInterval(params.pollInterval),
assertions.WithPostingInterval(params.postInterval),
assertions.WithMinimumGapToParentAssertion(params.minGapToParent),
}
if apiDB != nil {
amOpts = append(amOpts, assertions.WithAPIDB(apiDB))
Expand Down
1 change: 1 addition & 0 deletions testing/endtoend/e2e_crash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func TestEndToEnd_HonestValidatorCrashes(t *testing.T) {
cm.StackWithPostingInterval(timeCfg.assertionPostingInterval),
cm.StackWithAverageBlockCreationTime(timeCfg.blockTime),
cm.StackWithConfirmationInterval(timeCfg.assertionConfirmationAttemptInterval),
cm.StackWithMinimumGapToParentAssertion(0),
cm.StackWithHeaderProvider(shp),
}

Expand Down
1 change: 1 addition & 0 deletions testing/endtoend/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ func runEndToEndTest(t *testing.T, cfg *e2eConfig) {
cm.StackWithPostingInterval(cfg.timings.assertionPostingInterval),
cm.StackWithAverageBlockCreationTime(cfg.timings.blockTime),
cm.StackWithConfirmationInterval(cfg.timings.assertionConfirmationAttemptInterval),
cm.StackWithMinimumGapToParentAssertion(0),
cm.StackWithHeaderProvider(shp),
}

Expand Down
Loading