Ich entwickle eine sehr einfache React-Anwendung, bei der ein Benutzer auf eine Schaltfläche klickt und etwas Ether von einem Konto an ein anderes gesendet wird. Derzeit erstellt die Funktion onClick sendEther eine ordnungsgemäß signierte, serialisierte Transaktion und gibt (häufig) einen Transaktions-Hash zurück. Die Transaktion geht jedoch nie wirklich durch das Rinkeby-Testnetzwerk (auf das über Etherscan zugegriffen wird).
Meine Vermutung ist, dass ich Infura missbrauche (das ich in meinem DOMContentLoaded-Ereignis eingerichtet habe, siehe unten).
//1. Aufstellen
document.addEventListener('DOMContentLoaded', () => {
const endpoint = 'https://rinkeby.infura.io/APIKEY';
window.web3 = new Web3(new Web3.providers.HttpProvider(endpoint));
});
//2. Frontend-Komponente reagieren.
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: ''
});
}
Diese Linie ...
nonce: window.web3.utils.toHex(window.web3.eth.getTransactionCount(fromAccount)),
... setzt auf eine zuverlässige Transaktionszählung von Infura. Das Problem ist, dass es nicht so zuverlässig (oder sogar nahe) ist, wie Sie es brauchen. Wie Sie beobachtet haben, führt diese Methode zu unzuverlässigen, inkonsistenten Ergebnissen.
Einige Hintergrundinformationen helfen zu erklären, was vor sich geht und wie Sie damit umgehen können.
Ethereum verwendet einen nonce
für jedes Konto, um sich vor Replay-Angriffen zu schützen. Es gibt einige subtile Implementierungsdetails.
nonce
.nonce
. Eine blockierte Transaktion kann normalerweise abgebrochen werden (siehe Nr. 4).nonce
oder einem höheren Wert storniert werden, gas
wenn der Ersatz zuerst abgebaut wird. Eine übliche Methode zum Stornieren einer Transaktion besteht darin, die ETH zu wiederholen und vom Konto an sich selbst zu nonce
senden .0
getTransactionCount()
Berücksichtigt bestenfalls nicht die Transaktionen, die möglicherweise in der ausstehenden Warteschlange vorhanden sind.Alles in allem gibt es bekannte Gründe, warum Ihr Prozess unzuverlässig ist.
Der übliche Ansatz besteht darin, den Softwareclient zum Manager der nonce
. Das am einfachsten zu beschreibende Szenario ist der Fall, in dem es keine ausstehenden Transaktionen gibt, weil das Konto ruhig war oder es sich um ein neues Konto handelt.
Beginnen Sie bei 0
, oder der Transaktionsanzahl, und erhöhen Sie die Nonce, während Sie fortfahren, ohne sich auf Knoten zu verlassen. Sie müssen Ihrer eigenen Zählung mehr vertrauen als einem Signal aus dem Netzwerk.
Weitere Informationen finden Sie hier: Gleichzeitigkeitsmuster für das Konto Nonce
Ich hoffe es hilft.
Wie Rob Hitchens erklärte, ist Infura über einen Load Balancer mit mehreren Knoten dahinter aufgebaut. Dies bedeutet, dass zwei gleiche Anfragen an Infura zu unterschiedlichen Antworten führen können, da jede Anfrage einen anderen Knoten treffen könnte. Manchmal erhalten Sie Antworten von veralteten Blöcken, Knoten mit unterschiedlichen Transaktionen in ihren Mempools oder Knoten, die nicht den neuesten Block enthalten. Eine Alternative zu diesem Problem ist die Verwendung eines Dienstes wie Alchemy
Lauri Peltonen