Debido a la naturaleza del entorno de ejecución de los smart contracts, en los que se maneja dinero, existe un incentivo para que existan usuarios maliciosos para los que exploten las debilidades de implementación y obtengan lucro de dichas debilidades.
Consideremos el escenario, donde la blockchain se encuentra en un estado y hay un bloque nuevo que incluye dos transacciones ( y ) que invocan a un mismo contrato. En tal escenario, los usuario desconocen cual es el estado en que se encuentra el contrato cuando se aplican la ejecución de su contrato. Por ejemplo, se puede aplicar en el estado o en el estado que es cuando ya se aplicó . Esto implica que hay una discrepancia entre el estado que se encuentra el contrato que los usuarios invocan, y el estado actual depende del estado en que se hayan realizado las ejecuciones. Sólo el minero puede determinar el orden en que se ejecutan las transacciones. Esto tiene como consecuencia que el estado del contrato depende del orden en que el minero invocaba a las transacciones. Esto se conoce como Transaction Ordering Dependence (TOD).
TOD tiene puede ser utilizado para realizar ataques al estado de la blockchain de modo que se puedan obtener beneficios del modo en que se ejecutan estas transacciones.
Observemos el siguiente smart-contract que representa una tienda que vende un producto:
contract MarketPlace { uint public price; uint public stock; /.../ function updatePrice(uint _price) { if (msg.sender == owner) price = _price; } function buy(uint quant) returns (uint) { if (quant > stock || msg.value < quant * price) throw; stock -= quant; /.../ } }
A partir del código anterior, supongamos la siguiente ejecución dentro de la blockchain:
- y son transacciones que son invocadas de forma simultanea y son obtenidas por el mismo minero. corresponde a la transacción asociada con la compra de un objeto a la tienda y es la transacción que actualiza el precio del producto.
- El minero mina el bloque que contiene a y a
- se ejecuta y compra.
- se ejecuta y actualiza el producto.
- Se escribe el estado de la ejecución de las transacciones dentro del bloque y se actualiza el estado de la blockchain.
En esta ejecución todo funcionó de forma esperada sin que fallara nada. Pero que pasa si consideramos la siguiente ejecución:
- y son transacciones que son invocadas de forma simultanea y son obtenidas por el mismo minero. corresponde a la transacción asociada con la compra de un objeto a la tienda y es la transacción que actualiza el precio del producto.
- El minero mina el bloque que contiene a y a
- se ejecuta y actualiza el producto.
- se ejecuta y compra.
- Se escribe el estado de la ejecución de las transacciones dentro del bloque y se actualiza el estado de la blockchain.
En este caso el cliente compró el producto a un precio más caro que el que él esperaba. Esto se traduce en que el dueño se benefició de la forma en que la transacción se ejecutó, aunque esto no fue de forma consiente. ¿Qué pasaría si nos aprovechamos de esta falla?
Veamos un caso más en el que el orden de la ejecución de los contratos puede causar un estado imprevisto en la ejecución bajo TOD. Sea el siguiente código:
contract Puzzle { address public owner; bool public locked; uint public reward; byte32 public diff; bytes public solution; function Puzzle() { owner = msg.sender; reward = msg.value; locked = false; diff = bytes(111111); } function () { if (msg.sender == owner) { if (locked) throw; owner.send(reward); reward = msg.value; } else { if (msg.data.length > 0) { if (locked) throw; if (sha256(msg.data) < diff) { msg.sender.send(reward); solution = msg.data; locked = true; } } } } }
El contrato anterior recompensa a los usuarios quienes resuelven un acertijo computacional. Sólo si el hash del mensaje enviado por el jugador es menor que una diferencia predefinida, entonces, se paga la recompensa al jugador y se bloquea el contrato para que nadie más intente jugar después.
Igualmente consideremos dos ejecuciones de el contrato Puzzle en una blockchain. La primera ejecución la podemos describir de la siguiente forma:
- y son dos transacciones que son invocadas de forma simultanea y son obtenidas por el mismo minero. es la transacción enviada por el dueño del contrato y la transacción del usuario que envía una solución válida para reclamar la recompensa.
- El minero mina el bloque que contiene a y
- se ejecuta y actualiza la recompensa.
- se ejecuta y recibe la nueva recompensa.
- Se escribe el estado de la ejecución de las transacciones dentro del bloque se actualiza el estado de la blockchain.
En este caso el jugador esperaba recibir la recompensa que el observó cuando envió su solución, pero el recibió una recompensa distinta, el cuál pudo haber sido un accidente, pero ¿y si no fue un accidente?