BIP141: Witness program

This commit is contained in:
Pieter Wuille
2015-11-08 01:16:45 +01:00
parent 7030d9eb47
commit 449f9b8deb
16 changed files with 201 additions and 37 deletions

View File

@@ -1239,8 +1239,67 @@ bool TransactionSignatureChecker::CheckSequence(const CScriptNum& nSequence) con
return true;
}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
vector<vector<unsigned char> > stack;
CScript scriptPubKey;
if (witversion == 0) {
if (program.size() == 32) {
// Version 0 segregated witness program: SHA256(CScript) inside the program, CScript + inputs in witness
if (witness.stack.size() == 0) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WITNESS_EMPTY);
}
scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 1);
uint256 hashScriptPubKey;
CSHA256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
if (memcmp(hashScriptPubKey.begin(), &program[0], 32)) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
}
} else if (program.size() == 20) {
// Special case for pay-to-pubkeyhash; signature + pubkey in witness
if (witness.stack.size() != 2) {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); // 2 items in witness
}
scriptPubKey << OP_DUP << OP_HASH160 << program << OP_EQUALVERIFY << OP_CHECKSIG;
stack = witness.stack;
} else {
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
}
} else if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) {
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
} else {
// Higher version witness scripts return true for future softfork compatibility
return set_success(serror);
}
// Disallow stack item size > MAX_SCRIPT_ELEMENT_SIZE in witness stack
for (unsigned int i = 0; i < stack.size(); i++) {
if (stack.at(i).size() > MAX_SCRIPT_ELEMENT_SIZE)
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
}
if (!EvalScript(stack, scriptPubKey, flags, checker, serror)) {
return false;
}
// Scripts inside witness implicitly require cleanstack behaviour
if (stack.size() != 1)
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
if (!CastToBool(stack.back()))
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
return true;
}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
static const CScriptWitness emptyWitness;
if (witness == NULL) {
witness = &emptyWitness;
}
bool hadWitness = false;
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
@@ -1261,6 +1320,25 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
if (CastToBool(stack.back()) == false)
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
// Bare witness programs
int witnessversion;
std::vector<unsigned char> witnessprogram;
if (flags & SCRIPT_VERIFY_WITNESS) {
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
hadWitness = true;
if (scriptSig.size() != 0) {
// The scriptSig must be _exactly_ CScript(), otherwise we reintroduce malleability.
return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED);
}
if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) {
return false;
}
// Bypass the cleanstack check at the end. The actual stack is obviously not clean
// for witness programs.
stack.resize(1);
}
}
// Additional validation for spend-to-script-hash transactions:
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
{
@@ -1287,19 +1365,48 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
if (!CastToBool(stack.back()))
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
// P2SH witness program
if (flags & SCRIPT_VERIFY_WITNESS) {
if (pubKey2.IsWitnessProgram(witnessversion, witnessprogram)) {
hadWitness = true;
if (scriptSig != CScript() << std::vector<unsigned char>(pubKey2.begin(), pubKey2.end())) {
// The scriptSig must be _exactly_ a single push of the redeemScript. Otherwise we
// reintroduce malleability.
return set_error(serror, SCRIPT_ERR_WITNESS_MALLEATED_P2SH);
}
if (!VerifyWitnessProgram(*witness, witnessversion, witnessprogram, flags, checker, serror)) {
return false;
}
// Bypass the cleanstack check at the end. The actual stack is obviously not clean
// for witness programs.
stack.resize(1);
}
}
}
// The CLEANSTACK check is only performed after potential P2SH evaluation,
// as the non-P2SH evaluation of a P2SH script will obviously not result in
// a clean stack (the P2SH inputs remain).
// a clean stack (the P2SH inputs remain). The same holds for witness evaluation.
if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) {
// Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK
// would be possible, which is not a softfork (and P2SH should be one).
assert((flags & SCRIPT_VERIFY_P2SH) != 0);
assert((flags & SCRIPT_VERIFY_WITNESS) != 0);
if (stack.size() != 1) {
return set_error(serror, SCRIPT_ERR_CLEANSTACK);
}
}
if (flags & SCRIPT_VERIFY_WITNESS) {
// We can't check for correct unexpected witness data if P2SH was off, so require
// that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be
// possible, which is not a softfork.
assert((flags & SCRIPT_VERIFY_P2SH) != 0);
if (!hadWitness && !witness->IsNull()) {
return set_error(serror, SCRIPT_ERR_WITNESS_UNEXPECTED);
}
}
return set_success(serror);
}