Как работает транзакция изнутри
Что происходит с Ethereum-транзакцией после подписи: nonce, gas, mempool, inclusion в блок, receipt и подтверждения.
Как работает транзакция изнутри
Транзакция — это подписанная команда изменить State Ethereum.
Она может перевести ETH, вызвать функцию контракта или задеплоить новый контракт. Пока транзакция не попала в блок, State сети не изменился.
Путь транзакции
EOA подписывает транзакцию
↓
RPC-нода получает raw transaction
↓
Транзакция попадает в mempool
↓
Валидатор включает её в блок
↓
EVM выполняет транзакцию
↓
Сеть сохраняет receipt и меняет StateГлавное: транзакция не выполняется в момент подписи. Подпись только доказывает, что владелец адреса разрешил действие.
Читаем реальную транзакцию
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("https://ethereum.publicnode.com");
const block = await provider.getBlock("latest");
if (!block || block.transactions.length === 0) {
throw new Error("В последнем блоке нет транзакций");
}
const txHash = block.transactions[0];
const tx = await provider.getTransaction(txHash);
const receipt = await provider.getTransactionReceipt(txHash);
if (!tx || !receipt) {
throw new Error("Транзакция ещё не доступна через RPC");
}
console.log("Hash:", tx.hash);
console.log("From:", tx.from);
console.log("To:", tx.to);
console.log("Nonce:", tx.nonce);
console.log("Value ETH:", ethers.formatEther(tx.value));
console.log("Gas limit:", tx.gasLimit.toString());
console.log("Gas used:", receipt.gasUsed.toString());
console.log("Status:", receipt.status === 1 ? "success" : "failed");
console.log("Block:", receipt.blockNumber);
console.log("Confirmations:", await receipt.confirmations());Этот код не отправляет транзакцию. Он берёт уже включённую транзакцию из последнего блока и показывает, из каких частей она состоит.
Что лежит в транзакции
| Поле | Что означает |
|---|---|
from | адрес EOA, который подписал транзакцию |
to | получатель ETH или адрес контракта |
value | сколько ETH передаётся |
data | calldata для вызова контракта |
nonce | порядковый номер транзакции от from |
gasLimit | максимум gas, который отправитель разрешил потратить |
maxFeePerGas | максимальная цена gas в EIP-1559 транзакции |
signature | криптографическое доказательство, что транзакцию подписал владелец ключа |
Если to пустой, транзакция создаёт новый контракт. Если data не пустой, транзакция вызывает код контракта.
Как это работает
provider.getBlock("latest") — читает последний блок из Ethereum mainnet.
block.transactions[0] — берёт hash первой транзакции в блоке.
provider.getTransaction(txHash) — возвращает данные, которые отправитель подписал: from, to, value, nonce, gasLimit, data.
provider.getTransactionReceipt(txHash) — возвращает результат выполнения: статус, использованный gas, номер блока и события.
receipt.status — показывает, завершилась ли транзакция успешно. Даже failed-транзакция остаётся в блоке и всё равно тратит gas.
Nonce защищает порядок
nonce — это счётчик транзакций от конкретного EOA.
Адрес 0xabc...
nonce 0 → первая транзакция
nonce 1 → вторая транзакция
nonce 2 → третья транзакцияEthereum не выполнит транзакцию с nonce 2, пока не выполнена транзакция с nonce 1. Поэтому две транзакции от одного адреса имеют строгий порядок.
Gas ограничивает выполнение
Каждая операция EVM стоит gas. Отправитель заранее указывает gasLimit — максимум, который транзакция может потратить.
Если gas закончился во время выполнения, транзакция откатывает изменения State, но комиссия всё равно списывается. Это защищает сеть от бесконечных циклов и слишком дорогих вычислений.
Частые ошибки
Думать, что отправка в RPC уже изменила State → State меняется только после включения транзакции в блок.
Путать transaction и receipt → transaction описывает команду, receipt описывает результат выполнения.
Игнорировать nonce → если зависла старая транзакция с низким nonce, новые транзакции от того же адреса будут ждать.
Что дальше
- Gas и комиссии — как сеть считает стоимость транзакции
- Провайдер vs Сайнер — кто читает данные, а кто подписывает транзакции
- Что такое ABI — как
dataпревращается в вызов функции контракта