Lo siguiente es una simplificación del problema al que me enfrento;
pragma solidity 0.4.18;
contract ValueSetter {
struct BasicValue {
uint256 value;
}
address my_address; // Just for the require later
BasicValue fixed_value;
mapping(address => BasicValue) fixed_values;
function ValueSetter(address init_address) public {
my_address = init_address;
fixed_values[init_address] = fixed_value;
}
function set_value(uint256 my_value) external {
// Just to prove that the bug isn't in my calling params
require(msg.sender == my_address && my_value != 0);
fixed_values[msg.sender].value = my_value;
assert(fixed_value.value != 0);
}
}
Cuando llamo set_value
con un valor distinto de cero, presiono la afirmación. Parece que el problema es que en esta línea,
fixed_values[msg.sender].value = my_value;
mi intento de asignar a la estructura dentro del mapeo no se asigna a la estructura almacenada en fixed_value
. También probé lo siguiente en su lugar;
BasicValue storage basic_val = fixed_values[msg.sender];
basic_val.value = my_value;
Pero esto no cambia el resultado. Leí en la documentación de solidez que,
las asignaciones entre el almacenamiento y la memoria y también a una variable de estado (incluso de otras variables de estado) siempre crean una copia independiente
Si ese es el caso, ¿cómo puedo obtener una estructura "fuera" del mapeo para usarla localmente?
(Notas: parece que el contrato anterior hace cosas ridículamente más complicadas de lo necesario porque el contrato real tiene más requisitos. Por ejemplo, hay más de un atributo en la estructura, hay más de una estructura declarada en la inicialización, hay más de una estructura en el mapeo, y necesito hacer una lógica que involucre a más de uno de ellos).
Estas líneas son innecesarias.
BasicValue fixed_value;
fixed_values[my_address] = fixed_value;
pero el verdadero problema es que esta línea sería
assert(fixed_values[msg.sender].value != 0);
porque quieres la estructura en ese índice.
pragma solidity 0.4.18;
contract ValueSetter {
struct ValueStruct {
uint256 value;
}
address public my_address; // Just for the require later
mapping(address => ValueStruct) public valueStructs;
function ValueSetter() public {
my_address = msg.sender;
}
function set_value(uint256 my_value) external {
// this shows the function is called by the deployer account
require(msg.sender == my_address && my_value != 0);
// this stores a uint in the .value element of the ValueStruct
// stored in the mapping at the index which is the sender
valueStructs[msg.sender].value = my_value;
// this just gets confirms the value is where we put it
assert(valueStructs[msg.sender].value != 0);
}
}
Espero eso ayude.
Sí, todas las variables de estado se almacenan en blockchain antes del matrimonio. Pero llegando a tu pregunta por qué:
function ValueSetter(address init_address) public {
my_address = init_address;
fixed_values[init_address] = fixed_value;
}
En el código anterior, su inicialización fixed_values[init_address] = fixed_value;
significa internamente fixed_value = BasicValue(0)
y esto se asignará afixed_values[init_address] = fixed_value;
Internamente su código se parece a:
function ValueSetter(address init_address) public {
fixed_value = BasicValue(0);
my_address = init_address;
fixed_values[init_address] = fixed_value;
}
Y llegando a tu hay un error de lógica:
function set_value(uint256 my_value) external {
// Just to prove that the bug isn't in my calling params
require(msg.sender == my_address && my_value != 0);
fixed_values[msg.sender].value = my_value;
assert(fixed_value.value != 0);
}
Según mi explicación, fixed_value.value es cero. Afirmar fallará. Y sus transacciones volverán al estado anterior. No guardará el valor actual en la cadena de bloques. Pero la transacción se registrará en la cadena como un error.
Código modificado: pragma solidity 0.4.18;
contract ValueSetter {
struct BasicValue {
uint256 value;
}
address my_address; // Just for the require later
BasicValue fixed_value;
mapping(address => BasicValue) fixed_values;
function ValueSetter(address init_address) public {
my_address = init_address;
fixed_values[init_address] = BasicValue(1000);
}
function set_value(uint256 my_value) external {
// Just to prove that the bug isn't in my calling params
require(msg.sender == my_address && my_value != 0);
fixed_values[msg.sender].value = my_value;
//assert(fixed_value.value != 0);
}
}