Skip to content

Commit

Permalink
QGB Orchestrator only signs if part of valset (#523)
Browse files Browse the repository at this point in the history
* state machine verify validator not part of valset

* improve state machine error handling

* update orchestrator not to sign unnecessary confirms

* update e2e to support orch only signing if part of valset

* fix test

* fix test

* GOFUMPT

* Update x/qgb/keeper/msg_server.go

* Update x/qgb/keeper/msg_server.go
  • Loading branch information
rach-id committed Jul 12, 2022
1 parent 9fbfa7d commit 0ed87bb
Show file tree
Hide file tree
Showing 7 changed files with 510 additions and 197 deletions.
184 changes: 37 additions & 147 deletions e2e/qgb/orchestrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"os"
"testing"
"time"

"github.com/celestiaorg/celestia-app/x/qgb/orchestrator"
"github.com/celestiaorg/celestia-app/x/qgb/types"
Expand Down Expand Up @@ -118,26 +119,15 @@ func TestOrchestratorWithTwoValidators(t *testing.T) {
// assert that it carries the right eth address
assert.Equal(t, CORE0EVMADDRESS, core0DataCommitmentConfirm.EthAddress)

// check core1 submited the valset confirm
core1ValsetConfirm, err := querier.QueryValsetConfirm(ctx, 1, CORE1ACCOUNTADDRESS)
// check the confirm exist
// get the last valset where all validators were created
vs, err := network.GetValsetContainingVals(ctx, 2)
require.NoError(t, err)
require.NotNil(t, core1ValsetConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, core1ValsetConfirm.EthAddress)
require.NotNil(t, vs)

// check core1 submitted the data commitment confirm
core1DataCommitmentConfirm, err := querier.QueryDataCommitmentConfirm(
ctx,
types.DataCommitmentWindow,
0,
CORE1ACCOUNTADDRESS,
)
// check the confirm exist
// check core1 submited the attestation confirm
core1Confirm, err := network.GetAttestationConfirm(ctx, vs.Nonce+1, CORE1ACCOUNTADDRESS)
require.NoError(t, err)
require.NotNil(t, core1DataCommitmentConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, core1DataCommitmentConfirm.EthAddress)
require.NotNil(t, core1Confirm)
}

func TestOrchestratorWithMultipleValidators(t *testing.T) {
Expand Down Expand Up @@ -195,68 +185,25 @@ func TestOrchestratorWithMultipleValidators(t *testing.T) {
// assert that it carries the right eth address
assert.Equal(t, CORE0EVMADDRESS, core0DataCommitmentConfirm.EthAddress)

// check core1 submited the valset confirm
core1ValsetConfirm, err := querier.QueryValsetConfirm(ctx, 1, CORE1ACCOUNTADDRESS)
// check the confirm exist
require.NoError(t, err)
require.NotNil(t, core1ValsetConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, core1ValsetConfirm.EthAddress)

// check core1 submitted the data commitment confirm
core1DataCommitmentConfirm, err := querier.QueryDataCommitmentConfirm(
ctx,
types.DataCommitmentWindow,
0,
CORE1ACCOUNTADDRESS,
)
// check the confirm exist
require.NoError(t, err)
require.NotNil(t, core1DataCommitmentConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, core1DataCommitmentConfirm.EthAddress)

// check core2 submited the valset confirm
core2ValsetConfirm, err := querier.QueryValsetConfirm(ctx, 1, CORE2ACCOUNTADDRESS)
// check the confirm exist
// get the last valset where all validators were created
vs, err := network.GetValsetContainingVals(ctx, 4)
require.NoError(t, err)
require.NotNil(t, core2ValsetConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE2EVMADDRESS, core2ValsetConfirm.EthAddress)
require.NotNil(t, vs)

// check core1 submitted the data commitment confirm
core2DataCommitmentConfirm, err := querier.QueryDataCommitmentConfirm(
ctx,
types.DataCommitmentWindow,
0,
CORE2ACCOUNTADDRESS,
)
// check the confirm exist
// check core1 submited the attestation confirm
core1Confirm, err := network.GetAttestationConfirm(ctx, vs.Nonce+1, CORE1ACCOUNTADDRESS)
require.NoError(t, err)
require.NotNil(t, core2DataCommitmentConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE2EVMADDRESS, core2DataCommitmentConfirm.EthAddress)
require.NotNil(t, core1Confirm)

// check core3 submited the valset confirm
core3ValsetConfirm, err := querier.QueryValsetConfirm(ctx, 1, CORE3ACCOUNTADDRESS)
// check the confirm exist
// check core2 submited the attestation confirm
core2Confirm, err := network.GetAttestationConfirm(ctx, vs.Nonce+1, CORE2ACCOUNTADDRESS)
require.NoError(t, err)
require.NotNil(t, core3ValsetConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE3EVMADDRESS, core3ValsetConfirm.EthAddress)
require.NotNil(t, core2Confirm)

// check core1 submitted the data commitment confirm
core3DataCommitmentConfirm, err := querier.QueryDataCommitmentConfirm(
ctx,
types.DataCommitmentWindow,
0,
CORE3ACCOUNTADDRESS,
)
// check the confirm exist
// check core3 submited the attestation confirm
core3Confirm, err := network.GetAttestationConfirm(ctx, vs.Nonce+1, CORE3ACCOUNTADDRESS)
require.NoError(t, err)
require.NotNil(t, core3DataCommitmentConfirm)
// assert that it carries the right eth address
assert.Equal(t, CORE3EVMADDRESS, core3DataCommitmentConfirm.EthAddress)
require.NotNil(t, core3Confirm)
}

func TestOrchestratorReplayOld(t *testing.T) {
Expand Down Expand Up @@ -300,91 +247,34 @@ func TestOrchestratorReplayOld(t *testing.T) {
err = network.WaitForOrchestratorToStart(network.Context, CORE1ACCOUNTADDRESS)
HandleNetworkError(t, network, err, false)

// give the orchestrators some time to catchup
time.Sleep(30 * time.Second)

// FIXME should we use the querier here or go for raw queries?
querier, err := orchestrator.NewQuerier(network.CelestiaGRPC, network.TendermintRPC, nil, network.EncCfg)
HandleNetworkError(t, network, err, false)

// check core0 submitted valset 1 confirm
vs1Core0Confirm, err := querier.QueryValsetConfirm(ctx, 1, CORE0ACCOUNTADDRESS)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, vs1Core0Confirm)
require.NoError(t, err)
require.NotNil(t, vs1Core0Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE0EVMADDRESS, vs1Core0Confirm.EthAddress)

// check core0 submitted valset 2 confirm
vs2Core0Confirm, err := querier.QueryValsetConfirm(ctx, 1, CORE0ACCOUNTADDRESS)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, vs2Core0Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE0EVMADDRESS, vs2Core0Confirm.EthAddress)

// check core1 submitted valset 1 confirm
vs1Core1Confirm, err := querier.QueryValsetConfirm(ctx, 1, CORE1ACCOUNTADDRESS)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, vs1Core1Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, vs1Core1Confirm.EthAddress)

// check core1 submitted valset 2 confirm
vs2Core1Confirm, err := querier.QueryValsetConfirm(ctx, 1, CORE1ACCOUNTADDRESS)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, vs2Core1Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, vs2Core1Confirm.EthAddress)

// check core0 submitted data commitment confirm 0->window
dc0Core0Confirm, err := querier.QueryDataCommitmentConfirm(
ctx,
types.DataCommitmentWindow,
0,
CORE0ACCOUNTADDRESS,
)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, dc0Core0Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE0EVMADDRESS, dc0Core0Confirm.EthAddress)

// check core0 submitted data commitment confirm window->2*window
dc1Core0Confirm, err := querier.QueryDataCommitmentConfirm(
ctx,
2*types.DataCommitmentWindow,
types.DataCommitmentWindow,
CORE0ACCOUNTADDRESS,
)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, dc1Core0Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE0EVMADDRESS, dc1Core0Confirm.EthAddress)
// get the last valset where all validators were created
vs, err := network.GetValsetContainingVals(ctx, 2)
require.NoError(t, err)
require.NotNil(t, vs)

// check core1 submitted data commitment confirm 0->window
dc0Core1Confirm, err := querier.QueryDataCommitmentConfirm(
ctx,
types.DataCommitmentWindow,
0,
CORE1ACCOUNTADDRESS,
)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, dc0Core1Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, dc0Core1Confirm.EthAddress)
latestNonce, err := querier.QueryLatestAttestationNonce(ctx)
require.NoError(t, err)

// check core0 submitted data commitment confirm window->2*window
dc1Core1Confirm, err := querier.QueryDataCommitmentConfirm(
ctx,
2*types.DataCommitmentWindow,
types.DataCommitmentWindow,
CORE1ACCOUNTADDRESS,
)
// assert the confirm exist
assert.NoError(t, err)
assert.NotNil(t, dc1Core1Confirm)
// assert that it carries the right eth address
assert.Equal(t, CORE1EVMADDRESS, dc1Core1Confirm.EthAddress)
// checks that all nonces where all validators were part of the valset were signed
for i := vs.Nonce + 1; i <= latestNonce; i++ {
// check core1 submited the attestation confirm
core1Confirm, err := network.GetAttestationConfirm(ctx, i, CORE1ACCOUNTADDRESS)
require.NoError(t, err)
require.NotNil(t, core1Confirm)
}
}
121 changes: 117 additions & 4 deletions e2e/qgb/qgb_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
"strings"
"time"

"github.com/celestiaorg/celestia-app/x/qgb/types"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/celestiaorg/celestia-app/x/qgb/orchestrator"
wrapper "github.com/celestiaorg/quantum-gravity-bridge/wrappers/QuantumGravityBridge.sol"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand Down Expand Up @@ -381,11 +384,121 @@ func (network QGBNetwork) WaitForOrchestratorToStart(_ctx context.Context, accou
}
return ctx.Err()
default:
confirm, err := querier.QueryValsetConfirm(ctx, 1, accountAddress)
if err == nil && confirm != nil {
return nil
}
fmt.Println("waiting for orchestrator to start ...")
lastNonce, err := querier.QueryLatestAttestationNonce(ctx)
if err != nil {
fmt.Println(err.Error())
continue
}
for i := uint64(0); i < lastNonce; i++ {
vsConfirm, err := querier.QueryValsetConfirm(ctx, lastNonce-i, accountAddress)
if err == nil && vsConfirm != nil {
return nil
}
dcConfirm, err := querier.QueryDataCommitmentConfirm(
ctx,
(lastNonce-i+1)*types.DataCommitmentWindow,
(lastNonce-i)*types.DataCommitmentWindow,
accountAddress,
)
if err == nil && dcConfirm != nil {
return nil
}
}
time.Sleep(5 * time.Second)
}
}
}

// GetValsetContainingVals Gets the last valset that contains a certain number of validator.
// This is used after enabling orchestrators not to sign unless they belong to some valset.
// Thus, any nonce after the returned valset should be signed by all orchestrators.
func (network QGBNetwork) GetValsetContainingVals(_ctx context.Context, number int) (*types.Valset, error) {
querier, err := orchestrator.NewQuerier(network.CelestiaGRPC, network.TendermintRPC, nil, network.EncCfg)
if err != nil {
return nil, err
}
defer querier.Stop()
ctx, _ := context.WithTimeout(_ctx, 5*time.Minute) //nolint:govet
for {
select {
case <-ctx.Done():
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("couldn't find any valset containing %d validators", number)
}
return nil, ctx.Err()
default:
fmt.Printf("searching for valset with %d validator...\n", number)
lastNonce, err := querier.QueryLatestAttestationNonce(ctx)
if err != nil {
fmt.Println(err.Error())
continue
}
for i := uint64(0); i < lastNonce; i++ {
vs, err := querier.QueryValsetByNonce(ctx, lastNonce-i)
if err == nil && vs != nil && len(vs.Members) == number {
return vs, nil
}
}
time.Sleep(5 * time.Second)
}
}
}

// GetAttestationConfirm Returns the confirm sdk.Msg message for either a valset confirm or
// a data commitment confirm.
// Will be used as long as we don't have support for AttestationConfirm.
// https://github.com/celestiaorg/celestia-app/issues/505
func (network QGBNetwork) GetAttestationConfirm(
_ctx context.Context,
nonce uint64,
account string,
) (sdk.Msg, error) {
ctx, _ := context.WithTimeout(_ctx, 2*time.Minute) //nolint:govet
querier, err := orchestrator.NewQuerier(network.CelestiaGRPC, network.TendermintRPC, nil, network.EncCfg)
if err != nil {
return nil, err
}
defer querier.Stop()
for {
select {
case <-ctx.Done():
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("couldn't find confirm for nonce=%d", nonce)
}
return nil, ctx.Err()
default:
att, err := querier.QueryAttestationByNonce(ctx, nonce)
if err != nil {
continue
}
switch att.Type() {
case types.ValsetRequestType:
_, ok := att.(*types.Valset)
if !ok {
continue
}
resp, err := querier.QueryValsetConfirm(ctx, nonce, account)
if err == nil && resp != nil {
return resp, nil
}

case types.DataCommitmentRequestType:
dc, ok := att.(*types.DataCommitment)
if !ok {
continue
}
resp, err := querier.QueryDataCommitmentConfirm(
ctx,
dc.EndBlock,
dc.BeginBlock,
account,
)
if err == nil && resp != nil {
return resp, nil
}
}
fmt.Printf("waiting for confirm for nonce=%d\n", nonce)
time.Sleep(5 * time.Second)
}
}
Expand Down
Loading

0 comments on commit 0ed87bb

Please sign in to comment.