<p>Here's that source code, annotated. Each annotation refers to the code after it.</p>
<hr />
<p>This means that this part of the code handles both OP_PICK and OP_ROLL. This is because OP_PICK and OP_ROLL are very similar. The only difference is that PICK copies and ROLL moves.</p>
<pre><code>            case OP_PICK:
            case OP_ROLL:
            {
</code></pre>
<p>These are two examples of the stack before and after. This is sometimes called a 'precondition' and a 'postcondition.'</p>
<p>This one documents OP_PICK.</p>
<p>Precondition: <code>xn ... x2 x1 x0 n</code></p>
<p>Postcondition: <code>xn ... x2 x1 x0 xn</code></p>
<pre><code>                // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
</code></pre>
<p>This one documents OP_ROLL.</p>
<p>Precondition: <code>xn ... x2 x1 x0 n</code></p>
<p>Postcondition: <code>... x2 x1 x0 xn</code> (Note the lack of <code>xn</code> at the beginning.)</p>
<pre><code>                // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
</code></pre>
<p>You need to have at least two elements on the stack, or this operation makes no sense.</p>
<pre><code>                if (stack.size() &lt; 2)
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
</code></pre>
<p>Copy (but do not remove) the top element on the stack. Interpret it as a number. Convert it to a 32-bit integer, so it's easier to work with.</p>
<pre><code>                int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
</code></pre>
<p>Now remove the top element on the stack. (Which should be n, remember.)</p>
<pre><code>                popstack(stack);
</code></pre>
<p>If <code>n</code> is negative, fail. If n is larger than the stack, fail. (This is where I think your script is having an error.)</p>
<pre><code>                if (n &lt; 0 || n &gt;= (int)stack.size())
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
</code></pre>
<p>Copy the value we're after. Remember, <code>1 2 3 0 OP_PICK</code> should get the element just below n, 3. Also, <code>stacktop(-1)</code> refers to the top. So therefore, we need to invert n and subtract 1.</p>
<pre><code>                valtype vch = stacktop(-n-1);
</code></pre>
<p>Remember, OP_ROLL deletes the element from where it was originally. This code is not executed for OP_PICK.</p>
<pre><code>                if (opcode == OP_ROLL)
                    stack.erase(stack.end()-n-1);
</code></pre>
<p>Now add the element that we just got back on the top of the stack.</p>
<pre><code>                stack.push_back(vch);
</code></pre>
<p>We're done handling this case.</p>
<pre><code>            }
            break;
</code></pre>
<hr />
<p>Does that help?</p>

CC BY-SA 3.0
2015-06-21T11:29:39.210Z
It really does. I thought either it did nothing or used exactly the same code as OP_ROLL. The commented code around                 if (opcode == OP_ROLL) has been the key for me.
halftimepad
CC BY-SA 4.0
2015-06-21T00:57:27.617Z
2022-07-05T17:34:57.100Z
2022-07-05T17:34:57.100Z
Nick ODell
<p>OP_PICK should take the nth element from the back of the stack and take it on top:
for input 
xn ... x2 x1 x0 <br>
gives
xn ... x2 x1 x0 xn  </p>

<p>I have used it in some scripts, but I've noticed some strange behaviour. </p>

<p>For instance, using the tool in:
<a href="http://webbtc.com/script" rel="nofollow">http://webbtc.com/script</a>
an input script
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3
and an output script
19 OP_PICK 
produces an error.
However 18 OP_PICK works. For 25 elements in the stack it should work in both cases. 
The problem doesn't seem to be the number 19. If I add one input<br>
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3
the scripts works fine.</p>

<p>I have tried looking at the source code, but in 
<a href="https://github.com/bitcoin/bitcoin/blob/ce56f5621a94dcc2159ebe57e43da727eab18e6c/src/script/interpreter.cpp" rel="nofollow">https://github.com/bitcoin/bitcoin/blob/ce56f5621a94dcc2159ebe57e43da727eab18e6c/src/script/interpreter.cpp</a>
around line 551 I find:</p>

<pre><code>            case OP_OVER:
            {
                // (x1 x2 -- x1 x2 x1)
                if (stack.size() &lt; 2)
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
                valtype vch = stacktop(-2);
                stack.push_back(vch);
            }
            break;

            case OP_PICK:
            case OP_ROLL:
            {
                // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
                // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
                if (stack.size() &lt; 2)
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
                int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
                popstack(stack);
</code></pre>

<p>I'm not really sure how OP_PICK is implemented. Can anyone point me to the code for OP_PICK or explain the errors?</p>

CC BY-SA 3.0
2015-06-21T00:37:37.143Z
Is that 18 in decimal, or 18 in hex?
Nick ODell
CC BY-SA 3.0
2015-06-21T02:50:48.173Z
@NickODell: I think you've got it.  It appears that site inteprets "18" to be hex.
Nate Eldredge
CC BY-SA 3.0
2015-06-21T11:36:43.443Z
It really seems to be taking numbers above 16 as hexadecimal (with OP_16 the highest integer you can directly push to the stack). Still trying to figure out the whole format of http://webbtc.com/script and the minimaldata verification to work around the problem.
halftimepad
<script><opcodes>
Script. OP_PICK/OP_ROLL
halftimepad
# Script. OP_PICK/OP_ROLL

(Asked by: username_0 on 2015-06-21)

OP\_PICK should take the nth element from the back of the stack and take it on top:
for input
xn ... x2 x1 x0   
gives
xn ... x2 x1 x0 xn

I have used it in some scripts, but I've noticed some strange behaviour.

For instance, using the tool in:
<http://webbtc.com/script>
an input script
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3
and an output script
19 OP\_PICK
produces an error.
However 18 OP\_PICK works. For 25 elements in the stack it should work in both cases.
The problem doesn't seem to be the number 19. If I add one input  
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3
the scripts works fine.

I have tried looking at the source code, but in
<https://github.com/bitcoin/bitcoin/blob/ce56f5621a94dcc2159ebe57e43da727eab18e6c/src/script/interpreter.cpp>
around line 551 I find:

```
            case OP_OVER:
            {
                // (x1 x2 -- x1 x2 x1)
                if (stack.size() < 2)
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
                valtype vch = stacktop(-2);
                stack.push_back(vch);
            }
            break;

            case OP_PICK:
            case OP_ROLL:
            {
                // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
                // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
                if (stack.size() < 2)
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
                int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
                popstack(stack);

```

I'm not really sure how OP\_PICK is implemented. Can anyone point me to the code for OP\_PICK or explain the errors?

**Tags:** script, opcodes

> **Comments:**
> **username_1**: Is that 18 in decimal, or 18 in hex?  
> **username_2**: @username_1: I think you've got it.  It appears that site inteprets "18" to be hex.  
> **username_0**: It really seems to be taking numbers above 16 as hexadecimal (with OP_16 the highest integer you can directly push to the stack). Still trying to figure out the whole format of http://webbtc.com/script and the minimaldata verification to work around the problem.  

---

## 1 answers

### Answer by username_1 on 2015-06-21. Score: 3 | Accepted answer

Here's that source code, annotated. Each annotation refers to the code after it.

---

This means that this part of the code handles both OP\_PICK and OP\_ROLL. This is because OP\_PICK and OP\_ROLL are very similar. The only difference is that PICK copies and ROLL moves.

```
            case OP_PICK:
            case OP_ROLL:
            {

```

These are two examples of the stack before and after. This is sometimes called a 'precondition' and a 'postcondition.'

This one documents OP\_PICK.

Precondition: `xn ... x2 x1 x0 n`

Postcondition: `xn ... x2 x1 x0 xn`

```
                // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)

```

This one documents OP\_ROLL.

Precondition: `xn ... x2 x1 x0 n`

Postcondition: `... x2 x1 x0 xn` (Note the lack of `xn` at the beginning.)

```
                // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)

```

You need to have at least two elements on the stack, or this operation makes no sense.

```
                if (stack.size() < 2)
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

```

Copy (but do not remove) the top element on the stack. Interpret it as a number. Convert it to a 32-bit integer, so it's easier to work with.

```
                int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();

```

Now remove the top element on the stack. (Which should be n, remember.)

```
                popstack(stack);

```

If `n` is negative, fail. If n is larger than the stack, fail. (This is where I think your script is having an error.)

```
                if (n < 0 || n >= (int)stack.size())
                    return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);

```

Copy the value we're after. Remember, `1 2 3 0 OP_PICK` should get the element just below n, 3. Also, `stacktop(-1)` refers to the top. So therefore, we need to invert n and subtract 1.

```
                valtype vch = stacktop(-n-1);

```

Remember, OP\_ROLL deletes the element from where it was originally. This code is not executed for OP\_PICK.

```
                if (opcode == OP_ROLL)
                    stack.erase(stack.end()-n-1);

```

Now add the element that we just got back on the top of the stack.

```
                stack.push_back(vch);

```

We're done handling this case.

```
            }
            break;

```

---

Does that help?

> **Comments:**
> **username_0**: It really does. I thought either it did nothing or used exactly the same code as OP_ROLL. The commented code around                 if (opcode == OP_ROLL) has been the key for me.  

---

