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

Limit finalized header gap #1156

Merged
merged 35 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
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
39 changes: 39 additions & 0 deletions .github/workflows/relayer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: relayer

on:
push:
paths:
- "relayer/**"
branches:
- main
pull_request:
paths:
- "relayer/**"

jobs:
build:
runs-on: snowbridge-runner
timeout-minutes: 15
steps:
- uses: actions/checkout@v1
with:
fetch-depth: 2

- name: setup go
uses: actions/checkout@v4
with:
go-version: '^1.20.1'

- name: check go version
run: go version

- name: install dependencies
working-directory: relayer
run: go mod download

- name: Add gopath to bin
run: echo "$HOME/go/bin" >> $GITHUB_PATH

- name: test
working-directory: relayer
run: go test -v ./...
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ parachain/build_rs_cov.profraw
compiler_config.json
contracts/beefy-state.json

# beacon states generate by relayer
states/

go/
gocache/
go.work*
Expand Down
2 changes: 2 additions & 0 deletions relayer/chain/parachain/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
)

func TestConnect(t *testing.T) {
t.Skip("skip testing utility test")

conn := parachain.NewConnection("ws://127.0.0.1:11144/", sr25519.Alice().AsKeyringPair())
err := conn.Connect(context.Background())
if err != nil {
Expand Down
250 changes: 116 additions & 134 deletions relayer/chain/parachain/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,30 @@ import (
"fmt"
"sync"

"github.com/ethereum/go-ethereum/common"
log "github.com/sirupsen/logrus"
"github.com/snowfork/go-substrate-rpc-client/v4/rpc/author"
"github.com/snowfork/go-substrate-rpc-client/v4/types"
"github.com/snowfork/snowbridge/relayer/relays/beacon/header/syncer/scale"
"github.com/snowfork/snowbridge/relayer/relays/beacon/state"

"github.com/ethereum/go-ethereum/common"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
)

type ChainWriter interface {
BatchCall(ctx context.Context, extrinsic string, calls []interface{}) error
WriteToParachainAndRateLimit(ctx context.Context, extrinsicName string, payload ...interface{}) error
WriteToParachainAndWatch(ctx context.Context, extrinsicName string, payload ...interface{}) error
GetLastFinalizedHeaderState() (state.FinalizedHeader, error)
GetFinalizedStateByStorageKey(key string) (scale.BeaconState, error)
GetLastBasicChannelBlockNumber() (uint64, error)
GetLastBasicChannelNonceByAddress(address common.Address) (uint64, error)
GetFinalizedHeaderStateByBlockRoot(blockRoot types.H256) (state.FinalizedHeader, error)
GetCompactExecutionHeaderStateByBlockHash(blockHash types.H256) (state.CompactExecutionHeaderState, error)
GetLastFinalizedStateIndex() (types.U32, error)
GetFinalizedBeaconRootByIndex(index uint32) (types.H256, error)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract interfaces that we can mock out in tests.

}

type ParachainWriter struct {
conn *Connection
nonce uint32
Expand Down Expand Up @@ -133,105 +148,6 @@ func (wr *ParachainWriter) WriteToParachainAndWatch(ctx context.Context, extrins
}
}

func (wr *ParachainWriter) writeToParachain(ctx context.Context, extrinsicName string, payload ...interface{}) (*author.ExtrinsicStatusSubscription, error) {
extI, err := wr.prepExtrinstic(ctx, extrinsicName, payload...)
if err != nil {
return nil, err
}

sub, err := wr.conn.API().RPC.Author.SubmitAndWatchExtrinsic(*extI)
if err != nil {
return nil, err
}

return sub, nil
}

func (wr *ParachainWriter) queryAccountNonce() (uint32, error) {
key, err := types.CreateStorageKey(wr.conn.Metadata(), "System", "Account", wr.conn.Keypair().PublicKey, nil)
if err != nil {
return 0, err
}

var accountInfo types.AccountInfo
ok, err := wr.conn.API().RPC.State.GetStorageLatest(key, &accountInfo)
if err != nil {
return 0, err
}
if !ok {
return 0, fmt.Errorf("no account info found for %s", wr.conn.Keypair().URI)
}

return uint32(accountInfo.Nonce), nil
}

func (wr *ParachainWriter) prepExtrinstic(ctx context.Context, extrinsicName string, payload ...interface{}) (*types.Extrinsic, error) {
meta, err := wr.conn.API().RPC.State.GetMetadataLatest()
if err != nil {
return nil, err
}

c, err := types.NewCall(meta, extrinsicName, payload...)
if err != nil {
return nil, err
}

latestHash, err := wr.conn.API().RPC.Chain.GetFinalizedHead()
if err != nil {
return nil, err
}

latestBlock, err := wr.conn.API().RPC.Chain.GetBlock(latestHash)
if err != nil {
return nil, err
}

ext := types.NewExtrinsic(c)
era := NewMortalEra(uint64(latestBlock.Block.Header.Number))

genesisHash, err := wr.conn.API().RPC.Chain.GetBlockHash(0)
if err != nil {
return nil, err
}

rv, err := wr.conn.API().RPC.State.GetRuntimeVersionLatest()
if err != nil {
return nil, err
}

o := types.SignatureOptions{
BlockHash: latestHash,
Era: era,
GenesisHash: genesisHash,
Nonce: types.NewUCompactFromUInt(uint64(wr.nonce)),
SpecVersion: rv.SpecVersion,
Tip: types.NewUCompactFromUInt(0),
TransactionVersion: rv.TransactionVersion,
}

extI := ext

err = extI.Sign(*wr.conn.Keypair(), o)
if err != nil {
return nil, err
}

return &extI, nil
}

func (wr *ParachainWriter) prepCall(extrinsicName string, payload ...interface{}) (*types.Call, error) {
meta, err := wr.conn.API().RPC.State.GetMetadataLatest()
if err != nil {
return nil, err
}

c, err := types.NewCall(meta, extrinsicName, payload...)
if err != nil {
return nil, err
}
return &c, nil
}

func (wr *ParachainWriter) GetLastBasicChannelBlockNumber() (uint64, error) {
return wr.getNumberFromParachain("EthereumInboundQueue", "LatestVerifiedBlockNumber")
}
Expand Down Expand Up @@ -331,6 +247,105 @@ func (wr *ParachainWriter) GetFinalizedHeaderStateByBlockRoot(blockRoot types.H2
}, nil
}

func (wr *ParachainWriter) writeToParachain(ctx context.Context, extrinsicName string, payload ...interface{}) (*author.ExtrinsicStatusSubscription, error) {
extI, err := wr.prepExtrinstic(ctx, extrinsicName, payload...)
if err != nil {
return nil, err
}

sub, err := wr.conn.API().RPC.Author.SubmitAndWatchExtrinsic(*extI)
if err != nil {
return nil, err
}

return sub, nil
}

func (wr *ParachainWriter) queryAccountNonce() (uint32, error) {
key, err := types.CreateStorageKey(wr.conn.Metadata(), "System", "Account", wr.conn.Keypair().PublicKey, nil)
if err != nil {
return 0, err
}

var accountInfo types.AccountInfo
ok, err := wr.conn.API().RPC.State.GetStorageLatest(key, &accountInfo)
if err != nil {
return 0, err
}
if !ok {
return 0, fmt.Errorf("no account info found for %s", wr.conn.Keypair().URI)
}

return uint32(accountInfo.Nonce), nil
}

func (wr *ParachainWriter) prepExtrinstic(ctx context.Context, extrinsicName string, payload ...interface{}) (*types.Extrinsic, error) {
meta, err := wr.conn.API().RPC.State.GetMetadataLatest()
if err != nil {
return nil, err
}

c, err := types.NewCall(meta, extrinsicName, payload...)
if err != nil {
return nil, err
}

latestHash, err := wr.conn.API().RPC.Chain.GetFinalizedHead()
if err != nil {
return nil, err
}

latestBlock, err := wr.conn.API().RPC.Chain.GetBlock(latestHash)
if err != nil {
return nil, err
}

ext := types.NewExtrinsic(c)
era := NewMortalEra(uint64(latestBlock.Block.Header.Number))

genesisHash, err := wr.conn.API().RPC.Chain.GetBlockHash(0)
if err != nil {
return nil, err
}

rv, err := wr.conn.API().RPC.State.GetRuntimeVersionLatest()
if err != nil {
return nil, err
}

o := types.SignatureOptions{
BlockHash: latestHash,
Era: era,
GenesisHash: genesisHash,
Nonce: types.NewUCompactFromUInt(uint64(wr.nonce)),
SpecVersion: rv.SpecVersion,
Tip: types.NewUCompactFromUInt(0),
TransactionVersion: rv.TransactionVersion,
}

extI := ext

err = extI.Sign(*wr.conn.Keypair(), o)
if err != nil {
return nil, err
}

return &extI, nil
}

func (wr *ParachainWriter) prepCall(extrinsicName string, payload ...interface{}) (*types.Call, error) {
meta, err := wr.conn.API().RPC.State.GetMetadataLatest()
if err != nil {
return nil, err
}

c, err := types.NewCall(meta, extrinsicName, payload...)
if err != nil {
return nil, err
}
return &c, nil
}

Comment on lines +249 to +347
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just reordered the private methods.

func (wr *ParachainWriter) getHashFromParachain(pallet, storage string) (common.Hash, error) {
key, err := types.CreateStorageKey(wr.conn.Metadata(), pallet, storage, nil, nil)
if err != nil {
Expand Down Expand Up @@ -394,36 +409,3 @@ func (wr *ParachainWriter) GetFinalizedBeaconRootByIndex(index uint32) (types.H2

return beaconRoot, nil
}

func (wr *ParachainWriter) FindCheckPointBackward(slot uint64) (state.FinalizedHeader, error) {
var beaconState state.FinalizedHeader
lastIndex, err := wr.GetLastFinalizedStateIndex()
if err != nil {
return beaconState, fmt.Errorf("GetLastFinalizedStateIndex error: %w", err)
}
startIndex := uint32(lastIndex)
endIndex := uint32(0)
if lastIndex > 256 {
endIndex = endIndex - 256
}
for index := startIndex; index >= endIndex; index-- {
beaconRoot, err := wr.GetFinalizedBeaconRootByIndex(index)
if err != nil {
return beaconState, fmt.Errorf("GetFinalizedBeaconRootByIndex %d, error: %w", index, err)
}
beaconState, err = wr.GetFinalizedHeaderStateByBlockRoot(beaconRoot)
if err != nil {
return beaconState, fmt.Errorf("GetFinalizedHeaderStateByBlockRoot %s, error: %w", beaconRoot.Hex(), err)
}
if beaconState.BeaconSlot < slot {
break
}
if beaconState.BeaconSlot > slot && beaconState.BeaconSlot < slot+8192 {
break
}
}
if beaconState.BeaconSlot > slot && beaconState.BeaconSlot < slot+8192 {
return beaconState, nil
}
return beaconState, fmt.Errorf("Can't find checkpoint on chain for slot %d", slot)
}
2 changes: 2 additions & 0 deletions relayer/chain/relaychain/connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
)

func TestConnect(t *testing.T) {
t.Skip("skip testing utility test")

conn := relaychain.NewConnection("ws://127.0.0.1:9944/")
err := conn.Connect(context.Background())
if err != nil {
Expand Down
Loading
Loading