Auto merge of #2903 - str4d:1408-sighash, r=str4d

Overwinter SignatureHash

Implements ZIP 143.

Includes code cherry-picked from the following upstream PRs:

- bitcoin/bitcoin#7276
- bitcoin/bitcoin#7976
- bitcoin/bitcoin#8118
- bitcoin/bitcoin#8149
  - Only amount validation and SignatureHash commits.
- bitcoin/bitcoin#8346
- bitcoin/bitcoin#8524

Part of #2074 and #2254. Closes #1408 and #2584.
This commit is contained in:
Homu 2018-02-20 03:59:45 -08:00
commit 8487be8360
36 changed files with 1501 additions and 881 deletions

View File

@ -195,7 +195,7 @@ case "$1" in
zcash_rpc zcbenchmark verifyequihash 1000
;;
validatelargetx)
zcash_rpc zcbenchmark validatelargetx 5
zcash_rpc zcbenchmark validatelargetx 10 "${@:3}"
;;
trydecryptnotes)
zcash_rpc zcbenchmark trydecryptnotes 1000 "${@:3}"

View File

@ -6,6 +6,7 @@
#include "clientversion.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "consensus/upgrades.h"
#include "core_io.h"
#include "keystore.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("outaddr=VALUE:ADDRESS", _("Add address-based 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:") +
_("prevtxs=JSON object") + ", " +
_("privatekeys=JSON object") + ". " +
@ -322,10 +323,39 @@ vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
return ParseHexUV(o[strKey], strKey);
}
static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
static CAmount AmountFromValue(const UniValue& value)
{
int nHashType = SIGHASH_ALL;
if (!value.isNum() && !value.isStr())
throw runtime_error("Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw runtime_error("Invalid amount");
if (!MoneyRange(amount))
throw runtime_error("Amount out of range");
return amount;
}
static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
{
// 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 (!findSighashFlags(nHashType, flagStr))
throw runtime_error("unknown sighash flag/sign option");
@ -393,7 +423,10 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
coins->vout[nOut].scriptPubKey = scriptPubKey;
coins->vout[nOut].nValue = 0; // we don't know the actual output value
coins->vout[nOut].nValue = 0;
if (prevOut.exists("amount")) {
coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
}
}
// if redeemScript given and private keys given,
@ -412,6 +445,9 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
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:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
@ -421,17 +457,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
txin.scriptSig.clear();
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
BOOST_FOREACH(const CTransaction& txv, txVariants)
sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
UpdateTransaction(mergedTx, i, sigdata);
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId))
fComplete = false;
}

View File

@ -45,6 +45,8 @@ public:
CMutableTransaction GetValidTransaction() {
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CMutableTransaction mtx;
mtx.vin.resize(2);
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
@ -74,7 +76,7 @@ CMutableTransaction GetValidTransaction() {
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
if (dataToBeSigned == one) {
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) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
mtx.joinSplitSig[0] += 1;
CTransaction tx(mtx);
MockCValidationState state;
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) {
SelectParams(CBaseChainParams::REGTEST);
CMutableTransaction mtx = GetValidTransaction();
// Check that the signature is valid before we add L
{
CTransaction tx(mtx);
MockCValidationState state;
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100));
}
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
@ -389,7 +395,7 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) {
MockCValidationState state;
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) {

View File

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

View File

@ -12,6 +12,8 @@
#include "uint256.h"
#include "version.h"
#include "sodium.h"
#include <vector>
typedef uint256 ChainCode;
@ -150,6 +152,47 @@ public:
}
};
/** A writer stream (for serialization) that computes a 256-bit BLAKE2b hash. */
class CBLAKE2bWriter
{
private:
crypto_generichash_blake2b_state state;
public:
int nType;
int nVersion;
CBLAKE2bWriter(int nTypeIn, int nVersionIn, const unsigned char* personal) : nType(nTypeIn), nVersion(nVersionIn) {
assert(crypto_generichash_blake2b_init_salt_personal(
&state,
NULL, 0, // No key.
32,
NULL, // No salt.
personal) == 0);
}
CBLAKE2bWriter& write(const char *pch, size_t size) {
crypto_generichash_blake2b_update(&state, (const unsigned char*)pch, size);
return (*this);
}
// invalidates the object
uint256 GetHash() {
uint256 result;
crypto_generichash_blake2b_final(&state, (unsigned char*)&result, 32);
return result;
}
template<typename T>
CBLAKE2bWriter& operator<<(const T& obj) {
// Serialize to this stream
::Serialize(*this, obj, nType, nVersion);
return (*this);
}
};
/** Compute the 256-bit hash of an object's serialization. */
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)

View File

@ -758,7 +758,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
* 2. P2SH scripts with a crazy number of expensive
* 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())
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
// and this method isn't called.
vector<vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
return false;
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;
}
@ -1082,30 +1106,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
if (txin.prevout.IsNull())
return state.DoS(10, error("CheckTransaction(): prevout is 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);
} 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;
@ -1148,6 +1148,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (pfMissingInputs)
*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
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);
@ -1165,7 +1168,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// 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.
int nextBlockHeight = chainActive.Height() + 1;
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) {
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
if (Params().RequireStandard() && !AreInputsStandard(tx, view))
if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId))
return error("AcceptToMemoryPool: nonstandard transaction input");
// Check that the transaction doesn't have an excessive number of
@ -1347,7 +1349,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
PrecomputedTransactionData txdata(tx);
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
{
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
}
@ -1361,7 +1364,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks, however allowing such transactions into the mempool
// can be exploited as a DoS attack.
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, 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());
}
@ -1684,7 +1687,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
}
}
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight)
{
// mark inputs spent
if (!tx.IsCoinBase()) {
@ -1718,15 +1721,15 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
}
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight)
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
{
CTxUndo txundo;
UpdateCoins(tx, state, inputs, txundo, nHeight);
UpdateCoins(tx, inputs, txundo, nHeight);
}
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &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 true;
@ -1809,7 +1812,17 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
}
}// namespace Consensus
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, 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())
{
@ -1834,7 +1847,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
assert(coins);
// Verify signature
CScriptCheck check(*coins, tx, i, flags, cacheStore);
CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
@ -1846,9 +1859,9 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
// arguments; if so, don't trigger DoS protection to
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
if (check())
CScriptCheck check2(*coins, tx, i,
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
// Failures of other flags indicate a transaction that is
@ -2237,6 +2250,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
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;
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++)
{
const CTransaction &tx = block.vtx[i];
@ -2265,11 +2283,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (nSigOps > MAX_BLOCK_SIGOPS)
return state.DoS(100, error("ConnectBlock(): too many sigops"),
REJECT_INVALID, "bad-blk-sigops");
}
txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
@ -2278,7 +2301,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (i > 0) {
blockundo.vtxundo.push_back(CTxUndo());
}
UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
BOOST_FOREACH(const uint256 &note_commitment, joinsplit.commitments) {
@ -3713,7 +3736,7 @@ bool static LoadBlockIndexDB()
pindex->nCachedBranchId = pindex->pprev->nCachedBranchId;
}
} else {
pindex->nCachedBranchId = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId;
pindex->nCachedBranchId = SPROUT_BRANCH_ID;
}
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
setBlockIndexCandidates.insert(pindex);

View File

@ -45,6 +45,7 @@ class CInv;
class CScriptCheck;
class CValidationInterface;
class CValidationState;
class PrecomputedTransactionData;
struct CNodeStateStats;
@ -305,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
* @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
@ -330,14 +331,17 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
* instead of being performed inline.
*/
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams,
unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata,
const Consensus::Params& consensusParams, uint32_t consensusBranchId,
std::vector<CScriptCheck> *pvChecks = NULL);
/** Check a transaction contextually against a set of consensus rules */
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel);
/** Apply the effects of this transaction on the UTXO set represented by view */
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
/** Transaction validation functions */
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
@ -348,6 +352,17 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
*/
bool IsStandardTx(const CTransaction& tx, std::string& reason, int nHeight = 0);
namespace Consensus {
/**
* Check whether all inputs of this transaction are valid (no double spends and amounts)
* This does not modify the UTXO set. This does not check scripts and sigs.
* Preconditions: tx.IsCoinBase() is false.
*/
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
} // namespace Consensus
/**
* Check if transaction is final and can be included in a block with the
* specified height and time. Consensus critical.
@ -371,27 +386,33 @@ class CScriptCheck
{
private:
CScript scriptPubKey;
CAmount amount;
const CTransaction *ptxTo;
unsigned int nIn;
unsigned int nFlags;
bool cacheStore;
uint32_t consensusBranchId;
ScriptError error;
PrecomputedTransactionData *txdata;
public:
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey),
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), 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, uint32_t consensusBranchIdIn, PrecomputedTransactionData* txdataIn) :
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), consensusBranchId(consensusBranchIdIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
void swap(CScriptCheck &check) {
scriptPubKey.swap(check.scriptPubKey);
std::swap(ptxTo, check.ptxTo);
std::swap(amount, check.amount);
std::swap(nIn, check.nIn);
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(consensusBranchId, check.consensusBranchId);
std::swap(error, check.error);
std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
@ -534,10 +555,6 @@ extern CBlockTreeDB *pblocktree;
*/
int GetSpendHeight(const CCoinsViewCache& inputs);
namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, const Consensus::Params& consensusParams);
}
/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight);

View File

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

View File

@ -383,12 +383,7 @@ public:
*const_cast<bool*>(&fOverwintered) = header >> 31;
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
} else {
// When serializing v1 and v2, the 4 byte header is nVersion
uint32_t header = this->nVersion;
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
if (fOverwintered) {
header |= 1 << 31;
}
uint32_t header = GetHeader();
READWRITE(header);
}
nVersion = this->nVersion;
@ -428,6 +423,16 @@ public:
return hash;
}
uint32_t GetHeader() const {
// When serializing v1 and v2, the 4 byte header is nVersion
uint32_t header = this->nVersion;
// When serializing Overwintered tx, the 4 byte header is the combination of fOverwintered and nVersion
if (fOverwintered) {
header |= 1 << 31;
}
return header;
}
// Return sum of txouts.
CAmount GetValueOut() const;
// GetValueIn() is a method on CCoinsViewCache, because

View File

@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
@ -654,7 +655,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
" \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n, (numeric, required) The output number\n"
" \"scriptPubKey\": \"hex\", (string, required) script key\n"
" \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n"
" \"redeemScript\": \"hex\", (string, required for P2SH) redeem script\n"
" \"amount\": value (numeric, required) The amount spent\n"
" }\n"
" ,...\n"
" ]\n"
@ -792,7 +794,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
if ((unsigned int)nOut >= coins->vout.size())
coins->vout.resize(nOut+1);
coins->vout[nOut].scriptPubKey = scriptPubKey;
coins->vout[nOut].nValue = 0; // we don't know the actual output value
coins->vout[nOut].nValue = 0;
if (prevOut.exists("amount")) {
coins->vout[nOut].nValue = AmountFromValue(find_value(prevOut, "amount"));
}
}
// if redeemScript given and not using the local wallet (private keys
@ -835,9 +840,15 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Grab the current consensus branch ID
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
// Script verification errors
UniValue vErrors(UniValue::VARR);
// Use CTransaction for the constant parts of the
// transaction to avoid rehashing.
const CTransaction txConst(mergedTx);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
@ -847,18 +858,22 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
continue;
}
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
const CAmount& amount = coins->vout[txin.prevout.n].nValue;
txin.scriptSig.clear();
SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
// ... and merge in other signatures:
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
}
UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK;
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) {
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) {
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
}
}

View File

@ -5,6 +5,7 @@
#include "interpreter.h"
#include "consensus/upgrades.h"
#include "primitives/transaction.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
@ -232,7 +233,13 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true;
}
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, 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 bnOne(1);
@ -828,7 +835,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
//serror is set
return false;
}
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script);
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
popstack(stack);
popstack(stack);
@ -886,7 +893,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
}
// Check signature
bool fOk = checker.CheckSig(vchSig, vchPubKey, script);
bool fOk = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
if (fOk) {
isig++;
@ -1050,15 +1057,148 @@ public:
}
};
const unsigned char ZCASH_PREVOUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z','c','a','s','h','P','r','e','v','o','u','t','H','a','s','h'};
const unsigned char ZCASH_SEQUENCE_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z','c','a','s','h','S','e','q','u','e','n','c','H','a','s','h'};
const unsigned char ZCASH_OUTPUTS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z','c','a','s','h','O','u','t','p','u','t','s','H','a','s','h'};
const unsigned char ZCASH_JOINSPLITS_HASH_PERSONALIZATION[crypto_generichash_blake2b_PERSONALBYTES] =
{'Z','c','a','s','h','J','S','p','l','i','t','s','H','a','s','h'};
uint256 GetPrevoutHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_PREVOUTS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
ss << txTo.vin[n].prevout;
}
return ss.GetHash();
}
uint256 GetSequenceHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_SEQUENCE_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vin.size(); n++) {
ss << txTo.vin[n].nSequence;
}
return ss.GetHash();
}
uint256 GetOutputsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vout.size(); n++) {
ss << txTo.vout[n];
}
return ss.GetHash();
}
uint256 GetJoinSplitsHash(const CTransaction& txTo) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_JOINSPLITS_HASH_PERSONALIZATION);
for (unsigned int n = 0; n < txTo.vjoinsplit.size(); n++) {
ss << txTo.vjoinsplit[n];
}
ss << txTo.joinSplitPubKey;
return ss.GetHash();
}
} // anon namespace
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
{
hashPrevouts = GetPrevoutHash(txTo);
hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo);
hashJoinSplits = GetJoinSplitsHash(txTo);
}
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) {
// nIn out of range
throw logic_error("input index is out of range");
}
auto sigversion = SignatureHashVersion(txTo);
if (sigversion == SIGVERSION_OVERWINTER) {
uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
uint256 hashJoinSplits;
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
}
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}
if (!txTo.vjoinsplit.empty()) {
hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo);
}
uint32_t leConsensusBranchId = htole32(consensusBranchId);
unsigned char personalization[16] = {};
memcpy(personalization, "ZcashSigHash", 12);
memcpy(personalization+12, &leConsensusBranchId, 4);
CBLAKE2bWriter ss(SER_GETHASH, 0, personalization);
// Header
ss << txTo.GetHeader();
// Version group ID
ss << txTo.nVersionGroupId;
// Input prevouts/nSequence (none/all, depending on flags)
ss << hashPrevouts;
ss << hashSequence;
// Outputs (none/one/all, depending on flags)
ss << hashOutputs;
// JoinSplits
ss << hashJoinSplits;
// Locktime
ss << txTo.nLockTime;
// Expiry height
ss << txTo.nExpiryHeight;
// Sighash type
ss << nHashType;
// If this hash is for a transparent input signature
// (i.e. not for txTo.joinSplitSig):
if (nIn != NOT_AN_INPUT){
// The input being signed (replacing the scriptSig with scriptCode + amount)
// The prevout may already be contained in hashPrevout, and the nSequence
// may already be contained in hashSequence.
ss << txTo.vin[nIn].prevout;
ss << scriptCode;
ss << amount;
ss << txTo.vin[nIn].nSequence;
}
return ss.GetHash();
}
// Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
if (nIn >= txTo.vout.size()) {
@ -1076,12 +1216,17 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
return ss.GetHash();
}
bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
bool TransactionSignatureChecker::VerifySignature(
const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
return pubkey.Verify(sighash, vchSig);
}
bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
bool TransactionSignatureChecker::CheckSig(
const vector<unsigned char>& vchSigIn,
const vector<unsigned char>& vchPubKey,
const CScript& scriptCode,
uint32_t consensusBranchId) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@ -1096,7 +1241,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
uint256 sighash;
try {
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
} catch (logic_error ex) {
return false;
}
@ -1144,7 +1289,13 @@ 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);
@ -1153,12 +1304,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
}
vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, serror))
if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror))
// serror is set
return false;
if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack;
if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
if (!EvalScript(stack, scriptPubKey, flags, checker, consensusBranchId, serror))
// serror is set
return false;
if (stack.empty())
@ -1185,7 +1336,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stack);
if (!EvalScript(stack, pubKey2, flags, checker, serror))
if (!EvalScript(stack, pubKey2, flags, checker, consensusBranchId, serror))
// serror is set
return false;
if (stack.empty())

View File

@ -88,12 +88,36 @@ enum
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits;
PrecomputedTransactionData(const CTransaction& tx);
};
enum SigVersion
{
SIGVERSION_SPROUT = 0,
SIGVERSION_OVERWINTER = 1,
};
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
{
public:
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
virtual bool CheckSig(
const std::vector<unsigned char>& scriptSig,
const std::vector<unsigned char>& vchPubKey,
const CScript& scriptCode,
uint32_t consensusBranchId) const
{
return false;
}
@ -111,13 +135,16 @@ class TransactionSignatureChecker : public BaseSignatureChecker
private:
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
const PrecomputedTransactionData* txdata;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
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) {}
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;
};
@ -127,10 +154,22 @@ private:
const CTransaction txTo;
public:
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), 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, ScriptError* error = NULL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, 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,
uint32_t consensusBranchId,
ScriptError* serror = NULL);
#endif // BITCOIN_SCRIPT_INTERPRETER_H

View File

@ -18,7 +18,7 @@ private:
bool store;
public:
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {}
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};

View File

@ -17,9 +17,9 @@ using namespace std;
typedef vector<unsigned char> valtype;
TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {}
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) const
bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const
{
CKey key;
if (!keystore->GetKey(address, key))
@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
uint256 hash;
try {
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId);
} catch (logic_error ex) {
return false;
}
@ -38,16 +38,16 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
return true;
}
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, uint32_t consensusBranchId)
{
vector<unsigned char> vchSig;
if (!creator.CreateSig(vchSig, address, scriptCode))
if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId))
return false;
scriptSigRet << vchSig;
ret.push_back(vchSig);
return true;
}
static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet)
static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector<valtype>& ret, uint32_t consensusBranchId)
{
int nSigned = 0;
int nRequired = multisigdata.front()[0];
@ -55,7 +55,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
{
const valtype& pubkey = multisigdata[i];
CKeyID keyID = CPubKey(pubkey).GetID();
if (Sign1(keyID, creator, scriptCode, scriptSigRet))
if (Sign1(keyID, creator, scriptCode, ret, consensusBranchId))
++nSigned;
}
return nSigned==nRequired;
@ -68,9 +68,11 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
* Returns false if scriptPubKey could not be completely satisfied.
*/
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
CScript& scriptSigRet, txnouttype& whichTypeRet)
std::vector<valtype>& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId)
{
scriptSigRet.clear();
CScript scriptRet;
uint160 h160;
ret.clear();
vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
@ -84,85 +86,127 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
return false;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
return Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId);
case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId))
return false;
else
{
CPubKey vch;
creator.KeyStore().GetPubKey(keyID, vch);
scriptSigRet << ToByteVector(vch);
ret.push_back(ToByteVector(vch));
}
return true;
case TX_SCRIPTHASH:
return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);
case TX_MULTISIG:
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet));
}
return false;
}
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig)
{
txnouttype whichType;
if (!SignStep(creator, fromPubKey, scriptSig, whichType))
if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
return true;
}
return false;
if (whichType == TX_SCRIPTHASH)
case TX_MULTISIG:
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId));
default:
return false;
}
}
static CScript PushAll(const vector<valtype>& values)
{
CScript result;
BOOST_FOREACH(const valtype& v, values) {
if (v.size() == 0) {
result << OP_0;
} else if (v.size() == 1 && v[0] >= 1 && v[0] <= 16) {
result << CScript::EncodeOP_N(v[0]);
} else {
result << v;
}
}
return result;
}
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId)
{
CScript script = fromPubKey;
bool solved = true;
std::vector<valtype> result;
txnouttype whichType;
solved = SignStep(creator, script, result, whichType, consensusBranchId);
CScript subscript;
if (solved && whichType == TX_SCRIPTHASH)
{
// Solver returns the subscript that need to be evaluated;
// Solver returns the subscript that needs to be evaluated;
// the final scriptSig is the signatures from that
// and then the serialized subscript:
CScript subscript = scriptSig;
txnouttype subType;
bool fSolved =
SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH;
// Append serialized subscript whether or not it is completely signed:
scriptSig << static_cast<valtype>(subscript);
if (!fSolved) return false;
script = subscript = CScript(result[0].begin(), result[0].end());
solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH;
result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
}
sigdata.scriptSig = PushAll(result);
// Test solution
return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker(), consensusBranchId);
}
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn)
{
SignatureData data;
assert(tx.vin.size() > nIn);
data.scriptSig = tx.vin[nIn].scriptSig;
return data;
}
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data)
{
assert(tx.vin.size() > nIn);
tx.vin[nIn].scriptSig = data.scriptSig;
}
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());
CTxIn& txin = txTo.vin[nIn];
CTransaction txToConst(txTo);
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType);
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType);
return ProduceSignature(creator, fromPubKey, txin.scriptSig);
SignatureData sigdata;
bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId);
UpdateTransaction(txTo, nIn, sigdata);
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());
CTxIn& txin = txTo.vin[nIn];
assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n];
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId);
}
static CScript PushAll(const vector<valtype>& values)
{
CScript result;
BOOST_FOREACH(const valtype& v, values)
result << v;
return result;
}
static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const vector<valtype>& vSolutions,
const vector<valtype>& sigs1, const vector<valtype>& sigs2)
const vector<valtype>& sigs1, const vector<valtype>& sigs2, uint32_t consensusBranchId)
{
// Combine all the signatures we've got:
set<valtype> allsigs;
@ -190,7 +234,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
if (sigs.count(pubkey))
continue; // Already got a sig for this pubkey
if (checker.CheckSig(sig, pubkey, scriptPubKey))
if (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId))
{
sigs[pubkey] = sig;
break;
@ -199,87 +243,100 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
}
// Now build a merged CScript:
unsigned int nSigsHave = 0;
CScript result; result << OP_0; // pop-one-too-many workaround
std::vector<valtype> result; result.push_back(valtype()); // pop-one-too-many workaround
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
{
if (sigs.count(vSolutions[i+1]))
{
result << sigs[vSolutions[i+1]];
result.push_back(sigs[vSolutions[i+1]]);
++nSigsHave;
}
}
// Fill any missing with OP_0:
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
result << OP_0;
result.push_back(valtype());
return result;
}
static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
namespace
{
struct Stacks
{
std::vector<valtype> script;
Stacks() {}
explicit Stacks(const std::vector<valtype>& scriptSigStack_) : script(scriptSigStack_) {}
explicit Stacks(const SignatureData& data, uint32_t consensusBranchId) {
EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), consensusBranchId);
}
SignatureData Output() const {
SignatureData result;
result.scriptSig = PushAll(script);
return result;
}
};
}
static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const txnouttype txType, const vector<valtype>& vSolutions,
vector<valtype>& sigs1, vector<valtype>& sigs2)
Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId)
{
switch (txType)
{
case TX_NONSTANDARD:
case TX_NULL_DATA:
// Don't know anything about this, assume bigger one is correct:
if (sigs1.size() >= sigs2.size())
return PushAll(sigs1);
return PushAll(sigs2);
if (sigs1.script.size() >= sigs2.script.size())
return sigs1;
return sigs2;
case TX_PUBKEY:
case TX_PUBKEYHASH:
// Signatures are bigger than placeholders or empty scripts:
if (sigs1.empty() || sigs1[0].empty())
return PushAll(sigs2);
return PushAll(sigs1);
if (sigs1.script.empty() || sigs1.script[0].empty())
return sigs2;
return sigs1;
case TX_SCRIPTHASH:
if (sigs1.empty() || sigs1.back().empty())
return PushAll(sigs2);
else if (sigs2.empty() || sigs2.back().empty())
return PushAll(sigs1);
if (sigs1.script.empty() || sigs1.script.back().empty())
return sigs2;
else if (sigs2.script.empty() || sigs2.script.back().empty())
return sigs1;
else
{
// Recur to combine:
valtype spk = sigs1.back();
valtype spk = sigs1.script.back();
CScript pubKey2(spk.begin(), spk.end());
txnouttype txType2;
vector<vector<unsigned char> > vSolutions2;
Solver(pubKey2, txType2, vSolutions2);
sigs1.pop_back();
sigs2.pop_back();
CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
result << spk;
sigs1.script.pop_back();
sigs2.script.pop_back();
Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId);
result.script.push_back(spk);
return result;
}
case TX_MULTISIG:
return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2);
return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, consensusBranchId));
default:
return Stacks();
}
return CScript();
}
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
const CScript& scriptSig1, const CScript& scriptSig2)
{
TransactionSignatureChecker checker(&txTo, nIn);
return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
}
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const CScript& scriptSig1, const CScript& scriptSig2)
SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
const SignatureData& scriptSig1, const SignatureData& scriptSig2,
uint32_t consensusBranchId)
{
txnouttype txType;
vector<vector<unsigned char> > vSolutions;
Solver(scriptPubKey, txType, vSolutions);
vector<valtype> stack1;
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
vector<valtype> stack2;
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
return CombineSignatures(
scriptPubKey, checker, txType, vSolutions,
Stacks(scriptSig1, consensusBranchId),
Stacks(scriptSig2, consensusBranchId),
consensusBranchId).Output();
}
namespace {
@ -289,7 +346,11 @@ class DummySignatureChecker : public BaseSignatureChecker
public:
DummySignatureChecker() {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
bool CheckSig(
const std::vector<unsigned char>& scriptSig,
const std::vector<unsigned char>& vchPubKey,
const CScript& scriptCode,
uint32_t consensusBranchId) const
{
return true;
}
@ -302,7 +363,11 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
return dummyChecker;
}
bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) 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
vchSig.assign(72, '\000');

View File

@ -27,7 +27,7 @@ public:
virtual const BaseSignatureChecker& Checker() const =0;
/** Create a singular (non-script) signature. */
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) 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. */
@ -35,12 +35,20 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction* txTo;
unsigned int nIn;
int nHashType;
CAmount amount;
const TransactionSignatureChecker checker;
public:
TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, 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; }
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
};
class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
CTransaction tx;
public:
MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {}
};
/** A signature creator that just produces 72-byte empty signatyres. */
@ -48,20 +56,46 @@ class DummySignatureCreator : public BaseSignatureCreator {
public:
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
const BaseSignatureChecker& Checker() const;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
};
struct SignatureData {
CScript scriptSig;
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
};
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata, uint32_t consensusBranchId);
/** Produce a script signature for a transaction. */
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
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,
uint32_t consensusBranchId);
/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2);
SignatureData CombineSignatures(
const CScript& scriptPubKey,
const BaseSignatureChecker& checker,
const SignatureData& scriptSig1,
const SignatureData& scriptSig2,
uint32_t consensusBranchId);
/** Combine two script signatures on transactions. */
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
/** Extract signature data from a transaction, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
#endif // BITCOIN_SCRIPT_SIGN_H

View File

@ -5,6 +5,7 @@
#include "zcashconsensus.h"
#include "consensus/upgrades.h"
#include "primitives/transaction.h"
#include "pubkey.h"
#include "script/interpreter.h"
@ -84,8 +85,16 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int
// Regardless of the verification result, the tx did not error.
set_error(err, zcashconsensus_ERR_OK);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
PrecomputedTransactionData txdata(tx);
CAmount am(0);
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&) {
return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}

View File

@ -6,6 +6,8 @@
#ifndef BITCOIN_ZCASHCONSENSUS_H
#define BITCOIN_ZCASHCONSENSUS_H
#include <stdint.h>
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
#include "config/bitcoin-config.h"
#if defined(_WIN32)

View File

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

View File

@ -745,7 +745,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends)
BOOST_CHECK(tx.IsCoinBase());
CValidationState state;
UpdateCoins(tx, state, cache, 100);
UpdateCoins(tx, cache, 100);
// Create coinbase spend
CMutableTransaction mtx2;

View File

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

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/upgrades.h"
#include "key.h"
#include "keystore.h"
#include "main.h"
@ -26,9 +27,9 @@ typedef vector<unsigned char> valtype;
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
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);
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, consensusBranchId);
CScript result;
result << OP_0; // CHECKMULTISIG bug workaround
@ -44,10 +45,12 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
BOOST_AUTO_TEST_CASE(multisig_verify)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
ScriptError err;
CKey key[4];
CAmount amount = 0;
for (int i = 0; i < 4; i++)
key[i].MakeNewKey(true);
@ -82,21 +85,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
// Test a AND b:
keys.assign(1,key[0]);
keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err));
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++)
{
keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 1: %d", i));
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), consensusBranchId, &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]);
keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 2: %d", i));
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), consensusBranchId, &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@ -104,21 +107,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
for (int i = 0; i < 4; 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)
{
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &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));
}
else
{
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &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));
}
}
s.clear();
s << OP_0 << OP_1;
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &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));
@ -127,15 +130,15 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
{
keys.assign(1,key[i]);
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)
{
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &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));
}
else
{
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &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));
}
}
@ -276,6 +279,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_AUTO_TEST_CASE(multisig_Sign)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
CBasicKeyStore keystore;
CKey key[4];
@ -312,7 +317,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
for (int i = 0; i < 3; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), 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,8 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/upgrades.h"
#include "core_io.h"
#include "key.h"
#include "keystore.h"
#include "main.h"
@ -31,6 +33,8 @@ Serialize(const CScript& s)
static bool
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Create dummy to/from transactions:
CMutableTransaction txFrom;
txFrom.vout.resize(1);
@ -44,7 +48,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1;
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), consensusBranchId, &err);
}
@ -53,6 +57,7 @@ BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sign)
{
LOCK(cs_main);
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Pay-to-script-hash looks like this:
// scriptSig: <sig> <sig...> <serialized_script>
// scriptPubKey: HASH160 <hash> EQUAL
@ -106,22 +111,24 @@ BOOST_AUTO_TEST_CASE(sign)
}
for (int i = 0; i < 8; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), 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
// Check to make sure signature verification fails if we use the wrong ScriptSig:
for (int i = 0; i < 8; i++)
for (int i = 0; i < 8; i++) {
PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
CScript sigSave = txTo[i].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)();
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, consensusBranchId, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
txTo[i].vin[0].scriptSig = sigSave;
}
}
}
BOOST_AUTO_TEST_CASE(norecurse)
@ -154,6 +161,7 @@ BOOST_AUTO_TEST_CASE(norecurse)
BOOST_AUTO_TEST_CASE(set)
{
LOCK(cs_main);
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Test the CScript::Set* methods
CBasicKeyStore keystore;
CKey key[4];
@ -203,7 +211,7 @@ BOOST_AUTO_TEST_CASE(set)
}
for (int i = 0; i < 4; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), 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));
}
}
@ -262,6 +270,7 @@ BOOST_AUTO_TEST_CASE(switchover)
BOOST_AUTO_TEST_CASE(AreInputsStandard)
{
LOCK(cs_main);
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
CBasicKeyStore keystore;
@ -332,16 +341,16 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txTo.vin[i].prevout.n = i;
txTo.vin[i].prevout.hash = txFrom.GetHash();
}
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL, consensusBranchId));
// SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create
// 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[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]
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
@ -350,7 +359,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
{
CScript t = txTo.vin[i].scriptSig;
txTo.vin[i].scriptSig = (CScript() << 11) + t;
BOOST_CHECK(!::AreInputsStandard(txTo, coins));
BOOST_CHECK(!::AreInputsStandard(txTo, coins, consensusBranchId));
txTo.vin[i].scriptSig = t;
}
@ -363,7 +372,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
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);
CMutableTransaction txToNonStd2;
@ -375,7 +384,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
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);
}

View File

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

View File

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

View File

@ -8,6 +8,8 @@
#include "init.h"
#include "clientversion.h"
#include "checkqueue.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "core_io.h"
#include "key.h"
@ -15,6 +17,7 @@
#include "main.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "primitives/transaction.h"
#include "sodium.h"
@ -90,6 +93,8 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, JoinSplitTestingSetup)
BOOST_AUTO_TEST_CASE(tx_valid)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Read tests from test/data/tx_valid.json
// Format is an array of arrays
// Inner arrays are either [ "comment" ]
@ -147,6 +152,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest + comment);
BOOST_CHECK_MESSAGE(state.IsValid(), comment);
PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@ -155,9 +161,10 @@ BOOST_AUTO_TEST_CASE(tx_valid)
break;
}
CAmount amount = 0;
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, TransactionSignatureChecker(&tx, i), &err),
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err),
strTest + comment);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
}
@ -174,6 +181,8 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_AUTO_TEST_CASE(tx_invalid)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
// Read tests from test/data/tx_invalid.json
// Format is an array of arrays
// Inner arrays are either [ "comment" ]
@ -230,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
CValidationState state;
fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
@ -239,8 +249,9 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
}
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
CAmount amount = 0;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, TransactionSignatureChecker(&tx, i), &err);
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest + comment);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
@ -389,6 +400,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
auto verifier = libzcash::ProofVerifier::Strict();
CMutableTransaction tx;
tx.nVersion = 2;
@ -416,13 +428,14 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc->nullifiers[0] = 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");
// Empty output script.
CScript scriptCode;
CTransaction signTx(newTx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL,
dataToBeSigned.begin(), 32,
@ -430,6 +443,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
) == 0);
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
BOOST_CHECK(ContextualCheckTransaction(newTx, state, 0, 100));
}
{
// Ensure that values within the joinsplit are well-formed.
@ -519,6 +533,8 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
BOOST_AUTO_TEST_CASE(test_Get)
{
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CBasicKeyStore keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
@ -539,16 +555,99 @@ BOOST_AUTO_TEST_CASE(test_Get)
t1.vout[0].nValue = 90*CENT;
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);
// Adding extra junk to the scriptSig should make it non-standard:
t1.vin[0].scriptSig << OP_11;
BOOST_CHECK(!AreInputsStandard(t1, coins));
BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId));
// ... as should not having enough:
t1.vin[0].scriptSig = CScript();
BOOST_CHECK(!AreInputsStandard(t1, coins));
BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId));
}
BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
uint32_t consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
CMutableTransaction mtx;
mtx.fOverwintered = true;
mtx.nVersion = 3;
mtx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
CKey key;
key.MakeNewKey(false);
CBasicKeyStore keystore;
keystore.AddKeyPubKey(key, key.GetPubKey());
CKeyID hash = key.GetPubKey().GetID();
CScript scriptPubKey = GetScriptForDestination(hash);
vector<int> sigHashes;
sigHashes.push_back(SIGHASH_NONE | SIGHASH_ANYONECANPAY);
sigHashes.push_back(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY);
sigHashes.push_back(SIGHASH_ALL | SIGHASH_ANYONECANPAY);
sigHashes.push_back(SIGHASH_NONE);
sigHashes.push_back(SIGHASH_SINGLE);
sigHashes.push_back(SIGHASH_ALL);
// create a big transaction of 4500 inputs signed by the same key
for(uint32_t ij = 0; ij < 4500; ij++) {
uint32_t i = mtx.vin.size();
uint256 prevId;
prevId.SetHex("0000000000000000000000000000000000000000000000000000000000000100");
COutPoint outpoint(prevId, i);
mtx.vin.resize(mtx.vin.size() + 1);
mtx.vin[i].prevout = outpoint;
mtx.vin[i].scriptSig = CScript();
mtx.vout.resize(mtx.vout.size() + 1);
mtx.vout[i].nValue = 1000;
mtx.vout[i].scriptPubKey = CScript() << OP_1;
}
// sign all inputs
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()), consensusBranchId);
assert(hashSigned);
}
CTransaction tx;
CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION);
ssout << mtx;
ssout >> tx;
// check all inputs concurrently, with the cache
PrecomputedTransactionData txdata(tx);
boost::thread_group threadGroup;
CCheckQueue<CScriptCheck> scriptcheckqueue(128);
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
for (int i=0; i<20; i++)
threadGroup.create_thread(boost::bind(&CCheckQueue<CScriptCheck>::Thread, boost::ref(scriptcheckqueue)));
CCoins coins;
coins.nVersion = 1;
coins.fCoinBase = false;
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
CTxOut txout;
txout.nValue = 1000;
txout.scriptPubKey = scriptPubKey;
coins.vout.push_back(txout);
}
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks;
CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, consensusBranchId, &txdata);
vChecks.push_back(CScriptCheck());
check.swap(vChecks.back());
control.Add(vChecks);
}
bool controlCheck = control.Wait();
assert(controlCheck);
threadGroup.interrupt_all();
threadGroup.join_all();
}
BOOST_AUTO_TEST_CASE(test_IsStandard)

View File

@ -329,6 +329,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
uint64_t innerUsage = 0;
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate);
LOCK(cs);
list<const CTxMemPoolEntry*> waitingOnDependants;
@ -383,8 +384,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
waitingOnDependants.push_back(&(*it));
else {
CValidationState state;
assert(ContextualCheckInputs(tx, state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL));
UpdateCoins(tx, state, mempoolDuplicate, 1000000);
bool fCheckResult = tx.IsCoinBase() ||
Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, Params().GetConsensus());
assert(fCheckResult);
UpdateCoins(tx, mempoolDuplicate, 1000000);
}
}
unsigned int stepsSinceLastRemove = 0;
@ -397,8 +400,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
stepsSinceLastRemove++;
assert(stepsSinceLastRemove < waitingOnDependants.size());
} else {
assert(ContextualCheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL));
UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000);
bool fCheckResult = entry->GetTx().IsCoinBase() ||
Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, Params().GetConsensus());
assert(fCheckResult);
UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
stepsSinceLastRemove = 0;
}
}

View File

@ -4,6 +4,8 @@
#include "utiltest.h"
#include "consensus/upgrades.h"
CWalletTx GetValidReceive(ZCJoinSplit& params,
const libzcash::SpendingKey& sk, CAmount value,
bool randomInputs) {
@ -45,9 +47,10 @@ CWalletTx GetValidReceive(ZCJoinSplit& params,
mtx.vjoinsplit.push_back(jsdesc);
// Empty output script.
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
// Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
@ -129,9 +132,10 @@ CWalletTx GetValidSpend(ZCJoinSplit& params,
mtx.vjoinsplit.push_back(jsdesc);
// Empty output script.
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
// Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,

View File

@ -5,6 +5,7 @@
#include "asyncrpcoperation_sendmany.h"
#include "asyncrpcqueue.h"
#include "amount.h"
#include "consensus/upgrades.h"
#include "core_io.h"
#include "init.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("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
*
@ -994,7 +1001,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_);
// Add the signature
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()
uint32_t consensusBranchId_;
CAmount fee_;
int mindepth_;
std::string fromaddress_;

View File

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

View File

@ -5,6 +5,7 @@
#include "amount.h"
#include "base58.h"
#include "consensus/upgrades.h"
#include "core_io.h"
#include "init.h"
#include "main.h"
@ -2580,7 +2581,12 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
} else if (benchmarktype == "verifyequihash") {
sample_times.push_back(benchmark_verify_equihash());
} else if (benchmarktype == "validatelargetx") {
sample_times.push_back(benchmark_large_tx());
// Number of inputs in the spending transaction that we will simulate
int nInputs = 555;
if (params.size() >= 3) {
nInputs = params[2].get_int();
}
sample_times.push_back(benchmark_large_tx(nInputs));
} else if (benchmarktype == "trydecryptnotes") {
int nAddrs = params[2].get_int();
sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
@ -2840,7 +2846,8 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
// Add the signature
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,

View File

@ -8,6 +8,7 @@
#include "base58.h"
#include "checkpoints.h"
#include "coincontrol.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "init.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
int nIn = 0;
CTransaction txNewConst(txNew);
@ -2775,17 +2779,20 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
{
bool signSuccess;
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
SignatureData sigdata;
if (sign)
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes);
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, consensusBranchId);
else
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes);
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
if (!signSuccess)
{
strFailReason = _("Signing transaction failed");
return false;
} else {
UpdateTransaction(txNew, nIn, sigdata);
}
nIn++;
}

View File

@ -71,6 +71,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
}
break;
}
case TX_MULTISIG:
{
// Only consider transactions "mine" if we own ALL the

View File

@ -13,6 +13,7 @@
#include "crypto/equihash.h"
#include "chain.h"
#include "chainparams.h"
#include "consensus/upgrades.h"
#include "consensus/validation.h"
#include "main.h"
#include "miner.h"
@ -221,11 +222,8 @@ double benchmark_verify_equihash()
return timer_stop(tv_start);
}
double benchmark_large_tx()
double benchmark_large_tx(size_t nInputs)
{
// Number of inputs in the spending transaction that we will simulate
const size_t NUM_INPUTS = 555;
// Create priv/pub key
CKey priv;
priv.MakeNewKey(false);
@ -244,26 +242,20 @@ double benchmark_large_tx()
auto orig_tx = CTransaction(m_orig_tx);
CMutableTransaction spending_tx;
spending_tx.fOverwintered = true;
spending_tx.nVersion = 3;
spending_tx.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID;
auto input_hash = orig_tx.GetHash();
// Add NUM_INPUTS inputs
for (size_t i = 0; i < NUM_INPUTS; i++) {
// Add nInputs inputs
for (size_t i = 0; i < nInputs; i++) {
spending_tx.vin.emplace_back(input_hash, 0);
}
// Sign for all the inputs
for (size_t i = 0; i < NUM_INPUTS; i++) {
SignSignature(tempKeystore, prevPubKey, spending_tx, i, SIGHASH_ALL);
}
// Serialize:
{
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << spending_tx;
//std::cout << "SIZE OF SPENDING TX: " << ss.size() << std::endl;
auto error = MAX_TX_SIZE / 20; // 5% error
assert(ss.size() < MAX_TX_SIZE + error);
assert(ss.size() > MAX_TX_SIZE - error);
auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
for (size_t i = 0; i < nInputs; i++) {
SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId);
}
// Spending tx has all its inputs signed and does not need to be mutated anymore
@ -272,12 +264,14 @@ double benchmark_large_tx()
// Benchmark signature verification costs:
struct timeval tv_start;
timer_start(tv_start);
for (size_t i = 0; i < NUM_INPUTS; i++) {
PrecomputedTransactionData txdata(final_spending_tx);
for (size_t i = 0; i < nInputs; i++) {
ScriptError serror = SCRIPT_ERR_OK;
assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
prevPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS,
TransactionSignatureChecker(&final_spending_tx, i),
TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata),
consensusBranchId,
&serror));
}
return timer_stop(tv_start);

View File

@ -12,7 +12,7 @@ extern double benchmark_solve_equihash();
extern std::vector<double> benchmark_solve_equihash_threaded(int nThreads);
extern double benchmark_verify_joinsplit(const JSDescription &joinsplit);
extern double benchmark_verify_equihash();
extern double benchmark_large_tx();
extern double benchmark_large_tx(size_t nInputs);
extern double benchmark_try_decrypt_notes(size_t nAddrs);
extern double benchmark_increment_note_witnesses(size_t nTxs);
extern double benchmark_connectblock_slow();