Add consensus branch ID parameter to SignatureHash, remove SigVersion parameter

We do not need to be able to calculate multiple SignatureHash versions for a
single transaction format; instead, we use the transaction format to determine
the SigVersion.

The consensus branch ID *does* need to be passed in from the outside, as only
the caller knows the context in which the SignatureHash is being calculated
(ie. mempool acceptance vs. block validation).

JoinSplit signature verification has been moved into ContextualCheckTransaction,
where the consensus branch ID can be obtained.

The argument to the sign command for zcash-tx has been modified to take a height
in addition to the optional sigtype flags.
This commit is contained in:
Jack Grigg 2018-02-02 01:49:42 +00:00
parent 6514771a44
commit be12669982
No known key found for this signature in database
GPG Key ID: 665DBCD284F7DAFF
26 changed files with 360 additions and 237 deletions

View File

@ -6,6 +6,7 @@
#include "clientversion.h" #include "clientversion.h"
#include "coins.h" #include "coins.h"
#include "consensus/consensus.h" #include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "core_io.h" #include "core_io.h"
#include "keystore.h" #include "keystore.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
@ -70,7 +71,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX")); strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " + strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
_("This command requires JSON registers:") + _("This command requires JSON registers:") +
_("prevtxs=JSON object") + ", " + _("prevtxs=JSON object") + ", " +
_("privatekeys=JSON object") + ". " + _("privatekeys=JSON object") + ". " +
@ -334,10 +335,27 @@ static CAmount AmountFromValue(const UniValue& value)
return amount; return amount;
} }
static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
{ {
int nHashType = SIGHASH_ALL; // separate HEIGHT:SIGHASH-FLAGS in string
size_t pos = strInput.find(':');
if ((pos == 0) ||
(pos == (strInput.size() - 1)))
throw runtime_error("Invalid sighash flag separator");
// extract and validate HEIGHT
string strHeight = strInput.substr(0, pos);
int nHeight = atoi(strHeight);
if (nHeight <= 0) {
throw runtime_error("invalid height");
}
// extract and validate SIGHASH-FLAGS
int nHashType = SIGHASH_ALL;
string flagStr;
if (pos != string::npos) {
flagStr = strInput.substr(pos + 1, string::npos);
}
if (flagStr.size() > 0) if (flagStr.size() > 0)
if (!findSighashFlags(nHashType, flagStr)) if (!findSighashFlags(nHashType, flagStr))
throw runtime_error("unknown sighash flag/sign option"); throw runtime_error("unknown sighash flag/sign option");
@ -427,6 +445,9 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Grab the consensus branch ID for the given height
auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
// Sign what we can: // Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i]; CTxIn& txin = mergedTx.vin[i];
@ -441,14 +462,14 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
SignatureData sigdata; SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output: // Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size())) if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures: // ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants) BOOST_FOREACH(const CTransaction& txv, txVariants)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i)); sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
UpdateTransaction(mergedTx, i, sigdata); UpdateTransaction(mergedTx, i, sigdata);
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount))) if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId))
fComplete = false; fComplete = false;
} }

View File

@ -45,6 +45,8 @@ public:
CMutableTransaction GetValidTransaction() { CMutableTransaction GetValidTransaction() {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CMutableTransaction mtx; CMutableTransaction mtx;
mtx.vin.resize(2); mtx.vin.resize(2);
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
@ -74,7 +76,7 @@ CMutableTransaction GetValidTransaction() {
// 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, 0, SIGVERSION_BASE); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
if (dataToBeSigned == one) { if (dataToBeSigned == one) {
throw std::runtime_error("SignatureHash failed"); throw std::runtime_error("SignatureHash failed");
} }
@ -352,23 +354,27 @@ TEST(checktransaction_tests, bad_txns_prevout_null) {
} }
TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction(); CMutableTransaction mtx = GetValidTransaction();
mtx.joinSplitSig[0] += 1; mtx.joinSplitSig[0] += 1;
CTransaction tx(mtx); CTransaction tx(mtx);
MockCValidationState state; MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state); ContextualCheckTransaction(tx, state, 0, 100);
} }
TEST(checktransaction_tests, non_canonical_ed25519_signature) { TEST(checktransaction_tests, non_canonical_ed25519_signature) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction(); CMutableTransaction mtx = GetValidTransaction();
// Check that the signature is valid before we add L // Check that the signature is valid before we add L
{ {
CTransaction tx(mtx); CTransaction tx(mtx);
MockCValidationState state; MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100));
} }
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c // Copied from libsodium/crypto_sign/ed25519/ref10/open.c
@ -389,7 +395,7 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) {
MockCValidationState state; MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
CheckTransactionWithoutProofVerification(tx, state); ContextualCheckTransaction(tx, state, 0, 100);
} }
TEST(checktransaction_tests, OverwinterConstructors) { TEST(checktransaction_tests, OverwinterConstructors) {

View File

@ -1,5 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "consensus/upgrades.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#include "main.h" #include "main.h"
#include "utiltest.h" #include "utiltest.h"
@ -70,9 +71,10 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
FakeCoinsViewDB fakeDB; FakeCoinsViewDB fakeDB;
CCoinsViewCache view(&fakeDB); CCoinsViewCache view(&fakeDB);
auto consensusBranchId = SPROUT_BRANCH_ID;
CValidationState state; CValidationState state;
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus())); EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId));
} }
TEST(Validation, ReceivedBlockTransactions) { TEST(Validation, ReceivedBlockTransactions) {

View File

@ -758,7 +758,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
* 2. P2SH scripts with a crazy number of expensive * 2. P2SH scripts with a crazy number of expensive
* CHECKSIG/CHECKMULTISIG operations * CHECKSIG/CHECKMULTISIG operations
*/ */
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId)
{ {
if (tx.IsCoinBase()) if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally return true; // Coinbases don't use vin normally
@ -784,7 +784,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
// IsStandardTx() will have already returned false // IsStandardTx() will have already returned false
// and this method isn't called. // and this method isn't called.
vector<vector<unsigned char> > stack; vector<vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
return false; return false;
if (whichType == TX_SCRIPTHASH) if (whichType == TX_SCRIPTHASH)
@ -886,6 +886,30 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
} }
} }
if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) {
auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
// Empty output script.
CScript scriptCode;
uint256 dataToBeSigned;
try {
dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
} 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);
// 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");
}
}
return true; return true;
} }
@ -1082,30 +1106,6 @@ 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) {
// Empty output script.
CScript scriptCode;
uint256 dataToBeSigned;
try {
dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE);
} 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);
// 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");
}
}
} }
return true; return true;
@ -1148,6 +1148,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (pfMissingInputs) if (pfMissingInputs)
*pfMissingInputs = false; *pfMissingInputs = false;
int nextBlockHeight = chainActive.Height() + 1;
auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus());
// Node operator can choose to reject tx by number of transparent inputs // Node operator can choose to reject tx by number of transparent inputs
static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small"); static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small");
size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0); size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0);
@ -1165,7 +1168,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// DoS level set to 10 to be more forgiving. // DoS level set to 10 to be more forgiving.
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined. // Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
int nextBlockHeight = chainActive.Height() + 1;
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) { if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) {
return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
} }
@ -1260,7 +1262,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
} }
// Check for non-standard pay-to-script-hash in inputs // Check for non-standard pay-to-script-hash in inputs
if (Params().RequireStandard() && !AreInputsStandard(tx, view)) if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId))
return error("AcceptToMemoryPool: nonstandard transaction input"); return error("AcceptToMemoryPool: nonstandard transaction input");
// Check that the transaction doesn't have an excessive number of // Check that the transaction doesn't have an excessive number of
@ -1348,7 +1350,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Check against previous transactions // Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks. // This is done last to help prevent CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus())) if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{ {
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
} }
@ -1362,7 +1364,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// There is a similar check in CreateNewBlock() to prevent creating // There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool // invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack. // can be exploited as a DoS attack.
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus())) if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{ {
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
} }
@ -1727,7 +1729,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() { bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) { if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) {
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error)); return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
} }
return true; return true;
@ -1810,7 +1812,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
} }
}// namespace Consensus }// namespace Consensus
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks) bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams, uint32_t consensusBranchId, std::vector<CScriptCheck> *pvChecks)
{ {
if (!tx.IsCoinBase()) if (!tx.IsCoinBase())
{ {
@ -1835,7 +1837,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
assert(coins); assert(coins);
// Verify signature // Verify signature
CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata); CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata);
if (pvChecks) { if (pvChecks) {
pvChecks->push_back(CScriptCheck()); pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back()); check.swap(pvChecks->back());
@ -1848,7 +1850,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
// avoid splitting the network between upgraded and // avoid splitting the network between upgraded and
// non-upgraded nodes. // non-upgraded nodes.
CScriptCheck check2(*coins, tx, i, CScriptCheck check2(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata); flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata);
if (check2()) if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
} }
@ -2238,6 +2240,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
assert(tree.root() == old_tree_root); assert(tree.root() == old_tree_root);
} }
// Grab the consensus branch ID for the block's height
auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus());
std::vector<PrecomputedTransactionData> txdata; std::vector<PrecomputedTransactionData> txdata;
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++) for (unsigned int i = 0; i < block.vtx.size(); i++)
@ -2277,7 +2282,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
nFees += view.GetValueIn(tx)-tx.GetValueOut(); nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks; std::vector<CScriptCheck> vChecks;
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL)) if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL))
return false; return false;
control.Add(vChecks); control.Add(vChecks);
} }
@ -3721,7 +3726,7 @@ bool static LoadBlockIndexDB()
pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; pindex->nCachedBranchId = pindex->pprev->nCachedBranchId;
} }
} else { } else {
pindex->nCachedBranchId = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId; pindex->nCachedBranchId = SPROUT_BRANCH_ID;
} }
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
setBlockIndexCandidates.insert(pindex); setBlockIndexCandidates.insert(pindex);

View File

@ -306,7 +306,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
* @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, uint32_t consensusBranchId);
/** /**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way * Count ECDSA signature operations the old-fashioned (pre-0.6) way
@ -331,7 +331,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
* instead of being performed inline. * instead of being performed inline.
*/ */
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata,
const Consensus::Params& consensusParams, uint32_t consensusBranchId,
std::vector<CScriptCheck> *pvChecks = NULL); std::vector<CScriptCheck> *pvChecks = NULL);
/** Check a transaction contextually against a set of consensus rules */ /** Check a transaction contextually against a set of consensus rules */
@ -390,14 +391,15 @@ private:
unsigned int nIn; unsigned int nIn;
unsigned int nFlags; unsigned int nFlags;
bool cacheStore; bool cacheStore;
uint32_t consensusBranchId;
ScriptError error; ScriptError error;
PrecomputedTransactionData *txdata; PrecomputedTransactionData *txdata;
public: public:
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), consensusBranchId(0), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, uint32_t consensusBranchIdIn, PrecomputedTransactionData* txdataIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue), scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), consensusBranchId(consensusBranchIdIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()(); bool operator()();
@ -408,6 +410,7 @@ public:
std::swap(nIn, check.nIn); std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags); std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore); std::swap(cacheStore, check.cacheStore);
std::swap(consensusBranchId, check.consensusBranchId);
std::swap(error, check.error); std::swap(error, check.error);
std::swap(txdata, check.txdata); std::swap(txdata, check.txdata);
} }

View File

@ -12,6 +12,7 @@
#include "base58.h" #include "base58.h"
#include "chainparams.h" #include "chainparams.h"
#include "consensus/consensus.h" #include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#ifdef ENABLE_MINING #ifdef ENABLE_MINING
#include "crypto/equihash.h" #include "crypto/equihash.h"
@ -143,6 +144,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LOCK2(cs_main, mempool.cs); LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip(); CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1; const int nHeight = pindexPrev->nHeight + 1;
uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
pblock->nTime = GetAdjustedTime(); pblock->nTime = GetAdjustedTime();
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
CCoinsViewCache view(pcoinsTip); CCoinsViewCache view(pcoinsTip);
@ -294,7 +296,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// create only contains transactions that are valid in new blocks. // create only contains transactions that are valid in new blocks.
CValidationState state; CValidationState state;
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus())) if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
continue; continue;
UpdateCoins(tx, view, nHeight); UpdateCoins(tx, view, nHeight);

View File

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h" #include "base58.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#include "core_io.h" #include "core_io.h"
#include "init.h" #include "init.h"
@ -839,6 +840,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Grab the current consensus branch ID
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
// Script verification errors // Script verification errors
UniValue vErrors(UniValue::VARR); UniValue vErrors(UniValue::VARR);
@ -859,17 +863,17 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
SignatureData sigdata; SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output: // Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size())) if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures: // ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i)); sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
} }
UpdateTransaction(mergedTx, i, sigdata); UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK; ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) { if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
} }
} }

View File

@ -232,7 +232,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true; return true;
} }
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* serror)
{ {
static const CScriptNum bnZero(0); static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1); static const CScriptNum bnOne(1);
@ -828,7 +828,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, sigversion); bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
popstack(stack); popstack(stack);
popstack(stack); popstack(stack);
@ -886,7 +886,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
} }
// Check signature // Check signature
bool fOk = checker.CheckSig(vchSig, vchPubKey, script, sigversion); bool fOk = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
if (fOk) { if (fOk) {
isig++; isig++;
@ -1083,14 +1083,25 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
hashOutputs = GetOutputsHash(txTo); hashOutputs = GetOutputsHash(txTo);
} }
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) SigVersion SignatureHashVersion(const CTransaction& txTo)
{
if (txTo.fOverwintered) {
return SIGVERSION_OVERWINTER;
} else {
return SIGVERSION_SPROUT;
}
}
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, uint32_t consensusBranchId, const PrecomputedTransactionData* cache)
{ {
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) { if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
// nIn out of range // nIn out of range
throw logic_error("input index is out of range"); throw logic_error("input index is out of range");
} }
if (sigversion == SIGVERSION_WITNESS_V0) { auto sigversion = SignatureHashVersion(txTo);
if (sigversion == SIGVERSION_OVERWINTER) {
uint256 hashPrevouts; uint256 hashPrevouts;
uint256 hashSequence; uint256 hashSequence;
uint256 hashOutputs; uint256 hashOutputs;
@ -1159,7 +1170,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, SigVersion sigversion) const bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const
{ {
CPubKey pubkey(vchPubKey); CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid()) if (!pubkey.IsValid())
@ -1174,7 +1185,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
uint256 sighash; uint256 sighash;
try { try {
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
} catch (logic_error ex) { } catch (logic_error ex) {
return false; return false;
} }
@ -1222,7 +1233,7 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con
} }
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* serror)
{ {
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
@ -1231,12 +1242,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
} }
vector<vector<unsigned char> > stack, stackCopy; vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror))
// serror is set // serror is set
return false; return false;
if (flags & SCRIPT_VERIFY_P2SH) if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack; stackCopy = stack;
if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror)) if (!EvalScript(stack, scriptPubKey, flags, checker, consensusBranchId, serror))
// serror is set // serror is set
return false; return false;
if (stack.empty()) if (stack.empty())
@ -1263,7 +1274,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stack); popstack(stack);
if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror)) if (!EvalScript(stack, pubKey2, flags, checker, consensusBranchId, serror))
// serror is set // serror is set
return false; return false;
if (stack.empty()) if (stack.empty())

View File

@ -97,16 +97,16 @@ struct PrecomputedTransactionData
enum SigVersion enum SigVersion
{ {
SIGVERSION_BASE = 0, SIGVERSION_SPROUT = 0,
SIGVERSION_WITNESS_V0 = 1, SIGVERSION_OVERWINTER = 1,
}; };
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL); uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, uint32_t consensusBranchId, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker class BaseSignatureChecker
{ {
public: public:
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const
{ {
return false; return false;
} }
@ -133,7 +133,7 @@ protected:
public: public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {} TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const; bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckLockTime(const CScriptNum& nLockTime) const;
}; };
@ -146,7 +146,7 @@ public:
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {} MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
}; };
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL); bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* error = NULL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* serror = NULL);
#endif // BITCOIN_SCRIPT_INTERPRETER_H #endif // BITCOIN_SCRIPT_INTERPRETER_H

View File

@ -19,7 +19,7 @@ typedef vector<unsigned char> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {}
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const
{ {
CKey key; CKey key;
if (!keystore->GetKey(address, key)) if (!keystore->GetKey(address, key))
@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
uint256 hash; uint256 hash;
try { try {
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId);
} catch (logic_error ex) { } catch (logic_error ex) {
return false; return false;
} }
@ -38,16 +38,16 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
return true; return true;
} }
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, uint32_t consensusBranchId)
{ {
vector<unsigned char> vchSig; vector<unsigned char> vchSig;
if (!creator.CreateSig(vchSig, address, scriptCode, sigversion)) if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId))
return false; return false;
ret.push_back(vchSig); ret.push_back(vchSig);
return true; return true;
} }
static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, SigVersion sigversion) static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, uint32_t consensusBranchId)
{ {
int nSigned = 0; int nSigned = 0;
int nRequired = multisigdata.front()[0]; int nRequired = multisigdata.front()[0];
@ -55,7 +55,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
{ {
const valtype& pubkey = multisigdata[i]; const valtype& pubkey = multisigdata[i];
CKeyID keyID = CPubKey(pubkey).GetID(); CKeyID keyID = CPubKey(pubkey).GetID();
if (Sign1(keyID, creator, scriptCode, ret, sigversion)) if (Sign1(keyID, creator, scriptCode, ret, consensusBranchId))
++nSigned; ++nSigned;
} }
return nSigned==nRequired; return nSigned==nRequired;
@ -68,7 +68,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
* Returns false if scriptPubKey could not be completely satisfied. * Returns false if scriptPubKey could not be completely satisfied.
*/ */
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion) std::vector<valtype>& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId)
{ {
CScript scriptRet; CScript scriptRet;
uint160 h160; uint160 h160;
@ -86,10 +86,10 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
return false; return false;
case TX_PUBKEY: case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID(); keyID = CPubKey(vSolutions[0]).GetID();
return Sign1(keyID, creator, scriptPubKey, ret, sigversion); return Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId);
case TX_PUBKEYHASH: case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0])); keyID = CKeyID(uint160(vSolutions[0]));
if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion)) if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId))
return false; return false;
else else
{ {
@ -107,7 +107,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
case TX_MULTISIG: case TX_MULTISIG:
ret.push_back(valtype()); // workaround CHECKMULTISIG bug ret.push_back(valtype()); // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion)); return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId));
default: default:
return false; return false;
@ -129,13 +129,13 @@ static CScript PushAll(const vector<valtype>& values)
return result; return result;
} }
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId)
{ {
CScript script = fromPubKey; CScript script = fromPubKey;
bool solved = true; bool solved = true;
std::vector<valtype> result; std::vector<valtype> result;
txnouttype whichType; txnouttype whichType;
solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); solved = SignStep(creator, script, result, whichType, consensusBranchId);
CScript subscript; CScript subscript;
if (solved && whichType == TX_SCRIPTHASH) if (solved && whichType == TX_SCRIPTHASH)
@ -144,14 +144,14 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu
// the final scriptSig is the signatures from that // the final scriptSig is the signatures from that
// and then the serialized subscript: // and then the serialized subscript:
script = subscript = CScript(result[0].begin(), result[0].end()); script = subscript = CScript(result[0].begin(), result[0].end());
solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH;
result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end())); result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
} }
sigdata.scriptSig = PushAll(result); sigdata.scriptSig = PushAll(result);
// Test solution // Test solution
return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker(), consensusBranchId);
} }
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)
@ -168,7 +168,7 @@ void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const Signatur
tx.vin[nIn].scriptSig = data.scriptSig; tx.vin[nIn].scriptSig = data.scriptSig;
} }
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, uint32_t consensusBranchId)
{ {
assert(nIn < txTo.vin.size()); assert(nIn < txTo.vin.size());
@ -176,24 +176,24 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType);
SignatureData sigdata; SignatureData sigdata;
bool ret = ProduceSignature(creator, fromPubKey, sigdata); bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId);
UpdateTransaction(txTo, nIn, sigdata); UpdateTransaction(txTo, nIn, sigdata);
return ret; return ret;
} }
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, uint32_t consensusBranchId)
{ {
assert(nIn < txTo.vin.size()); assert(nIn < txTo.vin.size());
CTxIn& txin = txTo.vin[nIn]; CTxIn& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size()); assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n]; const CTxOut& txout = txFrom.vout[txin.prevout.n];
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId);
} }
static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const vector<valtype>& vSolutions, const vector<valtype>& vSolutions,
const vector<valtype>& sigs1, const vector<valtype>& sigs2, SigVersion sigversion) const vector<valtype>& sigs1, const vector<valtype>& sigs2, uint32_t consensusBranchId)
{ {
// Combine all the signatures we've got: // Combine all the signatures we've got:
set<valtype> allsigs; set<valtype> allsigs;
@ -221,7 +221,7 @@ static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSi
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, sigversion)) if (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId))
{ {
sigs[pubkey] = sig; sigs[pubkey] = sig;
break; break;
@ -254,8 +254,8 @@ struct Stacks
Stacks() {} Stacks() {}
explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_) {} explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_) {}
explicit Stacks(const SignatureData& data) { explicit Stacks(const SignatureData& data, uint32_t consensusBranchId) {
EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), consensusBranchId);
} }
SignatureData Output() const { SignatureData Output() const {
@ -268,7 +268,7 @@ struct Stacks
static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const txnouttype txType, const vector<valtype>& vSolutions, const txnouttype txType, const vector<valtype>& vSolutions,
Stacks sigs1, Stacks sigs2, SigVersion sigversion) Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId)
{ {
switch (txType) switch (txType)
{ {
@ -300,25 +300,26 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
Solver(pubKey2, txType2, vSolutions2); Solver(pubKey2, txType2, vSolutions2);
sigs1.script.pop_back(); sigs1.script.pop_back();
sigs2.script.pop_back(); sigs2.script.pop_back();
Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion); Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId);
result.script.push_back(spk); result.script.push_back(spk);
return result; return result;
} }
case TX_MULTISIG: case TX_MULTISIG:
return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion)); return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, consensusBranchId));
default: default:
return Stacks(); return Stacks();
} }
} }
SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const SignatureData& scriptSig1, const SignatureData& scriptSig2) const SignatureData& scriptSig1, const SignatureData& scriptSig2,
uint32_t consensusBranchId)
{ {
txnouttype txType; txnouttype txType;
vector<vector<unsigned char> > vSolutions; vector<vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions); Solver(scriptPubKey, txType, vSolutions);
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1, consensusBranchId), Stacks(scriptSig2, consensusBranchId), consensusBranchId).Output();
} }
namespace { namespace {
@ -328,7 +329,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, SigVersion sigversion) const bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const
{ {
return true; return true;
} }
@ -341,7 +342,7 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
return dummyChecker; return dummyChecker;
} }
bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const
{ {
// Create a dummy signature that is a valid DER-encoding // Create a dummy signature that is a valid DER-encoding
vchSig.assign(72, '\000'); vchSig.assign(72, '\000');

View File

@ -27,7 +27,7 @@ public:
virtual const BaseSignatureChecker& Checker() const =0; virtual const BaseSignatureChecker& Checker() const =0;
/** Create a singular (non-script) signature. */ /** Create a singular (non-script) signature. */
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0; virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const =0;
}; };
/** A signature creator for transactions. */ /** A signature creator for transactions. */
@ -41,7 +41,7 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
public: public:
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL);
const BaseSignatureChecker& Checker() const { return checker; } const BaseSignatureChecker& Checker() const { return checker; }
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const; bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
}; };
class MutableTransactionSignatureCreator : public TransactionSignatureCreator { class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
@ -56,7 +56,7 @@ class DummySignatureCreator : public BaseSignatureCreator {
public: public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
const BaseSignatureChecker& Checker() const; const BaseSignatureChecker& Checker() const;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const; bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
}; };
struct SignatureData { struct SignatureData {
@ -67,14 +67,14 @@ struct SignatureData {
}; };
/** Produce a script signature using a generic signature creator. */ /** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata); bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata, uint32_t consensusBranchId);
/** Produce a script signature for a transaction. */ /** Produce a script signature for a transaction. */
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, uint32_t consensusBranchId);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, uint32_t consensusBranchId);
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ /** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2); SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2, uint32_t consensusBranchId);
/** Extract signature data from a transaction, and insert it. */ /** Extract signature data from a transaction, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);

View File

@ -5,6 +5,7 @@
#include "zcashconsensus.h" #include "zcashconsensus.h"
#include "consensus/upgrades.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "pubkey.h" #include "pubkey.h"
#include "script/interpreter.h" #include "script/interpreter.h"
@ -86,7 +87,8 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int
set_error(err, zcashconsensus_ERR_OK); set_error(err, zcashconsensus_ERR_OK);
PrecomputedTransactionData txdata(tx); PrecomputedTransactionData txdata(tx);
CAmount am(0); CAmount am(0);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), NULL); uint32_t consensusBranchId = SPROUT_BRANCH_ID;
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), consensusBranchId, NULL);
} catch (const std::exception&) { } catch (const std::exception&) {
return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
} }

View File

@ -8,6 +8,7 @@
#include "consensus/upgrades.h"
#include "keystore.h" #include "keystore.h"
#include "main.h" #include "main.h"
#include "net.h" #include "net.h"
@ -119,6 +120,8 @@ CTransaction RandomOrphan()
BOOST_AUTO_TEST_CASE(DoS_mapOrphans) BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CKey key; CKey key;
key.MakeNewKey(true); key.MakeNewKey(true);
CBasicKeyStore keystore; CBasicKeyStore keystore;
@ -151,7 +154,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT; tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL); SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId);
AddOrphanTx(tx, i); AddOrphanTx(tx, i);
} }
@ -171,7 +174,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
tx.vin[j].prevout.n = j; tx.vin[j].prevout.n = j;
tx.vin[j].prevout.hash = txPrev.GetHash(); tx.vin[j].prevout.hash = txPrev.GetHash();
} }
SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL); SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId);
// Re-use same signature for other inputs // Re-use same signature for other inputs
// (they don't have to be valid for this test) // (they don't have to be valid for this test)
for (unsigned int j = 1; j < tx.vin.size(); j++) for (unsigned int j = 1; j < tx.vin.size(); j++)

View File

@ -53,7 +53,7 @@
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
"set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
"sign=ALL", "sign=1:ALL",
"outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"], "outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"],
"output_cmp": "txcreatesign.hex" "output_cmp": "txcreatesign.hex"
} }

View File

@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/upgrades.h"
#include "key.h" #include "key.h"
#include "keystore.h" #include "keystore.h"
#include "main.h" #include "main.h"
@ -26,9 +27,9 @@ typedef vector<unsigned char> valtype;
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) 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, uint32_t consensusBranchId)
{ {
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE); uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, consensusBranchId);
CScript result; CScript result;
result << OP_0; // CHECKMULTISIG bug workaround result << OP_0; // CHECKMULTISIG bug workaround
@ -44,6 +45,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
BOOST_AUTO_TEST_CASE(multisig_verify) BOOST_AUTO_TEST_CASE(multisig_verify)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
ScriptError err; ScriptError err;
@ -83,21 +85,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
// Test a AND b: // Test a AND b:
keys.assign(1,key[0]); keys.assign(1,key[0]);
keys.push_back(key[1]); keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0); s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err)); BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
keys.assign(1,key[i]); keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0); s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i)); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]); keys.assign(1,key[1]);
keys.push_back(key[i]); keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0); s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i)); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
@ -105,21 +107,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
keys.assign(1,key[i]); keys.assign(1,key[i]);
s = sign_multisig(a_or_b, keys, txTo[1], 0); s = sign_multisig(a_or_b, keys, txTo[1], 0, consensusBranchId);
if (i == 0 || i == 1) if (i == 0 || i == 1)
{ {
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
else else
{ {
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
} }
s.clear(); s.clear();
s << OP_0 << OP_1; s << OP_0 << OP_1;
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err)); BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
@ -128,15 +130,15 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
{ {
keys.assign(1,key[i]); keys.assign(1,key[i]);
keys.push_back(key[j]); keys.push_back(key[j]);
s = sign_multisig(escrow, keys, txTo[2], 0); s = sign_multisig(escrow, keys, txTo[2], 0, consensusBranchId);
if (i < j && i < 3 && j < 3) if (i < j && i < 3 && j < 3)
{ {
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j)); BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
else else
{ {
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j)); BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
} }
@ -277,6 +279,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_AUTO_TEST_CASE(multisig_Sign) BOOST_AUTO_TEST_CASE(multisig_Sign)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Test SignSignature() (and therefore the version of Solver() that signs transactions) // Test SignSignature() (and therefore the version of Solver() that signs transactions)
CBasicKeyStore keystore; CBasicKeyStore keystore;
CKey key[4]; CKey key[4];
@ -313,7 +317,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), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
} }
} }

View File

@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/upgrades.h"
#include "core_io.h" #include "core_io.h"
#include "key.h" #include "key.h"
#include "keystore.h" #include "keystore.h"
@ -32,6 +33,8 @@ Serialize(const CScript& s)
static bool static bool
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err) Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Create dummy to/from transactions: // Create dummy to/from transactions:
CMutableTransaction txFrom; CMutableTransaction txFrom;
txFrom.vout.resize(1); txFrom.vout.resize(1);
@ -45,7 +48,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig; txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1; txTo.vout[0].nValue = 1;
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), consensusBranchId, &err);
} }
@ -54,6 +57,7 @@ BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sign) BOOST_AUTO_TEST_CASE(sign)
{ {
LOCK(cs_main); LOCK(cs_main);
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Pay-to-script-hash looks like this: // Pay-to-script-hash looks like this:
// scriptSig: <sig> <sig...> <serialized_script> // scriptSig: <sig> <sig...> <serialized_script>
// scriptPubKey: HASH160 <hash> EQUAL // scriptPubKey: HASH160 <hash> EQUAL
@ -107,7 +111,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), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), 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:
@ -117,7 +121,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, false, &txdata)(); bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, consensusBranchId, &txdata)();
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
@ -157,6 +161,7 @@ BOOST_AUTO_TEST_CASE(norecurse)
BOOST_AUTO_TEST_CASE(set) BOOST_AUTO_TEST_CASE(set)
{ {
LOCK(cs_main); LOCK(cs_main);
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Test the CScript::Set* methods // Test the CScript::Set* methods
CBasicKeyStore keystore; CBasicKeyStore keystore;
CKey key[4]; CKey key[4];
@ -206,7 +211,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), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), 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));
} }
} }
@ -265,6 +270,7 @@ BOOST_AUTO_TEST_CASE(switchover)
BOOST_AUTO_TEST_CASE(AreInputsStandard) BOOST_AUTO_TEST_CASE(AreInputsStandard)
{ {
LOCK(cs_main); LOCK(cs_main);
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy); CCoinsViewCache coins(&coinsDummy);
CBasicKeyStore keystore; CBasicKeyStore keystore;
@ -335,16 +341,16 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].prevout.n = i; txTo.vin[i].prevout.n = i;
txTo.vin[i].prevout.hash = txFrom.GetHash(); txTo.vin[i].prevout.hash = txFrom.GetHash();
} }
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL, consensusBranchId));
// 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
// dummy signatures that DO include the correct P2SH scripts: // dummy signatures that DO include the correct P2SH scripts:
txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo); txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo);
txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops); txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops);
BOOST_CHECK(::AreInputsStandard(txTo, coins)); BOOST_CHECK(::AreInputsStandard(txTo, coins, consensusBranchId));
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
@ -353,7 +359,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
{ {
CScript t = txTo.vin[i].scriptSig; CScript t = txTo.vin[i].scriptSig;
txTo.vin[i].scriptSig = (CScript() << 11) + t; txTo.vin[i].scriptSig = (CScript() << 11) + t;
BOOST_CHECK(!::AreInputsStandard(txTo, coins)); BOOST_CHECK(!::AreInputsStandard(txTo, coins, consensusBranchId));
txTo.vin[i].scriptSig = t; txTo.vin[i].scriptSig = t;
} }
@ -366,7 +372,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops); txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops);
BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins, consensusBranchId));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
CMutableTransaction txToNonStd2; CMutableTransaction txToNonStd2;
@ -378,7 +384,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops); txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops);
BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins, consensusBranchId));
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
} }

View File

@ -5,6 +5,7 @@
#include "data/script_invalid.json.h" #include "data/script_invalid.json.h"
#include "data/script_valid.json.h" #include "data/script_valid.json.h"
#include "consensus/upgrades.h"
#include "core_io.h" #include "core_io.h"
#include "key.h" #include "key.h"
#include "keystore.h" #include "keystore.h"
@ -87,13 +88,13 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu
return txSpend; return txSpend;
} }
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, uint32_t consensusBranchId, bool expect, const std::string& message)
{ {
ScriptError err; ScriptError err;
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey); CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
CMutableTransaction tx2 = tx; CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message); BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), consensusBranchId, &err) == expect, message);
BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
#if defined(HAVE_CONSENSUS_LIB) #if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@ -188,6 +189,7 @@ private:
std::vector<unsigned char> push; std::vector<unsigned char> push;
std::string comment; std::string comment;
int flags; int flags;
uint32_t consensusBranchId;
void DoPush() void DoPush()
{ {
@ -205,7 +207,7 @@ private:
} }
public: public:
TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_) TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_), consensusBranchId(0)
{ {
if (P2SH) { if (P2SH) {
creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL); creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL);
@ -237,7 +239,7 @@ public:
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, 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, 0, SIGVERSION_BASE); uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId);
std::vector<unsigned char> vchSig, r, s; std::vector<unsigned char> vchSig, r, s;
uint32_t iter = 0; uint32_t iter = 0;
do { do {
@ -289,7 +291,7 @@ public:
{ {
TestBuilder copy = *this; // Make a copy so we can rollback the push. TestBuilder copy = *this; // Make a copy so we can rollback the push.
DoPush(); DoPush();
DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment); DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, consensusBranchId, expect, comment);
*this = copy; *this = copy;
return *this; return *this;
} }
@ -577,6 +579,7 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_AUTO_TEST_CASE(script_valid) BOOST_AUTO_TEST_CASE(script_valid)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Read tests from test/data/script_valid.json // Read tests from test/data/script_valid.json
// Format is an array of arrays // Format is an array of arrays
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ] // Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
@ -600,12 +603,13 @@ BOOST_AUTO_TEST_CASE(script_valid)
CScript scriptPubKey = ParseScript(scriptPubKeyString); CScript scriptPubKey = ParseScript(scriptPubKeyString);
unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest); DoTest(scriptPubKey, scriptSig, scriptflags, consensusBranchId, true, strTest);
} }
} }
BOOST_AUTO_TEST_CASE(script_invalid) BOOST_AUTO_TEST_CASE(script_invalid)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Scripts that should evaluate as invalid // Scripts that should evaluate as invalid
UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
@ -625,12 +629,14 @@ BOOST_AUTO_TEST_CASE(script_invalid)
CScript scriptPubKey = ParseScript(scriptPubKeyString); CScript scriptPubKey = ParseScript(scriptPubKeyString);
unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest); DoTest(scriptPubKey, scriptSig, scriptflags, consensusBranchId, false, strTest);
} }
} }
BOOST_AUTO_TEST_CASE(script_PushData) BOOST_AUTO_TEST_CASE(script_PushData)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
// the stack as the 1-75 opcodes do. // the stack as the 1-75 opcodes do.
static const unsigned char direct[] = { 1, 0x5a }; static const unsigned char direct[] = { 1, 0x5a };
@ -640,29 +646,29 @@ BOOST_AUTO_TEST_CASE(script_PushData)
ScriptError err; ScriptError err;
vector<vector<unsigned char> > directStack; vector<vector<unsigned char> > directStack;
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
vector<vector<unsigned char> > pushdata1Stack; vector<vector<unsigned char> > pushdata1Stack;
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK(pushdata1Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
vector<vector<unsigned char> > pushdata2Stack; vector<vector<unsigned char> > pushdata2Stack;
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK(pushdata2Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
vector<vector<unsigned char> > pushdata4Stack; vector<vector<unsigned char> > pushdata4Stack;
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK(pushdata4Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
CScript CScript
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction) sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, uint32_t consensusBranchId)
{ {
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, consensusBranchId);
CScript result; CScript result;
// //
@ -684,15 +690,17 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result; return result;
} }
CScript CScript
sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, uint32_t consensusBranchId)
{ {
std::vector<CKey> keys; std::vector<CKey> keys;
keys.push_back(key); keys.push_back(key);
return sign_multisig(scriptPubKey, keys, transaction); return sign_multisig(scriptPubKey, keys, transaction, consensusBranchId);
} }
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
ScriptError err; ScriptError err;
CKey key1, key2, key3; CKey key1, key2, key3;
key1.MakeNewKey(true); key1.MakeNewKey(true);
@ -705,24 +713,26 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12); CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2; txTo12.vout[0].nValue = 2;
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
ScriptError err; ScriptError err;
CKey key1, key2, key3, key4; CKey key1, key2, key3, key4;
key1.MakeNewKey(true); key1.MakeNewKey(true);
@ -738,60 +748,62 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys; std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2); keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key3); keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key3); keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &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)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Test the CombineSignatures function // Test the CombineSignatures function
CAmount amount = 0; CAmount amount = 0;
CBasicKeyStore keystore; CBasicKeyStore keystore;
@ -812,61 +824,61 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript& scriptSig = txTo.vin[0].scriptSig; CScript& scriptSig = txTo.vin[0].scriptSig;
SignatureData empty; SignatureData empty;
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig.empty()); BOOST_CHECK(combined.scriptSig.empty());
// Single signature case: // Single signature case:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
CScript scriptSigCopy = scriptSig; CScript scriptSigCopy = scriptSig;
// Signing again will give a different, valid signature: // Signing again will give a different, valid signature:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// P2SH, single-signature case: // P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
keystore.AddCScript(pkSingle); keystore.AddCScript(pkSingle);
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
scriptSigCopy = scriptSig; scriptSigCopy = scriptSig;
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// dummy scriptSigCopy with placeholder, should always choose non-placeholder: // dummy scriptSigCopy with placeholder, should always choose non-placeholder:
scriptSigCopy = CScript() << OP_0 << static_cast<vector<unsigned char> >(pkSingle); scriptSigCopy = CScript() << OP_0 << static_cast<vector<unsigned char> >(pkSingle);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
// Hardest case: Multisig 2-of-3 // Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys); scriptPubKey = GetScriptForMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey); keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSig);
// 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, 0, SIGVERSION_BASE); uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, consensusBranchId);
BOOST_CHECK(keys[0].Sign(hash1, sig1)); BOOST_CHECK(keys[0].Sign(hash1, sig1));
sig1.push_back(SIGHASH_ALL); sig1.push_back(SIGHASH_ALL);
vector<unsigned char> sig2; vector<unsigned char> sig2;
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE); uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, consensusBranchId);
BOOST_CHECK(keys[1].Sign(hash2, sig2)); BOOST_CHECK(keys[1].Sign(hash2, sig2));
sig2.push_back(SIGHASH_NONE); sig2.push_back(SIGHASH_NONE);
vector<unsigned char> sig3; vector<unsigned char> sig3;
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE); uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, consensusBranchId);
BOOST_CHECK(keys[2].Sign(hash3, sig3)); BOOST_CHECK(keys[2].Sign(hash3, sig3));
sig3.push_back(SIGHASH_SINGLE); sig3.push_back(SIGHASH_SINGLE);
@ -882,32 +894,34 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete13 = CScript() << OP_0 << sig1 << sig3;
CScript complete23 = CScript() << OP_0 << sig2 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3;
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == partial1a); BOOST_CHECK(combined.scriptSig == partial1a);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete12); BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete12); BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete12); BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete13); BOOST_CHECK(combined.scriptSig == complete13);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete23); BOOST_CHECK(combined.scriptSig == complete23);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete23); BOOST_CHECK(combined.scriptSig == complete23);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == partial3c); BOOST_CHECK(combined.scriptSig == partial3c);
} }
BOOST_AUTO_TEST_CASE(script_standard_push) BOOST_AUTO_TEST_CASE(script_standard_push)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
ScriptError err; ScriptError err;
for (int i=0; i<67000; i++) { for (int i=0; i<67000; i++) {
CScript script; CScript script;
script << i; script << i;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), consensusBranchId, &err), "Number " << i << " push is not minimal data.");
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
@ -916,7 +930,7 @@ BOOST_AUTO_TEST_CASE(script_standard_push)
CScript script; CScript script;
script << data; script << data;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), consensusBranchId, &err), "Length " << i << " push is not minimal data.");
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
} }

View File

@ -93,7 +93,7 @@ void static RandomScript(CScript &script) {
script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))]; script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
} }
void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { void static RandomTransaction(CMutableTransaction &tx, bool fSingle, uint32_t consensusBranchId) {
tx.fOverwintered = insecure_rand() % 2; tx.fOverwintered = insecure_rand() % 2;
if (tx.fOverwintered) { if (tx.fOverwintered) {
// Versions outside known ranges throw an exception during parsing // Versions outside known ranges throw an exception during parsing
@ -160,7 +160,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(tx); CTransaction signTx(tx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL,
dataToBeSigned.begin(), 32, dataToBeSigned.begin(), 32,
@ -173,11 +173,12 @@ BOOST_FIXTURE_TEST_SUITE(sighash_tests, JoinSplitTestingSetup)
BOOST_AUTO_TEST_CASE(sighash_test) BOOST_AUTO_TEST_CASE(sighash_test)
{ {
uint32_t overwinterBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
seed_insecure_rand(false); seed_insecure_rand(false);
#if defined(PRINT_SIGHASH_JSON) #if defined(PRINT_SIGHASH_JSON)
std::cout << "[\n"; std::cout << "[\n";
std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; std::cout << "\t[\"raw_transaction, script, input_index, hashType, branchId, signature_hash (result)\"],\n";
#endif #endif
int nRandomTests = 50000; int nRandomTests = 50000;
@ -186,15 +187,16 @@ BOOST_AUTO_TEST_CASE(sighash_test)
#endif #endif
for (int i=0; i<nRandomTests; i++) { for (int i=0; i<nRandomTests; i++) {
int nHashType = insecure_rand(); int nHashType = insecure_rand();
uint32_t consensusBranchId = insecure_rand() % 2 ? SPROUT_BRANCH_ID : overwinterBranchId;
CMutableTransaction txTo; CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE, consensusBranchId);
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, 0, SIGVERSION_BASE); sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, consensusBranchId);
#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;
@ -203,7 +205,8 @@ BOOST_AUTO_TEST_CASE(sighash_test)
std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; std::cout << HexStr(ss.begin(), ss.end()) << "\", \"";
std::cout << HexStr(scriptCode) << "\", "; std::cout << HexStr(scriptCode) << "\", ";
std::cout << nIn << ", "; std::cout << nIn << ", ";
std::cout << nHashType << ", \""; std::cout << nHashType << ", ";
std::cout << consensusBranchId << ", \"";
std::cout << (txTo.fOverwintered ? sh.GetHex() : sho.GetHex()) << "\"]"; std::cout << (txTo.fOverwintered ? sh.GetHex() : sho.GetHex()) << "\"]";
if (i+1 != nRandomTests) { if (i+1 != nRandomTests) {
std::cout << ","; std::cout << ",";
@ -236,6 +239,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
std::string raw_tx, raw_script, sigHashHex; std::string raw_tx, raw_script, sigHashHex;
int nIn, nHashType; int nIn, nHashType;
uint32_t consensusBranchId;
uint256 sh; uint256 sh;
CTransaction tx; CTransaction tx;
CScript scriptCode = CScript(); CScript scriptCode = CScript();
@ -246,7 +250,8 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
raw_script = test[1].get_str(); raw_script = test[1].get_str();
nIn = test[2].get_int(); nIn = test[2].get_int();
nHashType = test[3].get_int(); nHashType = test[3].get_int();
sigHashHex = test[4].get_str(); consensusBranchId = test[4].get_int();
sigHashHex = test[5].get_str();
uint256 sh; uint256 sh;
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
@ -278,7 +283,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
continue; continue;
} }
sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, SIGVERSION_BASE); sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, consensusBranchId);
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
} }
} }

View File

@ -9,6 +9,7 @@
#include "init.h" #include "init.h"
#include "clientversion.h" #include "clientversion.h"
#include "checkqueue.h" #include "checkqueue.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#include "core_io.h" #include "core_io.h"
#include "key.h" #include "key.h"
@ -92,6 +93,8 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, JoinSplitTestingSetup)
BOOST_AUTO_TEST_CASE(tx_valid) BOOST_AUTO_TEST_CASE(tx_valid)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Read tests from test/data/tx_valid.json // Read tests from test/data/tx_valid.json
// Format is an array of arrays // Format is an array of arrays
// Inner arrays are either [ "comment" ] // Inner arrays are either [ "comment" ]
@ -161,7 +164,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
CAmount amount = 0; CAmount amount = 0;
unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err), verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err),
strTest + comment); strTest + comment);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
} }
@ -178,6 +181,8 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_AUTO_TEST_CASE(tx_invalid) BOOST_AUTO_TEST_CASE(tx_invalid)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Read tests from test/data/tx_invalid.json // Read tests from test/data/tx_invalid.json
// Format is an array of arrays // Format is an array of arrays
// Inner arrays are either [ "comment" ] // Inner arrays are either [ "comment" ]
@ -246,7 +251,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
CAmount amount = 0; CAmount amount = 0;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err); verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err);
} }
BOOST_CHECK_MESSAGE(!fValid, strTest + comment); BOOST_CHECK_MESSAGE(!fValid, strTest + comment);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment); BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
@ -395,6 +400,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity) BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
auto verifier = libzcash::ProofVerifier::Strict(); auto verifier = libzcash::ProofVerifier::Strict();
CMutableTransaction tx; CMutableTransaction tx;
tx.nVersion = 2; tx.nVersion = 2;
@ -422,13 +428,14 @@ 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(CheckTransactionWithoutProofVerification(newTx, state));
BOOST_CHECK(!ContextualCheckTransaction(newTx, state, 0, 100));
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, 0, SIGVERSION_BASE); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL,
dataToBeSigned.begin(), 32, dataToBeSigned.begin(), 32,
@ -436,6 +443,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
) == 0); ) == 0);
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
BOOST_CHECK(ContextualCheckTransaction(newTx, state, 0, 100));
} }
{ {
// Ensure that values within the joinsplit are well-formed. // Ensure that values within the joinsplit are well-formed.
@ -525,6 +533,8 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
BOOST_AUTO_TEST_CASE(test_Get) BOOST_AUTO_TEST_CASE(test_Get)
{ {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CBasicKeyStore keystore; CBasicKeyStore keystore;
CCoinsView coinsDummy; CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy); CCoinsViewCache coins(&coinsDummy);
@ -545,19 +555,20 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].nValue = 90*CENT; t1.vout[0].nValue = 90*CENT;
t1.vout[0].scriptPubKey << OP_1; t1.vout[0].scriptPubKey << OP_1;
BOOST_CHECK(AreInputsStandard(t1, coins)); BOOST_CHECK(AreInputsStandard(t1, coins, consensusBranchId));
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT); BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
// Adding extra junk to the scriptSig should make it non-standard: // Adding extra junk to the scriptSig should make it non-standard:
t1.vin[0].scriptSig << OP_11; t1.vin[0].scriptSig << OP_11;
BOOST_CHECK(!AreInputsStandard(t1, coins)); BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId));
// ... as should not having enough: // ... as should not having enough:
t1.vin[0].scriptSig = CScript(); t1.vin[0].scriptSig = CScript();
BOOST_CHECK(!AreInputsStandard(t1, coins)); BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId));
} }
BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
uint32_t consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
CMutableTransaction mtx; CMutableTransaction mtx;
mtx.fOverwintered = true; mtx.fOverwintered = true;
mtx.nVersion = 3; mtx.nVersion = 3;
@ -596,7 +607,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
// sign all inputs // sign all inputs
for(uint32_t i = 0; i < mtx.vin.size(); i++) { for(uint32_t i = 0; i < mtx.vin.size(); i++) {
bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size())); bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()), consensusBranchId);
assert(hashSigned); assert(hashSigned);
} }
@ -626,7 +637,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
for(uint32_t i = 0; i < mtx.vin.size(); i++) { for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks; std::vector<CScriptCheck> vChecks;
CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, &txdata); CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, consensusBranchId, &txdata);
vChecks.push_back(CScriptCheck()); vChecks.push_back(CScriptCheck());
check.swap(vChecks.back()); check.swap(vChecks.back());
control.Add(vChecks); control.Add(vChecks);

View File

@ -4,6 +4,8 @@
#include "utiltest.h" #include "utiltest.h"
#include "consensus/upgrades.h"
CWalletTx GetValidReceive(ZCJoinSplit& params, CWalletTx GetValidReceive(ZCJoinSplit& params,
const libzcash::SpendingKey& sk, CAmount value, const libzcash::SpendingKey& sk, CAmount value,
bool randomInputs) { bool randomInputs) {
@ -45,11 +47,10 @@ CWalletTx GetValidReceive(ZCJoinSplit& params,
mtx.vjoinsplit.push_back(jsdesc); mtx.vjoinsplit.push_back(jsdesc);
// Empty output script. // Empty output script.
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); CTransaction signTx(mtx);
//fifth parameter amount will not be used for joinsplit signing, value arbitrary, also arbitrary decision what to use for sigverion uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
//This is just to get this merge commit to compile later will remove sigversion parameter as choosing sigversion by block height
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL,0, SIGVERSION_BASE);
// Add the signature // Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
@ -131,9 +132,10 @@ CWalletTx GetValidSpend(ZCJoinSplit& params,
mtx.vjoinsplit.push_back(jsdesc); mtx.vjoinsplit.push_back(jsdesc);
// Empty output script. // Empty output script.
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL,0,SIGVERSION_BASE); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
// Add the signature // Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,

View File

@ -5,6 +5,7 @@
#include "asyncrpcoperation_sendmany.h" #include "asyncrpcoperation_sendmany.h"
#include "asyncrpcqueue.h" #include "asyncrpcqueue.h"
#include "amount.h" #include "amount.h"
#include "consensus/upgrades.h"
#include "core_io.h" #include "core_io.h"
#include "init.h" #include "init.h"
#include "main.h" #include "main.h"
@ -337,6 +338,12 @@ bool AsyncRPCOperation_sendmany::main_impl() {
LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total)); LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total));
LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee)); LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee));
// Grab the current consensus branch ID
{
LOCK(cs_main);
consensusBranchId_ = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
}
/** /**
* SCENARIO #1 * SCENARIO #1
* *
@ -994,7 +1001,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, 0, SIGVERSION_BASE); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_);
// Add the signature // Add the signature
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,

View File

@ -73,6 +73,7 @@ private:
UniValue contextinfo_; // optional data to include in return value from getStatus() UniValue contextinfo_; // optional data to include in return value from getStatus()
uint32_t consensusBranchId_;
CAmount fee_; CAmount fee_;
int mindepth_; int mindepth_;
std::string fromaddress_; std::string fromaddress_;

View File

@ -4,6 +4,7 @@
#include "asyncrpcqueue.h" #include "asyncrpcqueue.h"
#include "amount.h" #include "amount.h"
#include "consensus/upgrades.h"
#include "core_io.h" #include "core_io.h"
#include "init.h" #include "init.h"
#include "main.h" #include "main.h"
@ -302,12 +303,15 @@ void AsyncRPCOperation_shieldcoinbase::sign_send_raw_transaction(UniValue obj)
UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) { UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) {
uint32_t consensusBranchId;
uint256 anchor; uint256 anchor;
{ {
LOCK(cs_main); LOCK(cs_main);
consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
anchor = pcoinsTip->GetBestAnchor(); anchor = pcoinsTip->GetBestAnchor();
} }
if (anchor.IsNull()) { if (anchor.IsNull()) {
throw std::runtime_error("anchor is null"); throw std::runtime_error("anchor is null");
} }
@ -369,7 +373,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
// 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, 0, SIGVERSION_BASE); uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
// Add the signature // Add the signature
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,

View File

@ -5,6 +5,7 @@
#include "amount.h" #include "amount.h"
#include "base58.h" #include "base58.h"
#include "consensus/upgrades.h"
#include "core_io.h" #include "core_io.h"
#include "init.h" #include "init.h"
#include "main.h" #include "main.h"
@ -2840,7 +2841,8 @@ 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, 0, SIGVERSION_BASE); auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
// Add the signature // Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,

View File

@ -8,6 +8,7 @@
#include "base58.h" #include "base58.h"
#include "checkpoints.h" #include "checkpoints.h"
#include "coincontrol.h" #include "coincontrol.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#include "init.h" #include "init.h"
#include "main.h" #include "main.h"
@ -2768,6 +2769,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
} }
} }
// Grab the current consensus branch ID
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
// Sign // Sign
int nIn = 0; int nIn = 0;
CTransaction txNewConst(txNew); CTransaction txNewConst(txNew);
@ -2777,9 +2781,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
SignatureData sigdata; SignatureData sigdata;
if (sign) if (sign)
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata); signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, consensusBranchId);
else else
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata); signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
if (!signSuccess) if (!signSuccess)
{ {

View File

@ -13,6 +13,7 @@
#include "crypto/equihash.h" #include "crypto/equihash.h"
#include "chain.h" #include "chain.h"
#include "chainparams.h" #include "chainparams.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h" #include "consensus/validation.h"
#include "main.h" #include "main.h"
#include "miner.h" #include "miner.h"
@ -251,8 +252,9 @@ double benchmark_large_tx()
} }
// Sign for all the inputs // Sign for all the inputs
auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
for (size_t i = 0; i < NUM_INPUTS; i++) { for (size_t i = 0; i < NUM_INPUTS; i++) {
SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL); SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId);
} }
// Serialize: // Serialize:
@ -278,6 +280,7 @@ double benchmark_large_tx()
prevPubKey, prevPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS, STANDARD_SCRIPT_VERIFY_FLAGS,
TransactionSignatureChecker(&final_spending_tx, i, 1000000), TransactionSignatureChecker(&final_spending_tx, i, 1000000),
consensusBranchId,
&serror)); &serror));
} }
return timer_stop(tv_start); return timer_stop(tv_start);