¿Cuál es la mejor manera de evitar ataques de repetición en el caso de una bifurcación dura de bitcoin?

Originalmente pensé que sería relativamente simple agregar protección contra ataques de repetición (cambiar algo sobre cómo se genera el hash tx) en caso de una bifurcación. Pero la gente de BU mencionó que esto rompería a los clientes de SPV (incluidas muchas billeteras móviles). Por lo tanto, no es gratis hacerlo de esa manera, aunque sigue siendo una opción.

Una solución de la que hicimos una lluvia de ideas fue usar algunas monedas que solo eran válidas en una cadena (por ejemplo, monedas recién extraídas) y agregar 1 satoshi de "mancha" a todas las transacciones generadas. Esto funcionaría pero no es perfecto. Por ejemplo, las monedas recién extraídas no se pueden gastar en 100 bloques, por lo que, como mínimo, provocaría un retraso en los nodos económicos en caso de una bifurcación dura. Tampoco es trivial que todo el software de billetera implemente esto (una cantidad considerable de trabajo, especialmente a escala). También hay un desafío operativo en el que tendría que apresurarse para obtener estas monedas recién extraídas mientras ocurría la bifurcación dura, por lo que no pudo prepararse con anticipación. Sería un lío seguro.

Otra opción sería intentar gastar dos veces algunas monedas en las cadenas bifurcadas (obtener una transacción con algunas monedas que van a dos direcciones diferentes extraídas en las dos cadenas). Estas monedas también podrían usarse para "manchar", pero no tendrías que esperar los 100 bloques completos. Esto es un poco mejor, pero aún no es perfecto.

Aunque sospecho que hay una solución mejor. ¿Cuáles son los pensamientos de la gente?

Respuestas (3)

Una solución de la que hicimos una lluvia de ideas fue usar algunas monedas que solo eran válidas en una cadena (por ejemplo, monedas recién extraídas) y agregar 1 satoshi de "mancha" a todas las transacciones generadas. Esto funcionaría pero no es perfecto.

Parece que tienes dos problemas:

  1. Cómo obtener algunos insumos que solo son válidos en un lado de la cadena.
  2. Cómo mezclar estas entradas con todas sus transacciones.

No tengo buenas respuestas para la segunda pregunta; tendrá que mezclar las entradas colocándolas en cada transacción que envíe o mezclándolas con una gran cantidad de monedas que luego dividirá en docenas o cientos de entradas que usará normalmente.

Para la primera pregunta:

división de monedas

La mejor manera sería impulsar la protección de reproducción en los clientes de bifurcación dura, ya que ya están cambiando las reglas. Pero si eso no es posible, existen algunas diferencias potenciales entre las cadenas que se pueden usar para confirmar una versión de una transacción en una cadena y confirmar otra versión de la misma transacción en la otra cadena.

Advertiré que (1) los clientes de Bitcoin no están diseñados para operar bajo bifurcaciones duras en curso, por lo que muchas cosas que normalmente funcionarían bien pueden terminar resultando en pérdidas monetarias, (2) sin protección contra ataques de reproducción, no hay garantía de que cualquiera de los mecanismos a continuación dividirá sus monedas, por lo que probablemente debería enviarse las monedas de usted mismo para que, si la división falla, todavía tenga todas sus monedas (menos las tarifas de transacción), y (3) en un bifurcación dura, se puede cambiar cualquier regla, por lo que la siguiente información genérica puede no aplicarse en la cadena bifurcada; consulte con los desarrolladores de hard fork para estar seguro.

Métodos:

  1. Transacciones de Coinbase: no del tipo que hace su empresa, sino del tipo que usan los mineros para reclamar subsidios y tarifas de transacción. Como indica su pregunta, estos solo son válidos en el lado de la bifurcación dura en la que se generan, pero también tienen que esperar 100 bloques para madurar.

    Pros: simple, garantizado para trabajar

    Contras: requiere ayuda de un minero, tiene que esperar 100 bloques

  2. nLockTime: si las dos cadenas difieren en altura, puede crear una transacción con nLockTime establecido en la altura de la cadena más larga. Esa transacción se puede confirmar de inmediato en esa cadena, pero no se puede agregar a la cadena más corta hasta que esa cadena alcance la misma altura, lo que le brinda una ventana de tiempo para transmitir una transacción alternativa en la cadena más corta. y divide tus monedas.

    Convenientemente, Bitcoin Core tiene una función llamada francotiradores anti-cargo que automáticamente (en las versiones actuales) establece nLockTime a la altura de bloque actual para las transacciones de billetera predeterminadas, por lo que este truco es bastante fácil si solo desea dividir su billetera Bitcoin Core.

    Pros: debería ser bastante efectivo porque depende de las reglas de consenso

    Contras: aún debe esperar algunas cuadras después de la bifurcación para que las cadenas tengan tiempo de divergir en la altura de la cadena.

    (Crédito: Escuché por primera vez de un método como este de Peter Todd; no sé si él lo originó, ni si este es exactamente el método en el que estaba pensando; tuve que adivinar cómo funcionaría de él) simplemente diciendo "usar nLockTime".)

    También puede hacer lo mismo con nSequence forzado por consenso, pero no obtiene nada adicional.

  3. Diferencias de tarifas: es posible que los mineros de un lado de la bifurcación extraigan transacciones con tarifas más bajas que en el otro lado, por lo que puede transmitir una versión de tarifa baja de su transacción en la cadena de tarifa baja, espere a que se confirme. y luego transmitir una versión de tarifa más alta en la cadena de tarifa alta.

    Ventajas: sencillo

    Contras: es posible que aún deba esperar algunos bloques para que las tarifas difieran mucho y, dado que cada minero tiene su propia política, es posible que deba intentarlo varias veces. Además, muchas billeteras no le permiten elegir tarifas arbitrarias (solo le dan una tarifa razonable o le permiten elegir entre un rango razonable de tarifas).

    (Crédito: escuché esto por primera vez descrito hoy por @ElectrumWallet en Twitter).

  4. Encuentre alguna otra característica que diverja entre los mineros en las dos cadenas. Por ejemplo, mientras escribo esto, creo que Bitcoin Core de forma predeterminada no aceptará en su grupo de memoria ninguna transacción que requiera extraer más de 20 ancestros primero (esto evita el abuso y permite que el código de minería se ejecute de manera más eficiente, ya que Bitcoin Core proporciona child -minería de pago por matriz (CPFP)); Bitcoin Unlimited, al estar basado en una versión anterior de Bitcoin Core, no proporciona la optimización de CPFP y, por lo tanto, permitirá que una profundidad ilimitada de ancestros de transacciones ingrese al mempool. Esto significa que podría obtener, digamos, 101 transacciones relacionadas extraídas en un lado de la bifurcación y luego tendría hasta cinco bloques para obtener una transacción 101 diferente extraída en el otro lado de la bifurcación.

    Hay potencialmente otras de estas diferencias de nivel de retransmisión entre clientes que podrían usarse.

    Pros: las diferencias de retransmisión posiblemente podrían usarse inmediatamente después de una bifurcación dura para obtener una transacción minada en el primer bloque de bifurcación (si sabía cuándo iba a suceder) o en el segundo bloque de bifurcación (si comenzó tan pronto como el primer bloque de bifurcación fue producido). Además, pueden ser bastante simples.

    Contras: estos trucos dependen de que todos los mineros de un lado de la cadena ejecuten una versión del código y todos los mineros del otro lado ejecuten una versión diferente del código. Cuanta más superposición haya, menor será la probabilidad de que estos trucos funcionen.

Aquí está el ticket de github donde hemos estado pensando en este problema para Zcash. En comparación con Bitcoin, Zcash tiene el lujo de una base instalada más pequeña y una pista más larga antes de cualquier probable división de la cadena de bloques, por lo que no tenemos tantas limitaciones en el espacio de diseño como las que tiene usted, pero, no obstante, algunas de estas ideas pueden ser útiles:

https://github.com/zcash/zcash/issues/174

Aquí hay una idea:

https://github.com/luke-jr/bips/blob/bip-noreplay/bip-noreplay.mediawiki

Me parece que esto funcionaría y no sería incompatible con los clientes SPV por lo que puedo pensar.

Hola Zooko, bienvenido a Bitcoin.SE. ¿Podría editar su respuesta para agregar un breve resumen de los recursos vinculados? Sería bueno tener un poco de idea en su respuesta sin necesidad de leer otra página.

R) Actualmente, Unlimited conserva el límite de política de 100K MAX_STANDARD_TX_SIZE https://github.com/BitcoinUnlimited/BitcoinUnlimited/blob/release/src/policy/policy.h#L23 , por lo que sería difícil propagar una transacción grande a través de P2P. Sin embargo, un minero podría extraer un TX grande de 1 MB si se lo entrega directamente, y luego los UTXO del TX grande podrían usarse para contaminar, ya que solo estarían en la cadena Ilimitada. Además, las diferencias de política de nodo entre Unlimited y Core probablemente podrían usarse para que las transacciones se propaguen y, por lo tanto, se extraigan, en solo un lado de la división.

B) La maleabilidad de TX podría ser útil para ayudar con la división. Por ejemplo, los mineros podrían brindar un servicio para ayudar a dividir las UTXO. Hay al menos algunas opciones:

Opción 1) Firme sus entradas con SIGHASH_ANYONECANPAY|SIGHASH_ALL y permita que los mineros agreguen una sola entrada contaminada con satosi que recuperan en forma de tarifas (los mineros no pueden agregar salidas debido a SIGHASH_ALL de las firmas para esta opción).

Opción 2) Firme sus entradas con SIGHASH_ANYONECANPAY|SIGHASH_SINGLE y use una sola salida de índice cero. Esto le permite a un minero agregar entradas y salidas que contaminan y pagan una de sus direcciones. Estos se destacarían porque están firmados de manera significativamente diferente a lo normal. Vea el ejemplo de registro a continuación.

Opción 3) Los mineros de un lado podrían realizar mecánicamente transformaciones de maleabilidad de scriptSig para obtener gastos para confirmar con diferentes TXID que la otra cadena.

regtest network example:
WIF private key --> regtest network address
cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA --> mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r
cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87K7XCyj5v --> mg8Jz5776UdyiYcBb9Z873NTozEiADRW5H
cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87KcLPVfXz --> mrzKXEpXfEDHk7vFS3LBXVXoa4YXFcCkje

> ./bitcoin/src/qt/bitcoin-qt -regtest -txindex -datadir=/test/1/

in debug window rpc console:
generatetoaddress 1 mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r
generatetoaddress 1 mrzKXEpXfEDHk7vFS3LBXVXoa4YXFcCkje
generate 100
getblock(getblockhash(1))[tx][0]
getblock(getblockhash(2))[tx][0]

User does this:
createrawtransaction '[{"txid":"54bdb97bdc75580f8564f348ab312f2147c945fcb96a7c2a01231aff50030212","vout":0}]' '{"mg8Jz5776UdyiYcBb9Z873NTozEiADRW5H":49.099}'
signrawtransaction 020000000112020350ff1a23012a7c6ab9fc45c947212f31ab48f364850f5875dc7bb9bd540000000000ffffffff01e020a724010000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00000000 'null' '["cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA"]' 'SINGLE|ANYONECANPAY'
020000000112020350ff1a23012a7c6ab9fc45c947212f31ab48f364850f5875dc7bb9bd54000000006a47304402202e229bf02236b209271da602cf9a16b2e651b8419d3610d311a5d443804b0bba022072c5cbc37310f27e047a5110ac2fae802d7fb51ed0fda86eeaa0c6ab5518b1ec83210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff01e020a724010000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00000000

The above raw transaction is what you would send to the network in actual usage.

Miner does this:
createrawtransaction '[{"txid":"cebee3f6f6f2d74f4513fa04d67040954ef216c962f3b000ed68cd7a37234293","vout":0}]' '{"mrzKXEpXfEDHk7vFS3LBXVXoa4YXFcCkje":50}'
0200000001934223377acd68ed00b0f362c916f24e954070d604fa13454fd7f2f6f6e3bece0000000000ffffffff0100f2052a010000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac00000000

Miners manually merge the previous two raw transactions into:
020000000212020350ff1a23012a7c6ab9fc45c947212f31ab48f364850f5875dc7bb9bd54000000006a47304402202e229bf02236b209271da602cf9a16b2e651b8419d3610d311a5d443804b0bba022072c5cbc37310f27e047a5110ac2fae802d7fb51ed0fda86eeaa0c6ab5518b1ec83210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff934223377acd68ed00b0f362c916f24e954070d604fa13454fd7f2f6f6e3bece0000000000ffffffff02e020a724010000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00f2052a010000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac00000000

signrawtransaction 020000000212020350ff1a23012a7c6ab9fc45c947212f31ab48f364850f5875dc7bb9bd54000000006a47304402202e229bf02236b209271da602cf9a16b2e651b8419d3610d311a5d443804b0bba022072c5cbc37310f27e047a5110ac2fae802d7fb51ed0fda86eeaa0c6ab5518b1ec83210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff934223377acd68ed00b0f362c916f24e954070d604fa13454fd7f2f6f6e3bece0000000000ffffffff02e020a724010000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00f2052a010000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac00000000 'null' '["cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87KcLPVfXz"]' 'ALL'
020000000212020350ff1a23012a7c6ab9fc45c947212f31ab48f364850f5875dc7bb9bd54000000006a47304402202e229bf02236b209271da602cf9a16b2e651b8419d3610d311a5d443804b0bba022072c5cbc37310f27e047a5110ac2fae802d7fb51ed0fda86eeaa0c6ab5518b1ec83210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff934223377acd68ed00b0f362c916f24e954070d604fa13454fd7f2f6f6e3bece000000006a473044022013d1c41326ff95dafc1f15a25bcec916d06da6e61a5808ca9ad6de0b8a527cb902206f120f53512809721cb71b3d1a797e698621229cba2b2e87b1c654e2f9336b02012102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9ffffffff02e020a724010000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00f2052a010000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac00000000

This is effectively what the miner would put in a block:
sendrawtransaction 020000000212020350ff1a23012a7c6ab9fc45c947212f31ab48f364850f5875dc7bb9bd54000000006a47304402202e229bf02236b209271da602cf9a16b2e651b8419d3610d311a5d443804b0bba022072c5cbc37310f27e047a5110ac2fae802d7fb51ed0fda86eeaa0c6ab5518b1ec83210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff934223377acd68ed00b0f362c916f24e954070d604fa13454fd7f2f6f6e3bece000000006a473044022013d1c41326ff95dafc1f15a25bcec916d06da6e61a5808ca9ad6de0b8a527cb902206f120f53512809721cb71b3d1a797e698621229cba2b2e87b1c654e2f9336b02012102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9ffffffff02e020a724010000001976a91406afd46bcdfd22ef94ac122aa11f241244a37ecc88ac00f2052a010000001976a9147dd65592d0ab2fe0d0257d571abf032cd9db93dc88ac00000000 true

double check that the tx is accepted and mined:
generate 6
gettxout(882f4d4faf6880572cde354dcc6d41de9d14fb2a184bc12635822e36dfa9b2e9, 0)[confirmations]
gettxout(882f4d4faf6880572cde354dcc6d41de9d14fb2a184bc12635822e36dfa9b2e9, 0)
gettxout(882f4d4faf6880572cde354dcc6d41de9d14fb2a184bc12635822e36dfa9b2e9, 1)

notes: to understand how this works and limitations, see:
https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1052-#L1141
https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1223-#L1243