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 }