Как вызвать функцию контракта из кода и подписать транзакцию?

Мой вариант использования заключается в том, что мне нужно вызывать функцию контракта при вызове API.

Теперь я пробовал несколько способов, но у меня есть проблемы с обоими. Имя моей функции — «передача» .

Метод - я

В этом методе я сначала разблокирую учетную запись пользователя. Затем вызовите функцию контракта с помощью contractInstance.methodName(). В методе обратного вызова я снова блокирую учетную запись

Проблема: проблема, которую я вижу здесь, заключается в том, что когда я получаю несколько вызовов своего API одновременно, это вызывает проблему. Поскольку один вызов может заблокировать учетную запись, когда еще один поток пытается вызвать функцию.

/ * Getting the contract Instance */

import Web3 from 'web3';
  const tokenABI = require('../ContractABI.json');

  if (typeof web3 !== 'undefined') {
    var web3 = new Web3(web3.currentProvider)
} else {
    var web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545'))
}

var TokenContract = web3.eth.contract(tokenABI.abi);
var tokenInstance = TokenContract.at(contractConfig.id);

/ * Getting the contract Instance */

router.post('/transferTokens',async (req,res,next)=>{
    let senderAddress = req.param("sender");
    let receiverAddress = req.param("receiver");
    let transferAmount = req.param("amount");

    let searchCriteria = {
        address:senderAddress
    }

    try{
        // Getting the private key of the user from DB.

        let senderDetails = await MongoHelper.findOneByCriteria('accounts',searchCriteria);
        console.log('senderDetails:',senderDetails);

        let chk = web3.personal.unlockAccount(senderDetails.address, senderDetails.pwd, 95000);

        // Unlocked the account and then invoke the transfer function with the necessary parameters.

        tokenInstance.transfer(receiverAddress, transferAmount, { from: senderDetails.address })
        .then(function (msg) {
            res.data = msg;
            let chk = web3.personal.lockAccount(senderDetails.address);
            next();

        }).catch(function (e) {
            console.log('Error %%%%%%%%%%%%%%%%%',e);
            let chk = web3.personal.lockAccount(senderDetails.address);
            next(e)

        });

    }catch(err){
        console.log(' Error err:',err);
        next(err);
    }

});

Метод - II

**В этом методе я получаю callData для своей контрактной функции. Я создаю необработанный объект транзакции. Я подписываю его закрытым ключом пользователя. Затем я использую web3.eth.sendRawTransaction для отправки транзакции **

Проблема: проблема, с которой я столкнулся: я вижу, что транзакция создана. Но он не делает того, что должен делать в идеале. Это просто фиктивная сделка. Метод контракта не вызывается. Я предполагаю, что данные вызова не являются правильными или что-то в этом роде.

Я вижу calldata примерно так, как показано ниже:

router.post('/transferTokens2',async (req,res,next)=>{
    let senderAddress = req.param("sender");
    let receiverAddress = req.param("receiver");
    let transferAmount = req.param("amount");

    let searchCriteria = {
        address:senderAddress
    }

    try{
        let senderDetails = await MongoHelper.findOneByCriteria('accounts',searchCriteria);
        let callData = tokenInstance.transfer.getData(receiverAddress,transferAmount);

        let rawTx = {
            from:senderAddress,
            nonce: 93,
            gasPrice: '0x4a817c800', // eth_estimateGas rpc result
            gasLimit: '0x2fd618',
            to:receiverAddress,
            data:callData 
        }
        var privateKey = new Buffer(senderDetails.key, 'hex')

        var tx = new Tx(rawTx);
        tx.sign(privateKey);

        var serializedTx = tx.serialize();

        web3.eth.sendRawTransaction('0x'+ serializedTx.toString('hex'), function(err, hash) {
            if (!err) {
                console.log('$$$$$:',hash); 
                res.data = hash;
                next();
            }else{
                next(err);
            }   
        });

    }catch(err){
        next(err);
    }

});

Ответы (1)

Для метода 1) вам необходимо сериализовать доступ к разблокировке/блокировке учетной записи. Вы можете использовать семафор для ограничения одной операции в любое время.

Для метода 2) вы жестко запрограммировали одноразовый номер. Вы должны рассчитывать перед каждой сделкой var nonce = web3.eth.getTransactionCount(<address>). Имейте в виду, что nonce — это последовательные числа без повторений. Вы также должны гарантировать, что каждый одноразовый номер используется только один раз.