Skip to content

Commit b266666

Browse files
committed
fix(solo): make solo-to-chain more robust
The solo's messagePool is now a proper store-and-forward implementation to prevent failures in delivery from impacting the message stream. Also, wake the sender if there is a new WebSocket to an RPC node. This prevents the stream from being wedged if the RPC connection changes.
1 parent b43df5a commit b266666

File tree

1 file changed

+23
-18
lines changed

1 file changed

+23
-18
lines changed

packages/solo/src/chain-cosmos-sdk.js

+23-18
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ export async function connectToChain(
189189
fullArgs,
190190
{ maxBuffer: MAX_BUFFER_SIZE },
191191
(_error, stdout, stderr) => {
192-
return resolve({ stdout, stderr });
192+
resolve({ stdout, stderr });
193193
},
194194
);
195195
if (stdin) {
@@ -332,6 +332,10 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
332332
};
333333
// Send that message, and wait for the subscription.
334334
ws.send(JSON.stringify(obj));
335+
336+
// Ensure our sender wakes up again.
337+
// eslint-disable-next-line no-use-before-define
338+
sendUpdater.updateState(true);
335339
});
336340
ws.addEventListener('message', ev => {
337341
// We received a message.
@@ -359,7 +363,11 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
359363

360364
const { notifier: sendNotifier, updater: sendUpdater } = makeNotifierKit();
361365

362-
// An array of [seqnum, message] ordered by unique seqnum.
366+
/**
367+
* @typedef {bigint} SeqNum
368+
* @type {Array<[SeqNum, any]>}
369+
* Ordered by seqnum
370+
*/
363371
let messagePool = [];
364372

365373
// Atomically add to the message pool, ensuring the pool is sorted by unique
@@ -384,15 +392,18 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
384392
messagePool = uniquePool;
385393
};
386394

395+
const removeAckedFromMessagePool = ack => {
396+
// Remove all messages sent at earlier acks.
397+
messagePool = messagePool.filter(m => m[0] > ack);
398+
};
399+
387400
let totalDeliveries = 0;
388401
let highestAck = -1;
389402
let sequenceNumber = 0n;
390403
const sendFromMessagePool = async () => {
391404
let tmpInfo;
392405

393-
// We atomically drain the message pool.
394406
const messages = messagePool;
395-
messagePool = [];
396407

397408
try {
398409
totalDeliveries += 1;
@@ -478,15 +489,12 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
478489
X`Unexpected output: ${stdout.trimRight()}`,
479490
);
480491

481-
// We submitted the transaction successfully.
492+
// We submitted the transaction to the mempool successfully.
493+
// Preemptively increment our sequence number to avoid needing to
494+
// retry next time.
482495
sequenceNumber += 1n;
483496
}
484497
}
485-
} catch (e) {
486-
// Put back the deliveries we tried to make.
487-
messagePool = messages.concat(messagePool);
488-
messagePool.sort((a, b) => a[0] - b[0]);
489-
throw e;
490498
} finally {
491499
if (tmpInfo) {
492500
await fs.promises.unlink(tmpInfo.path);
@@ -503,11 +511,9 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
503511
* @param {number=} lastBlockUpdate
504512
*/
505513
const recurseEachNewBlock = async (lastBlockUpdate = undefined) => {
506-
const { updateCount, value } = await blockNotifier.getUpdateSince(
507-
lastBlockUpdate,
508-
);
509-
assert(value, X`${GCI} unexpectedly finished!`);
514+
const { updateCount } = await blockNotifier.getUpdateSince(lastBlockUpdate);
510515
console.debug(`new block on ${GCI}, fetching mailbox`);
516+
assert(updateCount, X`${GCI} unexpectedly finished!`);
511517
await getMailbox()
512518
.then(ret => {
513519
if (!ret) {
@@ -516,6 +522,7 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
516522
const { outbox, ack } = ret;
517523
// console.debug('have outbox', outbox, ack);
518524
inbound(GCI, outbox, ack);
525+
removeAckedFromMessagePool(ack);
519526
})
520527
.catch(e => console.error(`Failed to fetch ${GCI} mailbox:`, e));
521528
recurseEachNewBlock(updateCount);
@@ -543,10 +550,8 @@ ${chainID} chain does not yet know of address ${clientAddr}${adviseEgress(
543550
// This function ensures we only have one outgoing send operation at a time.
544551
const recurseEachSend = async (lastSendUpdate = undefined) => {
545552
// See when there is another requested send since our last time.
546-
const { updateCount, value } = await sendNotifier.getUpdateSince(
547-
lastSendUpdate,
548-
);
549-
assert(value, X`Sending unexpectedly finished!`);
553+
const { updateCount } = await sendNotifier.getUpdateSince(lastSendUpdate);
554+
assert(updateCount, X`Sending unexpectedly finished!`);
550555

551556
await sendFromMessagePool().catch(retrySend);
552557
recurseEachSend(updateCount);

0 commit comments

Comments
 (0)