Fix transaction hash search for Aptos (#461)

### Description

Tracking issue: https://github.com/wormhole-foundation/wormhole-explorer/issues/430

In `GET /api/v1/vaas?txHash={hash}`, searching for Aptos VAAs by transaction hash was not working correctly. This pull request fixes the issue.
This commit is contained in:
agodnic 2023-06-27 10:12:32 -03:00 committed by GitHub
parent 471a6dad4d
commit 5663fed0c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 22 deletions

View File

@ -47,22 +47,32 @@ func NewRepository(db *mongo.Database, logger *zap.Logger) *Repository {
} }
} }
// FindVaasBySolanaTxHash searches the database for VAAs that match a given Solana transaction hash. // FindVaasByTxHashWorkaround searches the database for VAAs that match a given transaction hash.
func (r *Repository) FindVaasBySolanaTxHash( //
// This function exists to work around the issue that for Aptos and Solana, the real transaction
// hashes are stored in a different collection from other chains.
//
// When the `q.txHash` field is set, this function will look up transaction hashes in the `globalTransactions` collection.
// Then, if the transaction hash is not found, it will fall back to searching in the `vaas` collection.
func (r *Repository) FindVaasByTxHashWorkaround(
ctx context.Context, ctx context.Context,
txHash string, query *VaaQuery,
includeParsedPayload bool,
) ([]*VaaDoc, error) { ) ([]*VaaDoc, error) {
// Find globalTransactions that match the given Solana TxHash // Find globalTransactions that match the given TxHash
cur, err := r.collections.globalTransactions.Find( cur, err := r.collections.globalTransactions.Find(
ctx, ctx,
bson.D{bson.E{"originTx.nativeTxHash", txHash}}, bson.D{
{"$or", bson.A{
bson.D{{"originTx.nativeTxHash", bson.M{"$eq": query.txHash}}},
bson.D{{"originTx.nativeTxHash", bson.M{"$eq": "0x" + query.txHash}}},
}},
},
nil, nil,
) )
if err != nil { if err != nil {
requestID := fmt.Sprintf("%v", ctx.Value("requestid")) requestID := fmt.Sprintf("%v", ctx.Value("requestid"))
r.logger.Error("failed to find globalTransactions by Solana TxHash", r.logger.Error("failed to find globalTransactions by TxHash",
zap.Error(err), zap.Error(err),
zap.String("requestID", requestID), zap.String("requestID", requestID),
) )
@ -80,24 +90,29 @@ func (r *Repository) FindVaasBySolanaTxHash(
) )
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }
// If no results were found, return an empty slice instead of nil.
if len(globalTxs) == 0 {
result := make([]*VaaDoc, 0)
return result, nil
}
if len(globalTxs) > 1 { if len(globalTxs) > 1 {
return nil, fmt.Errorf("expected at most one transaction, but found %d", len(globalTxs)) return nil, fmt.Errorf("expected at most one transaction, but found %d", len(globalTxs))
} }
// If no documents were found, look up the transaction hash in the `vaas` collection instead.
if len(globalTxs) == 0 {
return r.FindVaas(ctx, query)
}
// Find VAAs that match the given VAA ID // Find VAAs that match the given VAA ID
q := Query(). q := *query // making a copy to avoid modifying the struct passed by the caller
SetID(globalTxs[0].ID). q.SetID(globalTxs[0].ID)
IncludeParsedPayload(includeParsedPayload) // Disable txHash filter, but keep all the other filters.
return r.FindVaas(ctx, q) // We have to do this because the transaction hashes in the `globalTransactions` collection
// may be different that the transaction hash in the `vaas` collection. This is the case
// for Aptos and Solana VAAs.
q.txHash = ""
return r.FindVaas(ctx, &q)
} }
// FindVaas searches the database for VAAs matching the given filters. // FindVaas searches the database for VAAs matching the given filters.
//
// When the `q.txHash` field is set, this function will look up transaction hashes in the `vaas` collection.
func (r *Repository) FindVaas( func (r *Repository) FindVaas(
ctx context.Context, ctx context.Context,
q *VaaQuery, q *VaaQuery,

View File

@ -48,7 +48,7 @@ func (s *Service) FindAll(
params *FindAllParams, params *FindAllParams,
) (*response.Response[[]*VaaDoc], error) { ) (*response.Response[[]*VaaDoc], error) {
// set up query parameters // Populate query parameters
query := Query(). query := Query().
IncludeParsedPayload(params.IncludeParsedPayload) IncludeParsedPayload(params.IncludeParsedPayload)
if params.Pagination != nil { if params.Pagination != nil {
@ -61,11 +61,16 @@ func (s *Service) FindAll(
query.SetAppId(params.AppId) query.SetAppId(params.AppId)
} }
// execute the database query // Execute the database query
//
// Unfortunately, for Aptos and Solana, the real transaction hashes are stored
// in a different collection from other chains.
//
// This block of code has additional logic to handle that case.
var err error var err error
var vaas []*VaaDoc var vaas []*VaaDoc
if params.TxHash != nil && params.TxHash.IsSolanaTxHash() { if query.txHash != "" {
vaas, err = s.repo.FindVaasBySolanaTxHash(ctx, params.TxHash.String(), params.IncludeParsedPayload) vaas, err = s.repo.FindVaasByTxHashWorkaround(ctx, query)
} else { } else {
vaas, err = s.repo.FindVaas(ctx, query) vaas, err = s.repo.FindVaas(ctx, query)
} }
@ -73,7 +78,7 @@ func (s *Service) FindAll(
return nil, err return nil, err
} }
// return the matching documents // Eeturn the matching documents
res := response.Response[[]*VaaDoc]{Data: vaas} res := response.Response[[]*VaaDoc]{Data: vaas}
return &res, nil return &res, nil
} }