Implement replay protection using FORKID scheme

modeled off of the BCH and BTG implementations
with a few tweaks (forkid signing is ignored below fork height)
moved joinsplit signature verifications into ConnectBlock()
as it has now become height dependent
This commit is contained in:
jc 2018-02-18 20:12:57 -05:00
parent d6dc745a5f
commit ac0231d2ba
No known key found for this signature in database
GPG Key ID: E87FC0C8A375F3CF
19 changed files with 2312 additions and 2319 deletions

View File

@ -82,11 +82,11 @@ int64_t forkCBPerBlock = FORK_COINBASE_PER_BLOCK;
std::string GetUTXOFileName(int nHeight) std::string GetUTXOFileName(int nHeight)
{ {
boost::filesystem::path utxo_path(forkUtxoPath); boost::filesystem::path utxo_path(forkUtxoPath);
if (utxo_path.empty() || !utxo_path.has_filename()) if (utxo_path.empty() || !utxo_path.has_filename())
{ {
LogPrintf("GetUTXOFileName(): UTXO path is not specified, add utxo-path=<path-to-utxop-files> to your btcprivate.conf and restart"); LogPrintf("GetUTXOFileName(): UTXO path is not specified, add utxo-path=<path-to-utxop-files> to your btcprivate.conf and restart");
return ""; return "";
} }
std::stringstream ss; std::stringstream ss;
@ -1019,30 +1019,39 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
if (txin.prevout.IsNull()) if (txin.prevout.IsNull())
return state.DoS(10, error("CheckTransaction(): prevout is null"), return state.DoS(10, error("CheckTransaction(): prevout is null"),
REJECT_INVALID, "bad-txns-prevout-null"); REJECT_INVALID, "bad-txns-prevout-null");
}
if (tx.vjoinsplit.size() > 0) { return true;
// Empty output script. }
CScript scriptCode;
uint256 dataToBeSigned;
try {
dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL|SIGHASH_FORKID);
} catch (std::logic_error ex) {
return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
REJECT_INVALID, "error-computing-signature-hash");
}
BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); bool CheckJoinSplitSigs(const CTransaction& tx, CValidationState &state, const unsigned int flags)
{
if (tx.vjoinsplit.size() > 0) {
// Empty output script.
CScript scriptCode;
uint256 dataToBeSigned;
int hashtype = SIGHASH_ALL;
if(flags & SCRIPT_VERIFY_FORKID)
hashtype |= SIGHASH_FORKID;
// We rely on libsodium to check that the signature is canonical. try {
// https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, hashtype);
if (crypto_sign_verify_detached(&tx.joinSplitSig[0], } catch (std::logic_error ex) {
dataToBeSigned.begin(), 32, return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
tx.joinSplitPubKey.begin() REJECT_INVALID, "error-computing-signature-hash");
) != 0) { }
return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32);
REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
} // We rely on libsodium to check that the signature is canonical.
// https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0
if (crypto_sign_verify_detached(&tx.joinSplitSig[0],
dataToBeSigned.begin(), 32,
tx.joinSplitPubKey.begin()
) != 0) {
return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"),
REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
} }
} }
@ -1793,6 +1802,9 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
} }
} }
if(!CheckJoinSplitSigs(tx, state, flags))
return false;
} }
} }
@ -1937,7 +1949,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
// Check that all outputs are available and match the outputs in the block itself // Check that all outputs are available and match the outputs in the block itself
// exactly. // exactly.
{ {
CCoinsModifier outs = view.ModifyCoins(hash); CCoinsModifier outs = view.ModifyCoins(hash);
outs->ClearUnspendable(); outs->ClearUnspendable();
@ -2134,6 +2146,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true; return true;
} }
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
if(isForkEnabled(pindex->nHeight))
flags |= SCRIPT_VERIFY_FORKID;
// Do not allow blocks that contain transactions which 'overwrite' older transactions, // Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent. // unless those are already completely spent.
BOOST_FOREACH(const CTransaction& tx, block.vtx) { BOOST_FOREACH(const CTransaction& tx, block.vtx) {
@ -2143,8 +2159,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
REJECT_INVALID, "bad-txns-BIP30"); REJECT_INVALID, "bad-txns-BIP30");
} }
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
// DERSIG (BIP66) is also always enforced, but does not have a flag. // DERSIG (BIP66) is also always enforced, but does not have a flag.
CBlockUndo blockundo; CBlockUndo blockundo;
@ -3337,7 +3351,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
} }
unsigned char* pks = (unsigned char*)pubKeyScript.get(); unsigned char* pks = (unsigned char*)pubKeyScript.get();
CScript script = CScript(pks, pks+pbsize); CScript script = CScript(pks, pks+pbsize);
txFromFile.push_back(make_pair(amount, script)); txFromFile.push_back(make_pair(amount, script));
if (!if_utxo.read(&term, 1)) { if (!if_utxo.read(&term, 1)) {
@ -3359,7 +3373,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
REJECT_INVALID, "bad-fork-block"); REJECT_INVALID, "bad-fork-block");
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex); setDirtyBlockIndex.insert(pindex);
return false; return false;
} }
int txid = 0; int txid = 0;
@ -3477,7 +3491,7 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
// NOTE: CheckBlockHeader is called by CheckBlock // NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev)) if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false; return false;
if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot)) if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot))
return false; return false;
if (!ContextualCheckBlock(block, state, pindexPrev)) if (!ContextualCheckBlock(block, state, pindexPrev))

View File

@ -162,11 +162,11 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */ /** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals); void UnregisterNodeSignals(CNodeSignals& nodeSignals);
/** /**
* Process an incoming block. This only returns after the best known valid * Process an incoming block. This only returns after the best known valid
* block is made active. Note that it does not, however, guarantee that the * block is made active. Note that it does not, however, guarantee that the
* specific block passed to it has been checked for validity! * specific block passed to it has been checked for validity!
* *
* @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation. * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process. * @param[in] pblock The block we want to process.
@ -295,7 +295,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
/** /**
* Check transaction inputs, and make sure any * Check transaction inputs, and make sure any
* pay-to-script-hash transactions are evaluating IsStandard scripts * pay-to-script-hash transactions are evaluating IsStandard scripts
* *
* Why bother? To avoid denial-of-service attacks; an attacker * Why bother? To avoid denial-of-service attacks; an attacker
* can submit a standard HASH... OP_EQUAL transaction, * can submit a standard HASH... OP_EQUAL transaction,
* which will get accepted into blocks. The redemption * which will get accepted into blocks. The redemption
@ -304,14 +304,14 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
* DUP CHECKSIG DROP ... repeated 100 times... OP_1 * DUP CHECKSIG DROP ... repeated 100 times... OP_1
*/ */
/** /**
* Check for standard transaction types * Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending * @param[in] mapInputs Map of previous transactions that have outputs we're spending
* @return True if all inputs (scriptSigs) use only standard transaction forms * @return True if all inputs (scriptSigs) use only standard transaction forms
*/ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
/** /**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way * Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent * @return number of sigops this transaction's outputs will produce when spent
* @see CTransaction::FetchInputs * @see CTransaction::FetchInputs
@ -320,7 +320,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx);
/** /**
* Count ECDSA signature operations in pay-to-script-hash inputs. * Count ECDSA signature operations in pay-to-script-hash inputs.
* *
* @param[in] mapInputs Map of previous transactions that have outputs we're spending * @param[in] mapInputs Map of previous transactions that have outputs we're spending
* @return maximum number of sigops required to validate this transaction's inputs * @return maximum number of sigops required to validate this transaction's inputs
* @see CTransaction::FetchInputs * @see CTransaction::FetchInputs
@ -343,6 +343,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier); bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state); bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
bool CheckJoinSplitSigs(const CTransaction& tx, CValidationState &state, const unsigned int flags);
/** Check for standard transaction types /** Check for standard transaction types
* @return True if all outputs (scriptPubKeys) use only standard transaction forms * @return True if all outputs (scriptPubKeys) use only standard transaction forms
@ -364,9 +365,9 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
*/ */
bool CheckFinalTx(const CTransaction &tx, int flags = -1); bool CheckFinalTx(const CTransaction &tx, int flags = -1);
/** /**
* Closure representing one script verification * Closure representing one script verification
* Note that this stores references to the spending transaction * Note that this stores references to the spending transaction
*/ */
class CScriptCheck class CScriptCheck
{ {
@ -596,7 +597,7 @@ inline bool isNextTipInForkRange()
} }
inline uint64_t bytes2uint64(char *array) inline uint64_t bytes2uint64(char *array)
{ {
uint64_t x = uint64_t x =
static_cast<uint64_t>(array[0]) & 0x00000000000000ff | static_cast<uint64_t>(array[0]) & 0x00000000000000ff |
static_cast<uint64_t>(array[1]) << 8 & 0x000000000000ff00 | static_cast<uint64_t>(array[1]) << 8 & 0x000000000000ff00 |
static_cast<uint64_t>(array[2]) << 16 & 0x0000000000ff0000 | static_cast<uint64_t>(array[2]) << 16 & 0x0000000000ff0000 |
@ -609,4 +610,9 @@ inline uint64_t bytes2uint64(char *array)
} }
#endif #endif
inline bool isForkEnabled(int nHeight)
{
return nHeight > forkStartHeight;
}
#endif // BITCOIN_MAIN_H #endif // BITCOIN_MAIN_H

View File

@ -809,17 +809,11 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
static map<string, int> mapSigHashValues = static map<string, int> mapSigHashValues =
boost::assign::map_list_of boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL)) (string("ALL"), int(SIGHASH_ALL))
(string("ALL|SIGHASH_FORKID"), int(SIGHASH_ALL|SIGHASH_FORKID))
(string("ALL|ANYONECANPAY|SIGHASH_FORKID"), int(SIGHASH_ALL|SIGHASH_FORKID))
(string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
(string("NONE"), int(SIGHASH_NONE)) (string("NONE"), int(SIGHASH_NONE))
(string("NONE|SIGHASH_FORKID"), int(SIGHASH_NONE|SIGHASH_FORKID))
(string("NONE|ANYONECANPAY|SIGHASH_FORKID"), int(SIGHASH_NONE|SIGHASH_FORKID|SIGHASH_ANYONECANPAY))
(string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
(string("SINGLE"), int(SIGHASH_SINGLE)) (string("SINGLE"), int(SIGHASH_SINGLE))
(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
(string("SINGLE|SIGHASH_FORKID"), int(SIGHASH_SINGLE|SIGHASH_FORKID))
(string("SINGLE|ANYONECANPAY|SIGHASH_FORKID"), int(SIGHASH_SINGLE|SIGHASH_FORKID|SIGHASH_ANYONECANPAY))
; ;
string strHashType = params[3].get_str(); string strHashType = params[3].get_str();
if (mapSigHashValues.count(strHashType)) if (mapSigHashValues.count(strHashType))
@ -827,11 +821,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
else else
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
if (!(nHashType & SIGHASH_FORKID)) nHashType |= SIGHASH_FORKID;
throw JSONRPCError(RPC_INVALID_PARAMETER, "Signature must use SIGHASH_FORKID");
} }
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); bool fHashSingle = ((nHashType & ~SIGHASH_FLAGS_MASK) == SIGHASH_SINGLE);
// Script verification errors // Script verification errors
UniValue vErrors(UniValue::VARR); UniValue vErrors(UniValue::VARR);

View File

@ -185,7 +185,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
if (vchSig.size() == 0) { if (vchSig.size() == 0) {
return false; return false;
} }
unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY|SIGHASH_FORKID)); unsigned char nHashType = GetHashType(vchSig) & (~(SIGHASH_ANYONECANPAY|SIGHASH_FORKID));
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
return false; return false;
@ -195,15 +195,12 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
bool static UsesForkId(uint32_t nHashType) { bool static UsesForkId(uint32_t nHashType) {
return nHashType & SIGHASH_FORKID; return nHashType & SIGHASH_FORKID;
} }
bool static UsesForkId(const valtype &vchSig) { bool static UsesForkId(const valtype &vchSig) {
uint32_t nHashType = GetHashType(vchSig); uint32_t nHashType = GetHashType(vchSig);
return UsesForkId(nHashType); return UsesForkId(nHashType);
} }
bool static AllowsNonForkId(unsigned int flags) {
return flags & SCRIPT_ALLOW_NON_FORKID;
}
bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
// Empty signature. Not strictly DER encoded, but allowed to provide a // Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG // compact way to provide an invalid signature for use with CHECK(MULTI)SIG
@ -214,18 +211,12 @@ bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, Sc
return set_error(serror, SCRIPT_ERR_SIG_DER); return set_error(serror, SCRIPT_ERR_SIG_DER);
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
return false; return false;
} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
} else if ((flags & SCRIPT_VERIFY_FORKID) != 0 && !UsesForkId(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
} }
return true;
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) {
if(!IsDefinedHashtypeSignature(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
}
bool requiresForkId = !AllowsNonForkId(flags);
bool usesForkId = UsesForkId(vchSig);
if (requiresForkId && !usesForkId)
return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID);
}
return true;
} }
bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
@ -866,7 +857,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// serror is set // serror is set
return false; return false;
} }
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script); bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, flags);
popstack(stack); popstack(stack);
popstack(stack); popstack(stack);
@ -924,7 +915,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
} }
// Check signature // Check signature
bool fOk = checker.CheckSig(vchSig, vchPubKey, script); bool fOk = checker.CheckSig(vchSig, vchPubKey, script, flags);
if (fOk) { if (fOk) {
isig++; isig++;
@ -1089,11 +1080,8 @@ public:
}; };
} // anon namespace } // anon namespace
//
// https://github.com/BTCGPU/BTCGPU/blob/bd007ae79c934f8c99d2247115637f8684ed861a/src/script/interpreter.cpp#L1204 uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const int forkid)
// forkid
//
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{ {
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) { if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
throw logic_error("input index is out of range"); throw logic_error("input index is out of range");
@ -1102,23 +1090,21 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
// Check for invalid use of SIGHASH_SINGLE // Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) { if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
if (nIn >= txTo.vout.size()) { if (nIn >= txTo.vout.size()) {
throw logic_error(" no matching output for SIGHASH_SINGLE"); throw logic_error("no matching output for SIGHASH_SINGLE");
} }
} }
int nForkHashType = nHashType;
if (UsesForkId(nHashType))
nForkHashType |= forkid << 8;
// Wrapper to serialize only the necessary parts of the transaction being signed // Wrapper to serialize only the necessary parts of the transaction being signed
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
// Serialize and hash // Serialize and hash
CHashWriter ss(SER_GETHASH, 0); CHashWriter ss(SER_GETHASH, 0);
ss << txTmp << (nHashType & ~SIGHASH_FORKID); ss << txTmp << nForkHashType;
// This ensures Two Way Replay Protection
//
// see instead: https://github.com/BTCGPU/BTCGPU/blob/bd007ae79c934f8c99d2247115637f8684ed861a/src/script/interpreter.cpp#L1276
//
// if (nHashType & SIGHASH_FORKID) {
// ss << std::string("btcp");
// }
return ss.GetHash(); return ss.GetHash();
} }
@ -1127,7 +1113,7 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned cha
return pubkey.Verify(sighash, vchSig); return pubkey.Verify(sighash, vchSig);
} }
bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, const unsigned int flags) const
{ {
CPubKey pubkey(vchPubKey); CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid()) if (!pubkey.IsValid())
@ -1142,7 +1128,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
uint256 sighash; uint256 sighash;
try { try {
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType); sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, (flags & SCRIPT_VERIFY_FORKID) ? FORKID_IN_USE : 0);
} catch (logic_error ex) { } catch (logic_error ex) {
return false; return false;
} }
@ -1198,11 +1184,6 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY); return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
} }
// If SIGHASH_FORKID is enabled, we also ensure strict encoding.
if (flags & SCRIPT_ENABLE_SIGHASH_FORKID) {
flags |= SCRIPT_VERIFY_STRICTENC;
}
// Do not allow spends of P2WPKH-P2SH and P2WSH-P2SH UTXOs // Do not allow spends of P2WPKH-P2SH and P2WSH-P2SH UTXOs
// To a non-segwit aware node these outputs are trivially spendable // To a non-segwit aware node these outputs are trivially spendable
// Detect them here and evaluate to false // Detect them here and evaluate to false

View File

@ -32,11 +32,14 @@ enum
SIGHASH_ANYONECANPAY = 0x80, SIGHASH_ANYONECANPAY = 0x80,
}; };
/** Fork IDs **/ static const int SIGHASH_FLAGS_MASK = SIGHASH_FORKID | SIGHASH_ANYONECANPAY;
static const int SIGHASH_BASE_MASK = ~SIGHASH_FLAGS_MASK;
enum enum
{ {
FORKID_BCC = 0, FORKID_NONE = 0,
FORKID_BTCP = 42, FORKID_BTCP = 42,
FORKID_BTCGPU = 79
}; };
static const int FORKID_IN_USE = FORKID_BTCP; static const int FORKID_IN_USE = FORKID_BTCP;
@ -97,20 +100,16 @@ enum
// See BIP65 for details. // See BIP65 for details.
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
// Do we accept signature using SIGHASH_FORKID // Require that all signatures sign the forkid
SCRIPT_ENABLE_SIGHASH_FORKID = (1U << 16), SCRIPT_VERIFY_FORKID = (1U << 17)
// Allow NON_FORKID in legacy tests and blocks under BTG hard fork height
SCRIPT_ALLOW_NON_FORKID = (1U << 17),
}; };
//
// TODO: add forkId uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const int forkid=FORKID_NONE);
//
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
class BaseSignatureChecker class BaseSignatureChecker
{ {
public: public:
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, const unsigned int flags) const
{ {
return false; return false;
} }
@ -134,7 +133,7 @@ protected:
public: public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, const unsigned int flags) const;
bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckLockTime(const CScriptNum& nLockTime) const;
}; };

View File

@ -52,9 +52,6 @@ typedef enum ScriptError_t
/* softfork safeness */ /* softfork safeness */
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,
/* SIGHASH_FORKID */
SCRIPT_ERR_ILLEGAL_FORKID,
/* SEGWIT LOCKED */ /* SEGWIT LOCKED */
SCRIPT_ERR_SEGWIT_LOCKED, SCRIPT_ERR_SEGWIT_LOCKED,

View File

@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
uint256 hash; uint256 hash;
try { try {
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType); hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, FORKID_IN_USE);
} catch (logic_error ex) { } catch (logic_error ex) {
return false; return false;
} }
@ -189,7 +189,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
if (sigs.count(pubkey)) if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey continue; // Already got a sig for this pubkey
if (checker.CheckSig(sig, pubkey, scriptPubKey)) if (checker.CheckSig(sig, pubkey, scriptPubKey, SCRIPT_VERIFY_FORKID))
{ {
sigs[pubkey] = sig; sigs[pubkey] = sig;
break; break;
@ -274,9 +274,9 @@ CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecke
Solver(scriptPubKey, txType, vSolutions); Solver(scriptPubKey, txType, vSolutions);
vector<valtype> stack1; vector<valtype> stack1;
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC|SCRIPT_ENABLE_SIGHASH_FORKID, BaseSignatureChecker()); EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC|SCRIPT_VERIFY_FORKID, BaseSignatureChecker());
vector<valtype> stack2; vector<valtype> stack2;
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC|SCRIPT_ENABLE_SIGHASH_FORKID, BaseSignatureChecker()); EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC|SCRIPT_VERIFY_FORKID, BaseSignatureChecker());
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
} }
@ -288,7 +288,7 @@ class DummySignatureChecker : public BaseSignatureChecker
public: public:
DummySignatureChecker() {} DummySignatureChecker() {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, const unsigned int flags) const
{ {
return true; return true;
} }

View File

@ -37,10 +37,7 @@ extern unsigned nMaxDatacarrierBytes;
* details. * details.
*/ */
// static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
// TODO https://github.com/BTCGPU/BTCGPU/blob/bd007ae79c934f8c99d2247115637f8684ed861a/src/script/standard.h#L43
//
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID;
/** /**
* Standard script verification flags that standard transactions will comply * Standard script verification flags that standard transactions will comply

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@ BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript CScript
sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn) sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)
{ {
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL|SIGHASH_FORKID); uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);
CScript result; CScript result;
result << OP_0; // CHECKMULTISIG bug workaround result << OP_0; // CHECKMULTISIG bug workaround
@ -36,7 +36,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig)); BOOST_CHECK(key.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL | SIGHASH_FORKID); vchSig.push_back((unsigned char)SIGHASH_ALL);
result << vchSig; result << vchSig;
} }
return result; return result;
@ -312,7 +312,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL | SIGHASH_FORKID), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
} }
} }

View File

@ -86,8 +86,8 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error); BOOST_CHECK_THROW(CallRPC("signrawtransaction null"), runtime_error);
BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error); BOOST_CHECK_THROW(CallRPC("signrawtransaction ff00"), runtime_error);
BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx)); BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx));
BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY|SIGHASH_FORKID")); BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null NONE|ANYONECANPAY"));
BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY|SIGHASH_FORKID")); BOOST_CHECK_NO_THROW(CallRPC(string("signrawtransaction ")+rawtx+" [] [] NONE|ANYONECANPAY"));
BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error); BOOST_CHECK_THROW(CallRPC(string("signrawtransaction ")+rawtx+" null null badenum"), runtime_error);
// Only check failure cases for sendrawtransaction, there's no network to send to... // Only check failure cases for sendrawtransaction, there's no network to send to...
@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
BOOST_AUTO_TEST_CASE(rpc_ban) BOOST_AUTO_TEST_CASE(rpc_ban)
{ {
BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned"))); BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
UniValue r; UniValue r;
BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add"))); BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add")));
BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed
@ -247,7 +247,7 @@ BOOST_AUTO_TEST_CASE(rpc_ban)
adr = find_value(o1, "address"); adr = find_value(o1, "address");
banned_until = find_value(o1, "banned_until"); banned_until = find_value(o1, "banned_until");
BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0"); BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0");
int64_t now = GetTime(); int64_t now = GetTime();
BOOST_CHECK(banned_until.get_int64() > now); BOOST_CHECK(banned_until.get_int64() > now);
BOOST_CHECK(banned_until.get_int64()-now <= 200); BOOST_CHECK(banned_until.get_int64()-now <= 200);

View File

@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(sign)
} }
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL| SIGHASH_FORKID), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
} }
// All of the above should be OK, and the txTos have valid signatures // All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig: // Check to make sure signature verification fails if we use the wrong ScriptSig:
@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(sign)
{ {
CScript sigSave = txTo[i].vin[0].scriptSig; CScript sigSave = txTo[i].vin[0].scriptSig;
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID, false)(); bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
if (i == j) if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else else
@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE(set)
} }
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL | SIGHASH_FORKID), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i));
} }
} }
@ -378,9 +378,9 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].prevout.hash = txFrom.GetHash(); txTo.vin[i].prevout.hash = txFrom.GetHash();
} }
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0,SIGHASH_ALL| SIGHASH_FORKID)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0,SIGHASH_ALL));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1,SIGHASH_ALL| SIGHASH_FORKID)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1,SIGHASH_ALL));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2,SIGHASH_ALL| SIGHASH_FORKID)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2,SIGHASH_ALL));
// SignSignature doesn't know how to sign these. We're // SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create // not testing validating signatures, so just create

View File

@ -34,7 +34,7 @@ using namespace std;
// Uncomment if you want to output updated JSON tests. // Uncomment if you want to output updated JSON tests.
// #define UPDATE_JSON_TESTS // #define UPDATE_JSON_TESTS
static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID; static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(string strFlags); unsigned int ParseScriptFlags(string strFlags);
string FormatScriptFlags(unsigned int flags); string FormatScriptFlags(unsigned int flags);
@ -234,10 +234,9 @@ public:
return *this; return *this;
} }
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL| SIGHASH_FORKID, unsigned int lenR = 32, unsigned int lenS = 32) TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32)
{ {
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType); uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType);
std::vector<unsigned char> vchSig, r, s; std::vector<unsigned char> vchSig, r, s;
uint32_t iter = 0; uint32_t iter = 0;
do { do {
@ -249,7 +248,6 @@ public:
s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]);
} while (lenR != r.size() || lenS != s.size()); } while (lenR != r.size() || lenS != s.size());
vchSig.push_back(static_cast<unsigned char>(nHashType)); vchSig.push_back(static_cast<unsigned char>(nHashType));
DoPush(vchSig); DoPush(vchSig);
return *this; return *this;
} }
@ -272,7 +270,6 @@ public:
std::vector<unsigned char> datain = ParseHex(hexin); std::vector<unsigned char> datain = ParseHex(hexin);
std::vector<unsigned char> dataout = ParseHex(hexout); std::vector<unsigned char> dataout = ParseHex(hexout);
assert(pos + datain.size() <= push.size()); assert(pos + datain.size() <= push.size());
BOOST_CHECK_MESSAGE(std::vector<unsigned char>(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); BOOST_CHECK_MESSAGE(std::vector<unsigned char>(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment);
push.erase(push.begin() + pos, push.begin() + pos + datain.size()); push.erase(push.begin() + pos, push.begin() + pos + datain.size());
push.insert(push.begin() + pos, dataout.begin(), dataout.end()); push.insert(push.begin() + pos, dataout.begin(), dataout.end());
@ -342,23 +339,23 @@ BOOST_AUTO_TEST_CASE(script_build)
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK anyonecanpay", 0 "P2PK anyonecanpay", 0
).PushSig(keys.key1, SIGHASH_ALL|SIGHASH_ANYONECANPAY | SIGHASH_FORKID)); ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK anyonecanpay marked with normal hashtype", 0 "P2PK anyonecanpay marked with normal hashtype", 0
).PushSig(keys.key1, SIGHASH_ALL|SIGHASH_ANYONECANPAY| SIGHASH_FORKID).EditPush(70, "C1", "03")); ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01"));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK)", SCRIPT_VERIFY_P2SH|SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem()); ).PushSig(keys.key0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
"P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH |SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem().DamagePush(10)); ).PushSig(keys.key0).PushRedeem().DamagePush(10));
good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true
).PushSig(keys.key0).DamagePush(10).PushRedeem()); ).PushSig(keys.key0).DamagePush(10).PushRedeem());
bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << ToByteVector(keys.pubkey1.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG,
"P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).DamagePush(10).PushRedeem()); ).PushSig(keys.key0).DamagePush(10).PushRedeem());
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
@ -369,34 +366,34 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0)); ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"P2SH(2-of-3)", SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true
).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem()); ).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem());
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
"P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true
).Num(0).PushSig(keys.key1).Num(0).PushRedeem()); ).Num(0).PushSig(keys.key1).Num(0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much R padding", 0 "P2PK with too much R padding", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID, 31, 32).EditPush(1, "43021F", "44022000")); ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too much S padding", 0 "P2PK with too much S padding", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID).EditPush(1, "44", "45").EditPush(37, "20", "2100")); ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"P2PK with too little R padding", 0 "P2PK with too little R padding", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220")); ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with bad sig with too much R padding", 0 "P2PK NOT with bad sig with too much R padding", 0
).PushSig(keys.key2, SIGHASH_ALL | SIGHASH_FORKID, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10)); ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with too much R padding", 0 "P2PK NOT with too much R padding", 0
).PushSig(keys.key2, SIGHASH_ALL | SIGHASH_FORKID, 31, 32).EditPush(1, "43021F", "44022000")); ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 1", 0 "BIP66 example 1", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220")); ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG << OP_NOT,
"BIP66 example 2", 0 "BIP66 example 2", 0
).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220")); ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKSIG,
"BIP66 example 3", 0 "BIP66 example 3", 0
).Num(0)); ).Num(0));
@ -411,73 +408,73 @@ BOOST_AUTO_TEST_CASE(script_build)
).Num(1)); ).Num(1));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 7", 0 "BIP66 example 7", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 8", 0 "BIP66 example 8", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL| SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").PushSig(keys.key2));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 9", 0 "BIP66 example 9", 0
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220")); ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 10", 0 "BIP66 example 10", 0
).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220")); ).Num(0).Num(0).PushSig(keys.key2, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220"));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG,
"BIP66 example 11", 0 "BIP66 example 11", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL| SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220").Num(0)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT, good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_2 << OP_CHECKMULTISIG << OP_NOT,
"BIP66 example 12", 0 "BIP66 example 12", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID, 33, 32).EditPush(1, "45022100", "440220").Num(0)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220").Num(0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with multi-byte hashtype", 0 "P2PK with multi-byte hashtype", 0
).PushSig(keys.key2, SIGHASH_ALL| SIGHASH_FORKID).EditPush(70, "41", "101")); ).PushSig(keys.key2, SIGHASH_ALL).EditPush(70, "01", "0101"));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S but no LOW_S", 0 "P2PK with high S but no LOW_S", 0
).PushSig(keys.key2, SIGHASH_ALL | SIGHASH_FORKID, 32, 33)); ).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2PK with high S", SCRIPT_VERIFY_LOW_S | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK with high S", SCRIPT_VERIFY_LOW_S
).PushSig(keys.key2, SIGHASH_ALL | SIGHASH_FORKID, 32, 33)); ).PushSig(keys.key2, SIGHASH_ALL, 32, 33));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG,
"P2PK with hybrid pubkey but no STRICTENC", 0 "P2PK with hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID)); ).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG,
"P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID)); ).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with hybrid pubkey but no STRICTENC", 0 "P2PK NOT with hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID)); ).PushSig(keys.key0, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID)); ).PushSig(keys.key0, SIGHASH_ALL));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0 "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0
).PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID).DamagePush(10)); ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key0, SIGHASH_ALL | SIGHASH_FORKID).DamagePush(10)); ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10));
good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0 "1-of-2 with the second 1 hybrid pubkey and no STRICTENC", 0
).Num(0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL));
good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, good.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "1-of-2 with the second 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).Num(0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL));
bad.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG, bad.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0H) << OP_2 << OP_CHECKMULTISIG,
"1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "1-of-2 with the first 1 hybrid pubkey", SCRIPT_VERIFY_STRICTENC
).Num(0).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_FORKID)); ).Num(0).PushSig(keys.key1, SIGHASH_ALL));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK with undefined hashtype but no STRICTENC", 0 "P2PK with undefined hashtype but no STRICTENC", 0
).PushSig(keys.key1, 5)); ).PushSig(keys.key1, 5));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG,
"P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key1, 5)); ).PushSig(keys.key1, 5));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0 "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0
).PushSig(keys.key1, 5).DamagePush(10)); ).PushSig(keys.key1, 5).DamagePush(10));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT,
"P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC
).PushSig(keys.key1, 5).DamagePush(10)); ).PushSig(keys.key1, 5).DamagePush(10));
good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG, good.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C) << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey2C) << OP_3 << OP_CHECKMULTISIG,
@ -497,7 +494,7 @@ BOOST_AUTO_TEST_CASE(script_build)
"2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0 "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0
).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP)); ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY | SCRIPT_ENABLE_SIGHASH_FORKID "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY
).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP)); ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
"P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0 "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0
@ -506,23 +503,23 @@ BOOST_AUTO_TEST_CASE(script_build)
"P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY "P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY
).PushSig(keys.key2).PushRedeem()); ).PushSig(keys.key2).PushRedeem());
good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG, good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
"2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY | SCRIPT_ENABLE_SIGHASH_FORKID "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY
).Num(0).PushSig(keys.key1).PushSig(keys.key1)); ).Num(0).PushSig(keys.key1).PushSig(keys.key1));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH
).Num(11).PushSig(keys.key0)); ).Num(11).PushSig(keys.key0));
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID "P2PK with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH
).Num(11).PushSig(keys.key0)); ).Num(11).PushSig(keys.key0));
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH with unnecessary input but no CLEANSTACK", SCRIPT_VERIFY_P2SH, true
).Num(11).PushSig(keys.key0).PushRedeem()); ).Num(11).PushSig(keys.key0).PushRedeem());
bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH with unnecessary input", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true
).Num(11).PushSig(keys.key0).PushRedeem()); ).Num(11).PushSig(keys.key0).PushRedeem());
good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG, good.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
"P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH | SCRIPT_ENABLE_SIGHASH_FORKID, true "P2SH with CLEANSTACK", SCRIPT_VERIFY_CLEANSTACK | SCRIPT_VERIFY_P2SH, true
).PushSig(keys.key0).PushRedeem()); ).PushSig(keys.key0).PushRedeem());
@ -589,7 +586,6 @@ BOOST_AUTO_TEST_CASE(script_valid)
for (size_t idx = 0; idx < tests.size(); idx++) { for (size_t idx = 0; idx < tests.size(); idx++) {
UniValue test = tests[idx]; UniValue test = tests[idx];
string strTest = test.write(); string strTest = test.write();
if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
{ {
if (test.size() != 1) { if (test.size() != 1) {
@ -665,7 +661,7 @@ BOOST_AUTO_TEST_CASE(script_PushData)
CScript CScript
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction) sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
{ {
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL | SIGHASH_FORKID); uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL);
CScript result; CScript result;
// //
@ -681,7 +677,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
BOOST_CHECK(key.Sign(hash, vchSig)); BOOST_CHECK(key.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL | SIGHASH_FORKID); vchSig.push_back((unsigned char)SIGHASH_ALL);
result << vchSig; result << vchSig;
} }
return result; return result;
@ -791,7 +787,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err)); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
} }
BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_AUTO_TEST_CASE(script_combineSigs)
{ {
@ -860,17 +856,17 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
// A couple of partially-signed versions: // A couple of partially-signed versions:
vector<unsigned char> sig1; vector<unsigned char> sig1;
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL | SIGHASH_FORKID); uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL);
BOOST_CHECK(keys[0].Sign(hash1, sig1)); BOOST_CHECK(keys[0].Sign(hash1, sig1));
sig1.push_back(SIGHASH_ALL| SIGHASH_FORKID); sig1.push_back(SIGHASH_ALL);
vector<unsigned char> sig2; vector<unsigned char> sig2;
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE | SIGHASH_FORKID); uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE);
BOOST_CHECK(keys[1].Sign(hash2, sig2)); BOOST_CHECK(keys[1].Sign(hash2, sig2));
sig2.push_back(SIGHASH_NONE| SIGHASH_FORKID); sig2.push_back(SIGHASH_NONE);
vector<unsigned char> sig3; vector<unsigned char> sig3;
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE | SIGHASH_FORKID); uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE);
BOOST_CHECK(keys[2].Sign(hash3, sig3)); BOOST_CHECK(keys[2].Sign(hash3, sig3));
sig3.push_back(SIGHASH_SINGLE | SIGHASH_FORKID); sig3.push_back(SIGHASH_SINGLE);
// Not fussy about order (or even existence) of placeholders or signatures: // Not fussy about order (or even existence) of placeholders or signatures:
CScript partial1a = CScript() << OP_0 << sig1 << OP_0; CScript partial1a = CScript() << OP_0 << sig1 << OP_0;
@ -885,7 +881,6 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript complete23 = CScript() << OP_0 << sig2 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3;
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b); combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b);
BOOST_CHECK(combined == partial1a); BOOST_CHECK(combined == partial1a);
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a); combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a);
BOOST_CHECK(combined == complete12); BOOST_CHECK(combined == complete12);

View File

@ -20,7 +20,6 @@
#include <univalue.h> #include <univalue.h>
extern UniValue read_json(const std::string& jsondata); extern UniValue read_json(const std::string& jsondata);
// Old script.cpp SignatureHash function // Old script.cpp SignatureHash function
@ -70,7 +69,7 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
} }
// Blank out other inputs completely, not recommended for open transactions // Blank out other inputs completely, not recommended for open transactions
if ((nHashType & 0x1f) == SIGHASH_ANYONECANPAY) if (nHashType & SIGHASH_ANYONECANPAY)
{ {
txTmp.vin[0] = txTmp.vin[nIn]; txTmp.vin[0] = txTmp.vin[nIn];
txTmp.vin.resize(1); txTmp.vin.resize(1);
@ -99,9 +98,8 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
tx.vout.clear(); tx.vout.clear();
tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0; tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0;
int ins = (insecure_rand() % 4) + 1; int ins = (insecure_rand() % 4) + 1;
int outs = fSingle ? ins + 1 : (insecure_rand() % 4) + 1; int outs = fSingle ? ins : (insecure_rand() % 4) + 1;
int joinsplits = (insecure_rand() % 4); int joinsplits = (insecure_rand() % 4);
for (int in = 0; in < ins; in++) { for (int in = 0; in < ins; in++) {
tx.vin.push_back(CTxIn()); tx.vin.push_back(CTxIn());
CTxIn &txin = tx.vin.back(); CTxIn &txin = tx.vin.back();
@ -155,16 +153,6 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
} }
BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup)
//
// NB Any change in the data created below will require that you define this,
// and
// $ ./test_bitcoin -t sighash_tests > data/sighash.json
// $ make -C .. bitcoin_test
//
// the first step rebuilds the json, the second step result in
// data/sighash.json.h being recreated and used in a recompile
//
// #define PRINT_SIGHASH_JSON
BOOST_AUTO_TEST_CASE(sighash_test) BOOST_AUTO_TEST_CASE(sighash_test)
{ {
@ -180,18 +168,16 @@ BOOST_AUTO_TEST_CASE(sighash_test)
nRandomTests = 500; nRandomTests = 500;
#endif #endif
for (int i=0; i<nRandomTests; i++) { for (int i=0; i<nRandomTests; i++) {
int nHashType = (insecure_rand() % 3) + 1; int nHashType = insecure_rand();
CMutableTransaction txTo; CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType == SIGHASH_SINGLE)); RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode; CScript scriptCode;
RandomScript(scriptCode); RandomScript(scriptCode);
int nIn = insecure_rand() % txTo.vin.size(); int nIn = insecure_rand() % txTo.vin.size();
uint256 sh, sho; uint256 sh, sho;
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType);
sh = SignatureHash(scriptCode, txTo, nIn, nHashType); sh = SignatureHash(scriptCode, txTo, nIn, nHashType);
#if defined(PRINT_SIGHASH_JSON) #if defined(PRINT_SIGHASH_JSON)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << txTo; ss << txTo;

View File

@ -418,16 +418,13 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc->nullifiers[0] = GetRandHash(); jsdesc->nullifiers[0] = GetRandHash();
jsdesc->nullifiers[1] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash();
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state)); BOOST_CHECK(!CheckJoinSplitSigs(newTx, state, 0));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(newTx); CTransaction signTx(newTx);
// uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
// NB SIGHASH_ALL | SIGHASH_FORKID
//
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, 0x41);
assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL,
dataToBeSigned.begin(), 32, dataToBeSigned.begin(), 32,

View File

@ -61,15 +61,15 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
if (minDepth < 0) { if (minDepth < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be negative"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be negative");
} }
if (fromAddress.size() == 0) { if (fromAddress.size() == 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "From address parameter missing"); throw JSONRPCError(RPC_INVALID_PARAMETER, "From address parameter missing");
} }
if (tOutputs.size() == 0 && zOutputs.size() == 0) { if (tOutputs.size() == 0 && zOutputs.size() == 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "No recipients"); throw JSONRPCError(RPC_INVALID_PARAMETER, "No recipients");
} }
fromtaddr_ = CBitcoinAddress(fromAddress); fromtaddr_ = CBitcoinAddress(fromAddress);
isfromtaddr_ = fromtaddr_.IsValid(); isfromtaddr_ = fromtaddr_.IsValid();
isfromzaddr_ = false; isfromzaddr_ = false;
@ -84,7 +84,7 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
if (!pwalletMain->GetSpendingKey(addr, key)) { if (!pwalletMain->GetSpendingKey(addr, key)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, no spending key found for zaddr"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, no spending key found for zaddr");
} }
isfromzaddr_ = true; isfromzaddr_ = true;
frompaymentaddress_ = addr; frompaymentaddress_ = addr;
spendingkey_ = key; spendingkey_ = key;
@ -197,9 +197,9 @@ bool AsyncRPCOperation_sendmany::main_impl() {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any non-coinbase UTXOs to spend."); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any non-coinbase UTXOs to spend.");
} }
} }
} }
} }
if (isfromzaddr_ && !find_unspent_notes()) { if (isfromzaddr_ && !find_unspent_notes()) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address."); throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address.");
} }
@ -235,7 +235,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
strprintf("Insufficient transparent funds, have %s, need %s", strprintf("Insufficient transparent funds, have %s, need %s",
FormatMoney(t_inputs_total), FormatMoney(targetAmount))); FormatMoney(t_inputs_total), FormatMoney(targetAmount)));
} }
if (isfromzaddr_ && (z_inputs_total < targetAmount)) { if (isfromzaddr_ && (z_inputs_total < targetAmount)) {
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
strprintf("Insufficient protected funds, have %s, need %s", strprintf("Insufficient protected funds, have %s, need %s",
@ -312,18 +312,18 @@ bool AsyncRPCOperation_sendmany::main_impl() {
/** /**
* SCENARIO #1 * SCENARIO #1
* *
* taddr -> taddrs * taddr -> taddrs
* *
* There are no zaddrs or joinsplits involved. * There are no zaddrs or joinsplits involved.
*/ */
if (isPureTaddrOnlyTx) { if (isPureTaddrOnlyTx) {
add_taddr_outputs_to_tx(); add_taddr_outputs_to_tx();
CAmount funds = selectedUTXOAmount; CAmount funds = selectedUTXOAmount;
CAmount fundsSpent = t_outputs_total + minersFee; CAmount fundsSpent = t_outputs_total + minersFee;
CAmount change = funds - fundsSpent; CAmount change = funds - fundsSpent;
if (change > 0) { if (change > 0) {
add_taddr_change_output_to_tx(change); add_taddr_change_output_to_tx(change);
@ -332,7 +332,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
FormatMoney(change) FormatMoney(change)
); );
} }
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("rawtxn", EncodeHexTx(tx_))); obj.push_back(Pair("rawtxn", EncodeHexTx(tx_)));
sign_send_raw_transaction(obj); sign_send_raw_transaction(obj);
@ -342,7 +342,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
* END SCENARIO #1 * END SCENARIO #1
*/ */
// Prepare raw transaction to handle JoinSplits // Prepare raw transaction to handle JoinSplits
CMutableTransaction mtx(tx_); CMutableTransaction mtx(tx_);
mtx.nVersion = 2; mtx.nVersion = 2;
@ -383,10 +383,10 @@ bool AsyncRPCOperation_sendmany::main_impl() {
/** /**
* SCENARIO #2 * SCENARIO #2
* *
* taddr -> taddrs * taddr -> taddrs
* -> zaddrs * -> zaddrs
* *
* Note: Consensus rule states that coinbase utxos can only be sent to a zaddr. * Note: Consensus rule states that coinbase utxos can only be sent to a zaddr.
* Local wallet rule does not allow any change when sending coinbase utxos * Local wallet rule does not allow any change when sending coinbase utxos
* since there is currently no way to specify a change address and we don't * since there is currently no way to specify a change address and we don't
@ -394,11 +394,11 @@ bool AsyncRPCOperation_sendmany::main_impl() {
*/ */
if (isfromtaddr_) { if (isfromtaddr_) {
add_taddr_outputs_to_tx(); add_taddr_outputs_to_tx();
CAmount funds = selectedUTXOAmount; CAmount funds = selectedUTXOAmount;
CAmount fundsSpent = t_outputs_total + minersFee + z_outputs_total; CAmount fundsSpent = t_outputs_total + minersFee + z_outputs_total;
CAmount change = funds - fundsSpent; CAmount change = funds - fundsSpent;
if (change > 0) { if (change > 0) {
if (selectedUTXOCoinbase) { if (selectedUTXOCoinbase) {
assert(isSingleZaddrOutput); assert(isSingleZaddrOutput);
@ -435,7 +435,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
jso.memo = get_memo_from_hex_string(hexMemo); jso.memo = get_memo_from_hex_string(hexMemo);
} }
info.vjsout.push_back(jso); info.vjsout.push_back(jso);
// Funds are removed from the value pool and enter the private pool // Funds are removed from the value pool and enter the private pool
info.vpub_old += value; info.vpub_old += value;
} }
@ -446,16 +446,16 @@ bool AsyncRPCOperation_sendmany::main_impl() {
} }
/** /**
* END SCENARIO #2 * END SCENARIO #2
*/ */
/** /**
* SCENARIO #3 * SCENARIO #3
* *
* zaddr -> taddrs * zaddr -> taddrs
* -> zaddrs * -> zaddrs
* *
* Send to zaddrs by chaining JoinSplits together and immediately consuming any change * Send to zaddrs by chaining JoinSplits together and immediately consuming any change
* Send to taddrs by creating dummy z outputs and accumulating value in a change note * Send to taddrs by creating dummy z outputs and accumulating value in a change note
* which is used to set vpub_new in the last chained joinsplit. * which is used to set vpub_new in the last chained joinsplit.
@ -581,9 +581,9 @@ bool AsyncRPCOperation_sendmany::main_impl() {
vOutPoints.push_back(jso); vOutPoints.push_back(jso);
vInputNotes.push_back(note); vInputNotes.push_back(note);
jsInputValue += noteFunds; jsInputValue += noteFunds;
int wtxHeight = -1; int wtxHeight = -1;
int wtxDepth = -1; int wtxDepth = -1;
{ {
@ -602,14 +602,14 @@ bool AsyncRPCOperation_sendmany::main_impl() {
wtxDepth wtxDepth
); );
} }
// Add history of previous commitments to witness // Add history of previous commitments to witness
if (vInputNotes.size() > 0) { if (vInputNotes.size() > 0) {
if (vInputWitnesses.size()==0) { if (vInputWitnesses.size()==0) {
throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment"); throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment");
} }
for (auto & optionalWitness : vInputWitnesses) { for (auto & optionalWitness : vInputWitnesses) {
if (!optionalWitness) { if (!optionalWitness) {
throw JSONRPCError(RPC_WALLET_ERROR, "Witness for note commitment is null"); throw JSONRPCError(RPC_WALLET_ERROR, "Witness for note commitment is null");
@ -724,7 +724,7 @@ bool AsyncRPCOperation_sendmany::main_impl() {
* Raw transaction as hex string should be in object field "rawtxn" * Raw transaction as hex string should be in object field "rawtxn"
*/ */
void AsyncRPCOperation_sendmany::sign_send_raw_transaction(UniValue obj) void AsyncRPCOperation_sendmany::sign_send_raw_transaction(UniValue obj)
{ {
// Sign the raw transaction // Sign the raw transaction
UniValue rawtxnValue = find_value(obj, "rawtxn"); UniValue rawtxnValue = find_value(obj, "rawtxn");
if (rawtxnValue.isNull()) { if (rawtxnValue.isNull()) {
@ -815,7 +815,7 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
if (isCoinbase && fAcceptCoinbase==false) { if (isCoinbase && fAcceptCoinbase==false) {
continue; continue;
} }
CAmount nValue = out.tx->vout[out.i].nValue; CAmount nValue = out.tx->vout[out.i].nValue;
SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, isCoinbase); SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, isCoinbase);
t_inputs_.push_back(utxo); t_inputs_.push_back(utxo);
@ -849,7 +849,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() {
HexStr(data).substr(0, 10) HexStr(data).substr(0, 10)
); );
} }
if (z_inputs_.size() == 0) { if (z_inputs_.size() == 0) {
return false; return false;
} }
@ -962,7 +962,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL | SIGHASH_FORKID, FORKID_IN_USE);
// Add the signature // Add the signature
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
@ -1070,7 +1070,7 @@ void AsyncRPCOperation_sendmany::add_taddr_change_output_to_tx(CAmount amount) {
boost::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_from_hex_string(std::string s) { boost::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_from_hex_string(std::string s) {
boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0x00}}; boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0x00}};
std::vector<unsigned char> rawMemo = ParseHex(s.c_str()); std::vector<unsigned char> rawMemo = ParseHex(s.c_str());
// If ParseHex comes across a non-hex char, it will stop but still return results so far. // If ParseHex comes across a non-hex char, it will stop but still return results so far.
@ -1078,11 +1078,11 @@ boost::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_f
if (slen % 2 !=0 || (slen>0 && rawMemo.size()!=slen/2)) { if (slen % 2 !=0 || (slen>0 && rawMemo.size()!=slen/2)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo must be in hexadecimal format"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo must be in hexadecimal format");
} }
if (rawMemo.size() > ZC_MEMO_SIZE) { if (rawMemo.size() > ZC_MEMO_SIZE) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Memo size of %d is too big, maximum allowed is %d", rawMemo.size(), ZC_MEMO_SIZE)); throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Memo size of %d is too big, maximum allowed is %d", rawMemo.size(), ZC_MEMO_SIZE));
} }
// copy vector into boost array // copy vector into boost array
int lenMemo = rawMemo.size(); int lenMemo = rawMemo.size();
for (int i = 0; i < ZC_MEMO_SIZE && i < lenMemo; i++) { for (int i = 0; i < ZC_MEMO_SIZE && i < lenMemo; i++) {
@ -1105,4 +1105,3 @@ UniValue AsyncRPCOperation_sendmany::getStatus() const {
obj.push_back(Pair("params", contextinfo_ )); obj.push_back(Pair("params", contextinfo_ ));
return obj; return obj;
} }

View File

@ -2829,7 +2829,7 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL | SIGHASH_FORKID); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL | SIGHASH_FORKID, FORKID_IN_USE);
// Add the signature // Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,