Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grpc): transaction retrieval #17

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft

Conversation

Reecepbcups
Copy link
Contributor

@Reecepbcups Reecepbcups commented Aug 24, 2024

Summary

For Interchaintest & IBC, we need to be able to get a transaction (by its hash) and verify its data.

Update

I am building on reece/ibc-slop-backup as my work in progress hack together POC for this now. Will be a large diff that will then be broken down into many PRs once something is working.

Comment on lines +52 to +59
// TODO: ValidateTx only does stateful validation, not execution. This here lets us get the Events in the TxResult.
res, _, err = g.am.Simulate(ctx, tx)
if err != nil {
// Simulate should only return an error at this level,
// if it failed to get state from the store.
g.log.Warn("Error attempting to simulate transaction", "route", "simulate_tx", "err", err)
return nil, fmt.Errorf("failed to simulate transaction: %w", err)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels wrong to get events. Must be another way or we are missing some call in the am, I need to dive into see how the SDK handles with comet

Comment on lines +37 to +38
txIdx map[string]*TxResultResponse
txIdxLock sync.Mutex
Copy link
Contributor Author

@Reecepbcups Reecepbcups Aug 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: I know sync.Map is typically bad & to stay away, but this may be a good case for it as we only write 1 time and read many (growing cache only) due to unique Txs only?

cc @mark-rushakoff am I right here or should I stick to standard map locks?

https://pkg.go.dev/sync#Map
The Map type is optimized for two common use cases: (1) when the entry for a given key is only ever written once but read many times, as in caches that only grow, or (2) when multiple goroutines read, write, and overwrite entries for disjoint sets of keys. In these two cases, use of a Map may significantly reduce lock contention compared to a Go map paired with a separate Mutex or RWMutex.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't really have an ever-growing cache, right? It's fine as a stub just to get through integrations, but at a minimum we need a // TODO next to it.

Maps and concurrency

The convention I'm most used to seeing would be

txIdxMu sync.Mutex
txIdx map[string]*TxResultResponse
  • mu name for mutexes, scoping the name as txIdxMu is appropriate given the narrow scope of the mutex's responsibility
  • mutex declared immediately before the fields it protects

I think a plain mutex and a map is a fine combination here. If we expected many more transaction queries than writes, maybe a RWMutex would be a better fit.

My rule of thumb is to avoid sync.Map until you really have evidence it's needed over the typical mutex and map pattern, and I don't think we have that yet. The type casting is the particular annoyance here.

I don't think the map value needs to be a pointer here.

Long-lived, growing cache

While the driver does need to provide the functionality to find a transaction by hash and return it to the user, I would have expected something in the SDK to provide the retrieval functionality directly. Something like AppManager.State.FindTxByHash(h).

If that really doesn't exist (yet) or there is some good reason we can't use it, then let's push the functionality behind some trivial interface, so we can at least trivially switch to an LRU or put it on disk so we don't have to introduce an OOM risk.

response := getGordianResponseFromSDKResult(res)

txHash := tx.Hash()
response.TxHash = strings.ToUpper(hex.EncodeToString(txHash[:]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think response.TxHash = fmt.Sprintf("%X", txHash) is more appropriate here, so we don't have to do two copies of the string (once encoded and once more to uppercase).

Same below on L111.

@@ -5,6 +5,7 @@ import (
"fmt"
"log/slog"
"net"
sync "sync"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just "sync" here of course -- goimports should resolve this automatically, and I think people have tended towards goimports instead of go fmt.

Comment on lines +37 to +38
txIdx map[string]*TxResultResponse
txIdxLock sync.Mutex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't really have an ever-growing cache, right? It's fine as a stub just to get through integrations, but at a minimum we need a // TODO next to it.

Maps and concurrency

The convention I'm most used to seeing would be

txIdxMu sync.Mutex
txIdx map[string]*TxResultResponse
  • mu name for mutexes, scoping the name as txIdxMu is appropriate given the narrow scope of the mutex's responsibility
  • mutex declared immediately before the fields it protects

I think a plain mutex and a map is a fine combination here. If we expected many more transaction queries than writes, maybe a RWMutex would be a better fit.

My rule of thumb is to avoid sync.Map until you really have evidence it's needed over the typical mutex and map pattern, and I don't think we have that yet. The type casting is the particular annoyance here.

I don't think the map value needs to be a pointer here.

Long-lived, growing cache

While the driver does need to provide the functionality to find a transaction by hash and return it to the user, I would have expected something in the SDK to provide the retrieval functionality directly. Something like AppManager.State.FindTxByHash(h).

If that really doesn't exist (yet) or there is some good reason we can't use it, then let's push the functionality behind some trivial interface, so we can at least trivially switch to an LRU or put it on disk so we don't have to introduce an OOM risk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants