Skip to content
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

Ability to test with more than one messageQueue #59

Open
9oelM opened this issue Dec 30, 2024 · 0 comments
Open

Ability to test with more than one messageQueue #59

9oelM opened this issue Dec 30, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@9oelM
Copy link

9oelM commented Dec 30, 2024

Is your feature request related to a problem? Please describe.

Once you send off a message using blockchain.sendMessageIter, messageQueue will be populated with the next PendingMessage:

protected messageQueue: PendingMessage[] = []

await this.pushMessage(message)

The current design of messageQueue only allows one chain of async messages to be stored. However on TON, it is sometimes useful to test how two different chains of async messages interact with a contract at the same time, for example in order to prevent MITM attack.

However this is just not possible with the current codebase because the current design only stores one chain of async messages.

So something like this will result in an unexpected result:

const A = blockchain.treasury(`A`)
const B = blockchain.treasury(`B`)
const C = blockchain.openContract(...)

const body_0 = ...;
const body_1 = ...;

const messages_0 = await blockchain.sendMessageIter(
                internal({
                    from: A.address,
                    to: C.address,
                    value: gas,
                    body: body_0,
                }),
            );
          
// There are outMessages, still
const result = await executeTill(messages_0, { success: true });

// Want to test MITM flow, so we send another message before outMessages from the messages_0 are processed
const messages_1 = await blockchain.sendMessageIter(
                internal({
                    from: B.address,
                    to: C.address,
                    value: gas,
                    body: body_0,
                }),
            );

// Exhaust the iterator (process all messages from messages_1)
for await (const tx of messages_1) {
   // do nothing
}

// Can't process outMessages from messages_0 anymore because `messageQueue` is replaced already. This will throw an error because there are no remaining messages left.
const result = await executeTill(messages_0, { success: true });

Describe the solution you'd like
There's a hacky solution that can be used by anyone now, which is to temporarily store the messageQueue yourself before you invoke another sendMessageIter:

const messages_0 = await blockchain.sendMessageIter(...)

const pending_messages_0 =
                // @ts-ignore: messageQueue is a protected property
                blockchain.messageQueue;
            // @ts-ignore: messageQueue is a protected property
            blockchain.messageQueue = [];
            
const messages_1 = await blockchain.sendMessageIter(...)

for await (const tx of messages_1) {
   // do nothing
}

// Recover messages_0
blockchain.messageQueue = pending_messages_0;

// This will now work
await executeTill(messages_0, ...)
...

But first of all, messageQueue is a protected property, so it requires using ts-ignore. Second of all, it is just very hacky.

I suggest that we maintain a map of PendingMessage[]: i.e. { [id: SomeUniqueId]: PendingMessage[] } so that any messageQueues can readily be accessed no matter how many different messageQueues there are.

@9oelM 9oelM added the enhancement New feature or request label Dec 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant