Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rfq-relayer): highly concurrent e2e test #3042

Merged
merged 7 commits into from
Aug 20, 2024
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions services/rfq/e2e/rfq_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package e2e_test

import (
"fmt"
"math/big"
"sync"
"testing"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/suite"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/core/metrics"
Expand All @@ -25,6 +28,7 @@
"github.com/synapsecns/sanguine/services/rfq/relayer/service"
"github.com/synapsecns/sanguine/services/rfq/testutil"
"github.com/synapsecns/sanguine/services/rfq/util"
"golang.org/x/sync/errgroup"
)

type IntegrationSuite struct {
Expand Down Expand Up @@ -468,3 +472,169 @@
return result.TxHash == fakeHash && result.Status == guarddb.Disputed && result.TransactionID == txID
})
}

func (i *IntegrationSuite) TestMultipleBridges() {

Check failure on line 476 in services/rfq/e2e/rfq_test.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

cognitive complexity 42 of func `(*IntegrationSuite).TestMultipleBridges` is high (> 30) (gocognit)
// start the relayer and guard
go func() {
_ = i.relayer.Start(i.GetTestContext())
}()
go func() {
_ = i.guard.Start(i.GetTestContext())
}()

// load token contracts
const startAmount = 10000
const rfqAmount = 10
opts := i.destBackend.GetTxContext(i.GetTestContext(), nil)
destUSDC, destUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.destBackend)
realStartAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(startAmount), destUSDC.ContractHandle())
i.NoError(err)
realRFQAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(rfqAmount), destUSDC.ContractHandle())
i.NoError(err)

// add initial usdc to relayer on destination
tx, err := destUSDCHandle.MintPublic(opts.TransactOpts, i.relayerWallet.Address(), realStartAmount)
i.Nil(err)
i.destBackend.WaitForConfirmation(i.GetTestContext(), tx)
i.Approve(i.destBackend, destUSDC, i.relayerWallet)

// add initial USDC to relayer on origin
optsOrigin := i.originBackend.GetTxContext(i.GetTestContext(), nil)
originUSDC, originUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.originBackend)
tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.relayerWallet.Address(), realStartAmount)
i.Nil(err)
i.originBackend.WaitForConfirmation(i.GetTestContext(), tx)
i.Approve(i.originBackend, originUSDC, i.relayerWallet)

// add initial USDC to user on origin
tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.userWallet.Address(), realStartAmount)
i.Nil(err)
i.originBackend.WaitForConfirmation(i.GetTestContext(), tx)
i.Approve(i.originBackend, originUSDC, i.userWallet)

// non decimal adjusted user want amount
// now our friendly user is going to check the quote and send us some USDC on the origin chain.
i.Eventually(func() bool {
// first he's gonna check the quotes.
userAPIClient, err := client.NewAuthenticatedClient(metrics.Get(), i.apiServer, localsigner.NewSigner(i.userWallet.PrivateKey()))
i.NoError(err)

allQuotes, err := userAPIClient.GetAllQuotes(i.GetTestContext())
i.NoError(err)

// let's figure out the amount of usdc we need
for _, quote := range allQuotes {
if common.HexToAddress(quote.DestTokenAddr) == destUSDC.Address() {
destAmountBigInt, _ := new(big.Int).SetString(quote.DestAmount, 10)
if destAmountBigInt.Cmp(realRFQAmount) > 0 {
// we found our quote!
// now we can move on
return true
}
}
}
return false
})

_, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend)
auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr())
parser, err := fastbridge.NewParser(originFastBridge.Address())
i.NoError(err)

txIDs := [][32]byte{}
txMux := sync.Mutex{}
sendBridgeReq := func(nonce *big.Int) (*types.Transaction, error) {
txMux.Lock()
auth.TransactOpts.Nonce = nonce
defer txMux.Unlock()
tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{
DstChainId: uint32(i.destBackend.GetChainID()),
To: i.userWallet.Address(),
OriginToken: originUSDC.Address(),
SendChainGas: true,
DestToken: destUSDC.Address(),
OriginAmount: realRFQAmount,
DestAmount: new(big.Int).Sub(realRFQAmount, big.NewInt(5_000_000)),
Deadline: new(big.Int).SetInt64(time.Now().Add(time.Hour * 24).Unix()),
})
if err != nil {
return nil, fmt.Errorf("failed to send bridge request: %w", err)
}
return tx, nil
}

// send several txs at once and record txids
numTxs := 100
txIDMux := sync.Mutex{}
g, ctx := errgroup.WithContext(i.GetTestContext())
for k := 0; k < numTxs; k++ {
nonce := big.NewInt(int64(k))
g.Go(func() error {
tx, err := sendBridgeReq(nonce)
if err != nil {
return fmt.Errorf("failed to send bridge request: %w", err)
}

i.originBackend.WaitForConfirmation(ctx, tx)
receipt, err := i.originBackend.TransactionReceipt(ctx, tx.Hash())
if err != nil {
return fmt.Errorf("failed to get receipt: %w", err)
}
for _, log := range receipt.Logs {
_, parsedEvent, ok := parser.ParseEvent(*log)
if !ok {
continue
}
event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRequested)
if ok {
txIDMux.Lock()
txIDs = append(txIDs, event.TransactionId)
txIDMux.Unlock()
return nil
}
}
return nil
})
}
err = g.Wait()
i.NoError(err)
i.Equal(numTxs, len(txIDs))

// TODO: this, but cleaner
anvilClient, err := anvil.Dial(i.GetTestContext(), i.originBackend.RPCAddress())
i.NoError(err)

go func() {
for {
select {
case <-i.GetTestContext().Done():
return
case <-time.After(time.Second * 4):
// increase time by 30 mintutes every second, should be enough to get us a fastish e2e test
// we don't need to worry about deadline since we're only doing this on origin
err = anvilClient.IncreaseTime(i.GetTestContext(), 60*30)
i.NoError(err)

// because can claim works on last block timestamp, we need to do something
err = anvilClient.Mine(i.GetTestContext(), 1)
i.NoError(err)
}
}

}()

Check failure on line 624 in services/rfq/e2e/rfq_test.go

View workflow job for this annotation

GitHub Actions / Lint (services/rfq)

unnecessary trailing newline (whitespace)

// verify that each tx is relayed
i.Eventually(func() bool {
for _, txID := range txIDs {
result, err := i.store.GetQuoteRequestByID(i.GetTestContext(), txID)
if err != nil {
return false
}
fmt.Printf("result: %+v\n", result)
if result.Status <= reldb.ProvePosted {
return false
}
}
return true
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor to reduce cognitive complexity.

The function TestMultipleBridges has a cognitive complexity of 42, which is above the recommended threshold of 30. Consider breaking down the function into smaller, more manageable pieces to improve readability and maintainability.

Address the TODO comment for time manipulation.

The comment suggests that the time manipulation logic should be cleaned up. Consider refactoring this part of the code to make it more concise and maintainable.

Remove unnecessary trailing newline.

There is an unnecessary trailing newline at the end of the function. Removing it will improve code cleanliness.

-  })
+  })

Committable suggestion was skipped due to low confidence.

Tools
GitHub Check: Lint (services/rfq)

[failure] 476-476:
cognitive complexity 42 of func (*IntegrationSuite).TestMultipleBridges is high (> 30) (gocognit)


[failure] 624-624:
unnecessary trailing newline (whitespace)

Loading