-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor and fix evm outbound tracker reporter to avoid invalid hashe…
…s; print log when outbound tracker is full of invalid hashes
- Loading branch information
1 parent
b4251e1
commit 5e6f77f
Showing
11 changed files
with
322 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package rpc | ||
|
||
import ( | ||
"context" | ||
|
||
ethcommon "github.com/ethereum/go-ethereum/common" | ||
"github.com/pkg/errors" | ||
|
||
"github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" | ||
) | ||
|
||
// IsTxConfirmed checks if the transaction is confirmed with given confirmations | ||
func IsTxConfirmed( | ||
ctx context.Context, | ||
client interfaces.EVMRPCClient, | ||
txHash string, | ||
confirmations uint64, | ||
) (bool, error) { | ||
// query the tx | ||
_, isPending, err := client.TransactionByHash(ctx, ethcommon.HexToHash(txHash)) | ||
if err != nil { | ||
return false, errors.Wrapf(err, "error getting transaction for tx %s", txHash) | ||
} | ||
if isPending { | ||
return false, nil | ||
} | ||
|
||
// query receipt | ||
receipt, err := client.TransactionReceipt(ctx, ethcommon.HexToHash(txHash)) | ||
if err != nil { | ||
return false, errors.Wrapf(err, "error getting transaction receipt for tx %s", txHash) | ||
} | ||
|
||
// should not happen | ||
if receipt == nil { | ||
return false, errors.Errorf("receipt is nil for tx %s", txHash) | ||
} | ||
|
||
// query last block height | ||
lastHeight, err := client.BlockNumber(ctx) | ||
if err != nil { | ||
return false, errors.Wrap(err, "error getting block number") | ||
} | ||
|
||
// check confirmations | ||
if lastHeight < receipt.BlockNumber.Uint64() { | ||
return false, nil | ||
} | ||
blocks := lastHeight - receipt.BlockNumber.Uint64() + 1 | ||
|
||
return blocks >= confirmations, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package rpc_test | ||
|
||
import ( | ||
"context" | ||
"math" | ||
|
||
"github.com/ethereum/go-ethereum/ethclient" | ||
"github.com/stretchr/testify/require" | ||
"github.com/zeta-chain/zetacore/zetaclient/chains/evm/rpc" | ||
|
||
"testing" | ||
) | ||
|
||
const ( | ||
URLEthMainnet = "https://rpc.ankr.com/eth" | ||
URLEthSepolia = "https://rpc.ankr.com/eth_sepolia" | ||
URLBscMainnet = "https://rpc.ankr.com/bsc" | ||
URLPolygonMainnet = "https://rpc.ankr.com/polygon" | ||
) | ||
|
||
// Test_EVMRPCLive is a phony test to run each live test individually | ||
func Test_EVMRPCLive(t *testing.T) { | ||
// LiveTest_IsTxConfirmed(t) | ||
} | ||
|
||
func LiveTest_IsTxConfirmed(t *testing.T) { | ||
client, err := ethclient.Dial(URLEthMainnet) | ||
require.NoError(t, err) | ||
|
||
// check if the transaction is confirmed | ||
ctx := context.Background() | ||
txHash := "0xd2eba7ac3da1b62800165414ea4bcaf69a3b0fb9b13a0fc32f4be11bfef79146" | ||
|
||
t.Run("should confirm tx", func(t *testing.T) { | ||
confirmed, err := rpc.IsTxConfirmed(ctx, client, txHash, 12) | ||
require.NoError(t, err) | ||
require.True(t, confirmed) | ||
}) | ||
|
||
t.Run("should not confirm tx if confirmations is not enough", func(t *testing.T) { | ||
confirmed, err := rpc.IsTxConfirmed(ctx, client, txHash, math.MaxUint64) | ||
require.NoError(t, err) | ||
require.False(t, confirmed) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Package signer implements the ChainSigner interface for EVM chains | ||
package signer | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/rs/zerolog" | ||
|
||
"github.com/zeta-chain/zetacore/zetaclient/chains/evm" | ||
"github.com/zeta-chain/zetacore/zetaclient/chains/evm/rpc" | ||
"github.com/zeta-chain/zetacore/zetaclient/chains/interfaces" | ||
"github.com/zeta-chain/zetacore/zetaclient/logs" | ||
) | ||
|
||
// reportToOutboundTracker reports outboundHash to tracker only when tx receipt is available | ||
func (signer *Signer) reportToOutboundTracker( | ||
ctx context.Context, | ||
zetacoreClient interfaces.ZetacoreClient, | ||
chainID int64, | ||
nonce uint64, | ||
outboundHash string, | ||
logger zerolog.Logger, | ||
) { | ||
// prepare logger | ||
logger = logger.With(). | ||
Str(logs.FieldMethod, "reportToOutboundTracker"). | ||
Int64(logs.FieldChain, chainID). | ||
Uint64(logs.FieldNonce, nonce). | ||
Str(logs.FieldTx, outboundHash). | ||
Logger() | ||
|
||
// set being reported flag to avoid duplicate reporting | ||
alreadySet := signer.Signer.SetBeingReportedFlag(outboundHash) | ||
if alreadySet { | ||
logger.Info(). | ||
Msgf("outbound %s for chain %d nonce %d is being reported", outboundHash, chainID, nonce) | ||
return | ||
} | ||
|
||
// launch a goroutine to monitor tx confirmation status | ||
go func() { | ||
defer func() { | ||
signer.Signer.ClearBeingReportedFlag(outboundHash) | ||
}() | ||
|
||
// try monitoring tx inclusion status for 20 minutes | ||
tStart := time.Now() | ||
for { | ||
// take a rest between each check | ||
time.Sleep(10 * time.Second) | ||
|
||
// give up (forget about the tx) after 20 minutes of monitoring, there are 2 reasons: | ||
// 1. the gas stability pool should have kicked in and replaced the tx by then. | ||
// 2. even if there is a chance that the tx is included later, most likely it's going to be a false tx hash (either replaced or dropped). | ||
if time.Since(tStart) > evm.OutboundInclusionTimeout { | ||
logger.Info(). | ||
Msgf("timeout waiting outbound %s inclusion for chain %d nonce %d", outboundHash, chainID, nonce) | ||
return | ||
} | ||
|
||
// check tx confirmation status | ||
confirmed, err := rpc.IsTxConfirmed(ctx, signer.client, outboundHash, evm.ReorgProtectBlockCount) | ||
if err != nil { | ||
logger.Err(err). | ||
Msgf("unable to check confirmation status for chain %d nonce %d outbound %s", chainID, nonce, outboundHash) | ||
} | ||
if !confirmed { | ||
continue | ||
} | ||
|
||
// report outbound hash to tracker | ||
zetaHash, err := zetacoreClient.AddOutboundTracker(ctx, chainID, nonce, outboundHash, nil, "", -1) | ||
if err != nil { | ||
logger.Err(err). | ||
Msgf("error adding outbound %s to tracker for chain %d nonce %d", outboundHash, chainID, nonce) | ||
} else if zetaHash != "" { | ||
logger.Info().Msgf("added outbound %s to tracker for chain %d nonce %d; zeta txhash %s", outboundHash, chainID, nonce, zetaHash) | ||
} else { | ||
// exit goroutine until the tracker contains the hash (reported by either this or other signers) | ||
logger.Info().Msgf("outbound %s now exists in tracker for chain %d nonce %d", outboundHash, chainID, nonce) | ||
return | ||
} | ||
} | ||
}() | ||
} |
Oops, something went wrong.