<p>The correct, but non gratifying, answer is 80,003.</p>
<p>I found it by changing <code>MAX_BLOCK_SIGOPS_COST</code>, recompiling and the using the <code>invalidateblock</code> and <code>reconsiderblock</code> RPC to recheck it.</p>
<p>The block fails validation with the sigops limit set to 80,002 as passes validation when it's set to 80,003.</p>

CC BY-SA 4.0
2023-04-05T19:12:01.517Z
Was this an april fools joke by them? Is there any context as to why this occurred?
Poseidon
CC BY-SA 4.0
2023-04-05T19:14:12.423Z
They probably miscounted the sigops on bare multisig transactions.
Murch
CC BY-SA 4.0
2023-04-05T19:31:24.273Z
@Poseidon that would be a $150K prank, and they already had a different April Fools joke on social media. So I think it was an accident. I suspect they use custom software to compose the block, not Bitcoin Core's `getblocktemplate`. See also: https://twitter.com/provoost/status/1642182022176161795
Sjors Provoost
CC BY-SA 4.0
2023-04-05T18:30:34.447Z
2023-04-05T18:36:17.613Z
2023-04-05T18:36:17.613Z
Sjors Provoost
<p>The answer is 80,003. I arrived at the same number as Sjors by writing <a href="https://gist.github.com/vostrnad/ce761880282d881dacb5337af7d73e35" rel="nofollow noreferrer">a script</a> that goes through every transaction in a block and counts the sigops.</p>
<p>Here is a detailed breakdown:</p>
<ul>
<li>Bare multisig outputs: 71,200. There are 890 and each contributes 80 sigops.</li>
<li>P2PKH outputs: 3320. There are 830 and each contributes 4 sigops.</li>
<li>P2WPKH-in-P2SH inputs: 2219. Each contributes a single sigop.</li>
<li>P2WPKH inputs: 1751. Each contributes a single sigop.</li>
<li>P2WSH inputs: 1160.
<ul>
<li>28 inputs contribute a single sigop.</li>
<li>363 inputs contribute 2 sigops.</li>
<li>128 inputs contribute 3 sigops.</li>
<li>2 inputs contribute 4 sigops.</li>
<li>2 inputs contribute 7 sigops.</li>
</ul>
</li>
<li>P2WSH-in-P2SH inputs: 193.
<ul>
<li>12 inputs contribute a single sigop.</li>
<li>29 inputs contribute 2 sigops.</li>
<li>33 inputs contribute 3 sigops.</li>
<li>6 inputs contribute 4 sigops.</li>
</ul>
</li>
<li>P2SH inputs: 160.
<ul>
<li>1 input contributes 4 sigops.</li>
<li>13 inputs contribute 12 sigops.</li>
</ul>
</li>
</ul>

CC BY-SA 4.0
2023-04-06T07:15:14.443Z
Can you share the script? Either in your answer or via a Github gist?
Sjors Provoost
CC BY-SA 4.0
2023-04-06T09:15:49.660Z
It's a "script" in a sense that it's a JavaScript (actually TypeScript) file sitting in a larger project of mine using some of its internals as dependencies. If you'd like I can produce a minimal standalone repo.
Vojtěch Strnad
CC BY-SA 4.0
2023-04-06T11:39:50.443Z
Even without the dependencies it could be useful to see the script and the queries it makes, so I can compare with what I was doing.
Sjors Provoost
CC BY-SA 4.0
2023-04-06T12:53:44.200Z
Here you go: https://gist.github.com/vostrnad/ce761880282d881dacb5337af7d73e35
Vojtěch Strnad
CC BY-SA 4.0
2023-04-05T22:38:45.373Z
2023-04-06T17:17:30.100Z
2023-04-06T17:17:30.100Z
Vojtěch Strnad
<p>I was able to do a partial count, but I'm having a hard time counting it for P2SH and SegWit transactions.</p>
<p>Parse the block and store result:</p>
<pre><code>bitcoin-cli getblock 00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4 2 &gt; block.json
</code></pre>
<p>This lists transactions like so:</p>
<pre class="lang-json prettyprint-override"><code>    {
      &quot;txid&quot;: &quot;914b24cf50f4bc930c3a11123411031010f010563ed293f65f1ef8cb9bc1e950&quot;,
      ...
      &quot;vin&quot;: [
        {
          &quot;txid&quot;: &quot;cf3349976fedfe34502333310f753d91c16dccb3220d37d5f4c1a11b70eceda2&quot;,
          &quot;vout&quot;: 1,
          &quot;scriptSig&quot;: {
            &quot;asm&quot;: &quot;30440220253e9a3fc9cbae7833abc38ea29ae4f7672cb33591c227446c71b26a8199760a022071042cde824b3cfddc51888d49ac8f85062921e1430ee85885252e1a6758fc17[ALL] 02b704c5bac9ed2e23193f28f0a9e1108ff6164e713552fca936c9447566df1d66&quot;,
            &quot;hex&quot;: &quot;...&quot;
          },
          &quot;sequence&quot;: 4294967295
        }
      ],
      &quot;vout&quot;: [
        {
          &quot;value&quot;: 0.00071520,
          &quot;n&quot;: 1,
          &quot;scriptPubKey&quot;: {
            &quot;asm&quot;: &quot;OP_DUP OP_HASH160 8342c5f824ae0806236e746b951e68192c1b124f OP_EQUALVERIFY OP_CHECKSIG&quot;,

            &quot;address&quot;: &quot;1Cy3Wd2pArq359z9d3VYMUoBQBM1kkANCn&quot;,
            &quot;type&quot;: &quot;pubkeyhash&quot;
          }
        }
      ]
</code></pre>
<p>I can use <code>jq</code>, <code>grep</code>, <code>sed, </code>awk<code>and</code>wc -l` to count various stuff.</p>
<p><em>Legacy OP_CHECKSIG:</em></p>
<pre><code>cat block.json | jq -r '.tx[].vout[].scriptPubKey.asm' | grep OP_CHECKSIG | wc -l
830
</code></pre>
<p>Each <code>OP_CHECKSIG</code> used to count as 1 sigop before SegWit, and now counts as 4.</p>
<p>This yields 830 * 4 = 3,320 sigops</p>
<p><em>Bare multisig:</em></p>
<pre><code>cat block.json | jq -r '.tx[].vout[].scriptPubKey.asm' | grep OP_CHECKMULTISIG | wc -l
890
</code></pre>
<p>Each <code>OP_CHECKMULTISIG</code> counted as 20 sigops before SegWit, regardless of the number of public keys.</p>
<p>This yields 890 * 20 * 4 = 71,200 sigops.</p>
<p><em>P2SH:</em></p>
<p>Now it gets a bit more complicated. Because the P2SH script is only revealed when you <em>spend</em> it, we have to look at <code>scriptSig</code> on the inputs. Specifically we're looking for a <code>scriptSig</code> that's <em>not</em> one of these:</p>
<ol>
<li>A regular <code>OP_CHECKSIG</code> spend, which always starts with a DER encoded signature (<code>^304.*\[.*</code>) and ends with a pubkey (<code>0.*$</code>).</li>
<li>P2SH wrapped v0 SegWit: <code>^0014.*</code></li>
</ol>
<p>We also assume it contains at least one signature, which we recognise by the presence of a sighash marker like <code>[ALL]</code>. The script itself is the last thing pushed on the stack, which is what the <code>awk</code> command gives us. We then pipe that into <code>decodescript</code>.</p>
<pre><code>cat block.json | jq -r '.tx[].vin[].scriptSig.asm'| grep . | grep -v &quot;^304.*\[.* 0.*$&quot; | grep -v &quot;^0014.*&quot; | grep &quot;\[&quot; | awk 'NF&gt;1{print $NF}' | xargs -i -n 1 bitcoin-cli decodescript {} | jq '.asm'
</code></pre>
<p>The result is a very short list consisting of 13 2-of-3 multisig transactions and 1 OP_CHECKSIG.</p>
<p>So that yields (13 * 3 + 1) * 4 = 160 sigops</p>
<p><em>Pay to witness public key hash:</em></p>
<p>For this we look at the <code>txinwitness</code> field. Specifically we check if the last stack entry is a public key.</p>
<pre><code>cat block.json | jq -r '.tx[].vin[].txinwitness[-1]' | grep . | grep -v null | grep &quot;^0..*&quot; | wc -l
3981
</code></pre>
<p>This yields 3,981 sigops. <em>Update: Vojtěch found 2219 + 1751 = 3,970 in <a href="https://bitcoin.stackexchange.com/questions/117837/how-many-sigops-are-in-the-invalid-block-783426/117842#117842">his answer</a></em></p>
<p><em>Pay to witness script hash:</em></p>
<p>We again look at the last item on the witness stack, which we assume to be the script. We do the opposite of P2WPK and drop all matches with a public key. We also drop (taproot) Schnorr signatures which are 64 bytes plus optionally 1 for the SIGHASH. We also drop entries that start with 33 bytes (I think these are Tapleaf script hashes).</p>
<pre><code>cat block.json | jq -r '.tx[].vin[].txinwitness[-1]' | grep . | grep -v null | grep -v &quot;^0..*&quot; | sed -r '/^.{128,130}$/d' | sed -r '/^.{66}$/d' | xargs -i -n 1 bitcoin-cli decodescript {} | jq '.asm' | grep -o &quot;OP_CHECKSIG&quot; | wc -l
231
</code></pre>
<p>This yields 231 sigops.</p>
<p>We count multisig in a similar way. First we sort them by N and not which N's are used:</p>
<pre><code>| jq -r '.tx[].vin[].txinwitness[-1]' | grep . | grep -v null | grep -v &quot;^03.*&quot; | sed -r '/^.{128,130}$/d' | sed -r '/^.{66}$/d' | xargs -i -n 1 bitcoin-cli decodescript {} | jq '.asm' | grep &quot;OP_CHECKMULTISIG&quot; | rev | sort | rev
</code></pre>
<p>Then count the number of occurrences:</p>
<ol>
<li>2 times m-of-7: 2 * 7 = 14 sigops</li>
<li>1 time m-of-4: 4 sigops</li>
<li>102 times m-of-3: 306 sigops</li>
<li>385 times m-of-2: 770 sigops</li>
<li>List item</li>
<li>27 times 1-of-1: 27 sigops</li>
</ol>
<p>So that yields 1,159 sigops.</p>
<p><strong>Total</strong></p>
<p>3320 + 71200 + 160 + 3981 + 231 + 1159 = <strong>80,051</strong></p>

CC BY-SA 4.0
2023-04-05T18:06:38.923Z
2023-04-06T07:27:19.700Z
2023-04-06T07:27:19.700Z
Sjors Provoost
<p>On April 1st 2023 F2Pool mined block 00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4 (<a href="https://bitcointalk.org/index.php?topic=5447129.msg62015952#msg62015952" rel="noreferrer">full block</a>) which my node failed with <code>bad-blk-sigops</code>.</p>
<p>Bitcoin Core stops counting as soon as it reaches the 80,000 limit.</p>
<p>I had a hard time counting this, but how many sigops did this block contain?</p>

<bitcoin-core><block><block-validity><signature-operations>
How many sigops are in the invalid block 783426?
Sjors Provoost
# How many sigops are in the invalid block 783426?

(Asked by: username_0 on 2023-04-05)

On April 1st 2023 F2Pool mined block 00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4 ([full block](https://bitcointalk.org/index.php?topic=5447129.msg62015952#msg62015952)) which my node failed with `bad-blk-sigops`.

Bitcoin Core stops counting as soon as it reaches the 80,000 limit.

I had a hard time counting this, but how many sigops did this block contain?

**Tags:** bitcoin-core, block, block-validity, signature-operations


---

## 3 answers

### Answer by username_0 on 2023-04-05. Score: 7

The correct, but non gratifying, answer is 80,003.

I found it by changing `MAX_BLOCK_SIGOPS_COST`, recompiling and the using the `invalidateblock` and `reconsiderblock` RPC to recheck it.

The block fails validation with the sigops limit set to 80,002 as passes validation when it's set to 80,003.

> **Comments:**
> **username_1**: Was this an april fools joke by them? Is there any context as to why this occurred?  
> **username_2**: They probably miscounted the sigops on bare multisig transactions.  
> **username_0**: @username_1 that would be a $150K prank, and they already had a different April Fools joke on social media. So I think it was an accident. I suspect they use custom software to compose the block, not Bitcoin Core's `getblocktemplate`. See also: https://twitter.com/provoost/status/1642182022176161795  

---

### Answer by username_3 on 2023-04-05. Score: 7

The answer is 80,003. I arrived at the same number as Sjors by writing [a script](https://gist.github.com/vostrnad/ce761880282d881dacb5337af7d73e35) that goes through every transaction in a block and counts the sigops.

Here is a detailed breakdown:

* Bare multisig outputs: 71,200. There are 890 and each contributes 80 sigops.
* P2PKH outputs: 3320. There are 830 and each contributes 4 sigops.
* P2WPKH-in-P2SH inputs: 2219. Each contributes a single sigop.
* P2WPKH inputs: 1751. Each contributes a single sigop.
* P2WSH inputs: 1160.
  + 28 inputs contribute a single sigop.
  + 363 inputs contribute 2 sigops.
  + 128 inputs contribute 3 sigops.
  + 2 inputs contribute 4 sigops.
  + 2 inputs contribute 7 sigops.
* P2WSH-in-P2SH inputs: 193.
  + 12 inputs contribute a single sigop.
  + 29 inputs contribute 2 sigops.
  + 33 inputs contribute 3 sigops.
  + 6 inputs contribute 4 sigops.
* P2SH inputs: 160.
  + 1 input contributes 4 sigops.
  + 13 inputs contribute 12 sigops.

> **Comments:**
> **username_0**: Can you share the script? Either in your answer or via a Github gist?  
> **username_3**: It's a "script" in a sense that it's a JavaScript (actually TypeScript) file sitting in a larger project of mine using some of its internals as dependencies. If you'd like I can produce a minimal standalone repo.  
> **username_0**: Even without the dependencies it could be useful to see the script and the queries it makes, so I can compare with what I was doing.  
> **username_3**: Here you go: https://gist.github.com/vostrnad/ce761880282d881dacb5337af7d73e35  

---

### Answer by username_0 on 2023-04-05. Score: 3

I was able to do a partial count, but I'm having a hard time counting it for P2SH and SegWit transactions.
Parse the block and store result:
bitcoin-cli getblock 00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4 2 > block.json

This lists transactions like so:
    {
      "txid": "914b24cf50f4bc930c3a11123411031010f010563ed293f65f1ef8cb9bc1e950",
      ...
      "vin": [
        {
          "txid": "cf3349976fedfe34502333310f753d91c16dccb3220d37d5f4c1a11b70eceda2",
          "vout": 1,
          "scriptSig": {
            "asm": "30440220253e9a3fc9cbae7833abc38ea29ae4f7672cb33591c227446c71b26a8199760a022071042cde824b3cfddc51888d49ac8f85062921e1430ee85885252e1a6758fc17[ALL] 02b704c5bac9ed2e23193f28f0a9e1108ff6164e713552fca936c9447566df1d66",
            "hex": "..."
          },
          "sequence": 4294967295
        }
      ],
      "vout": [
        {
          "value": 0.00071520,
          "n": 1,
          "scriptPubKey": {
            "asm": "OP_DUP OP_HASH160 8342c5f824ae0806236e746b951e68192c1b124f OP_EQUALVERIFY OP_CHECKSIG",

            "address": "1Cy3Wd2pArq359z9d3VYMUoBQBM1kkANCn",
            "type": "pubkeyhash"
          }
        }
      ]

I can use jq, grep, sed, awkandwc -l` to count various stuff.
Legacy OP_CHECKSIG:
cat block.json | jq -r '.tx[].vout[].scriptPubKey.asm' | grep OP_CHECKSIG | wc -l
830

Each OP_CHECKSIG used to count as 1 sigop before SegWit, and now counts as 4.
This yields 830 * 4 = 3,320 sigops
Bare multisig:
cat block.json | jq -r '.tx[].vout[].scriptPubKey.asm' | grep OP_CHECKMULTISIG | wc -l
890

Each OP_CHECKMULTISIG counted as 20 sigops before SegWit, regardless of the number of public keys.
This yields 890 * 20 * 4 = 71,200 sigops.
P2SH:
Now it gets a bit more complicated. Because the P2SH script is only revealed when you spend it, we have to look at scriptSig on the inputs. Specifically we're looking for a scriptSig that's not one of these:

A regular OP_CHECKSIG spend, which always starts with a DER encoded signature (^304.*\[.*) and ends with a pubkey (0.*$).
P2SH wrapped v0 SegWit: ^0014.*

We also assume it contains at least one signature, which we recognise by the presence of a sighash marker like [ALL]. The script itself is the last thing pushed on the stack, which is what the awk command gives us. We then pipe that into decodescript.
cat block.json | jq -r '.tx[].vin[].scriptSig.asm'| grep . | grep -v "^304.*\[.* 0.*$" | grep -v "^0014.*" | grep "\[" | awk 'NF>1{print $NF}' | xargs -i -n 1 bitcoin-cli decodescript {} | jq '.asm'

The result is a very short list consisting of 13 2-of-3 multisig transactions and 1 OP_CHECKSIG.
So that yields (13 * 3 + 1) * 4 = 160 sigops
Pay to witness public key hash:
For this we look at the txinwitness field. Specifically we check if the last stack entry is a public key.
cat block.json | jq -r '.tx[].vin[].txinwitness[-1]' | grep . | grep -v null | grep "^0..*" | wc -l
3981

This yields 3,981 sigops. Update: Vojtěch found 2219 + 1751 = 3,970 in his answer
Pay to witness script hash:
We again look at the last item on the witness stack, which we assume to be the script. We do the opposite of P2WPK and drop all matches with a public key. We also drop (taproot) Schnorr signatures which are 64 bytes plus optionally 1 for the SIGHASH. We also drop entries that start with 33 bytes (I think these are Tapleaf script hashes).
cat block.json | jq -r '.tx[].vin[].txinwitness[-1]' | grep . | grep -v null | grep -v "^0..*" | sed -r '/^.{128,130}$/d' | sed -r '/^.{66}$/d' | xargs -i -n 1 bitcoin-cli decodescript {} | jq '.asm' | grep -o "OP_CHECKSIG" | wc -l
231

This yields 231 sigops.
We count multisig in a similar way. First we sort them by N and not which N's are used:
| jq -r '.tx[].vin[].txinwitness[-1]' | grep . | grep -v null | grep -v "^03.*" | sed -r '/^.{128,130}$/d' | sed -r '/^.{66}$/d' | xargs -i -n 1 bitcoin-cli decodescript {} | jq '.asm' | grep "OP_CHECKMULTISIG" | rev | sort | rev

Then count the number of occurrences:

2 times m-of-7: 2 * 7 = 14 sigops
1 time m-of-4: 4 sigops
102 times m-of-3: 306 sigops
385 times m-of-2: 770 sigops
List item
27 times 1-of-1: 27 sigops

So that yields 1,159 sigops.
Total
3320 + 71200 + 160 + 3981 + 231 + 1159 = 80,051


---

