El contrato DAO fue atacado el 17 de junio de 2016, donde el atacante drenó alrededor de USD 50 millones en éteres utilizando una vulnerabilidad de llamada recursiva en el código del contrato DAO.
El atacante vació los éteres robados en unos pocos DAO infantiles y el Grupo Robin Hood vació los fondos restantes en otros DAO infantiles.
La cadena de bloques de Ethereum se bifurcó en el bloque n.º 1 920 000 el 20 de julio de 2016 para transferir los éteres del contrato DAO y sus DAO secundarios a un contrato WithdrawDAO .
Si bien la mayoría de los clientes de los nodos de Ethereum ejecutan la cadena de bloques de bifurcación dura (ETH), una minoría de los clientes de los nodos de Ethereum ejecutan la cadena de bloques clásica (ETC) de no bifurcación dura.
Los clientes de nodos de Ethereum se pueden configurar para usar la cadena de bloques bifurcada o la cadena de bloques no bifurcada. Algunos nodos se han configurado para transmitir las transacciones de la cadena de bloques bifurcada a la cadena de bloques no bifurcada, y viceversa. Las transacciones ejecutadas en la cadena de bloques ETH tienen una alta probabilidad de reproducirse en la cadena de bloques ETC, y las transacciones en la cadena de bloques ETC tienen una alta probabilidad de reproducirse en la cadena de bloques ETH.
Se han implementado varios contratos divididos en la misma dirección de contrato tanto en las cadenas de bloques de bifurcación dura como en las de no bifurcación.
¿Cómo se utilizan estos contratos divididos para enviar éteres condicionalmente a otras cuentas en la cadena ETH de bifurcación dura o en la cadena ETC clásica sin bifurcación?
Actualización 02 de junio de 2017
De ADVERTENCIA: ¡NO use SafeConditionalHFTransfer! O usarlo correctamente :
SafeConditionalHFTransfer ahorró muchos éteres que se movían incorrectamente en la cadena incorrecta después de la bifurcación dura de DAO. Hasta ahora ha habido 20549 txns + 16022 internalTxns pasando por SafeConditionalHFTransfer en 0x1e143b2588705dfea63a17f2032ca123df995ce0 . El autor me contactó esta mañana sobre 67,317.257581981046981598 ETH ~ USD 14,892,596.89 ($221.23/ETH) enviado incorrectamente al contrato.
Al usar este contrato, debe llamar a las funciones
classicTransfer(...)
otransfer(...)
para dirigir su ETH o ETC a la cadena prevista. Si envía ETH (o ETC) DIRECTAMENTE a la dirección del contrato, su ETH (o ETC) no se redirigirá a la dirección de destino en la cadena de destino, sino que quedará atrapado en este contrato PARA SIEMPRE.Como los clientes recientes en las cadenas ETH y ETC tienen incorporada la protección de reproducción EIP155 , NO tiene que usarla
SafeConditionalHFTransfer
más. ¡Solo asegúrese de estar usando un cliente reciente, con EIP155!Estos son los principales clientes y las versiones que implementan EIP155:
geth
Go Ethereum - EIP155 desde Let There Be Light (v1.5.0) 16 de noviembre de 2016. Última versión Hat Trick (v1.6.5) .- Parity: EIP155 desde Civility (v1.4), 7 de noviembre de 2016. Última versión de https://parity.io/parity.html o https://github.com/paritytech/parity/releases
- MyEtherWallet (recuerde usar la URL correcta https://www.myetherwallet.com/ ) tiene protección de reproducción EIP155.
Esta advertencia también se colocó en la parte superior de la respuesta a Cómo enviar éteres condicionalmente a otra cuenta después de una bifurcación dura para protegerse de los ataques de repetición .
Actualización del 26 de noviembre de 2016 : vea la respuesta de @eth a la pregunta anterior, ya que geth
1.5.3 implementó la protección contra ataques de repetición.
geth
transferir éteres a la cadena clásica bifurcada oSafeConditionalHFTransfer
no bifurcada a través del contrato.geth
transferir éteres a la cadena clásica bifurcada YReplaySafeSplitV2
no bifurcada a través del contrato.SafeConditionalHFTransfer
no bifurcada a través del contrato.ReplaySafeSplitV2
no bifurcada a través del contrato. Cualquiera de las cuentas puede ser su cuenta de origen para que los fondos se envíen de vuelta a su cuenta en una de las cadenas.PROBLEMAS
Si desea enviar ETC previamente bifurcado a una cuenta ETC de Exchange
support-hard-fork
o oppose-hard-fork
Ethereum para hacer esto.classicTransfer
método en geth
o Para transferir solo en la cadena clásica sin bifurcación en Ethereum Wallet .SafeConditionalHFTransfer
contrato que le devuelve su ETH.Ethereum Wallet y Mist Beta 0.8.2 ahora tiene prevención de reproducción:
Prevención de reproducción
Agregamos una función avanzada para evitar que sus transacciones se reproduzcan en otras cadenas, como ethereum classic. Esto le permite evitar que la transferencia ocurra en el clásico o usar esa transacción para enviar la misma cantidad a un contrato diferente, como una cuenta recién creada o un intercambio. Si desea separar por completo todas sus transacciones, le recomendamos que cree dos cuentas nuevas, una para Ethereum propiamente dicha y otra para Classic, y luego transfiera todos sus fondos a ellas (recuerde que necesita ether para mover tokens), asegurándose de que cada la cuenta tiene 0 éter en la otra cadena; hacer esto una vez evitaría que se reprodujera cualquier transacción futura. Para usar esto, use el botón "más opciones" en la página de envío.
Esta característica también admite la división de tokens, pero es muy experimental y no funcionará en todos los tokens. Dado que todo esto se hace mediante un contrato, primero debe permitir que ese contrato mueva tokens en su nombre haciendo clic en "Aprobar transferencia de token".
Como siempre, estas características son experimentales y deben probarse primero con pequeñas cantidades . Aunque la mayoría de las transacciones se reproducen en ambas cadenas, es posible que algunas no lo hagan por múltiples razones. Además, algunos intercambios tienen problemas para recibir ether de una dirección de contrato; si ese es su caso, comuníquese con el intercambio.
También eliminamos todo el código de Fork de la aplicación Mist, por lo que si desea utilizar Ether Classic, tendrá que descargar Classic Mist directamente desde su repositorio o usar su propio nodo como backend para su billetera (tanto Ethereum Wallet y Mist puede conectarse a cualquier nodo) como lo haría con una red privada.
El contrato de protección de reproducción se puede encontrar en 0x1ca4a86bba124426507d1ef67ad271cc5a02820a .
geth
y SafeConditionalHFTransfer
contratoAsegúrese de estar ejecutando la versión 1.4.10 o posterior de geth. Y ejecuta tus comandos geth con la opción --support-dao-fork para que estés en la cadena de bloques bifurcada. Para transferir utilizando las funciones transfer(...)
o classicTransfer(...)
:
user@Kumquat:~$ geth console
// Allow chain to sync
var fromAccount = "{from account}";
var toAccount = "{to account}";
var amount = web3.toWei(1.123, "ether");
personal.unlockAccount(fromAccount, "{password}")
var safeConditionalHFTransferAddress = "0x1e143b2588705dfea63a17f2032ca123df995ce0";
var safeConditionalHFTransferABI = [{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"classicTransfer","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"}];
var safeConditionalHFTransfer = eth.contract(safeConditionalHFTransferABI).at(safeConditionalHFTransferAddress);
// WARNING - Run the next statement to transfer ETH on the hard-forked chain
// This will only cost some gas on the non-hard-forked ETC Classic chain
// Test with a small amount first
var transfer = safeConditionalHFTransfer.transfer(toAccount, {from: fromAccount, value: amount});
console.log(transfer);
// WARNING - Run the next statement to transfer ETC on the non-hard-forked Classic chain
// This will only cost some gas on the hard-forked ETH chain
// Test with a small amount first
var classicTransfer = safeConditionalHFTransfer.classicTransfer(toAccount, {from: fromAccount, value: amount});
console.log(classicTransfer);
geth
y ReplaySafeSplitV2
contratoAsegúrese de estar ejecutando la versión 1.4.10 o posterior de geth. Y ejecuta tus comandos geth con la opción --support-dao-fork para que estés en la cadena de bloques bifurcada. Para transferir usando la split(...)
función:
user@Kumquat:~$ geth console
// Allow chain to sync
var fromAccount = "{from account}";
var toAccountFork = "{to account on forked chain}";
var toAccountNoFork = "{to account on non-forked chain}";
var amount = web3.toWei(1.123, "ether");
personal.unlockAccount(fromAccount, "{password}")
var replaySafeSplitV2Address = "0xaBbb6bEbFA05aA13e908EaA492Bd7a8343760477";
var replaySafeSplitV2ABI = [{"constant":false,"inputs":[{"name":"targetFork","type":"address"},{"name":"targetNoFork","type":"address"}],"name":"split","outputs":[{"name":"","type":"bool"}],"type":"function"}];
var replaySafeSplitV2 = eth.contract(replaySafeSplitV2ABI).at(replaySafeSplitV2Address);
var transfer = replaySafeSplitV2.split(toAccountFork, toAccountNoFork, {from: fromAccount, value: amount});
console.log(transfer);
SafeConditionalHFTransfer
contratoTenga en cuenta que el ReplaySafeSplitV2
contrato a continuación tiene más características de seguridad integradas.
Asegúrese de haber descargado Ethereum Wallet 0.8.1 o posterior.
La primera vez que inicie Ethereum Wallet 0.8.1, seleccione "Sí" a la pregunta "¿Desea activar la cadena en la que los fondos vinculados al exploit se restauran a un contrato donde los titulares de tokens DAO pueden retirarlos?" . Ahora ha tomado la decisión de utilizar la cadena Ethereum bifurcada.
En Ethereum Wallet, seleccione la página de CONTRATOS en el menú superior. Haga clic en VER CONTRATO.
SafeConditionalHFTransfer
0x1e143b2588705dfea63a17f2032ca123df995ce0
[{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"transfer","outputs":[],"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"}],"name":"classicTransfer","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"}]
Esto transferirá su ETH a la cuenta de destino en la cadena de bifurcación dura y solo le costará gasolina en la cadena clásica sin bifurcación.
Seleccione la página CONTRATOS en el menú superior. Haga clic en TRANSFERENCIA CONDICIONAL SEGURA. En el lado derecho de la página, debajo de ESCRIBIR PARA CONTRATAR, seleccione la función Transfer
. Ingrese su dirección de destino en la cadena de bifurcación en el campo de dirección Para . En Ejecutar desde , seleccione su cuenta. Ingrese el número de ETH en el campo Enviar ETHER . Haga clic en el botón EJECUTAR, ingrese su contraseña y confirme. Aquí hay una imagen de pantalla:
Esto transferirá su ETH a la cuenta de destino en la cadena clásica sin bifurcación y solo le costará gasolina en la cadena con bifurcación dura.
Seleccione la página CONTRATOS en el menú superior. Haga clic en TRANSFERENCIA CONDICIONAL SEGURA. En el lado derecho de la página, debajo de ESCRIBIR PARA CONTRATAR, seleccione la función Classic Transfer
. Ingrese su dirección de destino en la cadena sin bifurcación en el campo de dirección Para . En Ejecutar desde , seleccione su cuenta. Ingrese el número de ETH (ETC) en el campo Enviar ETHER . Haga clic en el botón EJECUTAR, ingrese su contraseña y confirme. Aquí hay una imagen de pantalla:
ReplaySafeSplitV2
contratoACTUALIZACIÓN 22:27 4 de septiembre de 2016 Esta es una nueva versión más segura de ReplaySafeSplit
lo comentado por @chevdor en thedao.slack.com/messages/general en Versión más segura del contrato inteligente ReplaySafeSplit . Esta nueva versión verifica que las direcciones que especifique no sean 0x0000...0000 antes de enviar sus ethers a las direcciones. Esta sección ha sido actualizada con los nuevos detalles del contrato.
Asegúrese de haber descargado Ethereum Wallet 0.8.1 o posterior.
La primera vez que inicie Ethereum Wallet 0.8.1, seleccione "Sí" a la pregunta "¿Desea activar la cadena en la que los fondos vinculados al exploit se restauran a un contrato donde los titulares de tokens DAO pueden retirarlos?" . Ahora ha tomado la decisión de utilizar la cadena Ethereum bifurcada.
En Ethereum Wallet, seleccione la página de CONTRATOS en el menú superior. Haga clic en VER CONTRATO.
ReplaySafeSplitV2
0x8201...
0xaBbb6bEbFA05aA13e908EaA492Bd7a8343760477
[{"constant":false,"inputs":[{"name":"targetFork","type":"address"},{"name":"targetNoFork","type":"address"}],"name":"split","outputs":[{"name":"","type":"bool"}],"type":"function"}]
Esto transferirá su ETH a dos cuentas, la primera será la cuenta de destino en la cadena de bifurcación dura y la segunda será la cuenta de destino en la cadena clásica sin bifurcación.
Seleccione la página CONTRATOS en el menú superior. Haga clic en REPLAYSAFESPLITV2. En el lado derecho de la página, debajo de ESCRIBIR PARA CONTRATAR, seleccione la función Split
. Ingrese su dirección de destino en la cadena de bifurcación dura en el campo Bifurcación de destino - dirección . Ingrese su dirección de destino en la cadena clásica sin bifurcación en el campo Dirección sin bifurcación de destino . En Ejecutar desde , seleccione su cuenta. Ingrese el número de éteres en el campo Enviar ETER . Haga clic en el botón EJECUTAR, ingrese su contraseña y confirme.
Aquí hay una imagen de pantalla:
SafeConditionalHFTransfer
ContratoTenga en cuenta que el ReplaySafeSplitV2
contrato a continuación tiene más características de seguridad integradas.
A continuación se muestra el código fuente del contrato SafeConditionalHFTransfer (sugerido el @shoraibit
26/07/2016). Este contrato no depende de que el contrato WithdrawDAO tenga un saldo superior a 1,000,000 ethers en el futuro.
contract ClassicCheck {
function isClassic() constant returns (bool isClassic);
}
contract SafeConditionalHFTransfer {
bool classic;
function SafeConditionalHFTransfer() {
classic = ClassicCheck(0x882fb4240f9a11e197923d0507de9a983ed69239).isClassic();
}
function classicTransfer(address to) {
if (!classic)
msg.sender.send(msg.value);
else
to.send(msg.value);
}
function transfer(address to) {
if (classic)
msg.sender.send(msg.value);
else
to.send(msg.value);
}
}
Este contrato depende del contrato ClassicCheck :
contract ClassicCheck {
bool public classic;
function ClassicCheck() {
if (address(0xbf4ed7b27f1d666546e30d74d50d173d20bca754).balance > 1000000 ether)
classic = false;
else
classic = true;
}
function isClassic() constant returns (bool isClassic) {
return classic;
}
}
Cuando SafeConditionalHFTransfer
se implementó el contrato, se usó el ClassicCheck
contrato para determinar si el código se implementaba en la cadena de bifurcación dura o no bifurcada. Y esta comprobación se realizó cuando el RetiroDAO tenía un saldo superior a 1.000.000. SafeConditionalHFTransfer
siempre debería funcionar ya que ya no tiene que verificar el saldo del saldo de WithdrawDAO.
ReplaySafeSplitV2
ContratoACTUALIZACIÓN 22:27 4 de septiembre de 2016 Esta es una nueva versión más segura de ReplaySafeSplit
lo comentado por @chevdor en thedao.slack.com/messages/general en Versión más segura del contrato inteligente ReplaySafeSplit . Esta nueva versión tiene comprobaciones de que las direcciones que especificas no son 0x0000...0000
antes de enviar tus ethers a las direcciones.
El siguiente es el código fuente del contrato ReplaySafeSplitV2 :
contract RequiringFunds {
modifier NeedEth () {
if (msg.value <= 0 ) throw;
_
}
}
contract AmIOnTheFork {
function forked() constant returns(bool);
}
contract ReplaySafeSplit is RequiringFunds {
// address private constant oracleAddress = 0x8128B12cABc6043d94BD3C4d9B9455077Eb18807; // testnet
address private constant oracleAddress = 0x2bd2326c993dfaef84f696526064ff22eba5b362; // mainnet
// Fork oracle to use
AmIOnTheFork amIOnTheFork = AmIOnTheFork(oracleAddress);
// Splits the funds into 2 addresses
function split(address targetFork, address targetNoFork) NeedEth returns(bool) {
// The 2 checks are to ensure that users provide BOTH addresses
// and prevent funds to be sent to 0x0 on one fork or the other.
if (targetFork == 0) throw;
if (targetNoFork == 0) throw;
if (amIOnTheFork.forked() // if we are on the fork
&& targetFork.send(msg.value)) { // send the ETH to the targetFork address
return true;
} else if (!amIOnTheFork.forked() // if we are NOT on the fork
&& targetNoFork.send(msg.value)) { // send the ETH to the targetNoFork address
return true;
}
throw; // don't accept value transfer, otherwise it would be trapped.
}
// Reject value transfers.
function() {
throw;
}
}
El siguiente es el código de VM de la cadena de bloques clásica sin bifurcación que coincide con el código de VM verificado + el código fuente en la cadena de bifurcación dura.
user@PussyWillow:~$ geth -exec 'eth.getCode("0xaBbb6bEbFA05aA13e908EaA492Bd7a8343760477")' attach
"0x6060604052361561001f5760e060020a60003504630f2c93298114610028575b6100005b610002565b6100406004356024356000348190116100e157610002565b60408051918252519081900360200190f35b80547f16c72721000000000000000000000000000000000000000000000000000000006060908152600160a060020a0391909116906316c727219060649060209060048187876161da5a03f11561000257505060405151905080156100d25750604051600160a060020a038416908290349082818181858883f193505050505b1561010f575060015b92915050565b82600160a060020a0316600014156100f857610002565b81600160a060020a03166000141561005257610002565b600060009054906101000a9004600160a060020a0316600160a060020a03166316c727216040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060405151159050801561018c5750604051600160a060020a038316908290349082818181858883f193505050505b15610023575060016100db56"
Este contrato depende del contrato AmIOnTheFork :
contract AmIOnTheFork {
bool public forked = false;
address constant darkDAO = 0x304a554a310c7e546dfe434669c62820b7d83490;
// Check the fork condition during creation of the contract.
// This function should be called between block 1920000 and 1921200.
// Approximately between 2016-07-20 12:00:00 UTC and 2016-07-20 17:00:00 UTC.
// After that the status will be locked in.
function update() {
if (block.number >= 1920000 && block.number <= 1921200) {
forked = darkDAO.balance < 3600000 ether;
}
}
function() {
throw;
}
}
--oppose-dao-fork
¡Funciona!var classicTransfer = hfConditionalTransfer
está defectuoso porque todavía usa hfConditionalTransfer
y no la versión segura.ReplaySafeSplit
actúa en dos cadenas de bloques? No entiendo esa parte. Esperaba que tuvieras que ejecutar algo dos veces, una vez desde una billetera apuntando a una de las dos cadenas de bloques.@mowliv
, las transacciones de la red HF se retransmiten actualmente a la red que no es HF y viceversa. He actualizado la respuesta anterior.Si usa un nuevo cliente, como Geth 1.5.3, implementa EIP 155 Protección de ataque de repetición simple para que sus transacciones ETH estén a salvo de un ataque de repetición en ETC.
Usando Geth 1.5.3 (o posterior), debe crear otra cuenta y mover todos sus ETH a la nueva dirección. No olvide hacer una copia de seguridad de esta nueva cuenta (y no elimine la cuenta anterior ya que tiene su ETC).
Mientras tanto, un paso adicional, ya que Geth 1.5.3 es muy nuevo: después de lo anterior, en la cadena ETC mueva todos los ETC a una dirección diferente. Esto ayudará a garantizar que esté realmente protegido contra ataques de repetición.
ética
q9f
Xavier Combelle
ética
forked
, obtiene un método de acceso generado automáticamente en Solidity.Xavier Combelle
ética
msg
ytx
variables). ¡No dude en hacer preguntas y bienvenido al sitio!