github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/testing/coordinator.go (about)

     1  package ibctesting
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/fibonacci-chain/fbc/libs/tendermint/types"
    10  
    11  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  const ChainIDPrefix = "testchain"
    16  
    17  var (
    18  	globalStartTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC)
    19  	TimeIncrement   = time.Second * 5
    20  )
    21  
    22  // Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains
    23  // in sync with regards to time.
    24  type Coordinator struct {
    25  	t *testing.T
    26  
    27  	CurrentTime time.Time
    28  	Chains      map[string]TestChainI
    29  }
    30  
    31  // NewCoordinator initializes Coordinator with N TestChain's
    32  func NewCoordinator(t *testing.T, n int) *Coordinator {
    33  	types.UnittestOnlySetMilestoneVenus1Height(-1)
    34  	chains := make(map[string]TestChainI)
    35  	coord := &Coordinator{
    36  		t:           t,
    37  		CurrentTime: globalStartTime,
    38  	}
    39  
    40  	for i := 0; i < n; i++ {
    41  		chainID := GetChainID(i)
    42  		chains[chainID] = NewTestChain(t, coord, chainID)
    43  	}
    44  	coord.Chains = chains
    45  
    46  	return coord
    47  }
    48  func NewEthCoordinator(t *testing.T, n int) *Coordinator {
    49  	types.UnittestOnlySetMilestoneVenus1Height(-1)
    50  	chains := make(map[string]TestChainI)
    51  	coord := &Coordinator{
    52  		t:           t,
    53  		CurrentTime: globalStartTime,
    54  	}
    55  
    56  	for i := 1; i <= n; i++ {
    57  		chainID := GetOKChainID(i)
    58  		chains[chainID] = NewTestEthChain(t, coord, chainID)
    59  	}
    60  	coord.Chains = chains
    61  
    62  	return coord
    63  }
    64  
    65  // IncrementTime iterates through all the TestChain's and increments their current header time
    66  // by 5 seconds.
    67  //
    68  // CONTRACT: this function must be called after every Commit on any TestChain.
    69  func (coord *Coordinator) IncrementTime() {
    70  	coord.IncrementTimeBy(TimeIncrement)
    71  }
    72  
    73  // IncrementTimeBy iterates through all the TestChain's and increments their current header time
    74  // by specified time.
    75  func (coord *Coordinator) IncrementTimeBy(increment time.Duration) {
    76  	coord.CurrentTime = coord.CurrentTime.Add(increment).UTC()
    77  	coord.UpdateTime()
    78  
    79  }
    80  
    81  // UpdateTime updates all clocks for the TestChains to the current global time.
    82  func (coord *Coordinator) UpdateTime() {
    83  	for _, chain := range coord.Chains {
    84  		coord.UpdateTimeForChain(chain)
    85  	}
    86  }
    87  
    88  // UpdateTimeForChain updates the clock for a specific chain.
    89  func (coord *Coordinator) UpdateTimeForChain(chain TestChainI) {
    90  	chain.CurrentHeaderTime(coord.CurrentTime.UTC())
    91  	chain.App().BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader()})
    92  }
    93  
    94  // Setup constructs a TM client, connection, and channel on both chains provided. It will
    95  // fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned
    96  // for both chains. The channels created are connected to the ibc-transfer application.
    97  func (coord *Coordinator) Setup(path *Path) {
    98  	coord.SetupConnections(path)
    99  
   100  	// channels can also be referenced through the returned connections
   101  	coord.CreateChannels(path)
   102  }
   103  
   104  // SetupClients is a helper function to create clients on both chains. It assumes the
   105  // caller does not anticipate any errors.
   106  func (coord *Coordinator) SetupClients(path *Path) {
   107  	err := path.EndpointA.CreateClient()
   108  	require.NoError(coord.t, err)
   109  
   110  	err = path.EndpointB.CreateClient()
   111  	require.NoError(coord.t, err)
   112  }
   113  
   114  // SetupClientConnections is a helper function to create clients and the appropriate
   115  // connections on both the source and counterparty chain. It assumes the caller does not
   116  // anticipate any errors.
   117  func (coord *Coordinator) SetupConnections(path *Path) {
   118  	coord.SetupClients(path)
   119  
   120  	coord.CreateConnections(path)
   121  }
   122  
   123  // CreateConnection constructs and executes connection handshake messages in order to create
   124  // OPEN channels on chainA and chainB. The connection information of for chainA and chainB
   125  // are returned within a TestConnection struct. The function expects the connections to be
   126  // successfully opened otherwise testing will fail.
   127  func (coord *Coordinator) CreateConnections(path *Path) {
   128  
   129  	err := path.EndpointA.ConnOpenInit()
   130  	require.NoError(coord.t, err)
   131  
   132  	err = path.EndpointB.ConnOpenTry()
   133  	require.NoError(coord.t, err)
   134  
   135  	err = path.EndpointA.ConnOpenAck()
   136  	require.NoError(coord.t, err)
   137  
   138  	err = path.EndpointB.ConnOpenConfirm()
   139  	require.NoError(coord.t, err)
   140  
   141  	// ensure counterparty is up to date
   142  	path.EndpointA.UpdateClient()
   143  }
   144  
   145  // CreateMockChannels constructs and executes channel handshake messages to create OPEN
   146  // channels that use a mock application module that returns nil on all callbacks. This
   147  // function is expects the channels to be successfully opened otherwise testing will
   148  // fail.
   149  func (coord *Coordinator) CreateMockChannels(path *Path) {
   150  	path.EndpointA.ChannelConfig.PortID = MockPort
   151  	path.EndpointB.ChannelConfig.PortID = MockPort
   152  
   153  	coord.CreateChannels(path)
   154  }
   155  
   156  // CreateTransferChannels constructs and executes channel handshake messages to create OPEN
   157  // ibc-transfer channels on chainA and chainB. The function expects the channels to be
   158  // successfully opened otherwise testing will fail.
   159  func (coord *Coordinator) CreateTransferChannels(path *Path) {
   160  	path.EndpointA.ChannelConfig.PortID = TransferPort
   161  	path.EndpointB.ChannelConfig.PortID = TransferPort
   162  
   163  	coord.CreateChannels(path)
   164  }
   165  
   166  // CreateChannel constructs and executes channel handshake messages in order to create
   167  // OPEN channels on chainA and chainB. The function expects the channels to be successfully
   168  // opened otherwise testing will fail.
   169  func (coord *Coordinator) CreateChannels(path *Path) {
   170  	err := path.EndpointA.ChanOpenInit()
   171  	require.NoError(coord.t, err)
   172  
   173  	err = path.EndpointB.ChanOpenTry()
   174  	require.NoError(coord.t, err)
   175  
   176  	err = path.EndpointA.ChanOpenAck()
   177  	require.NoError(coord.t, err)
   178  
   179  	err = path.EndpointB.ChanOpenConfirm()
   180  	require.NoError(coord.t, err)
   181  
   182  	// ensure counterparty is up to date
   183  	path.EndpointA.UpdateClient()
   184  }
   185  
   186  // GetChain returns the TestChain using the given chainID and returns an error if it does
   187  // not exist.
   188  func (coord *Coordinator) GetChain(chainID string) TestChainI {
   189  	chain, found := coord.Chains[chainID]
   190  	require.True(coord.t, found, fmt.Sprintf("%s chain does not exist", chainID))
   191  	return chain
   192  }
   193  
   194  // GetChainID returns the chainID used for the provided index.
   195  func GetChainID(index int) string {
   196  	return ChainIDPrefix + strconv.Itoa(index)
   197  }
   198  
   199  // GetChainID returns the chainID used for the provided index.
   200  func GetOKChainID(index int) string {
   201  	return ChainIDPrefix + "-" + strconv.Itoa(index)
   202  }
   203  
   204  // CommitBlock commits a block on the provided indexes and then increments the global time.
   205  //
   206  // CONTRACT: the passed in list of indexes must not contain duplicates
   207  func (coord *Coordinator) CommitBlock(chains ...TestChainI) {
   208  	for _, chain := range chains {
   209  		//chain.NextBlock()
   210  		//chain.BeginBlock()
   211  		chain.App().Commit(abci.RequestCommit{})
   212  		//chain.UpdateNextBlock()
   213  		chain.NextBlock()
   214  	}
   215  	coord.IncrementTime()
   216  }
   217  
   218  func (coord *Coordinator) UpdateNextBlock(chains ...TestChainI) {
   219  	for _, chain := range chains {
   220  		chain.UpdateNextBlock()
   221  	}
   222  }
   223  
   224  // CommitNBlocks commits n blocks to state and updates the block height by 1 for each commit.
   225  func (coord *Coordinator) CommitNBlocks(chain TestChainI, n uint64) {
   226  	for i := uint64(0); i < n; i++ {
   227  		chain.App().BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader()})
   228  		chain.App().Commit(abci.RequestCommit{})
   229  		chain.NextBlock()
   230  		coord.IncrementTime()
   231  	}
   232  }
   233  
   234  // ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT
   235  // using the OpenInit handshake call.
   236  func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error {
   237  	if err := path.EndpointA.ConnOpenInit(); err != nil {
   238  		return err
   239  	}
   240  
   241  	if err := path.EndpointB.ConnOpenInit(); err != nil {
   242  		return err
   243  	}
   244  
   245  	if err := path.EndpointA.UpdateClient(); err != nil {
   246  		return err
   247  	}
   248  
   249  	if err := path.EndpointB.UpdateClient(); err != nil {
   250  		return err
   251  	}
   252  
   253  	return nil
   254  }
   255  
   256  // ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain
   257  // with the state INIT using the OpenInit handshake call.
   258  func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error {
   259  	// NOTE: only creation of a capability for a transfer or mock port is supported
   260  	// Other applications must bind to the port in InitGenesis or modify this code.
   261  
   262  	if err := path.EndpointA.ChanOpenInit(); err != nil {
   263  		return err
   264  	}
   265  
   266  	if err := path.EndpointB.ChanOpenInit(); err != nil {
   267  		return err
   268  	}
   269  
   270  	if err := path.EndpointA.UpdateClient(); err != nil {
   271  		return err
   272  	}
   273  
   274  	if err := path.EndpointB.UpdateClient(); err != nil {
   275  		return err
   276  	}
   277  
   278  	return nil
   279  }