Я разрабатываю очень простое приложение React, в котором пользователь нажимает кнопку, и некоторое количество эфира отправляется с одной учетной записи на другую. В настоящее время функция onClick sendEther создает правильно подписанную сериализованную транзакцию и (часто) возвращает хэш транзакции. Однако на самом деле транзакция никогда не проходит через тестовую сеть Rinkeby (доступ к которой осуществляется через Etherscan).
Я подозреваю, что я неправильно использую infura (которую я настроил в своем событии DOMContentLoaded, см. ниже).
//1. Настраивать
document.addEventListener('DOMContentLoaded', () => {
const endpoint = 'https://rinkeby.infura.io/APIKEY';
window.web3 = new Web3(new Web3.providers.HttpProvider(endpoint));
});
//2. Компонент интерфейса React.
sendEther() {
const fromAccount = **acct1**;
const toAccount = **acct2**;
const rawTransaction = this.makeRawTransaction(fromAccount, toAccount);
const signedTransaction = this.makeSignedTransaction(rawTransaction);
const serializedTransaction = `0x${signedTransaction.serialize().toString('hex')}`;
window.web3.eth.sendSignedTransaction(serializedTransaction, (error, result) => {
if(!error) {
console.log(`Transaction hash is: ${result}`);
this.setState({
etherscanUrl: `https://rinkeby.etherscan.io/tx/${result}`,
error: null
});
} else {
this.setState({ error: error.message })
console.error(error);
}
});
}
makeSignedTransaction(rawTransaction) {
const privateKey = '**************';
const privateKeyX = new Buffer(privateKey, 'hex');
const transaction = new EthTx(rawTransaction);
transaction.sign(privateKeyX);
return transaction;
}
makeRawTransaction(fromAccount, toAccount) {
const { exchangeRate } = this.props;
const amount = (1 / exchangeRate) * 5;
return ({
nonce: window.web3.utils.toHex(window.web3.eth.getTransactionCount(fromAccount)),
to: toAccount,
gasPrice: window.web3.utils.toHex(100000000000),
gasLimit: window.web3.utils.toHex(100000),
value: window.web3.utils.toHex(window.web3.utils.toWei(`${amount}`, 'ether')),
data: ''
});
}
Эта линия...
nonce: window.web3.utils.toHex(window.web3.eth.getTransactionCount(fromAccount)),
... опирается на надежный подсчет транзакций от Infura. Проблема в том, что это не так надежно (или даже близко), как вам нужно. Как вы заметили, этот метод будет давать ненадежные и противоречивые результаты.
Некоторая предыстория поможет объяснить, что происходит и как вы можете решить эту проблему.
Ethereum использует nonce
для каждой учетной записи для защиты от повторных атак. Есть некоторые тонкие детали реализации.
nonce
порядку.nonce
остановятся. Застрявшую транзакцию обычно можно отменить (см. № 4).nonce
или более высоким gas
значением, если замена будет добыта первой. Распространенным методом отмены транзакции является повторение nonce
и отправка 0
ETH со счета на себя.getTransactionCount()
случае не учитываются транзакции, которые могут находиться в очереди ожидания.Все это говорит о том, что существуют известные причины, по которым ваш процесс ненадежен.
Обычный подход состоит в том, чтобы сделать программный клиент менеджером nonce
. Самый простой сценарий для описания — это случай, когда ожидающих транзакций нет, потому что учетная запись была закрыта или это новая учетная запись.
Начиная с 0
, или счетчика транзакций, увеличивайте одноразовый номер по мере продвижения, не полагаясь на узлы. Вы должны доверять своему собственному счету больше, чем любому сигналу из сети.
Дополнительную информацию можно найти здесь: Шаблоны параллелизма для одноразового номера учетной записи .
Надеюсь, это поможет.
Как объяснил Роб Хитченс, архитектура Infura построена на основе балансировщика нагрузки с несколькими узлами за ним. Это означает, что два одинаковых запроса к Infura могут привести к разным ответам, поскольку каждый запрос может попасть на другой узел. Иногда вы будете получать ответы от устаревших блоков, узлов с другими транзакциями в своих мемпулах или узлов, которые не содержат новейший блок. Альтернативой этой проблеме является использование такого сервиса, как Алхимия .
Лаури Пелтонен