Skip to content

Commit

Permalink
chore(halo/voter): attest to multiple versions (omni-network#1129)
Browse files Browse the repository at this point in the history
Add `ConfFinalized` as a confirmation level for all chains. This ensure
we attest to all chains either once (if `ConfFinalized`) or twice if
(`ConfFuzzy`).

Note this only affects halo voter and attest module. Relayer only
streams the expected conf level at this point.

Update `ForkProxy` to support custom `--slots-in-an-epoch` to speed up
finalization from 64 blocks (+1min) to 12sec.

task: none
  • Loading branch information
corverroos authored May 28, 2024
1 parent 9143287 commit 07620ef
Show file tree
Hide file tree
Showing 14 changed files with 83 additions and 49 deletions.
2 changes: 2 additions & 0 deletions e2e/docker/compose.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ services:
container_name: {{ .Chain.Name }}
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID={{ .Chain.ChainID }}
- FORKPROXY_BLOCK_TIME={{.Chain.BlockPeriod.Seconds}}
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod
{{ if .LoadState }}- FORKPROXY_LOAD_STATE=/anvil/state.json{{ end }}
ports:
- {{ if .ProxyPort }}{{ .ProxyPort }}:{{ end }}8545
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ services:
container_name: mock_rollup
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=99
- FORKPROXY_BLOCK_TIME=1
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod

ports:
- 9000:8545
Expand All @@ -48,9 +50,11 @@ services:
container_name: mock_l1
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=1
- FORKPROXY_BLOCK_TIME=3600
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod
- FORKPROXY_LOAD_STATE=/anvil/state.json
ports:
- 9000:8545
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ services:
container_name: mock_rollup
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=99
- FORKPROXY_BLOCK_TIME=1
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod

ports:
- 9000:8545
Expand All @@ -48,9 +50,11 @@ services:
container_name: mock_l1
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=1
- FORKPROXY_BLOCK_TIME=3600
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod
- FORKPROXY_LOAD_STATE=/anvil/state.json
ports:
- 9000:8545
Expand Down
4 changes: 4 additions & 0 deletions e2e/docker/testdata/TestComposeTemplate_main_explorer.golden
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ services:
container_name: mock_rollup
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=99
- FORKPROXY_BLOCK_TIME=1
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod

ports:
- 9000:8545
Expand All @@ -48,9 +50,11 @@ services:
container_name: mock_l1
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=1
- FORKPROXY_BLOCK_TIME=3600
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod
- FORKPROXY_LOAD_STATE=/anvil/state.json
ports:
- 9000:8545
Expand Down
44 changes: 27 additions & 17 deletions e2e/forkproxy/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@ import (
"golang.org/x/sync/errgroup"
)

const (
FinalizeDepth = 20
MaxForkDepth = FinalizeDepth / 2
)

type Config struct {
ListenAddr string
ChainID uint64
LoadState string
BlockTimeSecs uint64
Silent bool
EnableForking bool
SlotsInEpoch uint64
}

func (c Config) FinalizeDepth() uint64 {
return c.SlotsInEpoch * 2
}

func (c Config) MaxForkDepth() uint64 {
return c.FinalizeDepth() / 2
}

func DefaultConfig() Config {
Expand All @@ -46,6 +50,7 @@ func DefaultConfig() Config {
LoadState: "",
Silent: true,
BlockTimeSecs: 1,
SlotsInEpoch: 32,
}
}

Expand All @@ -61,8 +66,6 @@ func Run(ctx context.Context, cfg Config) error {
root, err := startAnvil(ctx, rootCfg)
if err != nil {
return errors.Wrap(err, "start root anvil")
} else if err := root.AwaitHeight(ctx, 0, time.Second*5); err != nil {
return errors.Wrap(err, "await anvil start")
}

proxy, err := newProxy(root)
Expand Down Expand Up @@ -125,7 +128,7 @@ func forkForever(ctx context.Context, cfg Config, newPort func() int, proxy *pro
}

for ctx.Err() == nil {
nextForkDepth := 1 + rand.Intn(MaxForkDepth-1) //nolint:gosec // Not a problem
nextForkDepth := 1 + rand.Intn(int(cfg.MaxForkDepth()-1)) //nolint:gosec // Not a problem
sleepSecs := (nextForkDepth * int(cfg.BlockTimeSecs)) * 12 / 10 // Wait 20% longer

select {
Expand Down Expand Up @@ -290,6 +293,7 @@ func startAnvil(ctx context.Context, cfg anvilConfig) (anvilInstance, error) {
"--port", strconv.Itoa(cfg.Port),
"--chain-id", strconv.FormatUint(cfg.ChainID, 10),
"--block-time", strconv.FormatUint(cfg.BlockTimeSecs, 10),
"--slots-in-an-epoch", strconv.FormatUint(cfg.SlotsInEpoch, 10),
}
if cfg.LoadState != "" {
args = append(args, "--load-state", cfg.LoadState)
Expand Down Expand Up @@ -320,14 +324,7 @@ func startAnvil(ctx context.Context, cfg anvilConfig) (anvilInstance, error) {
return anvilInstance{}, errors.Wrap(err, "start anvil", "out", out.String())
}

go func() {
err := logLines(ctx, &out, fmt.Sprint(cfg.Port))
if err != nil {
log.Error(ctx, "Failed logging lines", err)
}
}()

return anvilInstance{
resp := anvilInstance{
stop: func() {
log.Debug(ctx, "Stopping anvil", "port", cfg.Port)
cancel()
Expand All @@ -337,7 +334,20 @@ func startAnvil(ctx context.Context, cfg anvilConfig) (anvilInstance, error) {
Cfg: cfg,
Out: out,
Cmd: cmd,
}, nil
}

if err := resp.AwaitHeight(ctx, 0, time.Second*5); err != nil {
return resp, errors.Wrap(err, "await anvil startup", "out", out.String())
}

go func() {
err := logLines(ctx, &out, fmt.Sprint(cfg.Port))
if err != nil {
log.Error(ctx, "Failed logging lines", err)
}
}()

return resp, nil
}

func newPortProvider() func() int {
Expand Down
1 change: 1 addition & 0 deletions e2e/forkproxy/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ func bindFlags(flags *pflag.FlagSet, cfg *app.Config) {
flags.Uint64Var(&cfg.BlockTimeSecs, "block-time", cfg.BlockTimeSecs, "Block time in seconds for interval mining")
flags.BoolVar(&cfg.Silent, "silent", cfg.Silent, "Don't print anything on startup and don't print logs")
flags.BoolVar(&cfg.EnableForking, "fork", cfg.EnableForking, "Enable constant forking")
flags.Uint64Var(&cfg.SlotsInEpoch, "slots-in-an-epoch", cfg.SlotsInEpoch, "Slots in an epoch")
}
2 changes: 1 addition & 1 deletion e2e/test/attestations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestApprovedAttestations(t *testing.T) {
require.NoError(t, err)

// Only non-empty blocks are attested to, and we don't know how many that should be, so just ensure it isn't 0.
require.NotEmpty(t, atts)
require.NotEmpty(t, atts, "No attestations for chain version: %v", chainVer)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ services:
container_name: mock_l1
platform: linux/amd64
image: omniops/forkproxy:main
pull_policy: always
environment:
- FORKPROXY_CHAIN_ID=1652
- FORKPROXY_BLOCK_TIME=1
- FORKPROXY_SLOTS_IN_AN_EPOCH=6 # Finality in 6*2*BlockPeriod
- FORKPROXY_LOAD_STATE=/anvil/state.json
ports:
- 8545:8545
Expand Down
3 changes: 2 additions & 1 deletion halo/attest/voter/voter.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ func (v *Voter) runForever(ctx context.Context, chainVer xchain.ChainVersion) {
v.wg.Add(1)
defer v.wg.Done()

ctx = log.WithCtx(ctx, "chain", v.network.ChainName(chainVer.ID))
label := fmt.Sprintf("%s-%s", v.network.ChainName(chainVer.ID), chainVer.ConfLevel)
ctx = log.WithCtx(ctx, "chain_ver", label)

backoff := v.backoffFunc(ctx)
for ctx.Err() == nil {
Expand Down
5 changes: 4 additions & 1 deletion lib/netconf/netconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ func (c Chain) Shards() []uint64 {
// ConfLevels returns the uniq set of confirmation levels
// supported by the chain. This is inferred from the supported shards.
func (c Chain) ConfLevels() []xchain.ConfLevel {
dedup := make(map[xchain.ConfLevel]struct{})
dedup := map[xchain.ConfLevel]struct{}{
xchain.ConfFinalized: {}, // All chains require ConfFinalized.
}

for _, shard := range c.Shards() {
conf := xchain.ConfFromShard(shard)
if _, ok := dedup[conf]; ok {
Expand Down
14 changes: 14 additions & 0 deletions lib/netconf/netconf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/omni-network/omni/lib/k1util"
"github.com/omni-network/omni/lib/netconf"
"github.com/omni-network/omni/lib/tutil"
"github.com/omni-network/omni/lib/xchain"

"github.com/ethereum/go-ethereum/p2p/enode"

Expand Down Expand Up @@ -165,3 +166,16 @@ func TestExecutionSeeds(t *testing.T) {
require.NotEmpty(t, node.IP())
}
}

func TestConfLevels(t *testing.T) {
t.Parallel()

// Latest finalization start results in 1 shard and 2 conf levels.
chain := netconf.Chain{
FinalizationStrat: netconf.StratLatest,
}
require.Len(t, chain.Shards(), 1)
require.Len(t, chain.ConfLevels(), 2)
require.Equal(t, chain.Shards()[0], uint64(xchain.ConfLatest))
require.EqualValues(t, chain.ConfLevels(), []xchain.ConfLevel{xchain.ConfLatest, xchain.ConfFinalized})
}
6 changes: 3 additions & 3 deletions lib/xchain/conflevel_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 8 additions & 7 deletions lib/xchain/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/ethereum/go-ethereum/common"
)

//go:generate stringer -type=ConfLevel -trimprefix=Conf
//go:generate stringer -type=ConfLevel -linecomment

// ChainVersion defines a version of a source chain; either some draft (fuzzy) version or finalized.
type ChainVersion struct {
Expand All @@ -28,13 +28,14 @@ func (c ConfLevel) IsFuzzy() bool {
return c != ConfFinalized
}

// ConfLevel values MUST never change as they are persisted on-chain.
const (
ConfUnknown ConfLevel = 0
ConfLatest ConfLevel = 1
ConfFast ConfLevel = 2
ConfSafe ConfLevel = 3
ConfFinalized ConfLevel = 4
confSentinel ConfLevel = 5 // Sentinel must always be last.
ConfUnknown ConfLevel = 0 // unknown
ConfLatest ConfLevel = 1 // latest
ConfFast ConfLevel = 2 // fast
ConfSafe ConfLevel = 3 // safe
ConfFinalized ConfLevel = 4 // final
confSentinel ConfLevel = 5 // sentinel must always be last
)

// ConfFromShard returns confirmation level encoded in the
Expand Down
26 changes: 7 additions & 19 deletions relayer/app/cursors.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,16 @@ func getSubmittedCursors(ctx context.Context, network netconf.Network, dstChainI
) ([]xchain.StreamCursor, map[xchain.StreamID]uint64, error) {
var cursors []xchain.StreamCursor //nolint:prealloc // Not worth it.
initialOffsets := make(map[xchain.StreamID]uint64) // Initial submitted offsets for each stream.
for _, srcChain := range network.Chains {
if srcChain.ID == dstChainID {
for _, stream := range network.StreamsTo(dstChainID) {
cursor, ok, err := xClient.GetSubmittedCursor(ctx, stream)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to get submitted cursors", "src_chain", stream.SourceChainID)
} else if !ok {
continue
}

for _, shardID := range srcChain.Shards() {
stream := xchain.StreamID{
SourceChainID: srcChain.ID,
DestChainID: dstChainID,
ShardID: shardID,
}

cursor, ok, err := xClient.GetSubmittedCursor(ctx, stream)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to get submitted cursors", "src_chain", srcChain.Name)
} else if !ok {
continue
}

initialOffsets[cursor.StreamID] = cursor.MsgOffset
cursors = append(cursors, cursor)
}
initialOffsets[cursor.StreamID] = cursor.MsgOffset
cursors = append(cursors, cursor)
}

return cursors, initialOffsets, nil
Expand Down

0 comments on commit 07620ef

Please sign in to comment.