Skip to content

Commit bde1fc1

Browse files
committed
script: short-circuit GetLegacySigOpCount for known scripts
> build/bin/bench_bitcoin -filter='SigOpsBlockBench' --min-time=1000 | ns/sigops | sigops/s | err% | ins/sigops | cyc/sigops | IPC | bra/sigops | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 58.43 | 17,115,813.09 | 0.1% | 354.20 | 209.79 | 1.688 | 89.46 | 2.8% | 10.83 | `SigOpsBlockBench`
1 parent 04c3e00 commit bde1fc1

File tree

3 files changed

+34
-23
lines changed

3 files changed

+34
-23
lines changed

src/script/script.cpp

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -186,24 +186,35 @@ static constexpr std::pair<unsigned int, unsigned int> DecodePushData(
186186

187187
unsigned int CScript::GetLegacySigOpCount(bool fAccurate) const
188188
{
189-
unsigned int n = 0;
190-
const_iterator pc = begin();
191-
opcodetype lastOpcode = OP_INVALIDOPCODE;
192-
while (pc < end())
193-
{
194-
opcodetype opcode;
195-
if (!GetOp(pc, opcode))
196-
break;
197-
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
198-
n++;
199-
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
200-
{
201-
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
202-
n += DecodeOP_N(lastOpcode);
203-
else
189+
switch (size()) {
190+
case 0: return 0;
191+
case 4: if (IsPayToAnchor()) return 0; else break;
192+
case 22: if (IsPayToWitnessPubKeyHash()) return 0; else break;
193+
case 23: if (IsPayToScriptHash()) return 0; else break;
194+
case 25: if (IsPayToPubKeyHash()) return 1; else break;
195+
case 34: if (IsPayToTaproot() || IsPayToWitnessScriptHash()) return 0; else break;
196+
case 35: if (IsCompressedPayToPubKey()) return 1; else break;
197+
case 67: if (IsUncompressedPayToPubKey()) return 1; else break;
198+
}
199+
200+
unsigned int n{0};
201+
opcodetype prev{OP_INVALIDOPCODE};
202+
for (const_iterator pc{begin()}, pc_end{end()}; pc < pc_end;) {
203+
const auto opcode{static_cast<opcodetype>(*pc++)};
204+
if (opcode <= OP_PUSHDATA4) {
205+
auto [size_bytes, data_bytes]{DecodePushData(opcode, pc, pc_end - pc)};
206+
if (data_bytes == DECODE_ERR) break;
207+
pc += size_bytes + data_bytes;
208+
} else if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY) {
209+
++n;
210+
} else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY) {
211+
if (fAccurate && IsSmallInteger(prev)) {
212+
n += DecodeOP_N(prev);
213+
} else {
204214
n += MAX_PUBKEYS_PER_MULTISIG;
215+
}
205216
}
206-
lastOpcode = opcode;
217+
if (fAccurate) prev = opcode;
207218
}
208219
return n;
209220
}

src/script/script.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,12 @@ class CScript : public CScriptBase
535535
return (opcodetype)(OP_1+n-1);
536536
}
537537

538+
/** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
539+
static constexpr bool IsSmallInteger(opcodetype opcode)
540+
{
541+
return opcode >= OP_1 && opcode <= OP_16;
542+
}
543+
538544
/**
539545
* Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
540546
* as 20 sigops. With pay-to-script-hash, that changed:

src/script/solver.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,12 @@ static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
5555
return false;
5656
}
5757

58-
/** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
59-
static constexpr bool IsSmallInteger(opcodetype opcode)
60-
{
61-
return opcode >= OP_1 && opcode <= OP_16;
62-
}
63-
6458
/** Retrieve a minimally-encoded number in range [min,max] from an (opcode, data) pair,
6559
* whether it's OP_n or through a push. */
6660
static std::optional<int> GetScriptNumber(opcodetype opcode, valtype data, int min, int max)
6761
{
6862
int count;
69-
if (IsSmallInteger(opcode)) {
63+
if (CScript::IsSmallInteger(opcode)) {
7064
count = CScript::DecodeOP_N(opcode);
7165
} else if (IsPushdataOp(opcode)) {
7266
if (!CheckMinimalPush(data, opcode)) return {};

0 commit comments

Comments
 (0)