Merge pull request #36 from jc23424/segwit-lock

lock segwit utxos
This commit is contained in:
BlueSilver22 2018-02-04 09:28:00 -06:00 committed by GitHub
commit cf40f0fb30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 2 deletions

View File

@ -90,7 +90,7 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
* Where R and S are not negative (their first byte has its highest bit not set), and not
* excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
* in which case a single 0 byte is necessary and even required).
*
*
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
*
* This function is consensus-critical since BIP66.
@ -130,7 +130,7 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
// Verify that the length of the signature matches the sum of the length
// of the elements.
if ((size_t)(lenR + lenS + 7) != sig.size()) return false;
// Check whether the R element is an integer.
if (sig[2] != 0x02) return false;
@ -1190,6 +1190,13 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
flags |= SCRIPT_VERIFY_STRICTENC;
}
// Do not allow spends of P2WPKH-P2SH and P2WSH-P2SH UTXOs
// To a non-segwit aware node these outputs are trivially spendable
// Detect them here and evaluate to false
// TODO: remove this block post-segwit implementation
if( scriptPubKey.IsPayToWitnessPubKeyHash() || scriptPubKey.IsPayToWitnessScriptHash())
return set_error(serror, SCRIPT_ERR_SEGWIT_LOCKED);
vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, serror))
// serror is set
@ -1223,6 +1230,10 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stack);
// See TODO above
if(pubKey2.IsPayToWitnessPubKeyHash() || pubKey2.IsPayToWitnessScriptHash())
return set_error(serror, SCRIPT_ERR_SEGWIT_LOCKED);
if (!EvalScript(stack, pubKey2, flags, checker, serror))
// serror is set
return false;

View File

@ -220,6 +220,22 @@ bool CScript::IsPayToScriptHash() const
this->at(22) == OP_EQUAL);
}
bool CScript::IsPayToWitnessScriptHash() const
{
// Extra-fast test for pay-to-witness-script-hash CScripts:
return (this->size() == 34 &&
(*this)[0] == OP_0 &&
(*this)[1] == 0x20);
}
bool CScript::IsPayToWitnessPubKeyHash() const
{
// Extra-fast test for pay-to-witness-pubkey-hash CScripts:
return (this->size() == 22 &&
(*this)[0] == OP_0 &&
(*this)[1] == 0x14);
}
bool CScript::IsPushOnly() const
{
const_iterator pc = begin();

View File

@ -566,6 +566,9 @@ public:
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
bool IsPushOnly() const;
bool IsPayToWitnessScriptHash() const;
bool IsPayToWitnessPubKeyHash() const;
/**
* Returns whether the script is guaranteed to fail at execution,
* regardless of the initial stack. This allows outputs to be pruned

View File

@ -67,6 +67,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "NOPx reserved for soft-fork upgrades";
case SCRIPT_ERR_PUBKEYTYPE:
return "Public key is neither compressed or uncompressed";
case SCRIPT_ERR_SEGWIT_LOCKED:
return "Segwit fork outputs are currently locked pending full implementation";
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;

View File

@ -55,6 +55,9 @@ typedef enum ScriptError_t
/* SIGHASH_FORKID */
SCRIPT_ERR_ILLEGAL_FORKID,
/* SEGWIT LOCKED */
SCRIPT_ERR_SEGWIT_LOCKED,
SCRIPT_ERR_ERROR_COUNT
} ScriptError;

View File

@ -124,6 +124,41 @@ BOOST_AUTO_TEST_CASE(sign)
}
}
BOOST_AUTO_TEST_CASE(segwitlock)
{
ScriptError err;
// any scriptSig will do here
CScript scriptSig;
scriptSig << ToByteVector(uint256());
uint160 hash20;
CScript p2wpkh;
p2wpkh << OP_0 << ToByteVector(hash20);
BOOST_CHECK(!Verify(scriptSig, p2wpkh, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
CScript p2shp2wpkh = GetScriptForDestination(CScriptID(p2wpkh));
CScript p2shp2wpkhsig = scriptSig;
p2shp2wpkhsig << Serialize(p2wpkh);
BOOST_CHECK(!Verify(p2shp2wpkhsig, p2shp2wpkh, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
uint256 hash32;
CScript p2wsh;
p2wsh << OP_0 << ToByteVector(hash32);
BOOST_CHECK(!Verify(scriptSig, p2wsh, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
CScript p2shp2wsh = GetScriptForDestination(CScriptID(p2wsh));
CScript p2shp2wshsig = scriptSig;
p2shp2wshsig << Serialize(p2wsh);
BOOST_CHECK(!Verify(p2shp2wshsig, p2shp2wsh, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
}
BOOST_AUTO_TEST_CASE(norecurse)
{
ScriptError err;
@ -216,6 +251,15 @@ BOOST_AUTO_TEST_CASE(is)
p2sh << OP_HASH160 << ToByteVector(dummy) << OP_EQUAL;
BOOST_CHECK(p2sh.IsPayToScriptHash());
CScript p2wpkh;
p2wpkh << OP_0 << ToByteVector(dummy);
BOOST_CHECK(p2wpkh.IsPayToWitnessPubKeyHash());
uint256 dummy256;
CScript p2wsh;
p2wsh << OP_0 << ToByteVector(dummy256);
BOOST_CHECK(p2wsh.IsPayToWitnessScriptHash());
// Not considered pay-to-script-hash if using one of the OP_PUSHDATA opcodes:
static const unsigned char direct[] = { OP_HASH160, 20, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, OP_EQUAL };
BOOST_CHECK(CScript(direct, direct+sizeof(direct)).IsPayToScriptHash());