Estaba leyendo este artículo , que da un ejemplo de un contrato que no funcionará. Aunque lo han arreglado en el artículo, quería saber por qué no funciona. He copiado una versión simplificada a continuación:
pragma solidity ^0.4.18;
contract StructArrayInitWrong {
struct Room {
address[] players;
}
Room[] rooms;
function createRoom() public {
address[] adr;
adr.push(msg.sender);
Room memory room = Room(adr);
rooms.push(room);
}
function getRoomsLength() view returns (uint) {
return rooms.length;
}
}
Lo extraño es rooms
que la longitud de la matriz aumenta en dos cada vez createRoom
que se llama en este contrato. ¿Puedes explicar este comportamiento? Gracias.
el problema es con esta linea
address[] adr;
Hay una "advertencia" sobre el almacenamiento no inicializado. Están sucediendo más cosas aquí de lo que podría sugerir una advertencia amable. Realmente no entiendo por qué esto no es un error grave, por lo que el desarrollador no lo acepta.
Debido a que el almacenamiento no estaba inicializado, el compilador no sabía dónde colocar la matriz dinámica, adr[]
por lo que la colocó en la primera ranura . Has leído bien. Está pisando fuerte rooms[]
. ¡Ay!
Dado que el ocupante de esa ranura también es una matriz dinámica, también usa la primera palabra para describir la longitud de la matriz. Por lo tanto, obtenemos el extraño comportamiento observado... pase a una matriz, luego a la otra y ¡puf! - ambas matrices tienen una longitud de 2.
Este no es el único caso en el que el almacenamiento declarado dentro de las funciones en lugar de en el lugar habitual (fuera) provoca sobrescrituras de datos potencialmente catastróficas. Vea aquí otro ejemplo: ¿Supervisión del compilador de Solc? La declaración de asignación inapropiada sobrescribe el almacenamiento
Teniendo en cuenta que se supone que los contratos inteligentes son claros y libres de defectos, no soy un gran admirador de este tipo de resultado no deseado. Esto y las variables de referencia suman demasiado vudú para mi gusto.
Tal vez alguien más intervenga con mejores heurísticas. Podría sugerir formar dos hábitos
Aquí está el código con un cambio y funcionando como se esperaba:
pragma solidity ^0.4.18;
contract StructArrayInitWrong {
struct Room {
address[] players;
}
Room[] rooms;
address[] adr; // <=== if we're going to store this, then let's store this.
function createRoom() public {
// <=== note gaping hole
adr.push(msg.sender);
Room memory room = Room(adr);
rooms.push(room);
}
function getRoomsLength() public view returns (uint) {
return rooms.length;
}
}
Espero eso ayude.
luna
memory
esta manera:address[] memory adr = new address[](1); adr[0] = msg.sender;
. Esto parece funcionar también.