¿Por qué sendSignedTransaction devuelve un hash tx PERO no publica en la red Rinkeby (React, Metamask, web3, infura)

Estoy desarrollando una aplicación React muy simple en la que un usuario hace clic en un botón y se envía algo de éter de una cuenta a otra. Actualmente, la función onClick sendEther crea una transacción serializada firmada adecuada y (a menudo) devuelve un hash de transacción. Sin embargo, la transacción en realidad nunca pasa por la red de prueba de Rinkeby (a la que se accede a través de Etherscan).

Mi corazonada es que estoy haciendo un mal uso de infura (que configuré en mi evento DOMContentLoaded, ver más abajo).

//1. Configurar

document.addEventListener('DOMContentLoaded', () => {
   const endpoint = 'https://rinkeby.infura.io/APIKEY';
   window.web3 = new Web3(new Web3.providers.HttpProvider(endpoint));
}); 

//2. Reaccionar componente front-end.

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: ''
    });
  }
Solo una nota: Etherscan no es omnipotente. Incluso si algo no aparece en Etherscan no significa que no podría haber tenido éxito. ¿Quizás Etherscan simplemente no lo ve?

Respuestas (2)

Esta línea ...

nonce: window.web3.utils.toHex(window.web3.eth.getTransactionCount(fromAccount)),

... se basa en un recuento de transacciones fiable de Infura. El problema es que no es tan confiable (ni tan siquiera cerca) como usted necesita que sea. Este método producirá resultados poco fiables e inconsistentes como ha observado.

Algunos antecedentes ayudarán a explicar lo que está sucediendo y cómo puede abordarlo.

Ethereum usa una noncepara cada cuenta para protegerse contra ataques de repetición. Hay algunos detalles sutiles de implementación.

  1. Las transacciones de la misma cuenta seguramente se realizarán en nonceorden.
  2. Si una transacción no se extrae (se pierde, el gas es demasiado bajo para incluirlo en un bloque), todas las transacciones con un valor más alto noncese detendrán. Por lo general, una transacción estancada se puede cancelar (ver #4).
  3. Se espera que los clientes de software (nodos, billeteras) realicen un seguimiento del nonce y lo adjunten a las transacciones. Esto, para que los nodos conozcan el orden de ejecución correcto incluso en el caso de que las transacciones chismosas lleguen fuera de orden.
  4. Una transacción puede ser cancelada por otra transacción con el mismo noncey superior gassi el reemplazo se extrae primero. Un método común para cancelar una transacción es repetir noncey enviar 0ETH desde la cuenta a sí misma.
  5. En el mejor de los casos, getTransactionCount()no tiene en cuenta las transacciones que puedan existir en la cola pendiente.
  6. La cola pendiente es "no oficial" si tal cosa se puede decir sobre algo en el consenso distribuido. Los nodos solo pueden informar las transacciones pendientes de las que tienen conocimiento . Puede y obtendrá diferentes opiniones de diferentes nodos a medida que las transacciones propuestas atraviesan la red. La minería de bloques es el proceso que derrumba la ambigüedad.
  7. Infura es altamente paralelo, por lo que, aunque esté golpeando un punto final, la respuesta podría provenir de cualquier nodo orientado hacia el exterior en una base de equilibrio de carga.

Todo lo cual para decir que hay razones conocidas por las que su proceso no es confiable.

El enfoque habitual es hacer que el cliente de software sea el administrador del nonce. El escenario más fácil de describir es el caso en el que no hay transacciones pendientes porque la cuenta ha estado inactiva o es una cuenta nueva.

A partir de 0, o el recuento de transacciones, incremente el nonce a medida que avanza sin depender de los nodos. Tienes que confiar en tu propio conteo más de lo que confías en cualquier señal de la red.

Puede encontrar más información aquí: Patrones de concurrencia para cuenta nonce

Espero eso ayude.

Como explicó Rob Hitchens, Infura está diseñado a través de un balanceador de carga con múltiples nodos detrás. Esto significa que dos de las mismas solicitudes a Infura pueden generar respuestas diferentes porque cada solicitud podría llegar a un nodo diferente. A veces obtendrá respuestas de bloques obsoletos, nodos con diferentes transacciones en sus mempools o nodos que no contienen el bloque más nuevo. Una alternativa a este problema es usar un servicio como Alchemy

¡Bienvenido a Ethereum Stack Exchange! Esto fue marcado como spam. Consulte meta.stackexchange.com/questions/57497/… porque hay un patrón de mencionar Alchemy en sus respuestas, y debe divulgarse si trabaja para ellos.
¿Puedes explicar por qué es mejor Alchemy?