Как отправить много транзакций в Эфириум, используя js

Я пытаюсь отправить много транзакций в Ethereum с помощью одной программы, написанной на js. Я использую node js, web3 и infura ropsten. Проблема в том, что если я отправляю транзакции сразу, большинство из них просто исчезают. Пытаясь решить эту проблему, я отправляю транзакции с интервалами. Работает, но очень медленно. Я трачу час, чтобы отправить только 100 транзакций. Есть ли какое-то решение, как заставить его работать быстрее и правильно? Я думал об отправке транзакции после того, как предыдущая начинает ожидать, но я не понимаю, как я могу это сделать. Функция sendRaw получает номер транзакции только через некоторое время. Этот код читает файл, получает адрес, сумму и дополнительные данные и использует метод смарт-контракта для передачи токенов. Вот код:

function sendRaw(rawTx) {
var privateKey = new Buffer(key, 'hex');
var transaction = new tx(rawTx);
transaction.sign(privateKey);
var serializedTx = transaction.serialize().toString('hex');
web3.eth.sendRawTransaction(
'0x' + serializedTx, function(err, result) {
    if(err) {
        console.log(err);
    } else {

        console.log(result);
        Ntrans=result;
    }
});
}


var nonce = web3.eth.getTransactionCount(address);
var gasPrice = web3.eth.gasPrice;
var gasLimit = 90000;

var fs = require("fs");
var buf1 = new Buffer(1024);
var buf2 = new Buffer(1024);
var buf3 = new Buffer(1024);
var i = 0;
var j = 0;
var k = 0;

var fd = fs.openSync('/home/kate/Desktop/file.txt', 'r+');


function recurs()
{
    if(k==5) return -1;
    j = 0;
    do
    {
          fs.readSync(fd, buf1, j, 1, i);
          i++;
          j++;
    }
    while(buf1[j-1] != 32);
    AddressC = String(buf1.slice(0, j-1))
    console.log(AddressC);
    j = 0;
    do
    {
          fs.readSync(fd, buf2, j, 1, i)
          i++;
          j++;
    }
    while(buf2[j-1]!=32);
    ValueT = Number(buf2.slice(0, j-1))
    console.log(ValueT);
    j = 0;
    do
    {
          fs.readSync(fd, buf3, j, 1, i);
          i++;
          j++;
    }
    while(buf3[j-1]!=10);
    TxC = String(buf3.slice(0, j-1));

    txOptions =
    {
         nonce: web3.toHex(nonce),
         gasLimit: web3.toHex(gasLimit),
         gasPrice: web3.toHex(gasPrice),
         to: contractAddress

    }

    console.log(TxC);
    console.log(txOptions);
    rawTx = txutils.functionTx(interface, 'foreignBuy', [AddressC, 
    ValueT, TxC], txOptions);
    sendRaw(rawTx);
    k++;
    nonce++;
   /* while(web3.eth.getTransactionReceipt(Ntrans)=="null")
    {

    } */
}

setTimeout(function(){
    recurs();
}, 5000);
}
recurs();
Я подозреваю, что это ошибка — см. github.com/ethereum/go-ethereum/issues/14893 .
Infura — это государственная услуга, у них есть какое-то ограничение скорости в качестве меры безопасности, если вы хотите более высокий лимит, вам следует связаться с ними.
Не могли бы вы также отформатировать свой код, чтобы сделать его более читаемым для потенциальных ответчиков.
Он старый, но если у вас есть какой-то прогресс, напишите свой ответ.
Мы перешли на Alchemy ( alchemyapi.io ) после того, как столкнулись с теми же проблемами ограничения скорости и проблемами надежности, что и Infura. Я бы порекомендовал сделать то же самое для любых приложений производственного качества.

Ответы (3)

Большая часть путаницы при обработке больших объемов транзакций возникает из-за скрытых предположений, которые будут кусаться в масштабе.

Есть несколько важных и неочевидных фактов, которые нужно понять.

  1. Транзакционный одноразовый номер управляется отправителем.
  2. Транзакции от одного и того же отправителя будут обрабатываться в одноразовом порядке.

Неявно отсюда следует, что:

  1. Если транзакция не добыта, транзакции с более высоким одноразовым номером не могут быть добыты. Гэп нарушил бы пункт 2, и поэтому учетная запись может показаться заблокированной.

Наконец:

  1. Майнеры имеют полное право включать транзакции в блоки или игнорировать их.

Можно быстро отправлять транзакции, но это требует точности на уровне транзакции. Что-то может пойти не так, например:

  1. Цена на газ слишком низкая
  2. Транзакция потеряна (без причины)

Отсутствующие транзакции неоднозначны. Они действительно могут быть добыты, если подождать достаточно долго, или они никогда не будут добыты. Неоднозначность является проблемой для нетривиальных действий в масштабе. Процесс должен сделать что-то упреждающее, чтобы устранить двусмысленность.

Для каждой транзакции увеличивайте одноразовый номер и отправляйте, затем ждите, пока транзакция появится в цепочке с подтверждениями. Через несколько минут приступайте к делу с ошибкой.

Для повседневного использования может быть достаточно отправить транзакцию отмены. Вот удобный трюк, чтобы «разблокировать» кошелек, который отправил транзакцию со слишком низкой ценой газа. Аккаунт должен отправить ноль эфира самому себе, указав одноразовый номер транзакции для отмены и gasPrice выше, чем транзакция для отмены. Когда замещающая транзакция появляется в блоке, исходная транзакция (какой бы она ни была) не будет майнить из-за более высокой цены газа и идентичного одноразового номера — подтвержденной отмены. Желательно дождаться нескольких подтверждений, как и для любой другой транзакции.

Тот же принцип можно применить к повторной попытке. Используйте те же данные и одноразовый номер, что и отсутствующая транзакция, и более высокое значение gasPrice. Это означает, что отправитель управляет одноразовым номером по мере его поступления и знает данные, полезную нагрузку, одноразовый номер и gasPrice каждой отправленной транзакции, поэтому он может точно устранять сбои транзакций.

Для получения более подробной информации о технических проблемах ознакомьтесь с обсуждением Singleton Nonce Manager здесь: Шаблоны параллелизма для одноразового номера учетной записи .

Надеюсь, это поможет.

Возможно, сработают пакетные методы web3 1.0 ?

var contract = new web3.eth.Contract(abi, address);

var batch = new web3.BatchRequest();
batch.add(web3.eth.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback));
batch.add(contract.methods.balance(address).call.request({from: '0x0000000000000000000000000000000000000000'}, callback2));
batch.execute();

Это была распространенная проблема в игровом мире, поэтому был сформулирован EIP 1155 . Вы и другие лица можете получить выгоду, работая исключительно с ERC-1155, или обернув интересующие токены (при условии, что они ERC-20 или ERC-721) в ERC-1155.