Skip to content

Commit 3ad6427

Browse files
Fix open issues in TTP classic operation logic that were found as a part of full history verification (#5641)
* Format error message to include more info * Address suble difference in behavior for LiquidityPoolWithdraw operation * Make transaction index and operation index ot be 1-indexed
1 parent 10ea13d commit 3ad6427

File tree

5 files changed

+52
-26
lines changed

5 files changed

+52
-26
lines changed

ingest/processors/token_transfer/helpers.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,11 @@ func getImpactedLiquidityPoolEntriesFromOperation(tx ingest.LedgerTransaction, o
166166

167167
return entries, nil
168168
}
169+
170+
func formatError(err error, tx ingest.LedgerTransaction, opIndex uint32, op xdr.Operation) error {
171+
if err == nil {
172+
return nil
173+
}
174+
return fmt.Errorf("failed to process token transfer events for ledgerSequence: %v, txHash: %v, operationIndex: %v, operationType: %v. error: %w",
175+
tx.Ledger.LedgerSequence(), tx.Hash.HexString(), opIndex, op.Body.Type.String(), err)
176+
}

ingest/processors/token_transfer/token_transfer_event.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,20 @@ func NewFeeEvent(meta *EventMeta, from string, amount string, token *assetProto.
8484
}
8585

8686
func NewEventMetaFromTx(tx ingest.LedgerTransaction, operationIndex *uint32, contractAddress string) *EventMeta {
87+
// The input operationIndex is 0-indexed.
88+
// As per SEP-35, the OperationIndex in the output proto should be 1-indexed.
89+
// Make that conversion here
90+
var outputOpIndex *uint32
91+
if operationIndex != nil {
92+
temp := *operationIndex + 1
93+
outputOpIndex = &temp
94+
}
8795
return &EventMeta{
8896
LedgerSequence: tx.Ledger.LedgerSequence(),
8997
ClosedAt: timestamppb.New(tx.Ledger.ClosedAt()),
9098
TxHash: tx.Hash.HexString(),
91-
TransactionIndex: tx.Index - 1,
92-
OperationIndex: operationIndex,
99+
TransactionIndex: tx.Index, // The index in ingest.LedgerTransaction is already 1-indexed
100+
OperationIndex: outputOpIndex,
93101
ContractAddress: contractAddress,
94102
}
95103
}

ingest/processors/token_transfer/token_transfer_event.pb.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ingest/processors/token_transfer/token_transfer_processor.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func (p *EventsProcessor) EventsFromLedger(lcm xdr.LedgerCloseMeta) ([]*TokenTra
7070
}
7171
txEvents, err = p.EventsFromTransaction(tx)
7272
if err != nil {
73-
return nil, fmt.Errorf("error processing token transfer events from transaction: %w", err)
73+
return nil, err
7474
}
7575
events = append(events, txEvents...)
7676
}
@@ -105,8 +105,7 @@ func (p *EventsProcessor) EventsFromTransaction(tx ingest.LedgerTransaction) ([]
105105
// Process the operation and collect events
106106
opEvents, err := p.EventsFromOperation(tx, uint32(i), op, opResult)
107107
if err != nil {
108-
return nil,
109-
fmt.Errorf("error processing token transfer events from operation, index: %d, %s: %w", i, op.Body.Type.String(), err)
108+
return nil, err
110109
}
111110

112111
events = append(events, opEvents...)
@@ -167,7 +166,7 @@ func (p *EventsProcessor) EventsFromOperation(tx ingest.LedgerTransaction, opInd
167166
}
168167

169168
if err != nil {
170-
return nil, err
169+
return nil, formatError(err, tx, opIndex, op)
171170
}
172171

173172
// DO not run this reconciliation check for ledgers with protocol version >= 8
@@ -178,7 +177,7 @@ func (p *EventsProcessor) EventsFromOperation(tx ingest.LedgerTransaction, opInd
178177
// Run reconciliation for all operations except InvokeHostFunction
179178
reconciliationEvent, err := p.generateXlmReconciliationEvents(tx, opIndex, op, events)
180179
if err != nil {
181-
return nil, fmt.Errorf("error generating reconciliation events: %w", err)
180+
return nil, formatError(fmt.Errorf("error generating reconciliation events: %w", err), tx, opIndex, op)
182181
}
183182

184183
if reconciliationEvent != nil {
@@ -189,7 +188,7 @@ func (p *EventsProcessor) EventsFromOperation(tx ingest.LedgerTransaction, opInd
189188
// If it is a burn, put the burn event at the end of the list of other events for this operation
190189
events = append(events, reconciliationEvent)
191190
} else {
192-
return nil, fmt.Errorf("invalid reconciliation event type: %v. reconciliation event type can be only mint or burn", reconciliationEvent.GetEventType())
191+
return nil, formatError(fmt.Errorf("invalid reconciliation event type: %v. reconciliation event type can be only mint or burn", reconciliationEvent.GetEventType()), tx, opIndex, op)
193192
}
194193
}
195194

@@ -210,16 +209,15 @@ Those 2 will call the underlying proto function for clawback
210209
*/
211210
func (p *EventsProcessor) mintOrBurnOrTransferEvent(tx ingest.LedgerTransaction, opIndex *uint32, asset xdr.Asset, from addressWrapper, to addressWrapper, amt string) (*TokenTransferEvent, error) {
212211
var fromAddress, toAddress string
213-
// no need to have a separate flag for transferEvent. if neither burn nor mint, then it is regular transfer
214-
var isMintEvent, isBurnEvent bool
212+
var isFromIssuer, isToIssuer bool
215213

216214
assetIssuerAccountId, _ := asset.GetIssuerAccountId()
217215

218216
// Checking 'from' address
219217
if from.account != nil {
220218
fromAddress = protoAddressFromAccount(*from.account)
221219
if !asset.IsNative() && assetIssuerAccountId.Equals(from.account.ToAccountId()) {
222-
isMintEvent = true
220+
isFromIssuer = true
223221
}
224222
} else if from.liquidityPoolId != nil {
225223
fromAddress = lpIdToStrkey(*from.liquidityPoolId)
@@ -231,7 +229,7 @@ func (p *EventsProcessor) mintOrBurnOrTransferEvent(tx ingest.LedgerTransaction,
231229
if to.account != nil {
232230
toAddress = protoAddressFromAccount(*to.account)
233231
if !asset.IsNative() && assetIssuerAccountId.Equals(to.account.ToAccountId()) {
234-
isBurnEvent = true
232+
isToIssuer = true
235233
}
236234
} else if to.liquidityPoolId != nil {
237235
toAddress = lpIdToStrkey(*to.liquidityPoolId)
@@ -245,18 +243,18 @@ func (p *EventsProcessor) mintOrBurnOrTransferEvent(tx ingest.LedgerTransaction,
245243
// This means that the payment is a wierd one, where the src == dest AND in addition, the src/dest address is the issuer of the asset
246244
// Check this section out in CAP-67 https://github.com/stellar/stellar-protocol/blob/master/core/cap-0067.md#payment
247245
// We need to issue a TRANSFER event for this.
248-
// Keep in mind though that this wont show up in opeartionMeta as a balance change
246+
// Keep in mind though that this wont show up in operationMeta as a balance change
249247
// This has happened in ledgerSequence: 4522126 on pubnet
250-
if isMintEvent && isBurnEvent {
248+
if isFromIssuer && isToIssuer {
251249
return NewTransferEvent(meta, fromAddress, toAddress, amt, protoAsset), nil
252-
} else if isMintEvent {
250+
} else if isFromIssuer {
253251

254252
// Check for Mint Event
255253
if toAddress == "" {
256254
return nil, NewEventError("mint event error: to address is nil")
257255
}
258256
return NewMintEvent(meta, toAddress, amt, protoAsset), nil
259-
} else if isBurnEvent {
257+
} else if isToIssuer {
260258

261259
// Check for Burn Event
262260
if fromAddress == "" {
@@ -265,6 +263,12 @@ func (p *EventsProcessor) mintOrBurnOrTransferEvent(tx ingest.LedgerTransaction,
265263
return NewBurnEvent(meta, fromAddress, amt, protoAsset), nil
266264
}
267265

266+
if fromAddress == "" {
267+
return nil, NewEventError("transfer event error: from address is nil")
268+
}
269+
if toAddress == "" {
270+
return nil, NewEventError("transfer event error: to address is nil")
271+
}
268272
// Create transfer event
269273
return NewTransferEvent(meta, fromAddress, toAddress, amt, protoAsset), nil
270274
}
@@ -598,11 +602,11 @@ func (p *EventsProcessor) liquidityPoolDepositEvents(tx ingest.LedgerTransaction
598602
amtA, amtB := delta.amountChangeForAssetA, delta.amountChangeForAssetB
599603
if amtA <= 0 {
600604
return nil,
601-
fmt.Errorf("deposited amount (%v) for asset: %v, cannot be zero or negative in LiquidityPool: %v", amtA, assetA.String(), lpIdToStrkey(lpId))
605+
fmt.Errorf("deposited amount (%v) for asset: %v, cannot be zero or negative for LiquidityPool: %v", amtA, assetA.String(), lpIdToStrkey(lpId))
602606
}
603607
if amtB <= 0 {
604608
return nil,
605-
fmt.Errorf("deposited amount (%v) for asset: %v, cannot be zero or negative in LiquidityPool: %v", amtB, assetB.String(), lpIdToStrkey(lpId))
609+
fmt.Errorf("deposited amount (%v) for asset: %v, cannot be zero or negative for LiquidityPool: %v", amtB, assetB.String(), lpIdToStrkey(lpId))
606610
}
607611

608612
opSrcAcc := operationSourceAccount(tx, op)
@@ -639,13 +643,19 @@ func (p *EventsProcessor) liquidityPoolWithdrawEvents(tx ingest.LedgerTransactio
639643
lpId := delta.liquidityPoolId
640644
assetA, assetB := delta.assetA, delta.assetB
641645
amtA, amtB := delta.amountChangeForAssetA, delta.amountChangeForAssetB
642-
if amtA <= 0 {
646+
/*
647+
This is slightly different from the LpDeposit operation check. In LpDeposit, if amt <=0: then error
648+
However, for LpWithdraw, the check is if amt < 0: then error.
649+
This is because, the rounding on withdraw could result in nothing being withdrawn
650+
Refer https://github.com/sisuresh/stellar-protocol/blob/unified/core/cap-0038.md#price-bounds-for-liquiditypoolwithdrawop
651+
*/
652+
if amtA < 0 {
643653
return nil,
644-
fmt.Errorf("deposited amount (%v) for asset: %v, cannot be zero or negative in LiquidityPool: %v", amtA, assetA.String(), lpIdToStrkey(lpId))
654+
fmt.Errorf("withdrawn amount (%v) for asset: %v, cannot be negative for LiquidityPool: %v", amtA, assetA.String(), lpIdToStrkey(lpId))
645655
}
646-
if amtB <= 0 {
656+
if amtB < 0 {
647657
return nil,
648-
fmt.Errorf("deposited amount (%v) for asset: %v, cannot be zero or negative in LiquidityPool: %v", amtB, assetB.String(), lpIdToStrkey(lpId))
658+
fmt.Errorf("withdrawn amount (%v) for asset: %v, cannot be negative for LiquidityPool: %v", amtB, assetB.String(), lpIdToStrkey(lpId))
649659
}
650660

651661
opSrcAcc := operationSourceAccount(tx, op)

protos/ingest/processors/token_transfer/token_transfer_event.proto

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ message EventMeta {
1212
uint32 ledger_sequence = 1;
1313
google.protobuf.Timestamp closed_at = 2;
1414
string tx_hash = 3;
15-
// Index of transaction within this ledger. 0-indexed
15+
// Index of transaction within this ledger. This is 1-indexed as per SEP-35
1616
uint32 transaction_index = 4;
17-
// Index of operation within the transaction, if it is not a fee event. 0-indexed
17+
// Index of operation within the transaction, if it is not a fee event. This is 1-indexed as per SEP-35
1818
optional uint32 operation_index = 5;
1919
/* For a classic operation, this contract_address is the ContractID as derived from asset
2020
For a smart contract event, this contractId is the id of the contract emiting the core event

0 commit comments

Comments
 (0)