5

I have attached my contract, which works fine on populus and compiles on geth. It is a simple source code: Test() function appends data into my linkedlist that is defined in my library. And get() function's goal is to retrieve the head nodes' data in byte32 format.

My goal is to pull head node's data(bytes32). Inside my contract I have this following functions Test() and get().

On populus; when I called Link Contract's get() function, I can see the value that is stored in Struct's data which is bytes32 type.

my_contract.transact().Test();
contract_address = unmigrated_chain.wait.for_receipt(set_txn_hash)
output = my_contract.call().get();
print(output[0] + output[1]);
abc111 //this is my output result. String that is stored in head node  
       //printed correctly.

On the other hand, on geth (by using my private Ethereum Blockchain), when I call get() function, instead of returning (bytes32,bytes32) value it returns its transaction address value.

ret_value = link.get({from: eth.accounts[0]})
"0xb508d62ce8c32d792cccf41f04f607d93c672e3a7e53e3e9fedb433ecc1f7a83"

[Q] On geth how could I get the nodes' data (like on populus as "abc111") value since on geth when I call get() function it returns transaction's address value instead of (bytes32, bytes32).

Note: Returning string might be a solution so also in library if I change data's type from "bytes32" with "string" type, I have faced with following error: Error: Return argument type inaccessible dynamic type is not implicitly convertible to expected type (type of first return variable) string memory.

Thank you for your valuable help and time.

The example code as follows from this original implementation (https://github.com/ethereum/dapp-bin/blob/master/library/linkedList.sol):

library LinkedList {
      struct data {
        uint80 head;
        uint80 last;
        uint80 count;
        Item[] items; 
      }
      uint80 constant None = uint80(0);
      struct Item {
        uint80 prev;
        uint80 next;
        bytes32 data;
        bytes32 data2; 
      }

  /// Appends `_data` to the end of the list self. Pushes the _data.
  function append(data storage self, bytes32 _data, bytes32 _data2) {
    var index = uint80(self.items.push(Item({prev: self.last, next: None, data: _data, data2: _data2})));
    if (self.last == None)
      {
    if (self.head != None || self.count != 0) throw;
    self.head = self.last = index;
    self.count = 1;
      }
    else
      {
    self.items[self.last - 1].next = index;
    self.last = index;
    self.count++;
      }
  }

  function get_head_data(data storage self) returns (bytes32,bytes32) {
    var it = iterate_start(self);
    return (iterate_get(self, it));
  }

  function get_head_iterate(data storage self) returns (uint80) {
    var it = iterate_start(self);    
    return it;
  }

  // Interface of Iterator
  function iterate_start(data storage self) returns (uint80) { return self.head; }
  function iterate_next(data storage self, uint80 _index) returns (uint80) { return self.items[_index - 1].next; }
  function iterate_get(data storage self, uint80 _index) returns (bytes32, bytes32) {
    return (self.items[_index - 1].data, self.items[_index - 1].data2); }
}

contract Link {
  using LinkedList for LinkedList.data;
  LinkedList.data public list;
  function Test() {
    list.append("abc","111");
    list.append("def", "222");
    list.append("ghf", "333");
  }

  function get() returns (bytes32, bytes32) {
    return (list.get_head_data());
  }
}
alper
  • 8,395
  • 11
  • 63
  • 152

2 Answers2

6

You want to use

link.call.get()

Also, a better way to do it is just to mark the get function constant. Then it will do a call by default.

This does a simulated transaction call and returns the value. Otherwise, you're doing an actual transaction, and getting the return value.

Dealing with strings can be tricky; they aren't value types, like bytes32, but are a pointer to a dynamic array of bytes, similar to char* in C. See the docs for more info

alper
  • 8,395
  • 11
  • 63
  • 152
Tjaden Hess
  • 37,046
  • 10
  • 91
  • 118
  • Any advice for the geth side by doing the actual transaction? I come up with a solution that I can convert bytes32 into string and I can return that string value. – alper Oct 19 '16 at 19:28
  • function get() constant returns (string) {
    str = bytes32ToString(list.get_head_data()); return str; }
    – alper Oct 19 '16 at 19:28
  • could I force string to allocate memory like in C? ex: char * val = (char )malloc(sizeof(char) 5) – alper Oct 19 '16 at 19:41
  • 1
    In general, you should avoid doing reads and writes in the same operation. If you feel you need to, you should use events – Tjaden Hess Oct 19 '16 at 20:10
  • 1
    http://ethereum.stackexchange.com/questions/765/what-is-the-difference-between-a-transaction-and-a-call/770#770 covers much of what you want to know with regards to transactions. – Tjaden Hess Oct 19 '16 at 20:12
  • 1
    The issue that you're facing with strings is that you can't pass dynamically sized memory objects between contracts, including libraries. What you can do is pass a storage pointer to a string to the library function, then modify the string at that address, since libraries share the same storage as the caller – Tjaden Hess Oct 19 '16 at 20:16
  • 1
    Also, the "no dynamically sized memory objects" statement isn't quite true, but that's a separate question. You can always come chat on https://gitter.im/ethereum/solidity – Tjaden Hess Oct 19 '16 at 20:18
  • I get your point. When I updated my get() function by: instead of return (bytes32, bytes32) when I do return (bytes 32), it returns the value immediately as you said. Even I convert the bytes32 to string and "return string" it returns the value. – alper Oct 19 '16 at 21:16
  • For the dynamic approach the code I shared works with bytes32 type. But instead of bytes32 if I use "byte" or "string" in my library I do face with the problem that you have mentioned. So sticking with "bytes32" could also be a solution? Because in my approach since I am using a linked list (https://github.com/ethereum/dapp-bin/blob/master/library/linkedList.sol) the data seems like stored in Library side as "bytes32 data". – alper Oct 19 '16 at 21:18
  • 1
0

On Geth version 1.10.12, you can call your get method like this:

link.get.call()

Also, instead of constant, include the view and public modifiers to your get function definition in Solidity.

If your function isn't returning any value, you can call it directly without the call method like this

myContract.myFunction()
Udo E.
  • 115
  • 5
  • Why are you answering a 5 year old question? You are just copying the existing answer. – Ismael Jan 06 '22 at 00:18
  • 1
    ... because, I had same issue as the questioner and my Google search brought me here. The existing answer isn't same as mine. I've made a browser search for the keywords view and public on this page. I didn't copy this answer from anywhere. If similar answer exist elsewhere on this exchange, I didn't see it in my Google query. This was top of the list of questions Google showed me and I think it would help if some one stumbles in here with similar problem and finds a modern way to solve it without going through the whole stackexchange. Thanks. – Udo E. Jan 06 '22 at 03:26