2

How do you return the value pushed before with only one function? I read some information about events, so I think it may be a solution, but it doesn't return the exact value pushed before. There is my new source below which added events:

pragma solidity ^0.4.0;
////////////////////////////////////////////////////////////
// This is an example contract hacked together at a meetup.
// It is by far not complete and only used to show some
// features of Solidity.
////////////////////////////////////////////////////////////
contract queue
{
    struct Queue {
        uint256[] data;
        uint256 front;
        uint256 back;
    }
    /// @dev the number of elements stored in the queue.
    function length(Queue storage q) constant internal returns (uint256) {
        return q.back - q.front;
    }
    /// @dev the number of elements this queue can hold
    function capacity(Queue storage q) constant internal returns (uint256) {
        return q.data.length - 1;
    }
    /// @dev push a new element to the back of the queue
    function push(Queue storage q, uint256 data) internal
    {
        if ((q.back + 1) % q.data.length == q.front)
            return; // throw;
        q.data[q.back] = data;
        q.back = (q.back + 1) % q.data.length;
    }


    /// @dev remove and return the element at the front of the queue
    function pop(Queue storage q) internal returns (uint256 r)
    {
        if (q.back == q.front)
            return; // throw;
        r = q.data[q.front];
        delete q.data[q.front];
        q.front = (q.front + 1) % q.data.length;
        return r;
    }
    Queue requests;
    event PopEvent(bool ok); //my event designed by me here.
    function queue() {
        requests.data.length = 200;
    }
    function addRequest(uint256 d) {
        push(requests, d);
    }
    function popRequest()  returns (uint256) {
        PopEvent(true);
        return pop(requests);
    }
    function queueLength()  constant returns (uint256) {
        return length(requests);
    }
    function hello() constant returns(string s){ 
        return 'hello world!';
    }
}

I just want the popRequest function to return the exact value pushed before.

2 Answers 2

6

I saw this yesterday.

There are issues in the logic. When I made the queue size very small (3) I got incorrect results starting at job 4, so there are problems in the algo.

We're not in a memory-bound world here so I question the need for heroics unless trying to optimize gas cost. A fixed sized array might be ideal if you want to re-use slots. You can drop the delete operation.

The simplest possible implementation is just a queue of unlimited size and keep walking forward (2^256 maximum jobs, ever).

It IS possible to return a value while also mutating the state change, however it's not easy to SEE the result outside of a contract. What I mean is a FIFO queue is sort of useless unless it's got a client (another contract) that submits jobs. A client contract that sends a message will indeed receive the returned value from a function that also mutates state.

That's quite different (and admittedly confusing) from a Web3 client that sends a transaction and gets a txnhash but no result.

Event emissions are one way to go. I wonder if this is sufficient in a multi-threaded situation where the clients need to know which events belong to them.

I made a little example if a FIFO queue that seems to work. It uses unlimited (2^256) queue size so it's very simple. It returns the cursor position and the data value "popped" and it sends this information back to the fifoClient contract that logs all results.

Possibly you'll find some ideas that will help.

pragma solidity ^0.4.6;

contract FIFO {

    uint[] public fifoQueue;
    uint public cursorPosition;

    function queueDepth()
        public
        constant
        returns(uint queueDepth)
    {
        return fifoQueue.length - cursorPosition;
    }

    function push(uint requestData) 
        public
        returns(uint jobNumber)
    {
        if(fifoQueue.length + 1 < fifoQueue.length) throw; // exceeded 2^256 push requests
        return fifoQueue.push(requestData) - 1;
    }

    function pop() 
        public
        returns(uint, uint)
    {
        if(fifoQueue.length==0) throw;
        if(fifoQueue.length - 1 < cursorPosition) throw;
        cursorPosition += 1;
        return (cursorPosition -1, fifoQueue[cursorPosition -1]);
    }
}

contract FifoClient {

    FIFO public jobQueue;

    event LogPush(address sender, uint jobNumber, uint jobValue);
    event LogPop (address sender, uint jobNumber, uint jobValue);

    function FifoClient() {
        // fifoClient makes it's own FIFO queue
        jobQueue = new FIFO();
    } 

    function push(uint jobValue)
        public
        returns(uint jobNumber)
    {
        uint jobNum = jobQueue.push(jobValue);
        LogPush(msg.sender, jobNum, jobValue);
        return jobNum;
    }

    function pop() 
        public
        returns(uint, uint)
    {
        uint jobNum;
        uint jobVal;
        (jobNum, jobVal) = jobQueue.pop();
        LogPop(msg.sender, jobNum, jobVal);
        return(jobNum, jobVal);
    }

}

Here it is in Remix just to show it working.

Only necessary to deploy a FifoClient. It commissions its own FIFO contract to work with automatically.

enter image description here

Remix is a great tool for working out the contract details so you can be confident about what to expect before dealing with the Web3 interface to the outside world.

Hope it helps.

7
  • I can't tell you how much I appreciate your answer.
    – jiebang
    Commented Apr 7, 2017 at 1:47
  • Thank you for your help. Because I am a new hand of solidity, so there may be some errors in my procedure. I now can't find the cursor position and the data value "popped". Below are my procedure:
    – jiebang
    Commented Apr 7, 2017 at 2:45
  • I paste the Web3 deploy contents of client to the geth console. And then I mined for a while ,it shows me that Contract mined! address: 0x00f5a009c78505779eb174b897f6c002eeb80120 transactionHash: 0x23cfe4a3ececeb394af3edf14b436325013a75ac7f7e2e7f5f226878718096bb . Then : Contract mined! address: 0x00f5a009c78505779eb174b897f6c002eeb80120 transactionHash: 0x23cfe4a3ececeb394af3edf14b436325013a75ac7f7e2e7f5f226878718096bb
    – jiebang
    Commented Apr 7, 2017 at 2:48
  • My question is where or how to see the cursor position and the data value "popped"? thank you very much .
    – jiebang
    Commented Apr 7, 2017 at 2:49
  • I use > queue_sol_fifoclient.pop.call() [4, 3] could see the result, is it the right way to see the result?
    – jiebang
    Commented Apr 7, 2017 at 3:05
1

Basically it's not possible to both mutate the state while return a value via one function call AFAIK.

Here is a revised version that can achieve what you want, the PopEvent is better to accept the actually element value that gets popped out instead of a boolean value.

event ElementPopped(uint256 _element);

In the revised version, additionally I added an ElementPushed event which accepts a second parameter to tell the index in the queue where the element is pushed.

Hope this helps.

5
  • Thank you very much. I compile your revised source via ethereum.github.io/browser-solidity. And then paste the result to the geth console.After mining for a while, I type the commands below in the geth console,but it seems not to be suitable for my hope:
    – jiebang
    Commented Apr 7, 2017 at 1:36
  • > queue_sol_queue.addRequest(1) "0xfe2a3fafa8a47439b583a15c14c5282c1657bfbc9a485a591ca68fcb90a021b4" > queue_sol_queue.addRequest(2) "0x83d1c13a2573d997617238c736e8711522a7bf84613637cc581f66fb86daad59" > queue_sol_queue.addRequest(3) "0x0c428cbd9c4dd9e6638066c67a18c16dc386b01bfc9255e90d8d71ca911716eb" > queue_sol_queue.popRequest() "0x772bb011248822dc69a355d1ebb9c948981dc706b944653d034fb3287f4dcb73" you can see that the queue_sol_queue.popRequest() didin't show the value but a transaction hash. So what's wrong with my procedure? thank you.
    – jiebang
    Commented Apr 7, 2017 at 1:36
  • You need to watch the event stream via web3, event doesn't show up as the return value. And make sure to check the answer above, Rob has posted a more deep driven explanation. Commented Apr 7, 2017 at 1:40
  • Excuse me. I still don't know how to watch the event in web3 console? Could you tell me ?
    – jiebang
    Commented Apr 10, 2017 at 8:14
  • Related: ethereum.stackexchange.com/questions/2024/… Commented Apr 10, 2017 at 12:09

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.