Skip to content

Commit

Permalink
initial commit to simply IsSendOutTxProcessed func
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Apr 5, 2024
1 parent 9eb55e7 commit af26d74
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 277 deletions.
2 changes: 1 addition & 1 deletion cmd/zetaclientd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func start(_ *cobra.Command, _ []string) error {

// Initialize core parameters from zetacore
appContext := appcontext.NewAppContext(corecontext.NewZetaCoreContext(cfg), cfg)
err = zetaBridge.UpdateZetaCoreContext(appContext.ZetaCoreContext(), true)
err = zetaBridge.UpdateZetaCoreContext(appContext.ZetaCoreContext(), true, startLogger)
if err != nil {
startLogger.Error().Err(err).Msg("Error getting core parameters")
return err
Expand Down
338 changes: 65 additions & 273 deletions zetaclient/evm/evm_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,298 +317,90 @@ func (ob *ChainClient) Stop() {
ob.logger.Chain.Info().Msgf("%s observer stopped", ob.chain.String())
}

// returns: isIncluded, isConfirmed, Error
// If isConfirmed, it also post to ZetaCore
// IsSendOutTxProcessed checks outtx status and returns (isIncluded, isConfirmed, error)
// It also posts vote to zetacore if the tx is confirmed
func (ob *ChainClient) IsSendOutTxProcessed(cctx *crosschaintypes.CrossChainTx, logger zerolog.Logger) (bool, bool, error) {
sendHash := cctx.Index
cointype := cctx.InboundTxParams.CoinType
nonce := cctx.GetCurrentOutTxParam().OutboundTxTssNonce

// skip if outtx is not confirmed
params := ob.GetChainParams()
receipt, transaction := ob.GetTxNReceipt(nonce)
if receipt == nil || transaction == nil { // not confirmed yet
if !ob.isTxConfirmed(nonce) {
return false, false, nil
}

sendID := fmt.Sprintf("%s-%d", ob.chain.String(), nonce)
receipt, transaction := ob.GetTxNReceipt(nonce)
sendID := fmt.Sprintf("%d-%d", ob.chain.ChainId, nonce)

Check warning on line 332 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L331-L332

Added lines #L331 - L332 were not covered by tests
logger = logger.With().Str("sendID", sendID).Logger()

// get connector and erce20Custody contracts
connectorAddr, connector, err := ob.GetConnectorContract()
if err != nil {
return false, false, errors.Wrapf(err, "error getting zeta connector for chain %d", ob.chain.ChainId)

Check warning on line 338 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L336-L338

Added lines #L336 - L338 were not covered by tests
}
custodyAddr, custody, err := ob.GetERC20CustodyContract()
if err != nil {
return false, false, errors.Wrapf(err, "error getting erc20 custody for chain %d", ob.chain.ChainId)

Check warning on line 342 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L340-L342

Added lines #L340 - L342 were not covered by tests
}

// define a few common variables
txHash := receipt.TxHash.Hex()
var receiveValue *big.Int
var receiveStatus chains.ReceiveStatus

Check warning on line 348 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L346-L348

Added lines #L346 - L348 were not covered by tests

// compliance check, special handling the cancelled cctx
if compliance.IsCctxRestricted(cctx) {
recvStatus := chains.ReceiveStatus_Failed
// use cctx's amount to bypass the amount check in zetacore
receiveValue = cctx.GetCurrentOutTxParam().Amount.BigInt()
receiveStatus := chains.ReceiveStatus_Failed

Check warning on line 354 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L353-L354

Added lines #L353 - L354 were not covered by tests
if receipt.Status == 1 {
recvStatus = chains.ReceiveStatus_Success
}
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
// use cctx's amount to bypass the amount check in zetacore
cctx.GetCurrentOutTxParam().Amount.BigInt(),
recvStatus,
ob.chain,
nonce,
coin.CoinType_Cmd,
)
if err != nil {
logger.Error().Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
receiveStatus = chains.ReceiveStatus_Success

Check warning on line 356 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L356

Added line #L356 was not covered by tests
}
ob.PostVoteOutbound(sendHash, receipt, transaction, receiveValue, receiveStatus, nonce, cointype, logger)

Check warning on line 358 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L358

Added line #L358 was not covered by tests
return true, true, nil
}

if cointype == coin.CoinType_Cmd {
recvStatus := chains.ReceiveStatus_Failed
if receipt.Status == 1 {
recvStatus = chains.ReceiveStatus_Success
}
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
transaction.Value(),
recvStatus,
ob.chain,
nonce,
coin.CoinType_Cmd,
)
if err != nil {
logger.Error().Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil

} else if cointype == coin.CoinType_Gas { // the outbound is a regular Ether/BNB/Matic transfer; no need to check events
if receipt.Status == 1 {
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
transaction.Value(),
chains.ReceiveStatus_Success,
ob.chain,
nonce,
coin.CoinType_Gas,
)
if err != nil {
logger.Error().Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
} else if receipt.Status == 0 { // the same as below events flow
logger.Info().Msgf("Found (failed tx) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), receipt.TxHash.Hex())
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
big.NewInt(0),
chains.ReceiveStatus_Failed,
ob.chain,
nonce,
coin.CoinType_Gas,
)
if err != nil {
logger.Error().Err(err).Msgf("PostVoteOutbound error in WatchTxHashWithTimeout; zeta tx hash %s cctx %s nonce %d", zetaTxHash, sendHash, nonce)
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
}
} else if cointype == coin.CoinType_Zeta { // the outbound is a Zeta transfer; need to check events ZetaReceived
if receipt.Status == 1 {
logs := receipt.Logs
for _, vLog := range logs {
confHeight := vLog.BlockNumber + params.ConfirmationCount
// TODO rewrite this to return early if not confirmed
connectorAddr, connector, err := ob.GetConnectorContract()
if err != nil {
return false, false, fmt.Errorf("error getting connector contract: %w", err)
}
receivedLog, err := connector.ZetaConnectorNonEthFilterer.ParseZetaReceived(*vLog)
if err == nil {
logger.Info().Msgf("Found (outTx) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), vLog.TxHash.Hex())
if confHeight <= ob.GetLastBlockHeight() {
logger.Info().Msg("Confirmed! Sending PostConfirmation to zetabridge...")
// sanity check tx event
err = ValidateEvmTxLog(vLog, connectorAddr, transaction.Hash().Hex(), TopicsZetaReceived)
if err != nil {
logger.Error().Err(err).Msgf("CheckEvmTxLog error on ZetaReceived event, chain %d nonce %d txhash %s", ob.chain.ChainId, nonce, transaction.Hash().Hex())
return false, false, err
}
sendhash := vLog.Topics[3].Hex()
//var rxAddress string = ethcommon.HexToAddress(vLog.Topics[1].Hex()).Hex()
mMint := receivedLog.ZetaValue
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendhash,
vLog.TxHash.Hex(),
vLog.BlockNumber,
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
mMint,
chains.ReceiveStatus_Success,
ob.chain,
nonce,
coin.CoinType_Zeta,
)
if err != nil {
logger.Error().Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
continue
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
}
logger.Info().Msgf("Included; %d blocks before confirmed! chain %s nonce %d", confHeight-ob.GetLastBlockHeight(), ob.chain.String(), nonce)
return true, false, nil
}
revertedLog, err := connector.ZetaConnectorNonEthFilterer.ParseZetaReverted(*vLog)
if err == nil {
logger.Info().Msgf("Found (revertTx) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), vLog.TxHash.Hex())
if confHeight <= ob.GetLastBlockHeight() {
logger.Info().Msg("Confirmed! Sending PostConfirmation to zetabridge...")
// sanity check tx event
err = ValidateEvmTxLog(vLog, connectorAddr, transaction.Hash().Hex(), TopicsZetaReverted)
if err != nil {
logger.Error().Err(err).Msgf("CheckEvmTxLog error on ZetaReverted event, chain %d nonce %d txhash %s", ob.chain.ChainId, nonce, transaction.Hash().Hex())
return false, false, err
}
sendhash := vLog.Topics[2].Hex()
mMint := revertedLog.RemainingZetaValue
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendhash,
vLog.TxHash.Hex(),
vLog.BlockNumber,
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
mMint,
chains.ReceiveStatus_Success,
ob.chain,
nonce,
coin.CoinType_Zeta,
)
if err != nil {
logger.Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
continue
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
}
logger.Info().Msgf("Included; %d blocks before confirmed! chain %s nonce %d", confHeight-ob.GetLastBlockHeight(), ob.chain.String(), nonce)
return true, false, nil
}
}
} else if receipt.Status == 0 {
//FIXME: check nonce here by getTransaction RPC
logger.Info().Msgf("Found (failed tx) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), receipt.TxHash.Hex())
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
big.NewInt(0),
chains.ReceiveStatus_Failed,
ob.chain,
nonce,
coin.CoinType_Zeta,
)
if err != nil {
logger.Error().Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
}
} else if cointype == coin.CoinType_ERC20 {
if receipt.Status == 1 {
logs := receipt.Logs
addrCustody, ERC20Custody, err := ob.GetERC20CustodyContract()
if err != nil {
logger.Warn().Msgf("NewERC20Custody err: %s", err)
}
for _, vLog := range logs {
event, err := ERC20Custody.ParseWithdrawn(*vLog)
confHeight := vLog.BlockNumber + params.ConfirmationCount
if err == nil {
logger.Info().Msgf("Found (ERC20Custody.Withdrawn Event) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), vLog.TxHash.Hex())
// sanity check tx event
err = ValidateEvmTxLog(vLog, addrCustody, transaction.Hash().Hex(), TopicsWithdrawn)
if err != nil {
logger.Error().Err(err).Msgf("CheckEvmTxLog error on Withdrawn event, chain %d nonce %d txhash %s", ob.chain.ChainId, nonce, transaction.Hash().Hex())
return false, false, err
}
if confHeight <= ob.GetLastBlockHeight() {
logger.Info().Msg("Confirmed! Sending PostConfirmation to zetabridge...")
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
vLog.TxHash.Hex(),
vLog.BlockNumber,
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
event.Amount,
chains.ReceiveStatus_Success,
ob.chain,
nonce,
coin.CoinType_ERC20,
)
if err != nil {
logger.Error().Err(err).Msgf("error posting confirmation to meta core for cctx %s nonce %d", sendHash, nonce)
continue
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
}
logger.Info().Msgf("Included; %d blocks before confirmed! chain %s nonce %d", confHeight-ob.GetLastBlockHeight(), ob.chain.String(), nonce)
return true, false, nil
}
}
} else {
logger.Info().Msgf("Found (failed tx) sendHash %s on chain %s txhash %s", sendHash, ob.chain.String(), receipt.TxHash.Hex())
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
big.NewInt(0),
chains.ReceiveStatus_Failed,
ob.chain,
nonce,
coin.CoinType_ERC20,
)
if err != nil {
logger.Error().Err(err).Msgf("PostVoteOutbound error in WatchTxHashWithTimeout; zeta tx hash %s", zetaTxHash)
} else if zetaTxHash != "" {
logger.Info().Msgf("Zeta tx hash: %s cctx %s nonce %d ballot %s", zetaTxHash, sendHash, nonce, ballot)
}
return true, true, nil
}
// parse the received value from the outtx receipt
receiveStatus, receiveValue, err = ParseOuttxReceivedValue(receipt, transaction, cointype, connectorAddr, connector, custodyAddr, custody, sendHash, txHash)
if err != nil {
logger.Error().Err(err).Msgf("IsSendOutTxProcessed: error parsing outtx event for chain %d txhash %s", ob.chain.ChainId, txHash)
return false, false, err

Check warning on line 366 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L363-L366

Added lines #L363 - L366 were not covered by tests
}

return false, false, nil
// post vote to zetacore
ob.PostVoteOutbound(sendHash, receipt, transaction, receiveValue, receiveStatus, nonce, cointype, logger)
return true, true, nil

Check warning on line 371 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L370-L371

Added lines #L370 - L371 were not covered by tests
}

// PostVoteOutbound posts vote to zetacore for the confirmed outtx
func (ob *ChainClient) PostVoteOutbound(
sendHash string,
receipt *ethtypes.Receipt,
transaction *ethtypes.Transaction,
receiveValue *big.Int,
receiveStatus chains.ReceiveStatus,
nonce uint64,
cointype coin.CoinType,
logger zerolog.Logger,
) {
chainID := ob.chain.ChainId
zetaTxHash, ballot, err := ob.zetaClient.PostVoteOutbound(
sendHash,
receipt.TxHash.Hex(),
receipt.BlockNumber.Uint64(),
receipt.GasUsed,
transaction.GasPrice(),
transaction.Gas(),
receiveValue,
receiveStatus,
ob.chain,
nonce,
cointype,
)
if err != nil {
logger.Error().Err(err).Msgf("PostVoteOutbound: error posting vote for chain %d nonce %d outtx %s ", chainID, nonce, receipt.TxHash)
} else if zetaTxHash != "" {
logger.Info().Msgf("PostVoteOutbound: posted vote for chain %d nonce %d outtx %s vote %s ballot %s", chainID, nonce, receipt.TxHash, zetaTxHash, ballot)

Check warning on line 402 in zetaclient/evm/evm_client.go

View check run for this annotation

Codecov / codecov/patch

zetaclient/evm/evm_client.go#L384-L402

Added lines #L384 - L402 were not covered by tests
}
}

// WatchOutTx watches evm chain for outgoing txs status
Expand Down
Loading

0 comments on commit af26d74

Please sign in to comment.