Skip to content

Commit

Permalink
Fix Voluntary Exits Panic (#5688)
Browse files Browse the repository at this point in the history
* add fix and regression test
* Update beacon-chain/rpc/validator/exit_test.go

Co-Authored-By: Shay Zluf <thezluf@gmail.com>
* Update beacon-chain/rpc/validator/exit_test.go

Co-Authored-By: Shay Zluf <thezluf@gmail.com>
* Update exit_test.go
  • Loading branch information
nisdas authored Apr 30, 2020
1 parent 2f88174 commit 3a295fb
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
7 changes: 7 additions & 0 deletions beacon-chain/rpc/validator/exit.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/shared/params"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand All @@ -22,6 +23,12 @@ func (vs *Server) ProposeExit(ctx context.Context, req *ethpb.SignedVoluntaryExi
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get head state: %v", err)
}
if req.Exit == nil {
return nil, status.Error(codes.InvalidArgument, "voluntary exit does not exist")
}
if req.Signature == nil || len(req.Signature) != params.BeaconConfig().BLSSignatureLength {
return nil, status.Error(codes.InvalidArgument, "invalid signature provided")
}

// Confirm the validator is eligible to exit with the parameters provided.
val, err := s.ValidatorAtIndex(req.Exit.ValidatorIndex)
Expand Down
85 changes: 85 additions & 0 deletions beacon-chain/rpc/validator/exit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"
"time"

"github.com/prysmaticlabs/prysm/shared/bytesutil"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-ssz"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
Expand Down Expand Up @@ -110,3 +111,87 @@ func TestSub(t *testing.T) {
}
}
}

func TestProposeExit_NoPanic(t *testing.T) {
db := dbutil.SetupDB(t)
defer dbutil.TeardownDB(t, db)
ctx := context.Background()
testutil.ResetCache()
deposits, keys, err := testutil.DeterministicDepositsAndKeys(params.BeaconConfig().MinGenesisActiveValidatorCount)
if err != nil {
t.Fatal(err)
}
beaconState, err := state.GenesisBeaconState(deposits, 0, &ethpb.Eth1Data{BlockHash: make([]byte, 32)})
if err != nil {
t.Fatal(err)
}
block := blk.NewGenesisBlock([]byte{})
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
genesisRoot, err := ssz.HashTreeRoot(block.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)
}

// Set genesis time to be 100 epochs ago.
genesisTime := time.Now().Add(time.Duration(-100*int64(params.BeaconConfig().SecondsPerSlot*params.BeaconConfig().SlotsPerEpoch)) * time.Second)
mockChainService := &mockChain.ChainService{State: beaconState, Root: genesisRoot[:], Genesis: genesisTime}
server := &Server{
BeaconDB: db,
HeadFetcher: mockChainService,
SyncChecker: &mockSync.Sync{IsSyncing: false},
GenesisTimeFetcher: mockChainService,
StateNotifier: mockChainService.StateNotifier(),
OperationNotifier: mockChainService.OperationNotifier(),
ExitPool: voluntaryexits.NewPool(),
P2P: mockp2p.NewTestP2P(t),
}

// Subscribe to operation notifications.
opChannel := make(chan *feed.Event, 1024)
opSub := server.OperationNotifier.OperationFeed().Subscribe(opChannel)
defer opSub.Unsubscribe()

req := &ethpb.SignedVoluntaryExit{}
_, err = server.ProposeExit(context.Background(), req)
if err == nil {
t.Fatal("Expected error for no exit existing")
}

// Send the request, expect a result on the state feed.
epoch := uint64(2048)
validatorIndex := uint64(0)
req = &ethpb.SignedVoluntaryExit{
Exit: &ethpb.VoluntaryExit{
Epoch: epoch,
ValidatorIndex: validatorIndex,
},
}

_, err = server.ProposeExit(context.Background(), req)
if err == nil {
t.Fatal("Expected error for no signature exists")
}
req.Signature = bytesutil.FromBytes48([48]byte{})

_, err = server.ProposeExit(context.Background(), req)
if err == nil {
t.Fatal("Expected error for invalid signature length")
}

domain, err := helpers.Domain(beaconState.Fork(), epoch, params.BeaconConfig().DomainVoluntaryExit, beaconState.GenesisValidatorRoot())
if err != nil {
t.Fatal(err)
}
sigRoot, err := helpers.ComputeSigningRoot(req.Exit, domain)
if err != nil {
t.Fatalf("Could not compute signing root: %v", err)
}
req.Signature = keys[0].Sign(sigRoot[:]).Marshal()

_, err = server.ProposeExit(context.Background(), req)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
}

0 comments on commit 3a295fb

Please sign in to comment.