Skip to content
This repository was archived by the owner on Apr 15, 2024. It is now read-only.

Commit

Permalink
feat: authenticate the valset to the Blobstream contract
Browse files Browse the repository at this point in the history
  • Loading branch information
rach-id committed Oct 27, 2023
1 parent 755ff25 commit d4e6c41
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 3 deletions.
8 changes: 8 additions & 0 deletions evm/evm_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ func (ec *Client) StateLastEventNonce(opts *bind.CallOpts) (uint64, error) {
return nonce.Uint64(), nil
}

func (ec *Client) StateLastValidatorSetCheckpoint(opts *bind.CallOpts) ([32]byte, error) {
checkpoint, err := ec.Wrapper.StateLastValidatorSetCheckpoint(opts)
if err != nil {
return [32]byte{}, err
}
return checkpoint, nil
}

func (ec *Client) WaitForTransaction(
ctx context.Context,
backend bind.DeployBackend,
Expand Down
1 change: 1 addition & 0 deletions relayer/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ var (
ErrAttestationNotValsetRequest = errors.New("attestation is not a valset request")
ErrAttestationNotDataCommitmentRequest = errors.New("attestation is not a data commitment request")
ErrAttestationNotFound = errors.New("attestation not found")
ErrValidatorSetMismatch = errors.New("p2p validator set is different from the trusted contract one")
)
39 changes: 36 additions & 3 deletions relayer/relayer.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package relayer

import (
"bytes"
"context"
"encoding/hex"
"fmt"
"math/big"
"strconv"
Expand Down Expand Up @@ -144,12 +146,10 @@ func (r *Relayer) ProcessAttestation(ctx context.Context, opts *bind.TransactOpt
previousValset, err := r.AppQuerier.QueryLastValsetBeforeNonce(ctx, attI.GetNonce())
if err != nil {
r.logger.Error("failed to query the last valset before nonce (probably pruned). recovering via falling back to the P2P network", "err", err.Error())
latestValset, err := r.P2PQuerier.QueryLatestValset(ctx)
previousValset, err = r.QueryValsetFromP2PNetworkAndValidateIt(ctx)
if err != nil {
return nil, err
}
previousValset = latestValset.ToValset()
r.logger.Info("using the latest valset from P2P network. if the valset is malicious, the Blobstream contract will not accept it", "nonce", previousValset.Nonce)
}
switch att := attI.(type) {
case *celestiatypes.Valset:
Expand Down Expand Up @@ -194,6 +194,39 @@ func (r *Relayer) ProcessAttestation(ctx context.Context, opts *bind.TransactOpt
}
}

// QueryValsetFromP2PNetworkAndValidateIt Queries the latest valset from the P2P network
// and validates it against the validator set hash used in the contract.
func (r *Relayer) QueryValsetFromP2PNetworkAndValidateIt(ctx context.Context) (*celestiatypes.Valset, error) {
latestValset, err := r.P2PQuerier.QueryLatestValset(ctx)
if err != nil {
return nil, err
}
vs := latestValset.ToValset()
vsHash, err := vs.SignBytes()
if err != nil {
return nil, err
}
r.logger.Info("found the latest valset in P2P network. Authenticating it against the contract to verify it's valid", "nonce", vs.Nonce, "hash", vsHash.Hex())

contractHash, err := r.EVMClient.StateLastValidatorSetCheckpoint(&bind.CallOpts{Context: ctx})
if err != nil {
return nil, err
}

bzVSHash, err := hex.DecodeString(vsHash.Hex()[2:])
if err != nil {
return nil, err
}

if !bytes.Equal(bzVSHash, contractHash[:]) {
r.logger.Error("valset hash from contract mismatches that of P2P one, halting. try running the relayer with an archive node to continue relaying", "contract_vs_hash", ethcmn.Bytes2Hex(contractHash[:]), "p2p_vs_hash", vsHash.Hex())
return nil, ErrValidatorSetMismatch
}

r.logger.Info("valset is valid. continuing relaying using the latest valset from P2P network", "nonce", vs.Nonce)
return vs, nil
}

func (r *Relayer) UpdateValidatorSet(
ctx context.Context,
opts *bind.TransactOpts,
Expand Down
35 changes: 35 additions & 0 deletions relayer/relayer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package relayer_test

import (
"bytes"
"context"
"math/big"
"testing"
Expand Down Expand Up @@ -118,3 +119,37 @@ func TestUseValsetFromP2P(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, att.Nonce, lastNonce)
}

func (s *RelayerTestSuite) TestQueryValsetFromP2P() {
t := s.T()
_, err := s.Node.CelestiaNetwork.WaitForHeightWithTimeout(400, 30*time.Second)
require.NoError(t, err)

ctx := context.Background()

// process valset nonce so that it is added to the DHT
vs, err := s.Orchestrator.AppQuerier.QueryLatestValset(ctx)
require.NoError(t, err)
err = s.Orchestrator.ProcessValsetEvent(ctx, *vs)
require.NoError(t, err)

// the valset should be in the DHT
_, err = s.Orchestrator.P2PQuerier.QueryLatestValset(ctx)
require.NoError(t, err)

// query the valset and authenticate it
p2pVS, err := s.Relayer.QueryValsetFromP2PNetworkAndValidateIt(ctx)
require.NoError(t, err)

// check if the valset is the same
assert.Equal(t, vs.Nonce, p2pVS.Nonce)
assert.Equal(t, vs.Height, p2pVS.Height)

// check if the hash is the same
appVSHash, err := vs.Hash()
require.NoError(t, err)
p2pVSHash, err := p2pVS.Hash()
require.NoError(t, err)

assert.True(t, bytes.Equal(appVSHash.Bytes(), p2pVSHash.Bytes()))
}

0 comments on commit d4e6c41

Please sign in to comment.