Add methods to identify kujira & evmos (#729)

* Add methods to identify kujira & evmos

* Add fetch methods to kajira and evmos

* fix fetch kujira and evmos methods

* Add support to search vaas gateway chain txHash

* Add deploy config to tx-tracker for evmos & kujira
This commit is contained in:
walker-16 2023-10-26 19:34:00 -03:00 committed by GitHub
parent b46ba72d6b
commit f4fe630623
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 276 additions and 10 deletions

View File

@ -72,10 +72,13 @@ func (r *Repository) FindVaasByTxHashWorkaround(
{"$or", bson.A{
bson.D{{"originTx.nativeTxHash", bson.M{"$eq": query.txHash}}},
bson.D{{"originTx.nativeTxHash", bson.M{"$eq": "0x" + query.txHash}}},
bson.D{{"originTx.attribute.value.originTxHash", bson.M{"$eq": query.txHash}}},
bson.D{{"originTx.attribute.value.originTxHash", bson.M{"$eq": "0x" + query.txHash}}},
}},
},
nil,
)
if err != nil {
requestID := fmt.Sprintf("%v", ctx.Value("requestid"))
r.logger.Error("failed to find globalTransactions by TxHash",

View File

@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth
ETHEREUM_REQUESTS_PER_MINUTE=12
EVMOS_BASE_URL=https://tm.evmos.lava.build
EVMOS_REQUESTS_PER_MINUTE=12
FANTOM_BASE_URL=https://rpc.ankr.com/fantom
FANTOM_REQUESTS_PER_MINUTE=12
@ -54,6 +57,9 @@ KARURA_REQUESTS_PER_MINUTE=12
KLAYTN_BASE_URL=https://klaytn-mainnet-rpc.allthatnode.com:8551
KLAYTN_REQUESTS_PER_MINUTE=12
KUJIRA_BASE_URL=https://kujira-rpc.ibs.team
KUJIRA_REQUESTS_PER_MINUTE=12
MOONBEAM_BASE_URL=https://rpc.api.moonbeam.network
MOONBEAM_REQUESTS_PER_MINUTE=12

View File

@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth_goerli
ETHEREUM_REQUESTS_PER_MINUTE=12
EVMOS_BASE_URL=https://evmos-testnet-rpc.polkachu.com
EVMOS_REQUESTS_PER_MINUTE=12
FANTOM_BASE_URL=https://rpc.testnet.fantom.network
FANTOM_REQUESTS_PER_MINUTE=12
@ -52,6 +55,9 @@ KARURA_REQUESTS_PER_MINUTE=12
KLAYTN_BASE_URL=https://api.baobab.klaytn.net:8651
KLAYTN_REQUESTS_PER_MINUTE=12
KUJIRA_BASE_URL=https://kujira-testnet-rpc.polkachu.com
KUJIRA_REQUESTS_PER_MINUTE=12
MOONBEAM_BASE_URL=https://rpc.api.moonbase.moonbeam.network
MOONBEAM_REQUESTS_PER_MINUTE=12

View File

@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth
ETHEREUM_REQUESTS_PER_MINUTE=12
EVMOS_BASE_URL=https://tm.evmos.lava.build
EVMOS_REQUESTS_PER_MINUTE=12
FANTOM_BASE_URL=https://rpc.ankr.com/fantom
FANTOM_REQUESTS_PER_MINUTE=12
@ -54,6 +57,9 @@ KARURA_REQUESTS_PER_MINUTE=12
KLAYTN_BASE_URL=https://klaytn-mainnet-rpc.allthatnode.com:8551
KLAYTN_REQUESTS_PER_MINUTE=12
KUJIRA_BASE_URL=https://kujira-rpc.ibs.team
KUJIRA_REQUESTS_PER_MINUTE=12
MOONBEAM_BASE_URL=https://rpc.api.moonbeam.network
MOONBEAM_REQUESTS_PER_MINUTE=12

View File

@ -40,6 +40,9 @@ CELO_REQUESTS_PER_MINUTE=12
ETHEREUM_BASE_URL=https://rpc.ankr.com/eth_goerli
ETHEREUM_REQUESTS_PER_MINUTE=12
EVMOS_BASE_URL=https://evmos-testnet-rpc.polkachu.com
EVMOS_REQUESTS_PER_MINUTE=12
FANTOM_BASE_URL=https://rpc.testnet.fantom.network
FANTOM_REQUESTS_PER_MINUTE=12
@ -52,6 +55,9 @@ KARURA_REQUESTS_PER_MINUTE=12
KLAYTN_BASE_URL=https://api.baobab.klaytn.net:8651
KLAYTN_REQUESTS_PER_MINUTE=12
KUJIRA_BASE_URL=https://kujira-testnet-rpc.polkachu.com
KUJIRA_REQUESTS_PER_MINUTE=12
MOONBEAM_BASE_URL=https://rpc.api.moonbase.moonbeam.network
MOONBEAM_REQUESTS_PER_MINUTE=12

View File

@ -100,6 +100,10 @@ spec:
value: {{ .ETHEREUM_BASE_URL }}
- name: ETHEREUM_REQUESTS_PER_MINUTE
value: "{{ .ETHEREUM_REQUESTS_PER_MINUTE }}"
- name: EVMOS_BASE_URL
value: {{ .EVMOS_BASE_URL }}
- name: EVMOS_REQUESTS_PER_MINUTE
value: "{{ .EVMOS_REQUESTS_PER_MINUTE }}"
- name: FANTOM_BASE_URL
value: {{ .FANTOM_BASE_URL }}
- name: FANTOM_REQUESTS_PER_MINUTE
@ -116,6 +120,10 @@ spec:
value: {{ .KLAYTN_BASE_URL }}
- name: KLAYTN_REQUESTS_PER_MINUTE
value: "{{ .KLAYTN_REQUESTS_PER_MINUTE }}"
- name: KUJIRA_BASE_URL
value: {{ .KUJIRA_BASE_URL }}
- name: KUJIRA_REQUESTS_PER_MINUTE
value: "{{ .KUJIRA_REQUESTS_PER_MINUTE }}"
- name: MOONBEAM_BASE_URL
value: {{ .MOONBEAM_BASE_URL }}
- name: MOONBEAM_REQUESTS_PER_MINUTE

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/wormhole-foundation/wormhole-explorer/common/domain"
@ -13,6 +14,10 @@ import (
type apiWormchain struct {
osmosisUrl string
osmosisRateLimiter *time.Ticker
kujiraUrl string
kujiraRateLimiter *time.Ticker
evmosUrl string
evmosRateLimiter *time.Ticker
p2pNetwork string
}
@ -127,8 +132,6 @@ func fetchWormchainDetail(ctx context.Context, baseUrl string, rateLimiter *time
}
const queryTemplate = `send_packet.packet_sequence='%s' AND send_packet.packet_timeout_timestamp='%s' AND send_packet.packet_src_channel='%s' AND send_packet.packet_dst_channel='%s'`
type osmosisRequest struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
@ -174,14 +177,8 @@ type osmosisTx struct {
txHash string
}
type WorchainAttributeTxDetail struct {
OriginChainID sdk.ChainID `bson:"originChainId"`
OriginTxHash string `bson:"originTxHash"`
OriginAddress string `bson:"originAddress"`
}
func fetchOsmosisDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*osmosisTx, error) {
queryTemplate := `send_packet.packet_sequence='%s' AND send_packet.packet_timeout_timestamp='%s' AND send_packet.packet_src_channel='%s' AND send_packet.packet_dst_channel='%s'`
query := fmt.Sprintf(queryTemplate, sequence, timestamp, srcChannel, dstChannel)
q := osmosisRequest{
Jsonrpc: "2.0",
@ -201,6 +198,162 @@ func fetchOsmosisDetail(ctx context.Context, baseUrl string, rateLimiter *time.T
return nil, err
}
var kReponse kujiraResponse
err = json.Unmarshal(response, &kReponse)
if err != nil {
return nil, err
}
if len(kReponse.Result.Txs) == 0 {
return nil, fmt.Errorf("can not found hash for sequence %s, timestamp %s, srcChannel %s, dstChannel %s", sequence, timestamp, srcChannel, dstChannel)
}
return &osmosisTx{txHash: kReponse.Result.Txs[0].Hash}, nil
}
type evmosRequest struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
Method string `json:"method"`
Params struct {
Query string `json:"query"`
Page string `json:"page"`
} `json:"params"`
}
type evmosResponse struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
Result struct {
Txs []struct {
Hash string `json:"hash"`
Height string `json:"height"`
Index int `json:"index"`
TxResult struct {
Code int `json:"code"`
Data string `json:"data"`
Log string `json:"log"`
Info string `json:"info"`
GasWanted string `json:"gas_wanted"`
GasUsed string `json:"gas_used"`
Events []struct {
Type string `json:"type"`
Attributes []struct {
Key string `json:"key"`
Value string `json:"value"`
Index bool `json:"index"`
} `json:"attributes"`
} `json:"events"`
Codespace string `json:"codespace"`
} `json:"tx_result"`
Tx string `json:"tx"`
} `json:"txs"`
TotalCount string `json:"total_count"`
} `json:"result"`
}
type evmosTx struct {
txHash string
}
func fetchEvmosDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*evmosTx, error) {
queryTemplate := `send_packet.packet_sequence='%s' AND send_packet.packet_timeout_timestamp='%s' AND send_packet.packet_src_channel='%s' AND send_packet.packet_dst_channel='%s'`
query := fmt.Sprintf(queryTemplate, sequence, timestamp, srcChannel, dstChannel)
q := evmosRequest{
Jsonrpc: "2.0",
ID: 1,
Method: "tx_search",
Params: struct {
Query string `json:"query"`
Page string `json:"page"`
}{
Query: query,
Page: "1",
},
}
response, err := httpPost(ctx, rateLimiter, baseUrl, q)
if err != nil {
return nil, err
}
var eReponse evmosResponse
err = json.Unmarshal(response, &eReponse)
if err != nil {
return nil, err
}
if len(eReponse.Result.Txs) == 0 {
return nil, fmt.Errorf("can not found hash for sequence %s, timestamp %s, srcChannel %s, dstChannel %s", sequence, timestamp, srcChannel, dstChannel)
}
return &evmosTx{txHash: strings.ToLower(eReponse.Result.Txs[0].Hash)}, nil
}
type kujiraRequest struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
Method string `json:"method"`
Params struct {
Query string `json:"query"`
Page string `json:"page"`
} `json:"params"`
}
type kujiraResponse struct {
Jsonrpc string `json:"jsonrpc"`
ID int `json:"id"`
Result struct {
Txs []struct {
Hash string `json:"hash"`
Height string `json:"height"`
Index int `json:"index"`
TxResult struct {
Code int `json:"code"`
Data string `json:"data"`
Log string `json:"log"`
Info string `json:"info"`
GasWanted string `json:"gas_wanted"`
GasUsed string `json:"gas_used"`
Events []struct {
Type string `json:"type"`
Attributes []struct {
Key string `json:"key"`
Value string `json:"value"`
Index bool `json:"index"`
} `json:"attributes"`
} `json:"events"`
Codespace string `json:"codespace"`
} `json:"tx_result"`
Tx string `json:"tx"`
} `json:"txs"`
TotalCount string `json:"total_count"`
} `json:"result"`
}
type kujiraTx struct {
txHash string
}
func fetchKujiraDetail(ctx context.Context, baseUrl string, rateLimiter *time.Ticker, sequence, timestamp, srcChannel, dstChannel string) (*kujiraTx, error) {
queryTemplate := `send_packet.packet_sequence='%s' AND send_packet.packet_timeout_timestamp='%s' AND send_packet.packet_src_channel='%s' AND send_packet.packet_dst_channel='%s'`
query := fmt.Sprintf(queryTemplate, sequence, timestamp, srcChannel, dstChannel)
q := kujiraRequest{
Jsonrpc: "2.0",
ID: 1,
Method: "tx_search",
Params: struct {
Query string `json:"query"`
Page string `json:"page"`
}{
Query: query,
Page: "1",
},
}
response, err := httpPost(ctx, rateLimiter, baseUrl, q)
if err != nil {
return nil, err
}
var oReponse osmosisResponse
err = json.Unmarshal(response, &oReponse)
if err != nil {
@ -210,7 +363,13 @@ func fetchOsmosisDetail(ctx context.Context, baseUrl string, rateLimiter *time.T
if len(oReponse.Result.Txs) == 0 {
return nil, fmt.Errorf("can not found hash for sequence %s, timestamp %s, srcChannel %s, dstChannel %s", sequence, timestamp, srcChannel, dstChannel)
}
return &osmosisTx{txHash: oReponse.Result.Txs[0].Hash}, nil
return &kujiraTx{txHash: strings.ToLower(oReponse.Result.Txs[0].Hash)}, nil
}
type WorchainAttributeTxDetail struct {
OriginChainID sdk.ChainID `bson:"originChainId"`
OriginTxHash string `bson:"originTxHash"`
OriginAddress string `bson:"originAddress"`
}
func (a *apiWormchain) fetchWormchainTx(
@ -247,6 +406,46 @@ func (a *apiWormchain) fetchWormchainTx(
}, nil
}
// Verify if this transaction is from kujira by wormchain
if a.isKujiraTx(wormchainTx) {
kujiraTx, err := fetchKujiraDetail(ctx, a.kujiraUrl, a.kujiraRateLimiter, wormchainTx.sequence, wormchainTx.timestamp, wormchainTx.srcChannel, wormchainTx.dstChannel)
if err != nil {
return nil, err
}
return &TxDetail{
NativeTxHash: txHash,
From: wormchainTx.receiver,
Attribute: &AttributeTxDetail{
Type: "wormchain-gateway",
Value: &WorchainAttributeTxDetail{
OriginChainID: ChainIDKujira,
OriginTxHash: kujiraTx.txHash,
OriginAddress: wormchainTx.sender,
},
},
}, nil
}
// Verify if this transaction is from evmos by wormchain
if a.isEvmosTx(wormchainTx) {
evmosTx, err := fetchEvmosDetail(ctx, a.evmosUrl, a.evmosRateLimiter, wormchainTx.sequence, wormchainTx.timestamp, wormchainTx.srcChannel, wormchainTx.dstChannel)
if err != nil {
return nil, err
}
return &TxDetail{
NativeTxHash: txHash,
From: wormchainTx.receiver,
Attribute: &AttributeTxDetail{
Type: "wormchain-gateway",
Value: &WorchainAttributeTxDetail{
OriginChainID: ChainIDEvmos,
OriginTxHash: evmosTx.txHash,
OriginAddress: wormchainTx.sender,
},
},
}, nil
}
return &TxDetail{
NativeTxHash: txHash,
From: wormchainTx.receiver,
@ -262,3 +461,25 @@ func (a *apiWormchain) isOsmosisTx(tx *worchainTx) bool {
}
return false
}
func (a *apiWormchain) isKujiraTx(tx *worchainTx) bool {
if a.p2pNetwork == domain.P2pMainNet {
return tx.srcChannel == "channel-113" && tx.dstChannel == "channel-9"
}
// Pending get channels for testnet
// if a.p2pNetwork == domain.P2pTestNet {
// return tx.srcChannel == "" && tx.dstChannel == ""
// }
return false
}
func (a *apiWormchain) isEvmosTx(tx *worchainTx) bool {
if a.p2pNetwork == domain.P2pMainNet {
return tx.srcChannel == "channel-94" && tx.dstChannel == "channel-5"
}
// Pending get channels for testnet
// if a.p2pNetwork == domain.P2pTestNet {
// return tx.srcChannel == "" && tx.dstChannel == ""
// }
return false
}

View File

@ -25,6 +25,8 @@ var (
// WARNING: The following chain IDs are not supported by the wormhole-sdk:
const ChainIDOsmosis sdk.ChainID = 20
const ChainIDEvmos sdk.ChainID = 4001
const ChainIDKujira sdk.ChainID = 4002
type WormchainTxDetail struct {
}
@ -156,6 +158,10 @@ func FetchTx(
apiWormchain := &apiWormchain{
osmosisUrl: cfg.OsmosisBaseUrl,
osmosisRateLimiter: rateLimiter,
evmosUrl: cfg.EvmosBaseUrl,
evmosRateLimiter: rateLimiter,
kujiraUrl: cfg.KujiraBaseUrl,
kujiraRateLimiter: rateLimiter,
p2pNetwork: p2pNetwork,
}
fetchFunc = apiWormchain.fetchWormchainTx

View File

@ -80,6 +80,8 @@ type RpcProviderSettings struct {
CeloRequestsPerMinute uint16 `split_words:"true" required:"true"`
EthereumBaseUrl string `split_words:"true" required:"true"`
EthereumRequestsPerMinute uint16 `split_words:"true" required:"true"`
EvmosBaseUrl string `split_words:"true" required:"true"`
EvmosRequestsPerMinute uint16 `split_words:"true" required:"true"`
FantomBaseUrl string `split_words:"true" required:"true"`
FantomRequestsPerMinute uint16 `split_words:"true" required:"true"`
InjectiveBaseUrl string `split_words:"true" required:"true"`
@ -88,6 +90,8 @@ type RpcProviderSettings struct {
KaruraRequestsPerMinute uint16 `split_words:"true" required:"true"`
KlaytnBaseUrl string `split_words:"true" required:"true"`
KlaytnRequestsPerMinute uint16 `split_words:"true" required:"true"`
KujiraBaseUrl string `split_words:"true" required:"true"`
KujiraRequestsPerMinute uint16 `split_words:"true" required:"true"`
MoonbeamBaseUrl string `split_words:"true" required:"true"`
MoonbeamRequestsPerMinute uint16 `split_words:"true" required:"true"`
OasisBaseUrl string `split_words:"true" required:"true"`