<p>There's something unintuitive about Bitcoin transaction SigOp counting. Normally, the signature count of a block is calculated by looking at the scriptPubKey of each transaction and counting how many OP_CHECKSIG operations it contains. In other words, the SigOp count is gotten by looking at how many outputs you create, not how many inputs you redeem.</p>

<p>However, you obviously can't see how many operations a P2SH script does by looking at its hash. Instead, the transaction that spends the P2SH script "pays" for it.</p>

<p>The somewhat awkward thing is that you can't tell if a scriptSig is spending a P2SH output unless you look up the outpoint it's spending.</p>

<blockquote>
  <p>Why doesn't CheckBlock() just include the P2SH sig op count to avoid code duplication between the two methods?</p>
</blockquote>

<p>I don't think it's for backwards compatibility. While ConnectBlock <a href="https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1798" rel="nofollow">doesn't count</a> P2SH SigOps for <a href="http://blockexplorer.com/tx/6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192" rel="nofollow">transactions that appear to be P2SH but aren't</a>, that logic could be implemented in CheckBlock instead.</p>

<p>I don't think it's for efficiency. Rejecting blocks with too many SigOps isn't very common, since it takes about seven thousand dollars of electricity to make a block. I suspect that you could remove the SigOp check from CheckBlock for a very minor performance increase.</p>

<p>I think it's partially because it would be irritating to change. Getting the P2SH SigOp count requires access to the CCoinViewCache object, which isn't passed to CheckBlock.</p>

CC BY-SA 3.0
2014-12-31T15:30:38.387Z
Thanks, the use of the CCoinViewCache was what I was missing. Don't want to bog the CheckBlock() quick checks down with this slower check.
morsecoder
CC BY-SA 3.0
2014-12-31T17:28:17.537Z
Also, why bother counting the scriptPubKeys' signature operations, shouldn't the sig op count be just the approximate count of signature operations to validate the block? And scriptPubKeys of a block don't necessarily need to be validated that block, the previous scriptPubKeys and the inputs do need to be validated.
morsecoder
CC BY-SA 3.0
2014-12-31T21:43:48.087Z
@StephenM347 I agree, that would have made more sense. I don't know why they did it that way.
Nick ODell
CC BY-SA 3.0
2014-12-31T06:06:18.460Z
2014-12-31T06:06:18.460Z
Nick ODell
<p>In the bitcoin v0.9.3 source: <a href="https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp" rel="nofollow">https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp</a></p>

<p><code>ConnectBlock()</code> calls <code>CheckBlock()</code> as one of the first things it does. <a href="https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1756" rel="nofollow">https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1756</a>. And <code>CheckBlock()</code> does a count of the signature operations that <strong>doesn't include counting P2SH sig ops</strong> in the inputs. </p>

<p>But then <code>ConnectBlock()</code> goes on to do it's own nSigOps count, this time <strong>including the P2SH sig ops</strong> (<a href="https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1810" rel="nofollow">https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1810</a>). </p>

<p>Why doesn't <code>CheckBlock()</code> just include the P2SH sig op count to avoid code duplication between the two methods? Is it for efficiency? Or maybe backwards compatibility?</p>

<p>Thanks!</p>

<signature>
Double Counting SigOps to Prevent CPU Exhaustion Attacks
morsecoder
# Double Counting SigOps to Prevent CPU Exhaustion Attacks

(Asked by: username_0 on 2014-12-30)

In the bitcoin v0.9.3 source: <https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp>

`ConnectBlock()` calls `CheckBlock()` as one of the first things it does. <https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1756>. And `CheckBlock()` does a count of the signature operations that **doesn't include counting P2SH sig ops** in the inputs.

But then `ConnectBlock()` goes on to do it's own nSigOps count, this time **including the P2SH sig ops** (<https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1810>).

Why doesn't `CheckBlock()` just include the P2SH sig op count to avoid code duplication between the two methods? Is it for efficiency? Or maybe backwards compatibility?

Thanks!

**Tags:** signature


---

## 1 answers

### Answer by username_1 on 2014-12-31. Score: 2 | Accepted answer

There's something unintuitive about Bitcoin transaction SigOp counting. Normally, the signature count of a block is calculated by looking at the scriptPubKey of each transaction and counting how many OP\_CHECKSIG operations it contains. In other words, the SigOp count is gotten by looking at how many outputs you create, not how many inputs you redeem.

However, you obviously can't see how many operations a P2SH script does by looking at its hash. Instead, the transaction that spends the P2SH script "pays" for it.

The somewhat awkward thing is that you can't tell if a scriptSig is spending a P2SH output unless you look up the outpoint it's spending.

> Why doesn't CheckBlock() just include the P2SH sig op count to avoid code duplication between the two methods?

I don't think it's for backwards compatibility. While ConnectBlock [doesn't count](https://github.com/bitcoin/bitcoin/blob/v0.9.3/src/main.cpp#L1798) P2SH SigOps for [transactions that appear to be P2SH but aren't](http://blockexplorer.com/tx/6a26d2ecb67f27d1fa5524763b49029d7106e91e3cc05743073461a719776192), that logic could be implemented in CheckBlock instead.

I don't think it's for efficiency. Rejecting blocks with too many SigOps isn't very common, since it takes about seven thousand dollars of electricity to make a block. I suspect that you could remove the SigOp check from CheckBlock for a very minor performance increase.

I think it's partially because it would be irritating to change. Getting the P2SH SigOp count requires access to the CCoinViewCache object, which isn't passed to CheckBlock.

> **Comments:**
> **username_0**: Thanks, the use of the CCoinViewCache was what I was missing. Don't want to bog the CheckBlock() quick checks down with this slower check.  
> **username_0**: Also, why bother counting the scriptPubKeys' signature operations, shouldn't the sig op count be just the approximate count of signature operations to validate the block? And scriptPubKeys of a block don't necessarily need to be validated that block, the previous scriptPubKeys and the inputs do need to be validated.  
> **username_1**: @StephenM347 I agree, that would have made more sense. I don't know why they did it that way.  

---

