Skip to content

Commit

Permalink
WIP [2]
Browse files Browse the repository at this point in the history
  • Loading branch information
swift1337 committed Jun 19, 2024
1 parent 1e9506f commit 0274732
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 7 deletions.
2 changes: 1 addition & 1 deletion e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ var AllE2ETests = []runner.E2ETest{
runner.NewE2ETest(
TestBitcoinDepositRefundName,
"deposit Bitcoin into ZEVM; expect refund", []runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.001"},
{Description: "amount in btc", DefaultValue: "0.1"},
},
TestBitcoinDepositRefund,
),
Expand Down
39 changes: 34 additions & 5 deletions e2e/e2etests/test_bitcoin_deposit_refund.go
Original file line number Diff line number Diff line change
@@ -1,41 +1,70 @@
package e2etests

import (
"context"
"strconv"
"time"

"github.com/stretchr/testify/require"
"github.com/zeta-chain/zetacore/e2e/runner"
"github.com/zeta-chain/zetacore/e2e/utils"
"github.com/zeta-chain/zetacore/x/crosschain/types"
zetabitcoin "github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin"
)

func TestBitcoinDepositRefund(r *runner.E2ERunner, args []string) {
// ARRANGE
// Given amount to send
require.Len(r, args, 1)
amount := parseFloat(r, args[0])
amount += zetabitcoin.DefaultDepositorFee

// Given BTC address
r.SetBtcAddress(r.Name, false)

// Given a list of UTXOs
utxos, err := r.BtcRPCClient.ListUnspent()
utxos, err := r.ListDeployerUTXOs()
require.NoError(r, err)
require.NotEmpty(r, utxos)

// ACT
// Send a single UTXO to TSS address
// Send BTC to TSS address with a dummy memo
txHash, err := r.SendToTSSFromDeployerWithMemo(amount, utxos, []byte("gibberish-memo"))
require.NoError(r, err)
require.NotEmpty(r, txHash)

// Wait for processing in zetaclient
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.String(), r.CctxClient, r.Logger, r.CctxTimeout)
cctxs := utils.WaitCctxByInboundHash(r.Ctx, r, txHash.String(), r.CctxClient)

// ASSERT
require.Len(r, cctxs, 1)

// Check that it's status is related to tx reversal
actualStatus := cctx.CctxStatus.Status
expectedStatuses := []string{types.CctxStatus_PendingRevert.String(), types.CctxStatus_Reverted.String()}
actualStatus := cctxs[0].CctxStatus.Status.String()

require.Contains(r, expectedStatuses, actualStatus)

r.Logger.Info("CCTX revert status: %s", actualStatus)

// Now we want to make sure refund TX is completed. Let's check that zetaclient issued a refund on BTC
ctx, cancel := context.WithTimeout(r.Ctx, time.Minute*10)
defer cancel()

searchForCrossChainWithBtcRefund := utils.Matches(func(tx types.CrossChainTx) bool {
if len(tx.OutboundParams) != 2 {
return false
}

btcRefundTx := tx.OutboundParams[1]

return btcRefundTx.Hash != ""
})

cctxs = utils.WaitCctxByInboundHash(ctx, r, txHash.String(), r.CctxClient, searchForCrossChainWithBtcRefund)
require.Len(r, cctxs, 1)

require.Contains(r, []types.CctxStatus{types.CctxStatus_PendingRevert, types.CctxStatus_Reverted}, actualStatus)
// todo check that BTC refund is completed
}

func parseFloat(t require.TestingT, s string) float64 {
Expand Down
73 changes: 72 additions & 1 deletion e2e/utils/zetacore.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import (

rpchttp "github.com/cometbft/cometbft/rpc/client/http"
coretypes "github.com/cometbft/cometbft/rpc/core/types"

"github.com/stretchr/testify/require"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type CCTXClient = crosschaintypes.QueryClient

const (
FungibleAdminName = "fungibleadmin"

Expand Down Expand Up @@ -170,6 +174,73 @@ func WaitCCTXMinedByIndex(
}
}

type WaitOpts func(c *waitConfig)

// MatchStatus waits for a specific CCTX status.
func MatchStatus(s crosschaintypes.CctxStatus) WaitOpts {
return Matches(func(tx crosschaintypes.CrossChainTx) bool {
return tx.CctxStatus != nil && tx.CctxStatus.Status == s
})
}

func Matches(fn func(tx crosschaintypes.CrossChainTx) bool) WaitOpts {
return func(c *waitConfig) { c.matchFunction = fn }
}

type waitConfig struct {
matchFunction func(tx crosschaintypes.CrossChainTx) bool
}

// WaitCctxByInboundHash waits until cctx appears by inbound hash.
func WaitCctxByInboundHash(ctx context.Context, t require.TestingT, hash string, c CCTXClient, opts ...WaitOpts) []crosschaintypes.CrossChainTx {
const tick = time.Millisecond * 200

if _, hasDeadline := ctx.Deadline(); !hasDeadline {
var cancel func()
ctx, cancel = context.WithTimeout(ctx, DefaultCctxTimeout)
defer cancel()
}

in := &crosschaintypes.QueryInboundHashToCctxDataRequest{InboundHash: hash}

var cfg waitConfig
for _, opt := range opts {
opt(&cfg)
}

matches := func(txs []crosschaintypes.CrossChainTx) bool {
if cfg.matchFunction == nil {
return true
}

for _, tx := range txs {
if ok := cfg.matchFunction(tx); !ok {
return false
}
}

return true
}

for {
out, err := c.InTxHashToCctxData(ctx, in)
statusCode, _ := status.FromError(err)

switch {
case statusCode.Code() == codes.NotFound:
// expected; let's retry
case err != nil:
require.NoError(t, err, "failed to get cctx by inbound hash: %s", hash)
case len(out.CrossChainTxs) > 0 && matches(out.CrossChainTxs):
return out.CrossChainTxs
case ctx.Err() == nil:
require.NoError(t, err, "failed to get cctx by inbound hash (ctx error): %s", hash)
}

time.Sleep(tick)
}
}

func IsTerminalStatus(status crosschaintypes.CctxStatus) bool {
return status == crosschaintypes.CctxStatus_OutboundMined ||
status == crosschaintypes.CctxStatus_Aborted ||
Expand Down

0 comments on commit 0274732

Please sign in to comment.