-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Remove template matching and pseudo opcodes #13194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
OP_PUBKEYS = 0xfb, | ||
OP_PUBKEYHASH = 0xfd, | ||
OP_PUBKEY = 0xfe, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice to get rid of these fake opcodes here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK modulo nits and modulo this kind of unrelated thing I don't understand.
Perhaps a stupid question but, in https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.h#L59 why are there 3 ways to indicate non-compressed and 2 ways to indicate compressed? shouldn't one for each be enough? also, should using an enum or macros or constants be more clear?
src/script/standard.cpp
Outdated
CScript::const_iterator it = script.begin(); | ||
if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false; | ||
|
||
if (!script.GetOp(it, opcode, data) || (opcode != OP_0 && (opcode < OP_1 || opcode > OP_16))) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Souldn't this return false if it's op_0 too? or are 0 required sigs multisigs valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
key count can be 0, I think. The only checks in the interpreter I see are for negative numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to stick to the original logic as close as possible; optimizations / other tweaks can happen later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @sipa here. One step at a time is easier to review.
src/script/standard.cpp
Outdated
} | ||
if (opcode != OP_0 && (opcode < OP_1 || opcode > OP_16)) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, shouldn't OP_0 be invalid here too?
If 0 is allowed, why not just opcode < OP_0 || opcode > OP_16
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OP_0 is 0, OP_1 is 81. They aren't continuous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An isOP_N(opcode) helper function would make this (and the expression above) slightly better readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added an IsSmallInteger
function for this (which would be distinct from IsOP_N
by not accepting OP_1NEGATE
).
src/script/standard.cpp
Outdated
mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); | ||
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG) { | ||
pubkey = valtype(script.begin() + 1, script.begin() + 34); | ||
return CPubKey::ValidSize(pubkey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant check here? We know the size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CpubKey::ValidSize
checks the data-dependent size (depending on what the first byte is).
src/script/standard.cpp
Outdated
} | ||
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG) { | ||
pubkey = valtype(script.begin() + 1, script.begin() + 66); | ||
return CPubKey::ValidSize(pubkey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant check here? We know the size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could just use proper constants in the lines above for more belt and suspenders.
@jtimon Hybrid public keys (the 0x06 and 0x07 ones) are stupid, but were supported by OpenSSL, and because of that they're supported in Bitcoin. Nothing we can do about that. |
light tACK |
src/script/standard.cpp
Outdated
|
||
if (!script.GetOp(it, opcode, data) || (opcode != OP_0 && (opcode < OP_1 || opcode > OP_16))) return false; | ||
required = CScript::DecodeOP_N(opcode); | ||
while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it check the opcodes here?
Oh I guess not, all the push opcodes valid here will return non-empty data, and CPubKey::ValidSize
rejects empty data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed (that's also what the old code does).
688d796
to
2fc4fdd
Compare
src/script/standard.cpp
Outdated
pubkey = valtype(script.begin() + 1, script.begin() + 34); | ||
return CPubKey::ValidSize(pubkey); | ||
} | ||
if (script.size() == 67 && script[0] == 65 && script[66] == OP_CHECKSIG) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CPubKey::PUBLIC_KEY_SIZE == 65, would add clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/script/standard.cpp
Outdated
{ | ||
// Standard tx, sender provides pubkey, receiver adds signature | ||
mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); | ||
if (script.size() == 35 && script[0] == 33 && script[34] == OP_CHECKSIG) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CPubKey::COMPRESSED_PUBLIC_KEY_SIZE == 33, would add clarity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incidentally, I have #12461 to make these references more succinct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/script/standard.cpp
Outdated
return false; | ||
} | ||
|
||
static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See also IsToKeyID
in compressor.cpp, which looks equivalent.
Could split this up as CScript::IsPayToPubkeyHash
, and do the unpacking in Solver
, ala IsPayToScriptHash
. Would make the case handling more consistent in Solver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not merging with the versions in compressor - they may end up living separate lives as the standard templates change.
@@ -35,22 +35,55 @@ const char* GetTxnOutputType(txnouttype t) | |||
return nullptr; | |||
} | |||
|
|||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet) | |||
static bool MatchPayToPubkey(const CScript& script, valtype& pubkey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See also IsToPubKey
in compressor, which looks equivalent.
Concept ACK! Much simpler way to handle these 3 cases. |
Nice! |
2fc4fdd
to
fa1f642
Compare
ACK. |
src/script/standard.cpp
Outdated
} | ||
if (!IsSmallInteger(opcode)) return false; | ||
unsigned int keys = CScript::DecodeOP_N(opcode); | ||
if (pubkeys.size() != keys || required == 0 || keys < required) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this required == 0
check could be an earlier return
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
src/script/standard.cpp
Outdated
typeRet = TX_MULTISIG; | ||
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); | ||
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); | ||
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe worth noting these casts are safe due to small integer limits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
utACK fa1f642 |
fa1f642
to
89736a9
Compare
re-utACK 89736a9 just addresses comments above |
src/script/standard.cpp
Outdated
if (!IsSmallInteger(opcode)) return false; | ||
unsigned int keys = CScript::DecodeOP_N(opcode); | ||
if (pubkeys.size() != keys || keys < required) return false; | ||
if (it + 1 != script.end()) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
return it + 1 == script.end();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
utACK 89736a9. |
89736a9
to
c639f5a
Compare
src/script/standard.cpp
Outdated
{ | ||
// Standard tx, sender provides pubkey, receiver adds signature | ||
mTemplates.insert(std::make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); | ||
if (script.size() == CPubKey::PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::PUBLIC_KEY_SIZE && script[CPubKey::PUBLIC_KEY_SIZE + 1] == OP_CHECKSIG) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about script.back() == OP_CHECKSIG
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/script/standard.cpp
Outdated
/** Test for "small integer" script opcodes - OP_0 through OP_16. */ | ||
static constexpr bool IsSmallInteger(opcodetype opcode) | ||
{ | ||
return opcode == OP_0 || (opcode >= OP_1 && opcode <= OP_16); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you remove opcode == OP_0
here, you can remove if (required == 0) return false;
below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack.
c639f5a
to
c814e2e
Compare
This change has the side effect that invalid pubkeys (with correct size of 33 or 65) in bare multisig are now non-standard (see #14104) |
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
Bitcoin script PRs 1 Cherry-picked from the following upstream PRs: - bitcoin/bitcoin#6335 - bitcoin/bitcoin#6424 - bitcoin/bitcoin#11058 - bitcoin/bitcoin#12460 - bitcoin/bitcoin#13194 Part of #2074.
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are more easy to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Committer's note: This is a port of bitcoin/bitcoin/pull/13194 tha has been adapted to work with BU. The main differencies are related to the fact that we expose to the user two other kind of transaction use cases: TX_LABELPUBLIC, TX_CLTV.
5d96c91 add missing policy.cpp file to cmake (furszy) 2d0783d Standard Solver(): Include cold staking template matching. (furszy) b7fe4c0 Remove template matching and pseudo opcodes (furszy) fe31b31 Assert CPubKey::ValidLength to the pubkey's header-relevent size (Ben Woosley) 2f6b249 Make TX_SCRIPTHASH clear vSolutionsRet first (Peter Todd) 45e5102 Policy: MOVEONLY: 3 functions to policy (furszy) 2c7da7f Policy: MOVEONLY: Create policy/policy.h with some constants (furszy) Pull request description: Coming from the following PRs (with small customizations for our features): * bitcoin#6335 * bitcoin#6424 * bitcoin#12460 * bitcoin#13194 ACKs for top commit: random-zebra: Looking good. ACK 5d96c91 Fuzzbawls: ACK 5d96c91 Tree-SHA512: b3e7479864e16942682b9bc19f432b2a657561647eeadf0ef1285651feb05875d295ff530582ebbc8edacaf3c7d3888249513b4a93d871c2d6c2e1b157ace8c8
c814e2e Remove template matching and pseudo opcodes (Pieter Wuille) Pull request description: The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Tree-SHA512: 643b409c5c36821519f613a43efd399af0ec99b6131f35cd4024decfb2d483d719e0e921cd088bc9832a7ac797cb4a6b1158b8574c82f7fbebb75f1b31b359df
c814e2e Remove template matching and pseudo opcodes (Pieter Wuille) Pull request description: The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Tree-SHA512: 643b409c5c36821519f613a43efd399af0ec99b6131f35cd4024decfb2d483d719e0e921cd088bc9832a7ac797cb4a6b1158b8574c82f7fbebb75f1b31b359df
c814e2e Remove template matching and pseudo opcodes (Pieter Wuille) Pull request description: The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Tree-SHA512: 643b409c5c36821519f613a43efd399af0ec99b6131f35cd4024decfb2d483d719e0e921cd088bc9832a7ac797cb4a6b1158b8574c82f7fbebb75f1b31b359df
c814e2e Remove template matching and pseudo opcodes (Pieter Wuille) Pull request description: The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Tree-SHA512: 643b409c5c36821519f613a43efd399af0ec99b6131f35cd4024decfb2d483d719e0e921cd088bc9832a7ac797cb4a6b1158b8574c82f7fbebb75f1b31b359df
c814e2e Remove template matching and pseudo opcodes (Pieter Wuille) Pull request description: The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one. The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement. As a side-effect, it also gets rid of the pseudo opcodes hack. Tree-SHA512: 643b409c5c36821519f613a43efd399af0ec99b6131f35cd4024decfb2d483d719e0e921cd088bc9832a7ac797cb4a6b1158b8574c82f7fbebb75f1b31b359df
The current code contains a rather complex script template matching engine, which is only used for 3 particular script types (P2PK, P2PKH, multisig). The first two of these are trivial to match for otherwise, and a specialized matcher for multisig is both more compact and more efficient than a generic one.
The goal is being more flexible, so that for example larger standard multisigs inside SegWit outputs are easier to implement.
As a side-effect, it also gets rid of the pseudo opcodes hack.