¿Cómo recibir pagos en línea a una sola dirección por usuario de manera escalable?

Supongamos que estamos construyendo un casino/mercado en línea y queremos recibir pagos.

Para ser escalable , seguro y tener una buena experiencia de usuario, nosotros:

  • no puede generar una nueva dirección para cada pago individual. Tener una sola dirección de depósito es mucho más fácil. Además, los usuarios siempre pueden depositar en la dirección anterior por error, incluso si se genera una nueva dirección.
  • no se puede verificar listreceivedbyaddressporque verificar regularmente cientos de miles de direcciones no es escalable. También una gran salida de RPC cuando un solo usuario realiza miles de depósitos.
  • no debemos confiar en la API de blockchain en línea de servicios externos.

Absolutamente no podemos usar ninguna llamada RPC que enumere una lista completa y creciente de transacciones, como todas las transacciones para la billetera o todas las transacciones para la dirección.

Por lo tanto, la forma más sensata debería ser verificar listsinceblockpara analizar todas las transacciones "por bloque analizado" y unirse a los saldos de los usuarios por dirección de destino: aumente la cantidad del usuario en nuestro servicio en línea y marque este pago como "completado" para no contarlo por segunda vez . La forma más sencilla de marcar esta transacción como "ya resuelta" es almacenar su ID como "ya usado" en la misma transacción SQL que aumenta el saldo del usuario.

Pero escuché que es posible cambiar la identificación de la transacción en la cadena de bloques, entonces, ¿es segura esa solución?

¿Cómo puedo usar llamadas RPC para recibir pagos bloque tras bloque y qué datos puedo usar para marcar el pago como resuelto para estar a salvo de depósitos duplicados en un solo pago?

TL;DR, ¿cómo reciben pagos los "grandes jugadores" como Cryptsy?

Respuestas (3)

Use Bitcoin Core en modo servidor y use sus funciones de notificación:

server=1
blocknotify = curl\yoururl
walletnotify = curl\yoururl

Configúrelos para hacer una llamada a su aplicación.

De esta manera, no realizará costosas llamadas RPC a Bitcoin Core. Solo estarás recibiendo notificaciones de operaciones que el propio Bitcoin Core ya esté realizando. Por lo tanto, no traerá ninguna carga adicional a Bitcoin Core. Estará limitado por su propia escalabilidad.

¿Cómo reciben los pagos los "grandes jugadores" como Cryptsy?

La mayoría de los grandes jugadores confían en la escalabilidad de Bitcoin Core que se ejecuta en modo servidor sin traerle una carga adicional, hasta donde yo sé.

Pero escuché que es posible cambiar la identificación de la transacción en la cadena de bloques, entonces, ¿es segura esa solución?

No después de haber recibido una confirmación. Entonces, el método que describió funciona si espera la llamada blocknotify para un TX antes de actualizar el saldo de sus usuarios.

Estrictamente hablando, no es cierto que las ID de transacción no se puedan cambiar una vez que han recibido una confirmación. Si una bifurcación confirma la misma transacción con una ID diferente y la bifurcación se convierte en la cadena más larga, entonces la ID se ha cambiado efectivamente.
Sí. Verdadero. Pensé que una bifurcación bc estaba demasiado fuera del alcance de la pregunta.
+1 pero veo una desventaja de esto. Esto causará un problema en una situación en la que la billetera está funcionando pero el servicio web está inactivo (por ejemplo, para el mantenimiento) y se perderá la notificación. Pero, junto con el escaneo de los últimos bloques al inicio del intercambio, esto definitivamente puede traer algunas mejoras. Aceptará esto si no aparece una mejor respuesta durante la recompensa.
Le sugiero encarecidamente que implemente un servicio separado que se comunique con la billetera y deje que su software de intercambio se comunique con ese servicio. No haga que su intercambio hable directamente con Bitcoin Core. Y sí, lo que dices es cierto. Si pierde las primeras 6 confirmaciones, no recibirá notificaciones y deberá consultar Bitcoin Core. Si implementa un servicio de billetera y lo separa de su intercambio, esto debería ser más fácil de evitar.

Cryptsy está generando una nueva dirección por usuario. Una vez generado, sigue siendo el mismo, por lo que no hay riesgo de depositarlo en la "dirección anterior". Esto es escalable y también más fácil de asociar depósitos al usuario correcto independientemente de la dirección de envío.

la dirección única por usuario no garantiza la escalabilidad: si verifica los depósitos llamando a las transacciones RPC para la dirección, no será escalable. Después de cientos de depósitos, siempre devolverá una gran lista de transacciones.
Esa no es la mejor manera, puede escuchar websockets transmitiendo nuevas transacciones en la red y actualizar el saldo de su dirección solo si aparecen en una nueva transacción

Sé que es tarde para responder, pero proporciono mi solución que maneja la mayoría de los riesgos.

En primer lugar, prefiero generar una nueva dirección para cualquier momento en que el usuario quiera depositar; Pero si la condición no lo permite, ¡hay otra solución!

Solución: Hay una getreceivedbyaddressAPI que da la cantidad total de Bitcoins recibidos para una dirección específica. Uso esto y una base de datos para rastrear los depósitos de los usuarios.

Aquí está la forma en que lo rastreé:

var totalReceived = (RPC request including the address in params field)

var lastDeposit = (DB query for fetching the user's last deposit's data)

if(lastDeposit.amount < totalReceived) {
   // insert a new deposit record for user
   // record includes the following fields:
   // 1. userId (Obvious)
   // 2. amount 
   // 3. diff
   // 4. ts (for sorting, etc)
   
   insertNewDeposit(userId: userId, amount: totalReceived, diff: totalReceived - lastDeposit.amount)
}

// fetch the user's balance from db
var currentBalance = (db query)

// calculate the user's new balance (based on the new deposit)
var newBalance = currentBalance + (currenctBalance - lastDeposit.amount)

// update the user's balance in db
updateBalance(userId: userId, balance: newBalance)

Debe usar este método antes que cualquier otro que pueda requerir el último saldo de una dirección (usuario).

Esto siempre rastreará el saldo de una dirección específica (usuario) incluso si el servicio web se cae; justo después de que su servicio web esté en línea, cuando el usuario solicite algo relacionado con el saldo, ¡este método se actualizará y realizará un seguimiento del saldo!

¡El código podría haber sido más optimizado!

Saludos :)