code.vegaprotocol.io/vega@v0.79.0/core/validators/topology_snapshot_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package validators_test
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"encoding/hex"
    22  	"testing"
    23  
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/core/validators"
    26  	vegactx "code.vegaprotocol.io/vega/libs/context"
    27  	"code.vegaprotocol.io/vega/libs/proto"
    28  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    29  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    30  
    31  	"github.com/golang/mock/gomock"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  var topKey = (&types.PayloadTopology{}).Key()
    37  
    38  func TestEmptySnapshot(t *testing.T) {
    39  	top := getTestTopology(t)
    40  	defer top.ctrl.Finish()
    41  
    42  	s, p, err := top.GetState(topKey)
    43  	assert.Nil(t, err)
    44  	assert.Empty(t, p)
    45  	assert.NotEmpty(t, s)
    46  
    47  	assert.Equal(t, 1, len(top.Keys()))
    48  }
    49  
    50  func TestChangeOnValidatorPerfUpdate(t *testing.T) {
    51  	top := getTestTopology(t)
    52  	defer top.ctrl.Finish()
    53  	top.timeService.EXPECT().GetTimeNow().AnyTimes()
    54  
    55  	s, _, err := top.GetState(topKey)
    56  	assert.Nil(t, err)
    57  	assert.NotEmpty(t, s)
    58  
    59  	updateValidatorPerformanceToNonDefaultState(t, top.Topology)
    60  
    61  	s2, _, err := top.GetState(topKey)
    62  	assert.Nil(t, err)
    63  	assert.NotEmpty(t, s2)
    64  	require.False(t, bytes.Equal(s, s2))
    65  }
    66  
    67  func TestTopologySnapshot(t *testing.T) {
    68  	top := getTestTopWithMockedSignatures(t)
    69  	defer top.ctrl.Finish()
    70  	top.timeService.EXPECT().GetTimeNow().AnyTimes()
    71  
    72  	top.signatures.EXPECT().PrepareValidatorSignatures(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
    73  	top.signatures.EXPECT().SetNonce(gomock.Any()).Times(2)
    74  	top.signatures.EXPECT().ClearStaleSignatures().Times(2)
    75  	top.signatures.EXPECT().SerialisePendingSignatures().Times(1)
    76  	updateValidatorPerformanceToNonDefaultState(t, top.Topology)
    77  	s1, _, err := top.GetState(topKey)
    78  	require.Nil(t, err)
    79  
    80  	tmPubKeys := []string{"2w5hxsVqWFTV6/f0swyNVqOhY1vWI42MrfO0xkUqsiA=", "67g7+123M0kfMR35U7LLq09eEU1dVr6jHBEgEtPzkrs="}
    81  	ctx := context.Background()
    82  
    83  	nr1 := commandspb.AnnounceNode{
    84  		Id:               "vega-master-pubkey",
    85  		ChainPubKey:      tmPubKeys[0],
    86  		VegaPubKey:       hexEncode("vega-key"),
    87  		EthereumAddress:  "0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B",
    88  		SubmitterAddress: "0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B",
    89  	}
    90  	err = top.AddNewNode(ctx, &nr1, validators.ValidatorStatusTendermint)
    91  	assert.NoError(t, err)
    92  	nr2 := commandspb.AnnounceNode{
    93  		Id:              "vega-master-pubkey-2",
    94  		ChainPubKey:     tmPubKeys[1],
    95  		VegaPubKey:      hexEncode("vega-key-2"),
    96  		EthereumAddress: "0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B",
    97  	}
    98  	err = top.AddNewNode(ctx, &nr2, validators.ValidatorStatusTendermint)
    99  	assert.NoError(t, err)
   100  
   101  	kr1 := &commandspb.KeyRotateSubmission{
   102  		NewPubKeyIndex:    1,
   103  		TargetBlock:       10,
   104  		NewPubKey:         "new-vega-key",
   105  		CurrentPubKeyHash: hashKey("vega-key"),
   106  	}
   107  
   108  	err = top.AddKeyRotate(ctx, nr1.Id, 5, kr1)
   109  	assert.NoError(t, err)
   110  
   111  	kr2 := &commandspb.KeyRotateSubmission{
   112  		NewPubKeyIndex:    1,
   113  		TargetBlock:       11,
   114  		NewPubKey:         "new-vega-key-2",
   115  		CurrentPubKeyHash: hashKey("vega-key-2"),
   116  	}
   117  	err = top.AddKeyRotate(ctx, nr2.Id, 5, kr2)
   118  	assert.NoError(t, err)
   119  	ekr1 := newEthereumKeyRotationSubmission("0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B", "0x69bA3B3e6B5b1226A2e26De9a9E2D9C98f2b144B", 10, "")
   120  	err = top.ProcessEthereumKeyRotation(ctx, hexEncode("vega-key"), ekr1, MockVerify)
   121  	assert.NoError(t, err)
   122  
   123  	ekr2 := newEthereumKeyRotationSubmission("0x6d53C489bbda35B8096C8b4Cb362e2889F82E19B", "0xd6B6e9514f2793Af89745Fd69FDa0DAbC228d336", 11, "")
   124  	err = top.ProcessEthereumKeyRotation(ctx, hexEncode("vega-key-2"), ekr2, MockVerify)
   125  	assert.NoError(t, err)
   126  
   127  	// Check the hashes have changed after each state change
   128  	top.signatures.EXPECT().SerialisePendingSignatures().Times(1)
   129  	s3, _, err := top.GetState(topKey)
   130  	require.Nil(t, err)
   131  	require.False(t, bytes.Equal(s1, s3))
   132  
   133  	// Get the state ready to load into a new instance of the engine
   134  	top.signatures.EXPECT().SerialisePendingSignatures().Times(1)
   135  	state, _, _ := top.GetState(topKey)
   136  	snap := &snapshot.Payload{}
   137  	err = proto.Unmarshal(state, snap)
   138  	require.Nil(t, err)
   139  
   140  	snapTop := getTestTopWithMockedSignatures(t)
   141  	defer snapTop.ctrl.Finish()
   142  	snapTop.timeService.EXPECT().GetTimeNow().AnyTimes()
   143  	snapTop.signatures.EXPECT().SetNonce(gomock.Any()).Times(1)
   144  	snapTop.signatures.EXPECT().RestorePendingSignatures(gomock.Any()).Times(1)
   145  
   146  	ctx = vegactx.WithBlockHeight(ctx, 100)
   147  	_, err = snapTop.LoadState(ctx, types.PayloadFromProto(snap))
   148  	require.Nil(t, err)
   149  
   150  	// Check the new reloaded engine is the same as the original
   151  	snapTop.signatures.EXPECT().SerialisePendingSignatures().Times(1)
   152  	s4, _, err := snapTop.GetState(topKey)
   153  	require.Nil(t, err)
   154  	require.True(t, bytes.Equal(s3, s4))
   155  	assert.ElementsMatch(t, top.AllNodeIDs(), snapTop.AllNodeIDs())
   156  	assert.ElementsMatch(t, top.AllVegaPubKeys(), snapTop.AllVegaPubKeys())
   157  	assert.Equal(t, top.IsValidator(), snapTop.IsValidator())
   158  	assert.Equal(t, top.GetPendingKeyRotation(kr1.TargetBlock, nr1.Id), snapTop.GetPendingKeyRotation(kr1.TargetBlock, nr1.Id))
   159  	assert.Equal(t, top.GetPendingKeyRotation(kr2.TargetBlock, nr2.Id), snapTop.GetPendingKeyRotation(kr2.TargetBlock, nr2.Id))
   160  	assert.Equal(t, top.GetPendingEthereumKeyRotation(ekr1.TargetBlock, nr1.Id), snapTop.GetPendingEthereumKeyRotation(ekr1.TargetBlock, nr1.Id))
   161  	assert.Equal(t, top.GetPendingEthereumKeyRotation(ekr2.TargetBlock, nr2.Id), snapTop.GetPendingEthereumKeyRotation(ekr2.TargetBlock, nr2.Id))
   162  }
   163  
   164  func updateValidatorPerformanceToNonDefaultState(t *testing.T, top *validators.Topology) {
   165  	t.Helper()
   166  	top.BeginBlock(context.Background(), 1, hex.EncodeToString(address1))
   167  
   168  	// expecting address1 to propose but got address3
   169  	top.BeginBlock(context.Background(), 1, hex.EncodeToString(address3))
   170  }