code.vegaprotocol.io/vega@v0.79.0/core/client/eth/ethereum_confirmations_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 eth_test
    17  
    18  import (
    19  	"math/big"
    20  	"testing"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/client/eth"
    24  	localMocks "code.vegaprotocol.io/vega/core/client/eth/mocks"
    25  	"code.vegaprotocol.io/vega/core/staking/mocks"
    26  
    27  	ethtypes "github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  func TestEthereumConfirmations(t *testing.T) {
    33  	ctrl := gomock.NewController(t)
    34  	ethClient := mocks.NewMockEthereumClientConfirmations(ctrl)
    35  	tim := localMocks.NewMockTime(ctrl)
    36  	cfg := eth.NewDefaultConfig()
    37  	cfg.RetryDelay.Duration = 15 * time.Second
    38  	ethCfns := eth.NewEthereumConfirmations(cfg, ethClient, tim, eth.FinalityStateFinalized)
    39  	defer ctrl.Finish()
    40  
    41  	ethCfns.UpdateConfirmations(30)
    42  
    43  	tim.EXPECT().Now().Times(1).Return(time.Unix(10, 0))
    44  	// start a block 10
    45  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
    46  		Return(&ethtypes.Header{Number: big.NewInt(10)}, nil)
    47  
    48  	// block 10, request 50, we are in the past, return err
    49  	assert.ErrorIs(t, ethCfns.Check(50), eth.ErrMissingConfirmations)
    50  
    51  	// request again but before buf size
    52  	// no request to eth
    53  	tim.EXPECT().Now().Times(1).Return(time.Unix(15, 0))
    54  
    55  	// block 10, request 50, we are in the past, return err
    56  	assert.ErrorIs(t, ethCfns.Check(50), eth.ErrMissingConfirmations)
    57  
    58  	// request again but before buf size
    59  	// no request to eth
    60  	tim.EXPECT().Now().Times(1).Return(time.Unix(26, 0))
    61  	// do block 50 == requested block
    62  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
    63  		Return(&ethtypes.Header{Number: big.NewInt(50)}, nil)
    64  
    65  	// block 10, request 50, we are in the past, return err
    66  	assert.ErrorIs(t, ethCfns.Check(50), eth.ErrMissingConfirmations)
    67  
    68  	// request again but before buf size
    69  	// no request to eth
    70  	tim.EXPECT().Now().Times(1).Return(time.Unix(42, 0))
    71  	// do block 79 > requested block < confirmations
    72  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).Times(1).
    73  		Return(&ethtypes.Header{Number: big.NewInt(79)}, nil)
    74  
    75  	// block 10, request 50, we are in the past, return err
    76  	assert.ErrorIs(t, ethCfns.Check(50), eth.ErrMissingConfirmations)
    77  
    78  	// request again but before buf size
    79  	tim.EXPECT().Now().Times(2).Return(time.Unix(58, 0))
    80  	// do block 80 > requested block == confirmations, and also block is seen as finalized
    81  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(2).
    82  		Return(&ethtypes.Header{Number: big.NewInt(80)}, nil)
    83  
    84  	assert.NoError(t, ethCfns.Check(50))
    85  
    86  	// request again but before buf size
    87  	// no request to eth
    88  	tim.EXPECT().Now().Times(2).Return(time.Unix(1000, 0))
    89  	// do block 80 > requested block == confirmations
    90  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(2).
    91  		Return(&ethtypes.Header{Number: big.NewInt(100)}, nil)
    92  
    93  	// block 10, request 50, we are in the past, return err
    94  	assert.NoError(t, ethCfns.Check(50))
    95  }
    96  
    97  func TestBlockFinalisation(t *testing.T) {
    98  	ctrl := gomock.NewController(t)
    99  	ethClient := mocks.NewMockEthereumClientConfirmations(ctrl)
   100  	tim := localMocks.NewMockTime(ctrl)
   101  	cfg := eth.NewDefaultConfig()
   102  	cfg.RetryDelay.Duration = 15 * time.Second
   103  	ethCfns := eth.NewEthereumConfirmations(cfg, ethClient, tim, eth.FinalityStateFinalized)
   104  	defer ctrl.Finish()
   105  
   106  	ethCfns.UpdateConfirmations(10)
   107  
   108  	// testing with block 50 where we need 10 confirmations
   109  	// current Ethereum block is 70 so we have enough confirmations, but finalized block is 49
   110  	tim.EXPECT().Now().Times(2).Return(time.Unix(10, 0))
   111  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
   112  		Return(&ethtypes.Header{Number: big.NewInt(70)}, nil)
   113  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
   114  		Return(&ethtypes.Header{Number: big.NewInt(49)}, nil)
   115  
   116  	// block 10, request 50, we are in the past, return err
   117  	assert.ErrorIs(t, ethCfns.Check(50), eth.ErrBlockNotFinalized)
   118  
   119  	// now we are passed enough confirmations AND the block has been finalized
   120  	tim.EXPECT().Now().Times(2).Return(time.Unix(60, 0))
   121  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
   122  		Return(&ethtypes.Header{Number: big.NewInt(70)}, nil)
   123  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
   124  		Return(&ethtypes.Header{Number: big.NewInt(50)}, nil)
   125  	assert.NoError(t, ethCfns.Check(50))
   126  }
   127  
   128  func TestCheckRequiredConfirmations(t *testing.T) {
   129  	ctrl := gomock.NewController(t)
   130  	ethClient := mocks.NewMockEthereumClientConfirmations(ctrl)
   131  	tim := localMocks.NewMockTime(ctrl)
   132  	cfg := eth.NewDefaultConfig()
   133  	cfg.RetryDelay.Duration = 15 * time.Second
   134  	ethCfns := eth.NewEthereumConfirmations(cfg, ethClient, tim, eth.FinalityStateFinalized)
   135  	defer ctrl.Finish()
   136  
   137  	tim.EXPECT().Now().Times(1).Return(time.Unix(10, 0))
   138  	// start a block 10
   139  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
   140  		Return(&ethtypes.Header{Number: big.NewInt(10)}, nil)
   141  
   142  	// block 10, request 50, we are in the past, return err
   143  	assert.ErrorIs(t, ethCfns.CheckRequiredConfirmations(50, 30), eth.ErrMissingConfirmations)
   144  
   145  	tim.EXPECT().Now().Times(1).Return(time.Unix(58, 0))
   146  	// do block 80 > requested block == confirmations
   147  	ethClient.EXPECT().HeaderByNumber(gomock.Any(), gomock.Any()).Times(1).
   148  		Return(&ethtypes.Header{Number: big.NewInt(80)}, nil)
   149  
   150  	// block 10, request 50, we are in the past, return err
   151  	assert.NoError(t, ethCfns.CheckRequiredConfirmations(50, 30))
   152  
   153  	tim.EXPECT().Now().Times(1).Return(time.Unix(59, 0))
   154  	assert.ErrorIs(t, ethCfns.CheckRequiredConfirmations(50, 40), eth.ErrMissingConfirmations)
   155  }