El nonce de la cuenta es el único elemento en la estructura de la transacción que evita el ataque de reproducción (como se explica en esta muy buena respuesta ). Esencialmente fuerza la secuenciación de las transacciones de una cuenta.
Esto generalmente no causa problemas cuando las transacciones se envían a través de la interfaz web3 a un nodo Ethereum (por ejemplo, Geth, Parity), que luego realiza la firma. La secuenciación la realiza internamente el nodo y, por lo tanto, es transparente para el usuario final.
Este no es el caso cuando las transacciones son creadas y firmadas por una aplicación de usuario (es decir, no Geth o Parity), antes de enviarse a un nodo (por ejemplo, a través de web3.eth.sendRawTransaction).
La construcción de la transacción sin procesar requiere obtener un nonce de cuenta, lo que se puede hacer mediante web3.eth.getTransactionCount, como se explica en esta pregunta . Esto funciona bien cuando no hay concurrencia involucrada.
Sin embargo, considere un usuario final que tiene que firmar varias transacciones en paralelo. La secuenciación de la transacción pasa a ser responsabilidad de la aplicación del usuario.
"web3.eth.getTransactionCount" solo devuelve recuentos de transacciones confirmadas (consulte esta pregunta ). Como resultado, cuando las transacciones se firman en paralelo, a menos que manipulemos el conteo de manera inteligente, solo una de ellas tendrá éxito.
Mi pregunta es: ¿cuáles son algunos buenos patrones para manejar esta situación?
Esto permite transacciones concurrentes. Sin embargo, introduce una complejidad adicional en la aplicación del usuario. Además, no es demasiado escalable: considere si se necesitan decenas o cientos de transacciones simultáneas. Además, dado que la billetera Hierachical Deterministic no es nativa en Ethereum (soy consciente de que existe LightWallet ), esto no parece una solución fácil.
Esto crea un ciclo que verifica el resultado del envío de la transacción. Si el resultado de la devolución indica un nonce duplicado (p. ej., Geth devolvería 'transacción de reemplazo con un precio bajo'), vuelva a intentarlo con un nuevo nonce.
Esta solución no es portátil: diferentes clientes devuelven diferentes cadenas para el mismo error. En la práctica, parece que he notado que Geth a veces ni siquiera devuelve la cadena anterior, sino que descarta silenciosamente las otras transacciones (no confirmado porque no he encontrado una forma confiable de reproducir). Como resultado, la detección no funciona de forma fiable.
Cada construcción de transacción implica "solicitar" un nonce de un "administrador de nonce" global. El "administrador de nonce" de singleton puede tener una lógica inteligente para distribuir números de nonce ascendentes. Esto explota el comportamiento discutido aquí .
Esto no solo introduce un singleton (discutiblemente un antipatrón), sino que tampoco parece fácil hacerlo bien: si una transacción de bajo nivel falla de alguna manera (por ejemplo, ni siquiera se envía a la red), el resto de las transacciones quedará bloqueada indefinidamente. En general, es una solución pobre que introduce más complejidad y problemas de los que intenta resolver.
Esto no es realmente una solución. El problema más obvio es que la dependencia adicional no parece ser justificable, si es simplemente para el campo nonce.
Además, si la aplicación de usuario ya administra claves privadas, esto presenta una complejidad adicional: las claves privadas deberán ser coadministradas (o copiadas) por el nodo Geth o Parity. Nuevamente, la complejidad (y la vulnerabilidad potencial) no parece justificable si es solo para tratar con el nonce.
Sin relación. Me parece que la cuenta nonce no es el mejor diseño en Ethereum. Obliga a las aplicaciones de usuario a manejar detalles de protocolo de bajo nivel o a introducir dependencia en un nodo (Geth/Parity). De cualquier manera, agrega un volumen desproporcionado a las aplicaciones de los usuarios.
Todavía no he llegado al punto en el que pueda probar ninguna de estas cosas, pero mi intuición es que Singleton Nonce Manager sería el camino a seguir, con algunas mejoras:
Los detalles de implementación requerirían una familiaridad íntima con la programación concurrente, bloqueos, mutexs, asíncrono o lo que sea. Esencialmente, lo anterior es una suposición, ya que aún no he trabajado directamente con las llamadas RPC y no puedo probarlo, pero creo que esa es la base de la ruta que seguiría. Veo que la estructura de la cola ofrecería una API interna para enumerar las transacciones pendientes, procesadas y admitir otras operaciones de la interfaz de usuario como bonificación.
getTransactionCount también puede incluir transacciones pendientes, que es una mejor manera de determinar el nonce para una transacción sin procesar posterior. Esta solución es simple pero poco probable sin sus propios problemas. Pero para disparar un puñado de transacciones en estrecha sucesión, parece funcionar como se esperaba.
nonce: web3.toHex(web3.eth.getTransactionCount(fromAddress, "pending")),
Todo depende de tu contexto. Si es un usuario final que intenta emitir múltiples transacciones usted mismo, simplemente puede almacenar el nonce en algún lugar e incrementarlo en cada transacción paralela. Obviamente, desea evitar la creación de brechas en el momento, pero siempre que esté 100% seguro de que puede cubrir los fondos cuando se ejecutan las transacciones, una brecha está bien temporalmente. Lo peor que puede pasar es que un nonce se reproduzca dos veces, en cuyo caso, ha creado transacciones no válidas.
Si actúa en nombre de un usuario e intenta emitir transacciones masivas, podría usar una operación de base de datos atómica para almacenar el nonce. Esto podría funcionar en una billetera de procesamiento por lotes hipotética que intente enviar varias transacciones a la vez. Probablemente desee incluir un descargo de responsabilidad sobre el hecho de que un usuario debe evitar usar la clave mientras interactúa con la billetera, para evitar que el contador interno se desincronice.
Canción Linmao
Centinela
maljordan
Canción Linmao
runas