code.vegaprotocol.io/vega@v0.79.0/core/staking/checkpoint_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 staking_test
    17  
    18  import (
    19  	"context"
    20  	"testing"
    21  
    22  	"code.vegaprotocol.io/vega/core/staking"
    23  	"code.vegaprotocol.io/vega/core/staking/mocks"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  	"code.vegaprotocol.io/vega/libs/proto"
    27  	"code.vegaprotocol.io/vega/logging"
    28  	checkpoint "code.vegaprotocol.io/vega/protos/vega/checkpoint/v1"
    29  
    30  	"github.com/golang/mock/gomock"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  
    34  	_ "embed"
    35  )
    36  
    37  //go:embed testcp/20220627071230-316971-11a4d958cb7e0448f0cea0b7c617a1e4535e90c0d0f18fd86e961c97147757d7.cp
    38  var cpFile []byte
    39  
    40  type checkpointTest struct {
    41  	*staking.Checkpoint
    42  	sv  *stakeVerifierTest
    43  	acc *accountingTest
    44  
    45  	ctrl           *gomock.Controller
    46  	ethEventSource *mocks.MockEthereumEventSource
    47  }
    48  
    49  func getCheckpointTest(t *testing.T) *checkpointTest {
    50  	t.Helper()
    51  	sv := getStakeVerifierTest(t)
    52  	acc := getAccountingTest(t)
    53  
    54  	ctrl := gomock.NewController(t)
    55  	ethEventSource := mocks.NewMockEthereumEventSource(ctrl)
    56  
    57  	return &checkpointTest{
    58  		Checkpoint: staking.NewCheckpoint(
    59  			logging.NewTestLogger(),
    60  			acc.Accounting,
    61  			sv.StakeVerifier,
    62  			ethEventSource,
    63  		),
    64  		sv:             sv,
    65  		acc:            acc,
    66  		ctrl:           ctrl,
    67  		ethEventSource: ethEventSource,
    68  	}
    69  }
    70  
    71  func (c *checkpointTest) Finish() {
    72  	c.ctrl.Finish()
    73  	c.sv.ctrl.Finish()
    74  }
    75  
    76  // TestCheckpointLoadNoDuplicates is testing that with the recent changes
    77  // balance on mainnet are reconciled accurately. Due to a bug some eth events
    78  // go duplicated and balances became incorrect. The Load call without duplication
    79  // for the events would have panicked, this should not.
    80  func TestCheckpointLoadNoDuplicates(t *testing.T) {
    81  	cptest := getCheckpointTest(t)
    82  	defer cptest.Finish()
    83  
    84  	cp := &checkpoint.Checkpoint{}
    85  	if err := proto.Unmarshal(cpFile, cp); err != nil {
    86  		t.Fatal(err)
    87  	}
    88  
    89  	cptest.acc.broker.EXPECT().Send(gomock.Any()).AnyTimes()
    90  	cptest.acc.broker.EXPECT().SendBatch(gomock.Any()).Times(1)
    91  	cptest.sv.ocv.EXPECT().GetStakingBridgeAddresses().Times(1).Return([]string{"hello"})
    92  	cptest.ethEventSource.EXPECT().UpdateContractBlock(gomock.Any(), gomock.Any(), gomock.Any()).Do(
    93  		func(_, _ string, block uint64) {
    94  			// ensure we restart at the right block
    95  			// which is the last pending event we've seen
    96  			assert.Equal(t, int(block), 15026715)
    97  		},
    98  	)
    99  	require.NotPanics(t, func() { cptest.Load(context.Background(), cp.Staking) })
   100  
   101  	// now we ensure the balance which were incorrect are now OK
   102  	balance, err := cptest.acc.GetAvailableBalance(
   103  		"657c2a8a5867c43c831e24820b7544e2fdcc1cf610cfe0ece940fe78137400fd")
   104  	assert.NoError(t, err)
   105  	assert.Equal(t, balance, num.NewUint(0))
   106  }
   107  
   108  func TestCheckpoint(t *testing.T) {
   109  	cptest := getCheckpointTest(t)
   110  	defer cptest.Finish()
   111  
   112  	cptest.setupAccounting(t)
   113  	cptest.setupStakeVerifier(t)
   114  
   115  	cp, err := cptest.Checkpoint.Checkpoint()
   116  	assert.NoError(t, err)
   117  	assert.True(t, len(cp) > 0)
   118  
   119  	cptest2 := getCheckpointTest(t)
   120  
   121  	cptest2.acc.broker.EXPECT().Send(gomock.Any()).AnyTimes()
   122  	cptest2.sv.ocv.EXPECT().GetStakingBridgeAddresses().AnyTimes().Return([]string{"hello"})
   123  	cptest2.ethEventSource.EXPECT().UpdateContractBlock(gomock.Any(), gomock.Any(), gomock.Any()).Do(
   124  		func(_, _ string, block uint64) {
   125  			// ensure we restart at the right block
   126  			// which is the last pending event we've seen
   127  			assert.Equal(t, int(block), 42)
   128  		},
   129  	)
   130  
   131  	cptest2.acc.broker.EXPECT().SendBatch(gomock.Any()).Times(1)
   132  	assert.NoError(t, cptest2.Load(context.Background(), cp))
   133  
   134  	bal, err := cptest2.acc.GetAvailableBalance(testParty)
   135  	assert.NoError(t, err)
   136  	assert.Equal(t, bal, num.NewUint(10))
   137  }
   138  
   139  func (c *checkpointTest) setupAccounting(t *testing.T) {
   140  	t.Helper()
   141  	ctx := context.Background()
   142  	c.acc.broker.EXPECT().Send(gomock.Any()).Times(1)
   143  
   144  	evt := &types.StakeLinking{
   145  		ID:              "someid1",
   146  		Type:            types.StakeLinkingTypeDeposited,
   147  		TS:              100,
   148  		Party:           testParty,
   149  		Amount:          num.NewUint(10),
   150  		Status:          types.StakeLinkingStatusAccepted,
   151  		FinalizedAt:     100,
   152  		TxHash:          "0x123456",
   153  		BlockHeight:     1000,
   154  		BlockTime:       10,
   155  		LogIndex:        100,
   156  		EthereumAddress: "0x123456",
   157  	}
   158  	c.acc.AddEvent(ctx, evt)
   159  }
   160  
   161  func (c *checkpointTest) setupStakeVerifier(t *testing.T) {
   162  	t.Helper()
   163  	c.sv.tsvc.EXPECT().GetTimeNow().Times(1)
   164  	c.sv.broker.EXPECT().Send(gomock.Any()).Times(1)
   165  	c.sv.witness.EXPECT().StartCheck(gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
   166  
   167  	event := &types.StakeDeposited{
   168  		BlockNumber:     42,
   169  		LogIndex:        1789,
   170  		TxID:            "somehash",
   171  		ID:              "someid",
   172  		VegaPubKey:      "somepubkey",
   173  		EthereumAddress: "0xnothex",
   174  		Amount:          num.NewUint(1000),
   175  		BlockTime:       100000,
   176  	}
   177  
   178  	err := c.sv.ProcessStakeDeposited(context.Background(), event)
   179  	require.Nil(t, err)
   180  }