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:
commit
8487be8360
|
@ -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}"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
43
src/hash.h
43
src/hash.h
|
@ -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)
|
||||
|
|
107
src/main.cpp
107
src/main.cpp
|
@ -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 ¬e_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);
|
||||
|
|
39
src/main.h
39
src/main.h
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue