Что такое nonce и зачем он нужен
Nonce в Ethereum: как он задаёт порядок транзакций, защищает от повторной отправки и почему зависшая транзакция блокирует следующие.
Что такое nonce
Nonce — это порядковый номер транзакции от конкретного EOA.
Ethereum использует nonce, чтобы выполнять транзакции одного аккаунта строго по порядку и не принимать одну и ту же подписанную транзакцию дважды.
Как nonce растёт
Адрес 0xabc...
nonce 0 → первая транзакция
nonce 1 → вторая транзакция
nonce 2 → третья транзакцияКаждый EOA имеет свой счётчик. Если у Alice nonce 7, это ничего не говорит о nonce Bob.
Контракты тоже имеют nonce, но для разработчика приложений чаще важен nonce отправителя транзакции: EOA, который подписывает действие.
Читаем nonce через RPC
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://ethereum.publicnode.com");
const address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
const latestNonce = await provider.getTransactionCount(address, "latest");
const pendingNonce = await provider.getTransactionCount(address, "pending");
const balance = await provider.getBalance(address);
console.log("Address:", address);
console.log("Balance:", ethers.formatEther(balance), "ETH");
console.log("Latest nonce:", latestNonce);
console.log("Pending nonce:", pendingNonce);
console.log("Pending transactions:", pendingNonce - latestNonce);latest показывает nonce по уже подтверждённым блокам. pending учитывает транзакции, которые уже отправлены в mempool, но ещё не попали в блок.
Как это работает
provider.getTransactionCount(address, "latest") — возвращает количество подтверждённых транзакций от адреса.
provider.getTransactionCount(address, "pending") — возвращает следующий nonce с учётом pending-транзакций.
pendingNonce - latestNonce — показывает, сколько транзакций от адреса уже ждут включения в блок.
Если разницы нет, у адреса нет pending-транзакций по данным этой RPC-ноды.
Nonce в подписанной транзакции
Nonce входит в данные, которые подписывает кошелёк.
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://ethereum.publicnode.com");
// Тестовый ключ из документации Hardhat. Не используйте его для реальных средств.
const wallet = new ethers.Wallet(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
provider,
);
const nonce = await provider.getTransactionCount(wallet.address, "pending");
const txRequest = {
to: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
value: ethers.parseEther("0.001"),
nonce,
gasLimit: 21_000n,
maxFeePerGas: ethers.parseUnits("20", "gwei"),
maxPriorityFeePerGas: ethers.parseUnits("2", "gwei"),
chainId: 1,
type: 2,
};
const signedTx = await wallet.signTransaction(txRequest);
console.log("Wallet:", wallet.address);
console.log("Nonce:", nonce);
console.log("Signed transaction:", signedTx);Этот код подписывает транзакцию локально и не отправляет её в сеть. Если изменить nonce, изменится и подпись.
Зачем nonce нужен
Nonce решает две задачи.
Первая — порядок. Ethereum не выполнит транзакцию с nonce 8, пока не выполнена транзакция с nonce 7.
Вторая — защита от replay внутри сети. Если уже выполнена транзакция с nonce 7, эту же signed transaction нельзя выполнить ещё раз.
Как заменить зависшую транзакцию
Если транзакция застряла в mempool, новые транзакции с большим nonce будут ждать.
Чтобы заменить зависшую транзакцию, отправляют новую транзакцию:
тот же from
тот же nonce
более высокая комиссияКогда новая транзакция с тем же nonce попадёт в блок, старая станет недействительной. Две транзакции с одним nonce от одного адреса не могут выполниться обе.
Частые ошибки
Брать nonce только через latest → если у адреса уже есть pending-транзакция, вы можете случайно подписать новую транзакцию с тем же nonce.
Думать, что nonce глобальный для сети → nonce считается отдельно для каждого аккаунта.
Отправлять несколько транзакций параллельно без управления nonce → две транзакции могут получить один nonce, и одна из них заменит другую или будет отклонена RPC.
Что дальше
- Как работает транзакция изнутри — где nonce находится в жизненном цикле транзакции
- Gas — как считается и кто платит — почему для замены транзакции нужна более высокая комиссия
- Провайдер vs Сайнер — кто читает nonce и кто подписывает транзакцию