Es posible que este contrato tenga algún problema porque veo algo extraño en mi registro de contratos. Alguien ejecuta otra funcion de contrato para jugar con esta mini app de gamble y en 2 jugadas limpia todo el dinero xD.
Gracias por adelantado :)
pragma solidity ^0.4.11;
contract MetaCoin {
event FlipCoinEvent(
uint value,
address owner
);
event PlaySlotEvent(
uint value,
address owner
);
function() public payable {}
function flipCoin() public payable {
assert(msg.value < 100000000000000000);
uint value = (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
if (value > 55){
msg.sender.transfer(msg.value * 2);
}
FlipCoinEvent(value, msg.sender);
}
function playSlot() public payable {
require(msg.value < 100000000000000000);
uint r = (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
if(r >0 && r<3){
PlaySlotEvent(3,msg.sender);
msg.sender.transfer(msg.value * 12);
}else if(r >3 && r<6){
PlaySlotEvent(2,msg.sender);
msg.sender.transfer(msg.value * 6);
}else if(r >6 && r<9){
PlaySlotEvent(1,msg.sender);
msg.sender.transfer(msg.value * 3);
}else{
PlaySlotEvent(0,msg.sender);
}
}
function getBalance() public constant returns(uint bal) {
bal = this.balance;
return bal;
}
}
Según la documentaciónblock.timestamp
, , the block.blockhash
y the block.number
permanecen igual hasta que se agrega el siguiente bloque a la cadena de bloques. Dado que el tiempo de bloqueo es de alrededor de 15 a 17 segundos , es posible "obtener el bloque correcto" para atacar su contrato inteligente.
Uno podría simplemente escribir un contrato inteligente con una función getChances()
que verifique el valor actual (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1
y si está en el rango correcto (por ejemplo, <3) llama a la playSlot()
función de su contrato.
Entonces , la función getChances()
solo necesita ser invocada por un oráculo cada vez que se agrega un nuevo bloque a la cadena de bloques.
sin magia
Espero eso ayude
EDITAR :
Condensé su contrato inteligente y escribí otro para mostrar mejor lo que quise decir anteriormente:
pragma solidity ^0.4.11;
contract MetaCoin {
event PlaySlotEvent(
uint value,
address owner
);
function playSlot() public returns (uint){
uint r = (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
PlaySlotEvent(r,msg.sender);
}
}
contract Test {
function getCurrentR() constant returns (uint) {
return (block.timestamp + uint(block.blockhash(block.number-1)))%100 + 1;
}
}
Si intenta esto en Remix , simplemente llame getCurrentR()
e inmediatamente después de esa llamada playSlot()
. Verá que el valor difiere solo en la cantidad de segundos que espera antes de llamar playSlot()
. Por lo tanto, un jugador puede comprobar r
antes de empezar a jugar...
Su lotería no es verdaderamente aleatoria.
Cualquier decisión que tome un usuario que afecte el resultado le da a ese usuario una ventaja injusta. Ejemplos incluyen:
- Usando un blockhash, marca de tiempo u otro valor definido por el minero. Tenga en cuenta que el minero tiene la opción de publicar un bloque o no, por lo que posiblemente podría tener una oportunidad de obtener el premio por bloque que extrae.
Consulte esta respuesta para obtener una explicación más completa: ¿Cómo puedo generar de forma segura un número aleatorio en mi contrato inteligente? .
afirmar(mensaje.valor < 100000000000000000); require(mensaje.valor < 100000000000000000);
Esto significa que también puedo jugar con 0 wei y aun así ganar, ¿correcto?
Tal vez quisiste decir >?
Para generar el número aleatorio, utiliza la marca de tiempo del bloque actual y el hash del bloque anterior. El hash del bloque anterior es conocido, por lo que no agrega aleatoriedad. El minero conoce la marca de tiempo del bloque actual, por lo que puede llamar a flipCoin siempre que la marca de tiempo sea favorable para ellos.
Tenga en cuenta que no puede obtener el hash de bloque actual en Solidity. Como se especifica en los documentos:
block.blockhash(uint blockNumber) devuelve (bytes32): hash del bloque dado: solo funciona para los 256 bloques más recientes, excluyendo el actual
En su lugar, debes escupir el juego en 2 etapas:
flipCoin
registras el block.number
y msg.value
para el remitente.withdrawReward
usted transfiere la recompensa si el hash de bloque para el número de bloque registrado lo convierte en el ganador. Aquí también debe validar que el número de bloque grabado sea menor que el número de bloque actual.Está bien usar blockhash en este caso ya que la recompensa de 0.1 ether es mucho más baja que la recompensa del bloque. Para generar el número aleatorio, también debe incluir la dirección del remitente en la semilla, de lo contrario, un atacante puede enviar múltiples solicitudes de flipCoin que totalizarán más que la recompensa del bloque, lo que dará un incentivo para manipular el hash del bloque y dará la posibilidad de hacer trampa.
hugofreire
joffi
block.number
la que obtienes el número del bloque más reciente. También loblock.number-1
es el número del bloque añadido antes del actual. Por lo tanto, conblock.blockhash(block.number-1)
usted obtiene algo basado en información del pasado . ¿Me estoy perdiendo de algo?hugofreire
joffi
block.number-1
que tiene sentido. Perdon por la confusion. Pero a pesar de que está calculando un número basado en datos ya disponibles, ¿verdad?hugofreire
joffi
hugofreire