-
Notifications
You must be signed in to change notification settings - Fork 4
feat(cardano): Implement Cardano indexer with reorg handling and event optimization #26
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
base: main
Are you sure you want to change the base?
Conversation
Update file Branches cardano to test
…FromAddress tracking
Feat: enhance reorg check to support Cardano network type
…fetches suitable for blockforst free
pkg/events/emitter.go
Outdated
| return e.queue.Enqueue(infra.MultiAssetTransferEventTopicQueue, eventBytes, &infra.EnqueueOptions{ | ||
| IdempotententKey: event.TxHash, // Use TxHash for idempotency | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't support mult asset event, if there is multi asset transaciton. it should be broken down into multiple individual single token transaction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already updated! Multi-asset transactions are now broken down into individual single-token events in the convertBlock() function (lines 260-282) in file internal/indexer/cardano.go. Each asset in the output creates a separate transfer event.
internal/indexer/cardano.go
Outdated
| } | ||
| concurrency := c.config.Throttle.Concurrency | ||
| if concurrency <= 0 { | ||
| concurrency = 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should make this a constant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Already using constant! DefaultTxFetchConcurrency = 4 is defined in internal/rpc/cardano/client.go at line 18.
internal/indexer/cardano.go
Outdated
| // We use the payload to carry the rich data. | ||
| Payload: payload, | ||
| } | ||
| transactions = append(transactions, genericTx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it check if a transaction has status = success?
Otherwise we can index a transfer with status = failed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. This is handled in the RPC client (GetTransaction function, commit 1f1fec4).
We first ensure the transaction is finalized in a block, then we explicitly reject any transaction where valid_contract is false. Only fully successful transactions are ever indexed.
pkg/common/types/types.go
Outdated
| if len(t.Payload) > 0 { | ||
| builder.WriteByte('|') | ||
| builder.Write(t.Payload) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this for? should make a test file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the Payload field since we don't need it anymore
pkg/common/utils/codec.go
Outdated
|
|
||
| // Encode converts an interface into a byte slice using gob encoding. | ||
| // Useful for serializing complex data structures into a generic payload. | ||
| func Encode(data interface{}) ([]byte, error) { | ||
| var buf bytes.Buffer | ||
| enc := gob.NewEncoder(&buf) | ||
| if err := enc.Encode(data); err != nil { | ||
| return nil, err | ||
| } | ||
| return buf.Bytes(), nil | ||
| } | ||
|
|
||
| // Decode converts a byte slice back into an interface using gob decoding. | ||
| // The 'out' parameter must be a pointer to the target data structure. | ||
| func Decode(data []byte, out interface{}) error { | ||
| buf := bytes.NewBuffer(data) | ||
| dec := gob.NewDecoder(buf) | ||
| return dec.Decode(out) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
purpose of those functions?
Should give examples in test cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These Encode() and Decode() functions were originally used for the Payload field (to serialize complex data structures using gob encoding). Since we removed the Payload field, these functions are no longer needed and have been removed as well.
pkg/events/events.go
Outdated
| type MultiAssetTransactionEvent struct { | ||
| Chain string `json:"chain"` | ||
| TxHash string `json:"tx_hash"` | ||
| BlockHeight uint64 `json:"block_height"` | ||
| FromAddress string `json:"from_address"` // Representative from address | ||
| ToAddress string `json:"to_address"` // The address that received the assets | ||
| Assets []AssetTransfer `json:"assets"` // List of assets transferred to the ToAddress | ||
| Fee string `json:"fee"` | ||
| Timestamp uint64 `json:"timestamp"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mention above, our backend doesn't support transfer:multi_asset_event , should propose a solution that is backward compatible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multi-asset support removed. Each asset is now a separate transfer event. events.go and related code deleted.
…d block fetching logic
Feat: improve Cardano API interactions with enhanced rate limiting and block fetching logic
Add Validate Transaction
|
Hi team! Here's a summary of what's been updated since commit de3e3a3: Recent Changes (de3e3a3 → HEAD)Transaction Model Enhancements (a127947)
Concurrency & Performance (671bba0, 7f72270)
Transaction Validation (1f1fec4)
Code Cleanup (de3e3a3)
|
This pull request documents the step-by-step process of integrating a robust Cardano indexer into the existing multichain framework. The primary focus was to handle Cardano's unique EUTXO model without introducing breaking changes to other chains, while also ensuring production-readiness by implementing reorg handling.
What Was Done (The Process)
1. Handling the UTXO/EUTXO Model
To support Cardano's complex transactions (multiple inputs/outputs, multi-asset), i took the following steps:
RichTransactionstruct was created within thecardanopackage to accurately represent a Cardano transaction.types.Transactionstruct, thisRichTransactionis encoded and passed within thePayloadfield.BaseWorkerwas then updated with new logic to detect thisPayload. If present, it decodes the data and processes it using a Cardano-specific path, leaving the EVM/Tron logic untouched.FromAddress.2. Optimizing NATS Events
A naive implementation would have created an "event storm" on NATS to use with UTXO/EUTXO. To solve this:
pkg/events/events.gofile and defined aMultiAssetTransactionEvent.Emitterinterface and its implementation were extended to support this new event type.BaseWorkernow uses this new event, drastically reducing the number of messages published for multi-asset transactions.3. Implementing Reorg Handling
A critical step for production stability was to handle blockchain reorganizations.
RegularWorkerand discovered a pre-existing, chain-agnostic reorg detection mechanism (detectAndHandleReorg).ParentHashof new blocks against the storedHashof previous blocks, was only active for EVM.isReorgCheckRequiredfunction.