Несколько транзакций с одного адреса

Я хотел бы создать несколько транзакций с одного и того же адреса одновременно. Поскольку для каждой транзакции требуется одноразовый номер (количество транзакций адреса отправителя), я могу запросить у geth текущий счетчик и создать первый tx, затем увеличить одноразовый номер и создать следующий и так далее. Проблемы, как я их вижу:

  1. если одна транзакция не будет добыта, ни одна из следующих не будет добыта (поскольку nonce будет неправильным).
  2. что произойдет, если некоторые tx будут включены в один блок, а некоторые в другой блок, порядок может стать неправильным. Правильно ли это рассуждение?

Если это не так, мне интересно, есть ли лучший подход для этого случая.

Мне было бы интересно сначала посмотреть, что произойдет, если вы отправите ~ 10-20 транзакций «все сразу» и в какой момент это не удастся. Пожалуйста, сообщите.
тайвано, тест 30 транзакций сразу все ниже. Тесты проводились на блокчейне, где я не указал одноразовый номер.
@BokkyPooBah Пожалуйста, не оставляйте комментарий в качестве ответа. Ссылку, вероятно, можно было бы использовать, чтобы избежать длинных комментариев.
Ага. Август привыкает к этой системе.

Ответы (3)

Вы не указали, отправляете ли вы свои транзакции, будучи подключенными к блокчейну через geth (в блокчейне), или же вы создаете свою транзакцию, не подключаясь к блокчейну (вне блокчейна).

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

Если вы отправляете транзакцию в блокчейне, вы можете использовать eth.sendTransaction(...) без одноразового номера.

Например, вот 3 транзакции с одной и той же учетной записи «от» на одну и ту же учетную запись «куда». Нет необходимости указывать одноразовый номер, так как он генерируется автоматически:

> eth.sendTransaction({from: '0x5e83b635f96da0752f991f0ebddc31249f452dea', to: '0x68acc3a13441b69016560d23e134c7931bbb27bb', value: web3.toWei(1, "ether")});
"0x92d6d2285b198b6b5cf80eca6d4292c9675fb53f47f786063df600d3be06dd09"
> eth.sendTransaction({from: '0x5e83b635f96da0752f991f0ebddc31249f452dea', to: '0x68acc3a13441b69016560d23e134c7931bbb27bb', value: web3.toWei(2, "ether")});
"0x0c1280c8b2f38aec032494913c1d0e65edd511fcd15e2424483f9bbf51c7172e"
> eth.sendTransaction({from: '0x5e83b635f96da0752f991f0ebddc31249f452dea', to: '0x68acc3a13441b69016560d23e134c7931bbb27bb', value: web3.toWei(3, "ether")});
"0x8b6998eea8b343a0f754cf2732a1f28caac3acdfbe97cca69f244f0614ea546a"

> eth.getTransaction("0x92d6d2285b198b6b5cf80eca6d4292c9675fb53f47f786063df600d3be06dd09");
{
  blockHash: "0x8456088424a4cacd8b394b4e11732e3c96ca77ab4a999c6ba62b38ab61116b58",
  blockNumber: 225,
  from: "0x5e83b635f96da0752f991f0ebddc31249f452dea",
  gas: 90000,
  gasPrice: 20000000000,
  hash: "0x92d6d2285b198b6b5cf80eca6d4292c9675fb53f47f786063df600d3be06dd09",
  input: "0x",
  nonce: 0,
  to: "0x68acc3a13441b69016560d23e134c7931bbb27bb",
  transactionIndex: 0,
  value: 1000000000000000000
}
> eth.getTransaction("0x0c1280c8b2f38aec032494913c1d0e65edd511fcd15e2424483f9bbf51c7172e");
{
  blockHash: "0x8456088424a4cacd8b394b4e11732e3c96ca77ab4a999c6ba62b38ab61116b58",
  blockNumber: 225,
  from: "0x5e83b635f96da0752f991f0ebddc31249f452dea",
  gas: 90000,
  gasPrice: 20000000000,
  hash: "0x0c1280c8b2f38aec032494913c1d0e65edd511fcd15e2424483f9bbf51c7172e",
  input: "0x",
  nonce: 1,
  to: "0x68acc3a13441b69016560d23e134c7931bbb27bb",
  transactionIndex: 1,
  value: 2000000000000000000
}
> eth.getTransaction("0x8b6998eea8b343a0f754cf2732a1f28caac3acdfbe97cca69f244f0614ea546a");
{
  blockHash: "0x8456088424a4cacd8b394b4e11732e3c96ca77ab4a999c6ba62b38ab61116b58",
  blockNumber: 225,
  from: "0x5e83b635f96da0752f991f0ebddc31249f452dea",
  gas: 90000,
  gasPrice: 20000000000,
  hash: "0x8b6998eea8b343a0f754cf2732a1f28caac3acdfbe97cca69f244f0614ea546a",
  input: "0x",
  nonce: 2,
  to: "0x68acc3a13441b69016560d23e134c7931bbb27bb",
  transactionIndex: 2,
  value: 3000000000000000000
}
я использую web3.js весь день (подключен к geth в качестве провайдера), не возясь с одноразовым номером. Кто устанавливает для меня одноразовый номер?
Пол С., с github.com/ethereum/go-ethereum/blob/master/rpc/api/… кажется, что одноразовый номер будет угадываться, если он не указан.
звучит так, как будто для одноразового номера нужен отдельный вопрос. Поэтому я искал слово «одноразовый номер». много хороших вещей, чтобы узнать там. Не надо отдельного вопроса.
@PaulS интересно, вы узнали, как это сделать и установить одноразовый номер с помощью web3.js? или как отправить несколько trx?

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

Как правило, процесс

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

Нет хороших кратких примеров этого, которые я мог бы поместить в сообщение stackexchange, но вот несколько ссылок, которые показывают различные способы сделать это:

Как узнать, что ваша транзакция была заминирована. Вопрос об обмене стеками

Это встроено в Ether Pudding , см. функцию synchronizeFunction в index.js, чтобы узнать, как это работает. Делает ваш код приложения очень чистым, используя промисы. Однако index.js довольно сложно читать... просто поверьте мне, он работает ;-)

Вы можете заполнить опрос для получения транзакции

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

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

Во всех этих случаях вы не хотите ждать вечно, вам нужен какой-то тайм-аут. Как правило, в javascript вы запускаете обратный вызов для своего приложения или возвращаете выполненное обещание, когда транзакция добывается. Я полагаю, вы могли бы использовать некоторые другие идиомы javascript, такие как RXJS или Event, но я не пробовал их для этой цели.

Должны ли они быть все одновременно, или вы можете включить произвольную задержку, скажем, 30 секунд до срабатывания следующего? Это наверняка устранит любые описанные вами проблемы. Почти наверняка можно было бы использовать гораздо более короткие периоды времени.

Существует реальная вероятность того, что транзакции не будут отправлены/обработаны в том же порядке и, следовательно, не будут выполнены, но это будет зависеть от поставляемого газа, уровня сетевой активности, насколько быстро происходит «одновременно» на самом деле и т. д.

ждать 30 секунд не рекомендуется, так как время майнинга может варьироваться. Если у вас есть зависимости порядка между транзакциями, подождите, пока предыдущая транзакция не будет добыта, так как это положительное подтверждение. Что касается более сложной темы, если вы беспокоитесь о двойной трате, ожидая, пока будет добыто несколько блоков после того, как транзакция была добыта.
@PaulS Нет возможности дважды потратить из-за одноразового номера. Отправьте транзакцию с одноразовым номером 0, затем 1, затем 2. Если первая не будет добыта, 1-я и 2-я потерпят неудачу. Если 2 "прибудут" раньше 1, то произойдет аналогичный сбой. Если вы отправите их все с одноразовым номером 0, пройдет только первый добытый. И т. д. И т. д. Я считаю, что 30 секунд будет достаточно, но я собираюсь провести тест через несколько минут.
Что произойдет, если блок будет отменен протоколом блокчейна? Если вы находитесь вне блокчейна, вы можете подумать, что отправили эфир, но на самом деле это не так. ИМХО, вы должны отслеживать это для некоторых критических типов транзакций. (в блокчейне, в вашем коде прочности, это не имеет значения, потому что блок возвращается, и ваше состояние возвращается вместе с ним)
В документации web3.js есть несколько примеров ожидания обработки транзакции. По моему опыту, магические тайм-ауты очень хрупкие.
@PaulS Почему бы вам не опубликовать пример web3 в качестве ответа, поскольку он, безусловно, полезен в этом контексте.
Кстати, если вас не волнует заказ, вы можете просто отправить их одновременно. Я отправил сотню за раз, независимо от параллелизма по умолчанию для Promise.map bluebird, используя geth, он, кажется, работает нормально, пока не будет превышен maxGas блока.
Это рассчитало одноразовый номер для вас? Как вы с этим справились?
Я никогда не беспокоился о одноразовом номере. AFAICT, в web3.js или в geth есть какая-то магия, которая заботится о одноразовом номере для меня. Если это срочно, я могу попытаться воскресить этот код, я тестировал материал и переместил генерацию тестового примера на надежность из-за одной из этих забавных ошибок событий.