1

The following is a simplification of the problem I'm facing;

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);
  }
}

When I call set_value with a non-zero value, I hit the assert. It looks like the problem is that in this line,

fixed_values[msg.sender].value = my_value;

my attempt to assign to the struct inside the mapping is not assigning to the struct stored in fixed_value. I've also tried the following instead;

BasicValue storage basic_val = fixed_values[msg.sender];
basic_val.value = my_value;

But this doesn't change the result. I read in the solidity documentation that,

assignments between storage and memory and also to a state variable (even from other state variables) always create an independent copy

If that's the case, then how can I get a the struct "out of" the mapping, to use it locally?

(Notes; the contract above looks like it does ridiculously more complicated stuff than it needs to because the real contract has more requirements. For example, there's more than one attribute in the struct, there's more than one struct declared on initialization, there's more than one struct in the mapping, and I need to do logic involving more than one of them.)

2 Answers 2

0

These lines are unnecessary

BasicValue fixed_value;
fixed_values[my_address] = fixed_value;

but the real problem is this line would be

assert(fixed_values[msg.sender].value != 0);

because you want the struct at that index.

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);
  }
}

Hope it helps.

0

Yes all state variables are storing in blockchain premaritally. But coming to your qus why:

function ValueSetter(address init_address) public {
    my_address = init_address;
    fixed_values[init_address] = fixed_value;
}

In above code your initialise fixed_values[init_address] = fixed_value; that means internally fixed_value = BasicValue(0) and this will be assigned to fixed_values[init_address] = fixed_value;

Internally your code looks like:

function ValueSetter(address init_address) public {
    fixed_value = BasicValue(0);
    my_address = init_address;
    fixed_values[init_address] = fixed_value;
}

And coming to your there is a logic error:

  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);
  }

As per my explanation fixed_value.value is zero. Assert will fail. And your transactions will revert back to previous state. It will not save current value to block chain. But transaction will be recorded to chain as a failure.

So modified code: 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);
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.