Skip to content

Chainsync and optimism features #444

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

Open
wants to merge 8 commits into
base: gnosis-backup
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions rolling-shutter/docs/rolling-shutter_optimismkeyper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## rolling-shutter optimismkeyper

Run a Shutter optimism keyper node

### Synopsis

This command runs a keyper node. It will connect to both an Optimism and a
Shuttermint node which have to be started separately in advance.

```
rolling-shutter optimismkeyper [flags]
```

### Options

```
--config string config file
-h, --help help for optimismkeyper
```

### Options inherited from parent commands

```
--logformat string set log format, possible values: min, short, long, max (default "long")
--loglevel string set log level, possible values: warn, info, debug (default "info")
--no-color do not write colored logs
```

### SEE ALSO

* [rolling-shutter](rolling-shutter.md) - A collection of commands to run and interact with Rolling Shutter nodes
* [rolling-shutter optimismkeyper generate-config](rolling-shutter_optimismkeyper_generate-config.md) - Generate a 'optimismkeyper' configuration file
* [rolling-shutter optimismkeyper initdb](rolling-shutter_optimismkeyper_initdb.md) - Initialize the database of the 'optimismkeyper'

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
## rolling-shutter optimismkeyper generate-config

Generate a 'optimismkeyper' configuration file

```
rolling-shutter optimismkeyper generate-config [flags]
```

### Options

```
-h, --help help for generate-config
--output string output file
```

### Options inherited from parent commands

```
--config string config file
--logformat string set log format, possible values: min, short, long, max (default "long")
--loglevel string set log level, possible values: warn, info, debug (default "info")
--no-color do not write colored logs
```

### SEE ALSO

* [rolling-shutter optimismkeyper](rolling-shutter_optimismkeyper.md) - Run a Shutter optimism keyper node

27 changes: 27 additions & 0 deletions rolling-shutter/docs/rolling-shutter_optimismkeyper_initdb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## rolling-shutter optimismkeyper initdb

Initialize the database of the 'optimismkeyper'

```
rolling-shutter optimismkeyper initdb [flags]
```

### Options

```
-h, --help help for initdb
```

### Options inherited from parent commands

```
--config string config file
--logformat string set log format, possible values: min, short, long, max (default "long")
--loglevel string set log level, possible values: warn, info, debug (default "info")
--no-color do not write colored logs
```

### SEE ALSO

* [rolling-shutter optimismkeyper](rolling-shutter_optimismkeyper.md) - Run a Shutter optimism keyper node

8 changes: 6 additions & 2 deletions rolling-shutter/keyperimpl/optimism/keyper.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,10 @@ func (kpr *Keyper) newBlock(_ context.Context, ev *syncevent.LatestBlock) error

// TODO: sanity checks

idPreimage := identitypreimage.BigToIdentityPreimage(ev.Number.Int)
latestBlockNumber := ev.Number.Uint64()
idPreimage := identitypreimage.Uint64ToIdentityPreimage(latestBlockNumber + 1)
trig := &epochkghandler.DecryptionTrigger{
BlockNumber: ev.Number.Uint64(),
BlockNumber: latestBlockNumber + 1,
IdentityPreimages: []identitypreimage.IdentityPreimage{idPreimage},
}

Expand Down Expand Up @@ -144,11 +145,14 @@ func (kpr *Keyper) newEonPublicKey(ctx context.Context, pubKey keyper.EonPublicK
log.Info().
Uint64("eon", pubKey.Eon).
Uint64("activation-block", pubKey.ActivationBlock).
Bytes("pub-key", pubKey.PublicKey).
Msg("new eon pk")
// Currently all keypers call this and race to call this function first.
// For now this is fine, but a keyper should only send a transaction if
// the key is not set yet.
// Best would be a coordinatated leader election who will broadcast the key.
// FIXME: the syncer receives an empty key byte.
// Is this already
tx, err := kpr.l2Client.BroadcastEonKey(ctx, pubKey.Eon, pubKey.PublicKey)
if err != nil {
log.Error().Err(err).Msg("error broadcasting eon public key")
Expand Down
4 changes: 2 additions & 2 deletions rolling-shutter/medley/chainsync/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var noopLogger = &logger.NoopLogger{}
var ErrServiceNotInstantiated = errors.New("service is not instantiated, pass a handler function option")

type Client struct {
client.Client
client.SyncEthereumClient
log log.Logger

options *options
Expand Down Expand Up @@ -136,7 +136,7 @@ func (s *Client) BroadcastEonKey(ctx context.Context, eon uint64, eonPubKey []by
// This value is cached, since it is not expected to change.
func (s *Client) ChainID(ctx context.Context) (*big.Int, error) {
if s.chainID == nil {
cid, err := s.Client.ChainID(ctx)
cid, err := s.SyncEthereumClient.ChainID(ctx)
if err != nil {
return nil, err
}
Expand Down
15 changes: 14 additions & 1 deletion rolling-shutter/medley/chainsync/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
)

type Client interface {
type FullEthereumClient interface {
Close()
ChainID(ctx context.Context) (*big.Int, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
Expand Down Expand Up @@ -45,3 +45,16 @@ type Client interface {
EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error)
SendTransaction(ctx context.Context, tx *types.Transaction) error
}

type SyncEthereumClient interface {
Close()
ChainID(ctx context.Context) (*big.Int, error)
BlockNumber(ctx context.Context) (uint64, error)
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error)
FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error)
SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
}
170 changes: 170 additions & 0 deletions rolling-shutter/medley/chainsync/client/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package client

import (
"context"
"errors"
"math/big"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)

var ErrNotImplemented = errors.New("not implemented")

var _ SyncEthereumClient = &TestClient{}

type TestClient struct {
headerChain []*types.Header
latestHeadIndex int
intialProgress bool
latestHeadEmitter []chan<- *types.Header
latestHeadSubscription []*Subscription
}

func NewSubscription(idx int) *Subscription {
return &Subscription{
idx: idx,
err: make(chan error, 1),
}
}

type Subscription struct {
idx int
err chan error
}

func (su *Subscription) Unsubscribe() {
// TODO: not implemented yet, but we don't want to panic
}

func (su *Subscription) Err() <-chan error {
return su.err
}

type TestClientController struct {
c *TestClient
}

func NewTestClient() (*TestClient, *TestClientController) {
c := &TestClient{
headerChain: []*types.Header{},
latestHeadIndex: 0,
}
ctrl := &TestClientController{c}
return c, ctrl
}

func (c *TestClientController) ProgressHead() bool {
if c.c.latestHeadIndex >= len(c.c.headerChain)-1 {
return false
}
c.c.latestHeadIndex++
return true
}

func (c *TestClientController) EmitEvents(ctx context.Context) error {
if len(c.c.latestHeadEmitter) == 0 {
return nil
}
h := c.c.getLatestHeader()
for _, em := range c.c.latestHeadEmitter {
select {
case em <- h:
case <-ctx.Done():
return ctx.Err()
}
}
return nil
}

func (c *TestClientController) AppendNextHeaders(h ...*types.Header) {
c.c.headerChain = append(c.c.headerChain, h...)
}

func (t *TestClient) ChainID(_ context.Context) (*big.Int, error) {
return big.NewInt(42), nil
}

func (t *TestClient) Close() {
// TODO: cleanup
}

func (t *TestClient) getLatestHeader() *types.Header {
if len(t.headerChain) == 0 {
return nil
}
return t.headerChain[t.latestHeadIndex]
}

func (t *TestClient) searchBlock(f func(*types.Header) bool) *types.Header {
for i := t.latestHeadIndex; i >= 0; i-- {
h := t.headerChain[i]
if f(h) {
return h
}
}
return nil
}

func (t *TestClient) searchBlockByNumber(number *big.Int) *types.Header {
return t.searchBlock(
func(h *types.Header) bool {
return h.Number.Cmp(number) == 0
})
}

func (t *TestClient) searchBlockByHash(hash common.Hash) *types.Header {
return t.searchBlock(
func(h *types.Header) bool {
return hash.Cmp(h.Hash()) == 0
})
}

func (t *TestClient) BlockNumber(_ context.Context) (uint64, error) {
return t.getLatestHeader().Nonce.Uint64(), nil
}

func (t *TestClient) HeaderByHash(_ context.Context, hash common.Hash) (*types.Header, error) {
h := t.searchBlockByHash(hash)
if h == nil {
return nil, errors.New("header not found")
}
return h, nil
}

func (t *TestClient) HeaderByNumber(_ context.Context, number *big.Int) (*types.Header, error) {
if number == nil {
return t.getLatestHeader(), nil
}
h := t.searchBlockByNumber(number)
if h == nil {
return nil, errors.New("header not found")
}
return h, nil
}

func (t *TestClient) SubscribeNewHead(_ context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) {
t.latestHeadEmitter = append(t.latestHeadEmitter, ch)
su := NewSubscription(len(t.latestHeadSubscription) - 1)
t.latestHeadSubscription = append(t.latestHeadSubscription, su)
// TODO: unsubscribe and deleting from the array
// TODO: filling error promise in the subscription
return su, nil
}

func (t *TestClient) FilterLogs(_ context.Context, _ ethereum.FilterQuery) ([]types.Log, error) {
panic(ErrNotImplemented)
}

func (t *TestClient) SubscribeFilterLogs(_ context.Context, _ ethereum.FilterQuery, _ chan<- types.Log) (ethereum.Subscription, error) {
panic(ErrNotImplemented)
}

func (t *TestClient) CodeAt(_ context.Context, _ common.Address, _ *big.Int) ([]byte, error) {
panic(ErrNotImplemented)
}

func (t *TestClient) TransactionReceipt(_ context.Context, _ common.Hash) (*types.Receipt, error) {
panic(ErrNotImplemented)
}
Loading