5

I instantiate the following contract with _number as 10. When I check the value of number, I get 72370055773322622139731865630429942408293740416025352524660990004945706024960. Is this a problem with my contract, or is this a web3 bug?

contract Thing{
  uint public number;
  function Thing(bytes32 _number){
    number = uint(_number);
  }
}
5

72370055773322622139731865630429942408293740416025352524660990004945706024960 is 0xa000000000000000000000000000000000000000000000000000000000000000L - or 10 in hex, left shifted. Without seeing your web3 code, it's difficult to say why it was parsed this way, but it seems likely web3 treated your input as a single byte byte string, and left-aligned it into the bytes32 argument.

| improve this answer | |
3

Summary

There are some oddities when using bytes32 as function parameters.

From Solidity Features - Byte Arrays:

PT Basic support for variable-length byte arrays. This includes

  • bytes type for storage variables
  • msg.data is of bytes type and contains the calldata
  • functions taking arbitrary parameters (call, sha3, ...) can be called with bytes arguments.
  • copying between msg.data and bytes storage variables

What is not possible yet:

  • function parameters of bytes type
  • local variables of bytes type
  • index or slice access


Details

I use the following source code based on your source code:

contract ByteToInt {
    uint public number;
    bytes32 public thebytes32;

    function ByteToInt(bytes32 _number) {
        thebytes32 = _number;
        number = uint(_number);
    }
}

And flattened it to:

var byteToIntSource='contract ByteToInt { uint public number; bytes32 public thebytes32;  function ByteToInt(bytes32 _number) { thebytes32 = _number; number = uint(_number); }}'

Ran it in geth --dev console:

> var byteToIntSource='contract ByteToInt { uint public number; bytes32 public thebytes32;  function ByteToInt(bytes32 _number) { thebytes32 = _number; number = uint(_number); }}'
undefined

Compiled it:

> var byteToIntCompiled = web3.eth.compile.solidity(byteToIntSource);
undefined

Inserted it into the blockchain:

> var byteToIntContract = web3.eth.contract(byteToIntCompiled.ByteToInt.info.abiDefinition);
var byteToInt = byteToIntContract.new(10, {from:web3.eth.accounts[0], data: byteToIntCompiled.ByteToInt.code, gas: 1000000}, 
  function(e, contract) {
    if (!e) {
      if (!contract.address) {
        console.log("Contract transaction send: TransactionHash: " + 
          contract.transactionHash + " waiting to be mined...");
      } else {
        console.log("Contract mined! Address: " + contract.address);
        console.log(contract);
      }
    }
  }
)
...
Contract mined! Address: 0x49617e1728c53a3e31ccf21faf6ba344af90f04c

And checked the values:

> byteToInt.thebytes32()
"0xa000000000000000000000000000000000000000000000000000000000000000"

> byteToInt.number()
7.237005577332262213973186563042994240829374041602535252466099000494570602496e+76

I executed the following statements in Java:

BigInteger num = new BigInteger("a000000000000000000000000000000000000000000000000000000000000000", 16);
System.out.println(num.toString(10));

And the results are:

72370055773322622139731865630429942408293740416025352524660990004945706024960

So 10 is being encoded as the first byte in your bytes32 variable, and the uint(...) cast is converting the whole bytes32 data into a uint.


Checking how web3 converts the decimal values into the parameters, I tried sending in 0xabc into the constructor by using the decimal equivalent of 2748:

var byteToInt = byteToIntContract.new(2748, {from:web3.eth.accounts[0], data: byteToIntCompiled.ByteToInt.code, gas: 1000000}, 
  function(e, contract) {
    if (!e) {
      if (!contract.address) {
        console.log("Contract transaction send: TransactionHash: " + 
          contract.transactionHash + " waiting to be mined...");
      } else {
        console.log("Contract mined! Address: " + contract.address);
        console.log(contract);
      }
    }
  }
)
...
Contract mined! Address: 0xb086848ed791c87a6659ed17fb6fd85e37aae97b
...
> byteToInt.thebytes32()
"0xabc0000000000000000000000000000000000000000000000000000000000000"
> byteToInt.number()
7.7684731744176002203118424512664641303902811977827214350690781458433906311168e+76

Try out the following:

var byteToInt = byteToIntContract.new(0x0000000000000000000000000000000000000000000000000000000000000abc, {from:web3.eth.accounts[0], data: byteToIntCompiled.ByteToInt.code, gas: 1000000}, 
  function(e, contract) {
    if (!e) {
      if (!contract.address) {
        console.log("Contract transaction send: TransactionHash: " + 
          contract.transactionHash + " waiting to be mined...");
      } else {
        console.log("Contract mined! Address: " + contract.address);
        console.log(contract);
      }
    }
  }
)
...
> byteToInt.thebytes32()
"0xabc0000000000000000000000000000000000000000000000000000000000000"
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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