0

I want to end the process after sendTransaction return transactionHash. Here is my code currently :

const Web3 = require('web3');
const web3 = new Web3("http://127.0.0.1:8545");

async function task(db) {
    const accounts = await web3.eth.getAccounts();
    const length = accounts.length;

    // Do multiple transaction
    while (length--) {
        feeTx = {
            ...
        }
        await web3.eth.sendTransaction(feeTx, async function (err, transactionHash) {
            if (err) {
                // await for db(mongo) insert then continue loop
                await db.insert(err);
            } else {
                console.log("DONE");
                // await for db(mongo) insert then continue loop
                await db.insert(transactionHash);
            }
        });
    }
}
// do db connection first
db = ....
await task(db);
// Close db connection
db.close();
// The process should be ended here.
// but it doesn't end, if one of the transaction is still pending to be mined, 
// even I already get all the transactionHash from task()
// The process will be ended when all the transaction is success(mined).

This process won't be ended if one of the transaction is still pending even I already get all the transactionHash. I know can end the process by process.exit(0) manually, but I believe that this is risk for my code(Since it is an async loop). So is there any method and more safety way to end the process after I get all the transactionHash?

Sinice code above is a little bit complicated, this one would be clearly:

const Web3 = require('web3');
const web3 = new Web3("http://127.0.0.1:8545");

async function task(db) {
    const accounts = await web3.eth.getAccounts();
    const length = accounts.length;

    try {
        // Do multiple transaction
        while (length--) {
            feeTx = {
                ...
            }
            // What i want is only the transactionHash(It will return me immediately without the transaction be mined).
            // sendTransaction here will wait until it get the receipt (The transaction is already be mined). 
            const transactionHash = await web3.eth.sendTransaction(feeTx);
            // transactionHash logging
            await db.insert(transactionHash);
        }
    } catch (err) {
        // Error logging
        await db.insert(err);
    }
}
// do db connection first
db = ....
await task(db);
// Close db connection
db.close();
// The process will end here. With long processing since it wait until all the transaction be mined
  • BTW, if your web3 instance is connected via WebSocket (ws at the beginning of your provider URL), then you need to close it explicitly. – goodvibration Oct 4 at 9:43
  • BTW, if length < 0 then the process is gonna take a very long time to complete. – goodvibration Oct 4 at 10:16
  • Your recent edit - that won't even run! You can use await only inside an async function. So I know for a fact that you haven't even tried it (at least not the version you've just posted). – goodvibration Oct 4 at 10:27
  • And your loop is not "async". The calls to on are "async" (return before completion), which would actually make your loop end faster rather than running forever. Add printouts in your code, gather some more information and come back with that. Please. – goodvibration Oct 4 at 10:30
  • I have added more details in the code. I think it is clear enough now. The main point here is sendTransaction will keep waiting until it get the transaction receipts. – superrman777 Oct 4 at 10:36
0

The call to on(...) runs asynchronously (returns immediately).

You can fix it as follows:

async function task() {
    const receipts = new Array(length);
    for (let i = 0; i < length; i++) {
        feeTx = {
            ...
        };
        receipts[i] = await web3.eth.sendTransaction(feeTx);
    }
    // handle `receipts` here
}
task();
// do not count on anything performed by `task` at this point
// if you want to, then call `await task();` from some other `async function`

Alternatively, you could do something like:

function task(length) {
    feeTx = {
        ...
    };
    web3.eth.sendTransaction(feeTx)
        .on('transactionHash', transactionHash => {
            console.log(transactionHash);
            if (length > 1)
                task(length - 1);
        })
        .on('error', error => {
            console.log(error);
            task(length); // or abort
        });
    }
}
task(length);

As with regards to your process not ending, I would need to make an educated guess here, because your code doesn't seem like something which could lead to that... So here it is:

If your web3 connection is a web-socket, then you need to close it explicitly.

Here is one way to do this generally (i.e., regardless of the connection-type):

if (web3.currentProvider.constructor.name == "WebsocketProvider")
    web3.currentProvider.connection.close();

Again, note that you should not use it in the code posted in your question, because you would be closing the connection before all transactions have completed.

In the code posted in my answer, on the other hand:

  1. In my first suggestion, you can add it at the end of the task function
  2. In my second suggestion, you can add it after calling the task function
  • But the process will never end if the transaction is still pending? Even i already get the transactionHash. – superrman777 Oct 4 at 9:27
  • @superrman777: Have you tried that? – goodvibration Oct 4 at 9:36
  • I think the web3 connection is not the main issue here, because my web3 connection is not via ws. I have tried your code, for the first one, it will return the transaction receipt( the transaction is already be mined), what i need is only the transactionHash(the transaction haven't be mined). And the second one is same as my posted code. – superrman777 Oct 4 at 10:06
  • @superrman777: I suggest that you add some logging (printouts) after calling task, and also inside that function. In addition, it is not clear what length is used for in this context, or what its initial value is (for example, if it's -1 then it might take for the function a very long time to complete). Finally, as I've mentioned at the beginning of this answer, your code is generally ill-formed, all async keywords are in fact redundant (which implies that you're confused with the async/await scheme), and calls to on(...) return immediately without even handling the hashes. – goodvibration Oct 4 at 10:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.