Skip to content

Commit 885471d

Browse files
committed
tidy up
Signed-off-by: Chengxuan Xing <chengxuan.xing@kaleido.io>
1 parent 90b49e5 commit 885471d

File tree

2 files changed

+59
-28
lines changed

2 files changed

+59
-28
lines changed

internal/ethereum/blocklistener_blockquery.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,6 @@ func (bl *blockListener) addToBlockCache(blockInfo *blockInfoJSONRPC) {
5656
func (bl *blockListener) getBlockInfoContainsTxHash(ctx context.Context, txHash string) (*ffcapi.MinimalBlockInfo, error) {
5757

5858
// Query the chain to find the transaction block
59-
// Note: should consider have an in-memory map of transaction hash to block for faster lookup
60-
// The extra memory usage of the map should be outweighed by the speed improvement of lookup
61-
// But I saw we have a ffcapi.MinimalBlockInfo struct that intentionally removes the tx hashes
62-
// so need to figure out the reason first
63-
64-
// TODO: add a cache if map cannot be used
6559
res, reason, receiptErr := bl.c.TransactionReceipt(ctx, &ffcapi.TransactionReceiptRequest{
6660
TransactionHash: txHash,
6761
})

internal/ethereum/confirmation_reconciler.go

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
// See the License for the specific language governing permissions and
1515
// limitations under the License.
1616

17+
// The confirmation reconciler manages transaction confirmation queues by:
18+
// - Copying blocks from the canonical chain and the existing confirmation queue
19+
// - Detecting blockchain forks and rebuilding confirmation queues when necessary
20+
// - Filling gaps in confirmation queues by fetching missing blocks
21+
// - Determining when transactions have reached the target confirmation count
1722
package ethereum
1823

1924
import (
@@ -26,15 +31,17 @@ import (
2631
"github.com/hyperledger/firefly-transaction-manager/pkg/ffcapi"
2732
)
2833

34+
// reconcileConfirmationsForTransaction reconciles the confirmation queue for a transaction
2935
func (bl *blockListener) reconcileConfirmationsForTransaction(ctx context.Context, txHash string, existingConfirmations []*ffcapi.MinimalBlockInfo, targetConfirmationCount uint64) (*ffcapi.ConfirmationMapUpdateResult, error) {
30-
// Initialize the output context
36+
// Initialize the result with existing confirmations
3137
reconcileResult := &ffcapi.ConfirmationMapUpdateResult{
3238
Confirmations: existingConfirmations,
3339
NewFork: false,
3440
Confirmed: false,
3541
TargetConfirmationCount: targetConfirmationCount,
3642
}
3743

44+
// Fetch the block containing the transaction
3845
txBlockInfo, err := bl.getBlockInfoContainsTxHash(ctx, txHash)
3946
if err != nil {
4047
log.L(ctx).Errorf("Failed to fetch block info using tx hash %s: %v", txHash, err)
@@ -49,16 +56,17 @@ func (bl *blockListener) reconcileConfirmationsForTransaction(ctx context.Contex
4956
return bl.compareAndUpdateConfirmationQueue(ctx, reconcileResult, txBlockInfo, targetConfirmationCount)
5057
}
5158

59+
// compareAndUpdateConfirmationQueue orchestrates the confirmation reconciliation process.
60+
// It builds new confirmations from the canonical chain and fills gaps in the confirmation queue.
5261
func (bl *blockListener) compareAndUpdateConfirmationQueue(ctx context.Context, reconcileResult *ffcapi.ConfirmationMapUpdateResult, txBlockInfo *ffcapi.MinimalBlockInfo, targetConfirmationCount uint64) (*ffcapi.ConfirmationMapUpdateResult, error) {
5362
var err error
54-
// Compare the and build the tail part of the confirmation queue using the canonical chain
63+
// Build new confirmations from the canonical chain and get existing confirmations
5564
newConfirmationsWithoutTxBlock, existingConfirmations, returnResult := bl.buildConfirmationQueueUsingCanonicalChain(ctx, reconcileResult, txBlockInfo, targetConfirmationCount)
5665
if returnResult {
5766
return reconcileResult, nil
5867
}
5968

60-
// Validate and process existing confirmations
61-
// and fill in the gap in the confirmation queue
69+
// Validate existing confirmations and fill gaps in the confirmation queue
6270
var confirmations []*ffcapi.MinimalBlockInfo
6371
var newFork bool
6472
confirmations, newFork, err = bl.checkAndFillInGap(ctx, newConfirmationsWithoutTxBlock, existingConfirmations, txBlockInfo, targetConfirmationCount)
@@ -70,47 +78,52 @@ func (bl *blockListener) compareAndUpdateConfirmationQueue(ctx context.Context,
7078
return reconcileResult, err
7179
}
7280

73-
// NOTE: this function only build up the confirmation queue uses the in-memory canonical chain
74-
// it does not build up the canonical chain
75-
// compareAndUpdateConfirmationQueueUsingCanonicalChain compares the existing confirmation queue with the in-memory linked list
76-
// this function obtains the read lock on the canonical chain, so it should not make any long-running queries
77-
81+
// buildConfirmationQueueUsingCanonicalChain builds the confirmation queue using the in-memory canonical chain.
82+
// It does not modify the canonical chain itself, only reads from it.
83+
// This function holds a read lock on the canonical chain, so it should not make long-running queries.
7884
func (bl *blockListener) buildConfirmationQueueUsingCanonicalChain(ctx context.Context, reconcileResult *ffcapi.ConfirmationMapUpdateResult, txBlockInfo *ffcapi.MinimalBlockInfo, targetConfirmationCount uint64) (newConfirmationsWithoutTxBlock []*ffcapi.MinimalBlockInfo, existingConfirmations []*ffcapi.MinimalBlockInfo, returnResult bool) {
7985
bl.mux.RLock()
8086
defer bl.mux.RUnlock()
8187
txBlockNumber := txBlockInfo.BlockNumber.Uint64()
8288
targetBlockNumber := txBlockInfo.BlockNumber.Uint64() + targetConfirmationCount
8389

90+
// Check if the canonical chain has caught up to the transaction block
8491
chainTail := bl.canonicalChain.Back().Value.(*ffcapi.MinimalBlockInfo)
8592
if chainTail == nil || chainTail.BlockNumber.Uint64() < txBlockNumber {
8693
log.L(ctx).Debugf("Canonical chain is waiting for the transaction block %d to be indexed", txBlockNumber)
8794
return nil, nil, true
8895
}
8996

90-
// Initialize confirmation map and get existing queue
97+
// Initialize confirmation map and get existing confirmations
9198
existingConfirmations = bl.initializeConfirmationMap(reconcileResult, txBlockInfo)
9299

93-
// if the target confirmation count is 0, we should just return the transaction block
100+
// Special case: if targetConfirmationCount is 0, transaction is immediately confirmed
94101
if targetConfirmationCount == 0 {
95102
reconcileResult.Confirmed = true
96103
reconcileResult.Confirmations = []*ffcapi.MinimalBlockInfo{txBlockInfo}
97104
return nil, existingConfirmations, true
98105
}
99106

100-
// build the tail part of the queue from the canonical chain
107+
// Build new confirmations from blocks after the transaction block
101108

102109
newConfirmationsWithoutTxBlock = []*ffcapi.MinimalBlockInfo{}
103110
currentBlock := bl.canonicalChain.Front()
104111
for currentBlock != nil {
105112
currentBlockInfo := currentBlock.Value.(*ffcapi.MinimalBlockInfo)
113+
114+
// If we've reached the target confirmation count, mark as confirmed
106115
if currentBlockInfo.BlockNumber.Uint64() > targetBlockNumber {
107116
reconcileResult.Confirmed = true
108117
break
109118
}
119+
120+
// Skip blocks at or before the transaction block
110121
if currentBlockInfo.BlockNumber.Uint64() <= txBlockNumber {
111122
currentBlock = currentBlock.Next()
112123
continue
113124
}
125+
126+
// Add blocks after the transaction block to confirmations
114127
newConfirmationsWithoutTxBlock = append(newConfirmationsWithoutTxBlock, &ffcapi.MinimalBlockInfo{
115128
BlockHash: currentBlockInfo.BlockHash,
116129
BlockNumber: fftypes.FFuint64(currentBlockInfo.BlockNumber.Uint64()),
@@ -121,18 +134,22 @@ func (bl *blockListener) buildConfirmationQueueUsingCanonicalChain(ctx context.C
121134
return newConfirmationsWithoutTxBlock, existingConfirmations, false
122135
}
123136

137+
// initializeConfirmationMap initializes the confirmation map with the transaction block
138+
// and validates existing confirmations against the current transaction block.
139+
// Returns existing confirmations if valid, or nil if a fork is detected.
124140
func (bl *blockListener) initializeConfirmationMap(reconcileResult *ffcapi.ConfirmationMapUpdateResult, txBlockInfo *ffcapi.MinimalBlockInfo) []*ffcapi.MinimalBlockInfo {
141+
// If no existing confirmations, initialize with the transaction block
125142
if len(reconcileResult.Confirmations) == 0 {
126143
reconcileResult.Confirmations = []*ffcapi.MinimalBlockInfo{txBlockInfo}
127144
return nil
128145
}
129146

147+
// Validate existing confirmations against the current transaction block
130148
existingQueue := reconcileResult.Confirmations
131149
if len(existingQueue) > 0 {
132150
existingTxBlock := existingQueue[0]
133151
if !existingTxBlock.Equal(txBlockInfo) {
134-
// the tx block in the existing queue does not match the new tx block we queried from the chain
135-
// rebuild a new confirmation queue with the new tx block
152+
// Transaction block mismatch indicates a fork - rebuild confirmation queue
136153
reconcileResult.NewFork = true
137154
reconcileResult.Confirmations = []*ffcapi.MinimalBlockInfo{txBlockInfo}
138155
return nil
@@ -142,9 +159,13 @@ func (bl *blockListener) initializeConfirmationMap(reconcileResult *ffcapi.Confi
142159
return existingQueue
143160
}
144161

162+
// checkAndFillInGap validates existing confirmations, detects forks, and fills gaps
163+
// in the confirmation queue using existing confirmations or fetching missing blocks from the blockchain.
164+
// It ensures the confirmation chain is valid and connected to the transaction block.
145165
func (bl *blockListener) checkAndFillInGap(ctx context.Context, newConfirmationsWithoutTxBlock []*ffcapi.MinimalBlockInfo, existingConfirmations []*ffcapi.MinimalBlockInfo, txBlockInfo *ffcapi.MinimalBlockInfo, targetConfirmationCount uint64) ([]*ffcapi.MinimalBlockInfo, bool, error) {
146166
var hasNewFork bool
147-
// check whether there are forks in the newConfirmations
167+
168+
// Detect forks by comparing new confirmations with existing ones
148169
for _, confirmation := range newConfirmationsWithoutTxBlock {
149170
for _, existingConfirmation := range existingConfirmations {
150171
if confirmation.BlockNumber.Uint64() == existingConfirmation.BlockNumber.Uint64() && !confirmation.Equal(existingConfirmation) {
@@ -157,59 +178,75 @@ func (bl *blockListener) checkAndFillInGap(ctx context.Context, newConfirmations
157178
}
158179
}
159180

181+
// Determine the range of blocks to validate and fill gaps
160182
blockNumberToReach := txBlockInfo.BlockNumber.Uint64() + targetConfirmationCount
161183
var lastValidatedBlock *ffcapi.MinimalBlockInfo
162184
if len(newConfirmationsWithoutTxBlock) > 0 {
185+
// Start from the block before the first new confirmation
163186
blockNumberToReach = newConfirmationsWithoutTxBlock[0].BlockNumber.Uint64() - 1
164187
lastValidatedBlock = newConfirmationsWithoutTxBlock[0]
165188
}
166189

190+
// Fill gaps by validating blocks from target down to transaction block
167191
for i := blockNumberToReach; i > txBlockInfo.BlockNumber.Uint64(); i-- {
168-
// first use the block info from the confirmation queue if matches are found
169192
fetchedFromExistingQueue := false
170-
if lastValidatedBlock != nil {
171193

194+
// First, try to use existing confirmations if they match
195+
if lastValidatedBlock != nil {
172196
for _, confirmation := range existingConfirmations {
173197
if confirmation.BlockNumber.Uint64() == i {
174198
if confirmation.IsParentOf(lastValidatedBlock) {
199+
// Valid existing confirmation - prepend to queue
175200
newConfirmationsWithoutTxBlock = append([]*ffcapi.MinimalBlockInfo{confirmation}, newConfirmationsWithoutTxBlock...)
176201
lastValidatedBlock = confirmation
177202
fetchedFromExistingQueue = true
178203
break
179204
}
205+
// Block number matches but parent relationship is invalid - fork detected
180206
hasNewFork = true
181207
}
182208
}
183209
}
210+
184211
if fetchedFromExistingQueue {
185212
continue
186213
}
187-
// if no match is found, fetch the block info from the chain
214+
215+
// Fetch block from blockchain if not found in existing confirmations
188216
freshBlockInfo, _, err := bl.getBlockInfoByNumber(ctx, i, false, "", "")
189217
if err != nil {
190218
return nil, hasNewFork, err
191219
}
220+
if freshBlockInfo == nil {
221+
return nil, hasNewFork, i18n.NewError(ctx, msgs.MsgBlockNotAvailable)
222+
}
223+
192224
fetchedBlock := &ffcapi.MinimalBlockInfo{
193225
BlockNumber: fftypes.FFuint64(freshBlockInfo.Number.BigInt().Uint64()),
194226
BlockHash: freshBlockInfo.Hash.String(),
195227
ParentHash: freshBlockInfo.ParentHash.String(),
196228
}
229+
230+
// Validate parent-child relationship
197231
if lastValidatedBlock != nil && !fetchedBlock.IsParentOf(lastValidatedBlock) {
198-
// the fetched block is not the parent of the last validated block
199-
// chain is not in a stable stable to build the confirmation queue
200232
return nil, hasNewFork, i18n.NewError(ctx, msgs.MsgFailedToBuildConfirmationQueue)
201233
}
234+
235+
// Prepend fetched block to confirmation queue
202236
newConfirmationsWithoutTxBlock = append([]*ffcapi.MinimalBlockInfo{fetchedBlock}, newConfirmationsWithoutTxBlock...)
203237
lastValidatedBlock = fetchedBlock
204238
}
205239

206-
// we've rebuilt the confirmations queue, now check the front of the queue still connect to the tx block
207-
if !txBlockInfo.IsParentOf(newConfirmationsWithoutTxBlock[0]) {
240+
// Final validation: ensure the confirmation chain connects to the transaction block
241+
if len(newConfirmationsWithoutTxBlock) > 0 && !txBlockInfo.IsParentOf(newConfirmationsWithoutTxBlock[0]) {
208242
return nil, hasNewFork, i18n.NewError(ctx, msgs.MsgFailedToBuildConfirmationQueue)
209243
}
244+
210245
return append([]*ffcapi.MinimalBlockInfo{txBlockInfo}, newConfirmationsWithoutTxBlock...), hasNewFork, nil
211246
}
212247

248+
// ReconcileConfirmationsForTransaction is the public API for reconciling transaction confirmations.
249+
// It delegates to the blockListener's internal reconciliation logic.
213250
func (c *ethConnector) ReconcileConfirmationsForTransaction(ctx context.Context, txHash string, existingConfirmations []*ffcapi.MinimalBlockInfo, targetConfirmationCount uint64) (*ffcapi.ConfirmationMapUpdateResult, error) {
214251
return c.blockListener.reconcileConfirmationsForTransaction(ctx, txHash, existingConfirmations, targetConfirmationCount)
215252
}

0 commit comments

Comments
 (0)