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
|
zcash_rpc zcbenchmark verifyequihash 1000
|
||||||
;;
|
;;
|
||||||
validatelargetx)
|
validatelargetx)
|
||||||
zcash_rpc zcbenchmark validatelargetx 5
|
zcash_rpc zcbenchmark validatelargetx 10 "${@:3}"
|
||||||
;;
|
;;
|
||||||
trydecryptnotes)
|
trydecryptnotes)
|
||||||
zcash_rpc zcbenchmark trydecryptnotes 1000 "${@:3}"
|
zcash_rpc zcbenchmark trydecryptnotes 1000 "${@:3}"
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "clientversion.h"
|
#include "clientversion.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
@ -70,7 +71,7 @@ static bool AppInitRawTx(int argc, char* argv[])
|
||||||
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
|
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
|
||||||
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
|
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
|
||||||
strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
|
strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
|
||||||
strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
|
strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
|
||||||
_("This command requires JSON registers:") +
|
_("This command requires JSON registers:") +
|
||||||
_("prevtxs=JSON object") + ", " +
|
_("prevtxs=JSON object") + ", " +
|
||||||
_("privatekeys=JSON object") + ". " +
|
_("privatekeys=JSON object") + ". " +
|
||||||
|
@ -322,10 +323,39 @@ vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
|
||||||
return ParseHexUV(o[strKey], 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 (flagStr.size() > 0)
|
||||||
if (!findSighashFlags(nHashType, flagStr))
|
if (!findSighashFlags(nHashType, flagStr))
|
||||||
throw runtime_error("unknown sighash flag/sign option");
|
throw runtime_error("unknown sighash flag/sign option");
|
||||||
|
@ -393,7 +423,10 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
||||||
if ((unsigned int)nOut >= coins->vout.size())
|
if ((unsigned int)nOut >= coins->vout.size())
|
||||||
coins->vout.resize(nOut+1);
|
coins->vout.resize(nOut+1);
|
||||||
coins->vout[nOut].scriptPubKey = scriptPubKey;
|
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,
|
// 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);
|
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
|
||||||
|
|
||||||
|
// Grab the consensus branch ID for the given height
|
||||||
|
auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
|
||||||
|
|
||||||
// Sign what we can:
|
// Sign what we can:
|
||||||
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
||||||
CTxIn& txin = mergedTx.vin[i];
|
CTxIn& txin = mergedTx.vin[i];
|
||||||
|
@ -421,17 +457,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
|
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:
|
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||||
if (!fHashSingle || (i < mergedTx.vout.size()))
|
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:
|
// ... and merge in other signatures:
|
||||||
BOOST_FOREACH(const CTransaction& txv, txVariants) {
|
BOOST_FOREACH(const CTransaction& txv, txVariants)
|
||||||
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
|
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)))
|
|
||||||
|
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId))
|
||||||
fComplete = false;
|
fComplete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,8 @@ public:
|
||||||
|
|
||||||
|
|
||||||
CMutableTransaction GetValidTransaction() {
|
CMutableTransaction GetValidTransaction() {
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
CMutableTransaction mtx;
|
CMutableTransaction mtx;
|
||||||
mtx.vin.resize(2);
|
mtx.vin.resize(2);
|
||||||
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
|
@ -74,7 +76,7 @@ CMutableTransaction GetValidTransaction() {
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(mtx);
|
CTransaction signTx(mtx);
|
||||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
if (dataToBeSigned == one) {
|
if (dataToBeSigned == one) {
|
||||||
throw std::runtime_error("SignatureHash failed");
|
throw std::runtime_error("SignatureHash failed");
|
||||||
}
|
}
|
||||||
|
@ -352,23 +354,27 @@ TEST(checktransaction_tests, bad_txns_prevout_null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) {
|
TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) {
|
||||||
|
SelectParams(CBaseChainParams::REGTEST);
|
||||||
|
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
mtx.joinSplitSig[0] += 1;
|
mtx.joinSplitSig[0] += 1;
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
|
||||||
MockCValidationState state;
|
MockCValidationState state;
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
|
||||||
CheckTransactionWithoutProofVerification(tx, state);
|
ContextualCheckTransaction(tx, state, 0, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, non_canonical_ed25519_signature) {
|
TEST(checktransaction_tests, non_canonical_ed25519_signature) {
|
||||||
|
SelectParams(CBaseChainParams::REGTEST);
|
||||||
|
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
|
|
||||||
// Check that the signature is valid before we add L
|
// Check that the signature is valid before we add L
|
||||||
{
|
{
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
MockCValidationState state;
|
MockCValidationState state;
|
||||||
EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state));
|
EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
|
// Copied from libsodium/crypto_sign/ed25519/ref10/open.c
|
||||||
|
@ -389,7 +395,7 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) {
|
||||||
|
|
||||||
MockCValidationState state;
|
MockCValidationState state;
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1);
|
||||||
CheckTransactionWithoutProofVerification(tx, state);
|
ContextualCheckTransaction(tx, state, 0, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, OverwinterConstructors) {
|
TEST(checktransaction_tests, OverwinterConstructors) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utiltest.h"
|
#include "utiltest.h"
|
||||||
|
@ -70,8 +71,10 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) {
|
||||||
FakeCoinsViewDB fakeDB;
|
FakeCoinsViewDB fakeDB;
|
||||||
CCoinsViewCache view(&fakeDB);
|
CCoinsViewCache view(&fakeDB);
|
||||||
|
|
||||||
|
auto consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
CValidationState state;
|
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) {
|
TEST(Validation, ReceivedBlockTransactions) {
|
||||||
|
|
43
src/hash.h
43
src/hash.h
|
@ -12,6 +12,8 @@
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
#include "sodium.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
typedef uint256 ChainCode;
|
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. */
|
/** Compute the 256-bit hash of an object's serialization. */
|
||||||
template<typename T>
|
template<typename T>
|
||||||
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
|
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
|
* 2. P2SH scripts with a crazy number of expensive
|
||||||
* CHECKSIG/CHECKMULTISIG operations
|
* CHECKSIG/CHECKMULTISIG operations
|
||||||
*/
|
*/
|
||||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId)
|
||||||
{
|
{
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase())
|
||||||
return true; // Coinbases don't use vin normally
|
return true; // Coinbases don't use vin normally
|
||||||
|
@ -784,7 +784,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||||
// IsStandardTx() will have already returned false
|
// IsStandardTx() will have already returned false
|
||||||
// and this method isn't called.
|
// and this method isn't called.
|
||||||
vector<vector<unsigned char> > stack;
|
vector<vector<unsigned char> > stack;
|
||||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
|
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (whichType == TX_SCRIPTHASH)
|
if (whichType == TX_SCRIPTHASH)
|
||||||
|
@ -886,6 +886,30 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) {
|
||||||
|
auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
|
||||||
|
// Empty output script.
|
||||||
|
CScript scriptCode;
|
||||||
|
uint256 dataToBeSigned;
|
||||||
|
try {
|
||||||
|
dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
} catch (std::logic_error ex) {
|
||||||
|
return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
|
||||||
|
REJECT_INVALID, "error-computing-signature-hash");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32);
|
||||||
|
|
||||||
|
// We rely on libsodium to check that the signature is canonical.
|
||||||
|
// https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0
|
||||||
|
if (crypto_sign_verify_detached(&tx.joinSplitSig[0],
|
||||||
|
dataToBeSigned.begin(), 32,
|
||||||
|
tx.joinSplitPubKey.begin()
|
||||||
|
) != 0) {
|
||||||
|
return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"),
|
||||||
|
REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,30 +1106,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
||||||
if (txin.prevout.IsNull())
|
if (txin.prevout.IsNull())
|
||||||
return state.DoS(10, error("CheckTransaction(): prevout is null"),
|
return state.DoS(10, error("CheckTransaction(): prevout is null"),
|
||||||
REJECT_INVALID, "bad-txns-prevout-null");
|
REJECT_INVALID, "bad-txns-prevout-null");
|
||||||
|
|
||||||
if (tx.vjoinsplit.size() > 0) {
|
|
||||||
// Empty output script.
|
|
||||||
CScript scriptCode;
|
|
||||||
uint256 dataToBeSigned;
|
|
||||||
try {
|
|
||||||
dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL);
|
|
||||||
} catch (std::logic_error ex) {
|
|
||||||
return state.DoS(100, error("CheckTransaction(): error computing signature hash"),
|
|
||||||
REJECT_INVALID, "error-computing-signature-hash");
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32);
|
|
||||||
|
|
||||||
// We rely on libsodium to check that the signature is canonical.
|
|
||||||
// https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0
|
|
||||||
if (crypto_sign_verify_detached(&tx.joinSplitSig[0],
|
|
||||||
dataToBeSigned.begin(), 32,
|
|
||||||
tx.joinSplitPubKey.begin()
|
|
||||||
) != 0) {
|
|
||||||
return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"),
|
|
||||||
REJECT_INVALID, "bad-txns-invalid-joinsplit-signature");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1148,6 +1148,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
if (pfMissingInputs)
|
if (pfMissingInputs)
|
||||||
*pfMissingInputs = false;
|
*pfMissingInputs = false;
|
||||||
|
|
||||||
|
int nextBlockHeight = chainActive.Height() + 1;
|
||||||
|
auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus());
|
||||||
|
|
||||||
// Node operator can choose to reject tx by number of transparent inputs
|
// Node operator can choose to reject tx by number of transparent inputs
|
||||||
static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small");
|
static_assert(std::numeric_limits<size_t>::max() >= std::numeric_limits<int64_t>::max(), "size_t too small");
|
||||||
size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0);
|
size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0);
|
||||||
|
@ -1165,7 +1168,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
|
|
||||||
// DoS level set to 10 to be more forgiving.
|
// DoS level set to 10 to be more forgiving.
|
||||||
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
|
// Check transaction contextually against the set of consensus rules which apply in the next block to be mined.
|
||||||
int nextBlockHeight = chainActive.Height() + 1;
|
|
||||||
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) {
|
if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) {
|
||||||
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
|
return error("AcceptToMemoryPool: ContextualCheckTransaction failed");
|
||||||
}
|
}
|
||||||
|
@ -1260,7 +1262,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for non-standard pay-to-script-hash in inputs
|
// Check for non-standard pay-to-script-hash in inputs
|
||||||
if (Params().RequireStandard() && !AreInputsStandard(tx, view))
|
if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId))
|
||||||
return error("AcceptToMemoryPool: nonstandard transaction input");
|
return error("AcceptToMemoryPool: nonstandard transaction input");
|
||||||
|
|
||||||
// Check that the transaction doesn't have an excessive number of
|
// Check that the transaction doesn't have an excessive number of
|
||||||
|
@ -1347,7 +1349,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||||
|
|
||||||
// Check against previous transactions
|
// Check against previous transactions
|
||||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||||
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());
|
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
|
// There is a similar check in CreateNewBlock() to prevent creating
|
||||||
// invalid blocks, however allowing such transactions into the mempool
|
// invalid blocks, however allowing such transactions into the mempool
|
||||||
// can be exploited as a DoS attack.
|
// can be exploited as a DoS attack.
|
||||||
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
|
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId))
|
||||||
{
|
{
|
||||||
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
|
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
|
||||||
}
|
}
|
||||||
|
@ -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
|
// mark inputs spent
|
||||||
if (!tx.IsCoinBase()) {
|
if (!tx.IsCoinBase()) {
|
||||||
|
@ -1718,15 +1721,15 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
|
||||||
inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight);
|
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;
|
CTxUndo txundo;
|
||||||
UpdateCoins(tx, state, inputs, txundo, nHeight);
|
UpdateCoins(tx, inputs, txundo, nHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CScriptCheck::operator()() {
|
bool CScriptCheck::operator()() {
|
||||||
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
|
||||||
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, 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 ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1809,7 +1812,17 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins
|
||||||
}
|
}
|
||||||
}// namespace Consensus
|
}// namespace Consensus
|
||||||
|
|
||||||
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
bool ContextualCheckInputs(
|
||||||
|
const CTransaction& tx,
|
||||||
|
CValidationState &state,
|
||||||
|
const CCoinsViewCache &inputs,
|
||||||
|
bool fScriptChecks,
|
||||||
|
unsigned int flags,
|
||||||
|
bool cacheStore,
|
||||||
|
PrecomputedTransactionData& txdata,
|
||||||
|
const Consensus::Params& consensusParams,
|
||||||
|
uint32_t consensusBranchId,
|
||||||
|
std::vector<CScriptCheck> *pvChecks)
|
||||||
{
|
{
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
|
@ -1834,7 +1847,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
|
||||||
assert(coins);
|
assert(coins);
|
||||||
|
|
||||||
// Verify signature
|
// Verify signature
|
||||||
CScriptCheck check(*coins, tx, i, flags, cacheStore);
|
CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata);
|
||||||
if (pvChecks) {
|
if (pvChecks) {
|
||||||
pvChecks->push_back(CScriptCheck());
|
pvChecks->push_back(CScriptCheck());
|
||||||
check.swap(pvChecks->back());
|
check.swap(pvChecks->back());
|
||||||
|
@ -1846,9 +1859,9 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
|
||||||
// arguments; if so, don't trigger DoS protection to
|
// arguments; if so, don't trigger DoS protection to
|
||||||
// avoid splitting the network between upgraded and
|
// avoid splitting the network between upgraded and
|
||||||
// non-upgraded nodes.
|
// non-upgraded nodes.
|
||||||
CScriptCheck check(*coins, tx, i,
|
CScriptCheck check2(*coins, tx, i,
|
||||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore);
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata);
|
||||||
if (check())
|
if (check2())
|
||||||
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
||||||
}
|
}
|
||||||
// Failures of other flags indicate a transaction that is
|
// 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);
|
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++)
|
for (unsigned int i = 0; i < block.vtx.size(); i++)
|
||||||
{
|
{
|
||||||
const CTransaction &tx = block.vtx[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)
|
if (nSigOps > MAX_BLOCK_SIGOPS)
|
||||||
return state.DoS(100, error("ConnectBlock(): too many sigops"),
|
return state.DoS(100, error("ConnectBlock(): too many sigops"),
|
||||||
REJECT_INVALID, "bad-blk-sigops");
|
REJECT_INVALID, "bad-blk-sigops");
|
||||||
|
}
|
||||||
|
|
||||||
|
txdata.emplace_back(tx);
|
||||||
|
|
||||||
|
if (!tx.IsCoinBase())
|
||||||
|
{
|
||||||
nFees += view.GetValueIn(tx)-tx.GetValueOut();
|
nFees += view.GetValueIn(tx)-tx.GetValueOut();
|
||||||
|
|
||||||
std::vector<CScriptCheck> vChecks;
|
std::vector<CScriptCheck> vChecks;
|
||||||
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
|
if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL))
|
||||||
return false;
|
return false;
|
||||||
control.Add(vChecks);
|
control.Add(vChecks);
|
||||||
}
|
}
|
||||||
|
@ -2278,7 +2301,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
blockundo.vtxundo.push_back(CTxUndo());
|
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 JSDescription &joinsplit, tx.vjoinsplit) {
|
||||||
BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) {
|
BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) {
|
||||||
|
@ -3713,7 +3736,7 @@ bool static LoadBlockIndexDB()
|
||||||
pindex->nCachedBranchId = pindex->pprev->nCachedBranchId;
|
pindex->nCachedBranchId = pindex->pprev->nCachedBranchId;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pindex->nCachedBranchId = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId;
|
pindex->nCachedBranchId = SPROUT_BRANCH_ID;
|
||||||
}
|
}
|
||||||
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
|
if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL))
|
||||||
setBlockIndexCandidates.insert(pindex);
|
setBlockIndexCandidates.insert(pindex);
|
||||||
|
|
39
src/main.h
39
src/main.h
|
@ -45,6 +45,7 @@ class CInv;
|
||||||
class CScriptCheck;
|
class CScriptCheck;
|
||||||
class CValidationInterface;
|
class CValidationInterface;
|
||||||
class CValidationState;
|
class CValidationState;
|
||||||
|
class PrecomputedTransactionData;
|
||||||
|
|
||||||
struct CNodeStateStats;
|
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
|
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||||
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
||||||
*/
|
*/
|
||||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
|
||||||
|
@ -330,14 +331,17 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
|
||||||
* instead of being performed inline.
|
* instead of being performed inline.
|
||||||
*/
|
*/
|
||||||
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
|
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
|
||||||
unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams,
|
unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata,
|
||||||
|
const Consensus::Params& consensusParams, uint32_t consensusBranchId,
|
||||||
std::vector<CScriptCheck> *pvChecks = NULL);
|
std::vector<CScriptCheck> *pvChecks = NULL);
|
||||||
|
|
||||||
/** Check a transaction contextually against a set of consensus rules */
|
/** Check a transaction contextually against a set of consensus rules */
|
||||||
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel);
|
bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, int nHeight, int dosLevel);
|
||||||
|
|
||||||
/** Apply the effects of this transaction on the UTXO set represented by view */
|
/** 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 */
|
/** Context-independent validity checks */
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
|
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);
|
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
|
* Check if transaction is final and can be included in a block with the
|
||||||
* specified height and time. Consensus critical.
|
* specified height and time. Consensus critical.
|
||||||
|
@ -371,27 +386,33 @@ class CScriptCheck
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CScript scriptPubKey;
|
CScript scriptPubKey;
|
||||||
|
CAmount amount;
|
||||||
const CTransaction *ptxTo;
|
const CTransaction *ptxTo;
|
||||||
unsigned int nIn;
|
unsigned int nIn;
|
||||||
unsigned int nFlags;
|
unsigned int nFlags;
|
||||||
bool cacheStore;
|
bool cacheStore;
|
||||||
|
uint32_t consensusBranchId;
|
||||||
ScriptError error;
|
ScriptError error;
|
||||||
|
PrecomputedTransactionData *txdata;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
|
CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), consensusBranchId(0), error(SCRIPT_ERR_UNKNOWN_ERROR) {}
|
||||||
CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) :
|
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),
|
scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue),
|
||||||
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { }
|
ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), consensusBranchId(consensusBranchIdIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
|
||||||
|
|
||||||
bool operator()();
|
bool operator()();
|
||||||
|
|
||||||
void swap(CScriptCheck &check) {
|
void swap(CScriptCheck &check) {
|
||||||
scriptPubKey.swap(check.scriptPubKey);
|
scriptPubKey.swap(check.scriptPubKey);
|
||||||
std::swap(ptxTo, check.ptxTo);
|
std::swap(ptxTo, check.ptxTo);
|
||||||
|
std::swap(amount, check.amount);
|
||||||
std::swap(nIn, check.nIn);
|
std::swap(nIn, check.nIn);
|
||||||
std::swap(nFlags, check.nFlags);
|
std::swap(nFlags, check.nFlags);
|
||||||
std::swap(cacheStore, check.cacheStore);
|
std::swap(cacheStore, check.cacheStore);
|
||||||
|
std::swap(consensusBranchId, check.consensusBranchId);
|
||||||
std::swap(error, check.error);
|
std::swap(error, check.error);
|
||||||
|
std::swap(txdata, check.txdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptError GetScriptError() const { return error; }
|
ScriptError GetScriptError() const { return error; }
|
||||||
|
@ -534,10 +555,6 @@ extern CBlockTreeDB *pblocktree;
|
||||||
*/
|
*/
|
||||||
int GetSpendHeight(const CCoinsViewCache& inputs);
|
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 */
|
/** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */
|
||||||
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight);
|
CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "consensus/consensus.h"
|
#include "consensus/consensus.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#ifdef ENABLE_MINING
|
#ifdef ENABLE_MINING
|
||||||
#include "crypto/equihash.h"
|
#include "crypto/equihash.h"
|
||||||
|
@ -143,6 +144,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
LOCK2(cs_main, mempool.cs);
|
LOCK2(cs_main, mempool.cs);
|
||||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||||
const int nHeight = pindexPrev->nHeight + 1;
|
const int nHeight = pindexPrev->nHeight + 1;
|
||||||
|
uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
|
||||||
pblock->nTime = GetAdjustedTime();
|
pblock->nTime = GetAdjustedTime();
|
||||||
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast();
|
||||||
CCoinsViewCache view(pcoinsTip);
|
CCoinsViewCache view(pcoinsTip);
|
||||||
|
@ -293,10 +295,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||||
// policy here, but we still have to ensure that the block we
|
// policy here, but we still have to ensure that the block we
|
||||||
// create only contains transactions that are valid in new blocks.
|
// create only contains transactions that are valid in new blocks.
|
||||||
CValidationState state;
|
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;
|
continue;
|
||||||
|
|
||||||
UpdateCoins(tx, state, view, nHeight);
|
UpdateCoins(tx, view, nHeight);
|
||||||
|
|
||||||
// Added
|
// Added
|
||||||
pblock->vtx.push_back(tx);
|
pblock->vtx.push_back(tx);
|
||||||
|
|
|
@ -383,12 +383,7 @@ public:
|
||||||
*const_cast<bool*>(&fOverwintered) = header >> 31;
|
*const_cast<bool*>(&fOverwintered) = header >> 31;
|
||||||
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
|
*const_cast<int32_t*>(&this->nVersion) = header & 0x7FFFFFFF;
|
||||||
} else {
|
} else {
|
||||||
// When serializing v1 and v2, the 4 byte header is nVersion
|
uint32_t header = GetHeader();
|
||||||
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;
|
|
||||||
}
|
|
||||||
READWRITE(header);
|
READWRITE(header);
|
||||||
}
|
}
|
||||||
nVersion = this->nVersion;
|
nVersion = this->nVersion;
|
||||||
|
@ -428,6 +423,16 @@ public:
|
||||||
return hash;
|
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.
|
// Return sum of txouts.
|
||||||
CAmount GetValueOut() const;
|
CAmount GetValueOut() const;
|
||||||
// GetValueIn() is a method on CCoinsViewCache, because
|
// GetValueIn() is a method on CCoinsViewCache, because
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
|
@ -654,7 +655,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||||
" \"txid\":\"id\", (string, required) The transaction id\n"
|
" \"txid\":\"id\", (string, required) The transaction id\n"
|
||||||
" \"vout\":n, (numeric, required) The output number\n"
|
" \"vout\":n, (numeric, required) The output number\n"
|
||||||
" \"scriptPubKey\": \"hex\", (string, required) script key\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"
|
" ,...\n"
|
||||||
" ]\n"
|
" ]\n"
|
||||||
|
@ -792,7 +794,10 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||||
if ((unsigned int)nOut >= coins->vout.size())
|
if ((unsigned int)nOut >= coins->vout.size())
|
||||||
coins->vout.resize(nOut+1);
|
coins->vout.resize(nOut+1);
|
||||||
coins->vout[nOut].scriptPubKey = scriptPubKey;
|
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
|
// 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);
|
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
|
||||||
|
|
||||||
|
// Grab the current consensus branch ID
|
||||||
|
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||||
|
|
||||||
// Script verification errors
|
// Script verification errors
|
||||||
UniValue vErrors(UniValue::VARR);
|
UniValue vErrors(UniValue::VARR);
|
||||||
|
|
||||||
|
// Use CTransaction for the constant parts of the
|
||||||
|
// transaction to avoid rehashing.
|
||||||
|
const CTransaction txConst(mergedTx);
|
||||||
// Sign what we can:
|
// Sign what we can:
|
||||||
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
|
||||||
CTxIn& txin = mergedTx.vin[i];
|
CTxIn& txin = mergedTx.vin[i];
|
||||||
|
@ -847,18 +858,22 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
|
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:
|
// Only sign SIGHASH_SINGLE if there's a corresponding output:
|
||||||
if (!fHashSingle || (i < mergedTx.vout.size()))
|
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:
|
// ... and merge in other signatures:
|
||||||
BOOST_FOREACH(const CMutableTransaction& txv, txVariants) {
|
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;
|
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));
|
TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "crypto/ripemd160.h"
|
#include "crypto/ripemd160.h"
|
||||||
#include "crypto/sha1.h"
|
#include "crypto/sha1.h"
|
||||||
|
@ -232,7 +233,13 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
|
bool EvalScript(
|
||||||
|
vector<vector<unsigned char> >& stack,
|
||||||
|
const CScript& script,
|
||||||
|
unsigned int flags,
|
||||||
|
const BaseSignatureChecker& checker,
|
||||||
|
uint32_t consensusBranchId,
|
||||||
|
ScriptError* serror)
|
||||||
{
|
{
|
||||||
static const CScriptNum bnZero(0);
|
static const CScriptNum bnZero(0);
|
||||||
static const CScriptNum bnOne(1);
|
static const CScriptNum bnOne(1);
|
||||||
|
@ -828,7 +835,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||||
//serror is set
|
//serror is set
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script);
|
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
|
||||||
|
|
||||||
popstack(stack);
|
popstack(stack);
|
||||||
popstack(stack);
|
popstack(stack);
|
||||||
|
@ -886,7 +893,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check signature
|
// Check signature
|
||||||
bool fOk = checker.CheckSig(vchSig, vchPubKey, script);
|
bool fOk = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId);
|
||||||
|
|
||||||
if (fOk) {
|
if (fOk) {
|
||||||
isig++;
|
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
|
} // 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) {
|
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
|
||||||
// nIn out of range
|
// nIn out of range
|
||||||
throw logic_error("input index is out of range");
|
throw logic_error("input index is out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// Check for invalid use of SIGHASH_SINGLE
|
||||||
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
|
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
|
||||||
if (nIn >= txTo.vout.size()) {
|
if (nIn >= txTo.vout.size()) {
|
||||||
|
@ -1076,12 +1216,17 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig
|
||||||
return ss.GetHash();
|
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);
|
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);
|
CPubKey pubkey(vchPubKey);
|
||||||
if (!pubkey.IsValid())
|
if (!pubkey.IsValid())
|
||||||
|
@ -1096,7 +1241,7 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
|
||||||
|
|
||||||
uint256 sighash;
|
uint256 sighash;
|
||||||
try {
|
try {
|
||||||
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
|
sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata);
|
||||||
} catch (logic_error ex) {
|
} catch (logic_error ex) {
|
||||||
return false;
|
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);
|
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;
|
vector<vector<unsigned char> > stack, stackCopy;
|
||||||
if (!EvalScript(stack, scriptSig, flags, checker, serror))
|
if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror))
|
||||||
// serror is set
|
// serror is set
|
||||||
return false;
|
return false;
|
||||||
if (flags & SCRIPT_VERIFY_P2SH)
|
if (flags & SCRIPT_VERIFY_P2SH)
|
||||||
stackCopy = stack;
|
stackCopy = stack;
|
||||||
if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
|
if (!EvalScript(stack, scriptPubKey, flags, checker, consensusBranchId, serror))
|
||||||
// serror is set
|
// serror is set
|
||||||
return false;
|
return false;
|
||||||
if (stack.empty())
|
if (stack.empty())
|
||||||
|
@ -1185,7 +1336,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
|
||||||
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
||||||
popstack(stack);
|
popstack(stack);
|
||||||
|
|
||||||
if (!EvalScript(stack, pubKey2, flags, checker, serror))
|
if (!EvalScript(stack, pubKey2, flags, checker, consensusBranchId, serror))
|
||||||
// serror is set
|
// serror is set
|
||||||
return false;
|
return false;
|
||||||
if (stack.empty())
|
if (stack.empty())
|
||||||
|
|
|
@ -88,12 +88,36 @@ enum
|
||||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
|
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
|
class BaseSignatureChecker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
virtual bool CheckSig(
|
||||||
|
const std::vector<unsigned char>& scriptSig,
|
||||||
|
const std::vector<unsigned char>& vchPubKey,
|
||||||
|
const CScript& scriptCode,
|
||||||
|
uint32_t consensusBranchId) const
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -111,13 +135,16 @@ class TransactionSignatureChecker : public BaseSignatureChecker
|
||||||
private:
|
private:
|
||||||
const CTransaction* txTo;
|
const CTransaction* txTo;
|
||||||
unsigned int nIn;
|
unsigned int nIn;
|
||||||
|
const CAmount amount;
|
||||||
|
const PrecomputedTransactionData* txdata;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
|
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {}
|
||||||
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, 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;
|
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,10 +154,22 @@ private:
|
||||||
const CTransaction txTo;
|
const CTransaction txTo;
|
||||||
|
|
||||||
public:
|
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 EvalScript(
|
||||||
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
|
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
|
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||||
|
|
|
@ -18,7 +18,7 @@ private:
|
||||||
bool store;
|
bool store;
|
||||||
|
|
||||||
public:
|
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;
|
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;
|
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;
|
CKey key;
|
||||||
if (!keystore->GetKey(address, key))
|
if (!keystore->GetKey(address, key))
|
||||||
|
@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
||||||
|
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
try {
|
try {
|
||||||
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType);
|
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId);
|
||||||
} catch (logic_error ex) {
|
} catch (logic_error ex) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -38,16 +38,16 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, 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;
|
vector<unsigned char> vchSig;
|
||||||
if (!creator.CreateSig(vchSig, address, scriptCode))
|
if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId))
|
||||||
return false;
|
return false;
|
||||||
scriptSigRet << vchSig;
|
ret.push_back(vchSig);
|
||||||
return true;
|
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 nSigned = 0;
|
||||||
int nRequired = multisigdata.front()[0];
|
int nRequired = multisigdata.front()[0];
|
||||||
|
@ -55,7 +55,7 @@ static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreato
|
||||||
{
|
{
|
||||||
const valtype& pubkey = multisigdata[i];
|
const valtype& pubkey = multisigdata[i];
|
||||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||||
if (Sign1(keyID, creator, scriptCode, scriptSigRet))
|
if (Sign1(keyID, creator, scriptCode, ret, consensusBranchId))
|
||||||
++nSigned;
|
++nSigned;
|
||||||
}
|
}
|
||||||
return nSigned==nRequired;
|
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.
|
* Returns false if scriptPubKey could not be completely satisfied.
|
||||||
*/
|
*/
|
||||||
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
|
static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey,
|
||||||
CScript& scriptSigRet, txnouttype& whichTypeRet)
|
std::vector<valtype>& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId)
|
||||||
{
|
{
|
||||||
scriptSigRet.clear();
|
CScript scriptRet;
|
||||||
|
uint160 h160;
|
||||||
|
ret.clear();
|
||||||
|
|
||||||
vector<valtype> vSolutions;
|
vector<valtype> vSolutions;
|
||||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||||
|
@ -84,85 +86,127 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
|
||||||
return false;
|
return false;
|
||||||
case TX_PUBKEY:
|
case TX_PUBKEY:
|
||||||
keyID = CPubKey(vSolutions[0]).GetID();
|
keyID = CPubKey(vSolutions[0]).GetID();
|
||||||
return Sign1(keyID, creator, scriptPubKey, scriptSigRet);
|
return Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId);
|
||||||
case TX_PUBKEYHASH:
|
case TX_PUBKEYHASH:
|
||||||
keyID = CKeyID(uint160(vSolutions[0]));
|
keyID = CKeyID(uint160(vSolutions[0]));
|
||||||
if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet))
|
if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CPubKey vch;
|
CPubKey vch;
|
||||||
creator.KeyStore().GetPubKey(keyID, vch);
|
creator.KeyStore().GetPubKey(keyID, vch);
|
||||||
scriptSigRet << ToByteVector(vch);
|
ret.push_back(ToByteVector(vch));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case TX_SCRIPTHASH:
|
case TX_SCRIPTHASH:
|
||||||
return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
if (creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptRet)) {
|
||||||
|
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
||||||
case TX_MULTISIG:
|
return true;
|
||||||
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))
|
|
||||||
return false;
|
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
|
// the final scriptSig is the signatures from that
|
||||||
// and then the serialized subscript:
|
// and then the serialized subscript:
|
||||||
CScript subscript = scriptSig;
|
script = subscript = CScript(result[0].begin(), result[0].end());
|
||||||
|
solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH;
|
||||||
txnouttype subType;
|
result.push_back(std::vector<unsigned char>(subscript.begin(), subscript.end()));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sigdata.scriptSig = PushAll(result);
|
||||||
|
|
||||||
// Test solution
|
// 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());
|
assert(nIn < txTo.vin.size());
|
||||||
CTxIn& txin = txTo.vin[nIn];
|
|
||||||
|
|
||||||
CTransaction txToConst(txTo);
|
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());
|
assert(nIn < txTo.vin.size());
|
||||||
CTxIn& txin = txTo.vin[nIn];
|
CTxIn& txin = txTo.vin[nIn];
|
||||||
assert(txin.prevout.n < txFrom.vout.size());
|
assert(txin.prevout.n < txFrom.vout.size());
|
||||||
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
||||||
|
|
||||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CScript PushAll(const vector<valtype>& values)
|
static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||||
{
|
|
||||||
CScript result;
|
|
||||||
BOOST_FOREACH(const valtype& v, values)
|
|
||||||
result << v;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
|
||||||
const vector<valtype>& vSolutions,
|
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:
|
// Combine all the signatures we've got:
|
||||||
set<valtype> allsigs;
|
set<valtype> allsigs;
|
||||||
|
@ -190,7 +234,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
|
||||||
if (sigs.count(pubkey))
|
if (sigs.count(pubkey))
|
||||||
continue; // Already got a sig for this pubkey
|
continue; // Already got a sig for this pubkey
|
||||||
|
|
||||||
if (checker.CheckSig(sig, pubkey, scriptPubKey))
|
if (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId))
|
||||||
{
|
{
|
||||||
sigs[pubkey] = sig;
|
sigs[pubkey] = sig;
|
||||||
break;
|
break;
|
||||||
|
@ -199,87 +243,100 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureC
|
||||||
}
|
}
|
||||||
// Now build a merged CScript:
|
// Now build a merged CScript:
|
||||||
unsigned int nSigsHave = 0;
|
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++)
|
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
|
||||||
{
|
{
|
||||||
if (sigs.count(vSolutions[i+1]))
|
if (sigs.count(vSolutions[i+1]))
|
||||||
{
|
{
|
||||||
result << sigs[vSolutions[i+1]];
|
result.push_back(sigs[vSolutions[i+1]]);
|
||||||
++nSigsHave;
|
++nSigsHave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Fill any missing with OP_0:
|
// Fill any missing with OP_0:
|
||||||
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
||||||
result << OP_0;
|
result.push_back(valtype());
|
||||||
|
|
||||||
return result;
|
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,
|
const txnouttype txType, const vector<valtype>& vSolutions,
|
||||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId)
|
||||||
{
|
{
|
||||||
switch (txType)
|
switch (txType)
|
||||||
{
|
{
|
||||||
case TX_NONSTANDARD:
|
case TX_NONSTANDARD:
|
||||||
case TX_NULL_DATA:
|
case TX_NULL_DATA:
|
||||||
// Don't know anything about this, assume bigger one is correct:
|
// Don't know anything about this, assume bigger one is correct:
|
||||||
if (sigs1.size() >= sigs2.size())
|
if (sigs1.script.size() >= sigs2.script.size())
|
||||||
return PushAll(sigs1);
|
return sigs1;
|
||||||
return PushAll(sigs2);
|
return sigs2;
|
||||||
case TX_PUBKEY:
|
case TX_PUBKEY:
|
||||||
case TX_PUBKEYHASH:
|
case TX_PUBKEYHASH:
|
||||||
// Signatures are bigger than placeholders or empty scripts:
|
// Signatures are bigger than placeholders or empty scripts:
|
||||||
if (sigs1.empty() || sigs1[0].empty())
|
if (sigs1.script.empty() || sigs1.script[0].empty())
|
||||||
return PushAll(sigs2);
|
return sigs2;
|
||||||
return PushAll(sigs1);
|
return sigs1;
|
||||||
case TX_SCRIPTHASH:
|
case TX_SCRIPTHASH:
|
||||||
if (sigs1.empty() || sigs1.back().empty())
|
if (sigs1.script.empty() || sigs1.script.back().empty())
|
||||||
return PushAll(sigs2);
|
return sigs2;
|
||||||
else if (sigs2.empty() || sigs2.back().empty())
|
else if (sigs2.script.empty() || sigs2.script.back().empty())
|
||||||
return PushAll(sigs1);
|
return sigs1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Recur to combine:
|
// Recur to combine:
|
||||||
valtype spk = sigs1.back();
|
valtype spk = sigs1.script.back();
|
||||||
CScript pubKey2(spk.begin(), spk.end());
|
CScript pubKey2(spk.begin(), spk.end());
|
||||||
|
|
||||||
txnouttype txType2;
|
txnouttype txType2;
|
||||||
vector<vector<unsigned char> > vSolutions2;
|
vector<vector<unsigned char> > vSolutions2;
|
||||||
Solver(pubKey2, txType2, vSolutions2);
|
Solver(pubKey2, txType2, vSolutions2);
|
||||||
sigs1.pop_back();
|
sigs1.script.pop_back();
|
||||||
sigs2.pop_back();
|
sigs2.script.pop_back();
|
||||||
CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2);
|
Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId);
|
||||||
result << spk;
|
result.script.push_back(spk);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
case TX_MULTISIG:
|
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,
|
SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
||||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
const SignatureData& scriptSig1, const SignatureData& scriptSig2,
|
||||||
{
|
uint32_t consensusBranchId)
|
||||||
TransactionSignatureChecker checker(&txTo, nIn);
|
|
||||||
return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2);
|
|
||||||
}
|
|
||||||
|
|
||||||
CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker,
|
|
||||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
|
||||||
{
|
{
|
||||||
txnouttype txType;
|
txnouttype txType;
|
||||||
vector<vector<unsigned char> > vSolutions;
|
vector<vector<unsigned char> > vSolutions;
|
||||||
Solver(scriptPubKey, txType, vSolutions);
|
Solver(scriptPubKey, txType, vSolutions);
|
||||||
|
|
||||||
vector<valtype> stack1;
|
return CombineSignatures(
|
||||||
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
|
scriptPubKey, checker, txType, vSolutions,
|
||||||
vector<valtype> stack2;
|
Stacks(scriptSig1, consensusBranchId),
|
||||||
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
|
Stacks(scriptSig2, consensusBranchId),
|
||||||
|
consensusBranchId).Output();
|
||||||
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -289,7 +346,11 @@ class DummySignatureChecker : public BaseSignatureChecker
|
||||||
public:
|
public:
|
||||||
DummySignatureChecker() {}
|
DummySignatureChecker() {}
|
||||||
|
|
||||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
bool CheckSig(
|
||||||
|
const std::vector<unsigned char>& scriptSig,
|
||||||
|
const std::vector<unsigned char>& vchPubKey,
|
||||||
|
const CScript& scriptCode,
|
||||||
|
uint32_t consensusBranchId) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +363,11 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const
|
||||||
return dummyChecker;
|
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
|
// Create a dummy signature that is a valid DER-encoding
|
||||||
vchSig.assign(72, '\000');
|
vchSig.assign(72, '\000');
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
virtual const BaseSignatureChecker& Checker() const =0;
|
virtual const BaseSignatureChecker& Checker() const =0;
|
||||||
|
|
||||||
/** Create a singular (non-script) signature. */
|
/** Create a singular (non-script) signature. */
|
||||||
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0;
|
virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A signature creator for transactions. */
|
/** A signature creator for transactions. */
|
||||||
|
@ -35,12 +35,20 @@ class TransactionSignatureCreator : public BaseSignatureCreator {
|
||||||
const CTransaction* txTo;
|
const CTransaction* txTo;
|
||||||
unsigned int nIn;
|
unsigned int nIn;
|
||||||
int nHashType;
|
int nHashType;
|
||||||
|
CAmount amount;
|
||||||
const TransactionSignatureChecker checker;
|
const TransactionSignatureChecker checker;
|
||||||
|
|
||||||
public:
|
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; }
|
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. */
|
/** A signature creator that just produces 72-byte empty signatyres. */
|
||||||
|
@ -48,20 +56,46 @@ class DummySignatureCreator : public BaseSignatureCreator {
|
||||||
public:
|
public:
|
||||||
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
|
DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
|
||||||
const BaseSignatureChecker& Checker() const;
|
const BaseSignatureChecker& Checker() const;
|
||||||
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) 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. */
|
/** 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. */
|
/** 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(
|
||||||
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
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. */
|
/** 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. */
|
/** Extract signature data from a transaction, and insert it. */
|
||||||
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn);
|
||||||
|
void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const SignatureData& data);
|
||||||
|
|
||||||
#endif // BITCOIN_SCRIPT_SIGN_H
|
#endif // BITCOIN_SCRIPT_SIGN_H
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "zcashconsensus.h"
|
#include "zcashconsensus.h"
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "pubkey.h"
|
#include "pubkey.h"
|
||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
|
@ -84,8 +85,16 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int
|
||||||
|
|
||||||
// Regardless of the verification result, the tx did not error.
|
// Regardless of the verification result, the tx did not error.
|
||||||
set_error(err, zcashconsensus_ERR_OK);
|
set_error(err, zcashconsensus_ERR_OK);
|
||||||
|
PrecomputedTransactionData txdata(tx);
|
||||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
|
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&) {
|
} catch (const std::exception&) {
|
||||||
return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#ifndef BITCOIN_ZCASHCONSENSUS_H
|
#ifndef BITCOIN_ZCASHCONSENSUS_H
|
||||||
#define BITCOIN_ZCASHCONSENSUS_H
|
#define BITCOIN_ZCASHCONSENSUS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
|
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||||
#include "config/bitcoin-config.h"
|
#include "config/bitcoin-config.h"
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
@ -119,6 +120,8 @@ CTransaction RandomOrphan()
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
CKey key;
|
CKey key;
|
||||||
key.MakeNewKey(true);
|
key.MakeNewKey(true);
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
|
@ -151,7 +154,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||||
tx.vout.resize(1);
|
tx.vout.resize(1);
|
||||||
tx.vout[0].nValue = 1*CENT;
|
tx.vout[0].nValue = 1*CENT;
|
||||||
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
|
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
|
||||||
SignSignature(keystore, txPrev, tx, 0);
|
SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId);
|
||||||
|
|
||||||
AddOrphanTx(tx, i);
|
AddOrphanTx(tx, i);
|
||||||
}
|
}
|
||||||
|
@ -171,7 +174,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
|
||||||
tx.vin[j].prevout.n = j;
|
tx.vin[j].prevout.n = j;
|
||||||
tx.vin[j].prevout.hash = txPrev.GetHash();
|
tx.vin[j].prevout.hash = txPrev.GetHash();
|
||||||
}
|
}
|
||||||
SignSignature(keystore, txPrev, tx, 0);
|
SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId);
|
||||||
// Re-use same signature for other inputs
|
// Re-use same signature for other inputs
|
||||||
// (they don't have to be valid for this test)
|
// (they don't have to be valid for this test)
|
||||||
for (unsigned int j = 1; j < tx.vin.size(); j++)
|
for (unsigned int j = 1; j < tx.vin.size(); j++)
|
||||||
|
|
|
@ -745,7 +745,7 @@ BOOST_AUTO_TEST_CASE(coins_coinbase_spends)
|
||||||
BOOST_CHECK(tx.IsCoinBase());
|
BOOST_CHECK(tx.IsCoinBase());
|
||||||
|
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
UpdateCoins(tx, state, cache, 100);
|
UpdateCoins(tx, cache, 100);
|
||||||
|
|
||||||
// Create coinbase spend
|
// Create coinbase spend
|
||||||
CMutableTransaction mtx2;
|
CMutableTransaction mtx2;
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
|
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
|
||||||
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
|
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
|
||||||
"set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
|
"set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
|
||||||
"sign=ALL",
|
"sign=1:ALL",
|
||||||
"outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"],
|
"outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"],
|
||||||
"output_cmp": "txcreatesign.hex"
|
"output_cmp": "txcreatesign.hex"
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,6 +2,7 @@
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -26,9 +27,9 @@ typedef vector<unsigned char> valtype;
|
||||||
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
|
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
|
||||||
|
|
||||||
CScript
|
CScript
|
||||||
sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn)
|
sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn, uint32_t consensusBranchId)
|
||||||
{
|
{
|
||||||
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL);
|
uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
|
||||||
CScript result;
|
CScript result;
|
||||||
result << OP_0; // CHECKMULTISIG bug workaround
|
result << OP_0; // CHECKMULTISIG bug workaround
|
||||||
|
@ -44,10 +45,12 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multisig_verify)
|
BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
CKey key[4];
|
CKey key[4];
|
||||||
|
CAmount amount = 0;
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
key[i].MakeNewKey(true);
|
key[i].MakeNewKey(true);
|
||||||
|
|
||||||
|
@ -82,21 +85,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||||
// Test a AND b:
|
// Test a AND b:
|
||||||
keys.assign(1,key[0]);
|
keys.assign(1,key[0]);
|
||||||
keys.push_back(key[1]);
|
keys.push_back(key[1]);
|
||||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
|
||||||
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err));
|
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
keys.assign(1,key[i]);
|
keys.assign(1,key[i]);
|
||||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
|
||||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 1: %d", i));
|
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.assign(1,key[1]);
|
keys.assign(1,key[1]);
|
||||||
keys.push_back(key[i]);
|
keys.push_back(key[i]);
|
||||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
|
||||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0), &err), strprintf("a&b 2: %d", i));
|
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,21 +107,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
keys.assign(1,key[i]);
|
keys.assign(1,key[i]);
|
||||||
s = sign_multisig(a_or_b, keys, txTo[1], 0);
|
s = sign_multisig(a_or_b, keys, txTo[1], 0, consensusBranchId);
|
||||||
if (i == 0 || i == 1)
|
if (i == 0 || i == 1)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
|
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err), strprintf("a|b: %d", i));
|
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << OP_1;
|
s << OP_0 << OP_1;
|
||||||
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0), &err));
|
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,15 +130,15 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||||
{
|
{
|
||||||
keys.assign(1,key[i]);
|
keys.assign(1,key[i]);
|
||||||
keys.push_back(key[j]);
|
keys.push_back(key[j]);
|
||||||
s = sign_multisig(escrow, keys, txTo[2], 0);
|
s = sign_multisig(escrow, keys, txTo[2], 0, consensusBranchId);
|
||||||
if (i < j && i < 3 && j < 3)
|
if (i < j && i < 3 && j < 3)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
|
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
|
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,6 +279,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(multisig_Sign)
|
BOOST_AUTO_TEST_CASE(multisig_Sign)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
|
// Test SignSignature() (and therefore the version of Solver() that signs transactions)
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
CKey key[4];
|
CKey key[4];
|
||||||
|
@ -312,7 +317,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign)
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), 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
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
|
#include "core_io.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -31,6 +33,8 @@ Serialize(const CScript& s)
|
||||||
static bool
|
static bool
|
||||||
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
|
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
// Create dummy to/from transactions:
|
// Create dummy to/from transactions:
|
||||||
CMutableTransaction txFrom;
|
CMutableTransaction txFrom;
|
||||||
txFrom.vout.resize(1);
|
txFrom.vout.resize(1);
|
||||||
|
@ -44,7 +48,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
|
||||||
txTo.vin[0].scriptSig = scriptSig;
|
txTo.vin[0].scriptSig = scriptSig;
|
||||||
txTo.vout[0].nValue = 1;
|
txTo.vout[0].nValue = 1;
|
||||||
|
|
||||||
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &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)
|
BOOST_AUTO_TEST_CASE(sign)
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
// Pay-to-script-hash looks like this:
|
// Pay-to-script-hash looks like this:
|
||||||
// scriptSig: <sig> <sig...> <serialized_script>
|
// scriptSig: <sig> <sig...> <serialized_script>
|
||||||
// scriptPubKey: HASH160 <hash> EQUAL
|
// scriptPubKey: HASH160 <hash> EQUAL
|
||||||
|
@ -106,22 +111,24 @@ BOOST_AUTO_TEST_CASE(sign)
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
|
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
|
||||||
}
|
}
|
||||||
// All of the above should be OK, and the txTos have valid signatures
|
// All of the above should be OK, and the txTos have valid signatures
|
||||||
// Check to make sure signature verification fails if we use the wrong ScriptSig:
|
// Check to make sure signature verification fails if we use the wrong ScriptSig:
|
||||||
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++)
|
for (int j = 0; j < 8; j++)
|
||||||
{
|
{
|
||||||
CScript sigSave = txTo[i].vin[0].scriptSig;
|
CScript sigSave = txTo[i].vin[0].scriptSig;
|
||||||
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
|
txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig;
|
||||||
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)();
|
bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, consensusBranchId, &txdata)();
|
||||||
if (i == j)
|
if (i == j)
|
||||||
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
|
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||||
else
|
else
|
||||||
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
|
BOOST_CHECK_MESSAGE(!sigOK, strprintf("VerifySignature %d %d", i, j));
|
||||||
txTo[i].vin[0].scriptSig = sigSave;
|
txTo[i].vin[0].scriptSig = sigSave;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(norecurse)
|
BOOST_AUTO_TEST_CASE(norecurse)
|
||||||
|
@ -154,6 +161,7 @@ BOOST_AUTO_TEST_CASE(norecurse)
|
||||||
BOOST_AUTO_TEST_CASE(set)
|
BOOST_AUTO_TEST_CASE(set)
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
// Test the CScript::Set* methods
|
// Test the CScript::Set* methods
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
CKey key[4];
|
CKey key[4];
|
||||||
|
@ -203,7 +211,7 @@ BOOST_AUTO_TEST_CASE(set)
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
|
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
|
||||||
BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i));
|
BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,6 +270,7 @@ BOOST_AUTO_TEST_CASE(switchover)
|
||||||
BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
CCoinsView coinsDummy;
|
CCoinsView coinsDummy;
|
||||||
CCoinsViewCache coins(&coinsDummy);
|
CCoinsViewCache coins(&coinsDummy);
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
|
@ -332,16 +341,16 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||||
txTo.vin[i].prevout.n = i;
|
txTo.vin[i].prevout.n = i;
|
||||||
txTo.vin[i].prevout.hash = txFrom.GetHash();
|
txTo.vin[i].prevout.hash = txFrom.GetHash();
|
||||||
}
|
}
|
||||||
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0));
|
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId));
|
||||||
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1));
|
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId));
|
||||||
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2));
|
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL, consensusBranchId));
|
||||||
// SignSignature doesn't know how to sign these. We're
|
// SignSignature doesn't know how to sign these. We're
|
||||||
// not testing validating signatures, so just create
|
// not testing validating signatures, so just create
|
||||||
// dummy signatures that DO include the correct P2SH scripts:
|
// dummy signatures that DO include the correct P2SH scripts:
|
||||||
txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo);
|
txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast<vector<unsigned char> >(oneAndTwo);
|
||||||
txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops);
|
txTo.vin[4].scriptSig << static_cast<vector<unsigned char> >(fifteenSigops);
|
||||||
|
|
||||||
BOOST_CHECK(::AreInputsStandard(txTo, coins));
|
BOOST_CHECK(::AreInputsStandard(txTo, coins, consensusBranchId));
|
||||||
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
|
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
|
||||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
|
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U);
|
||||||
|
|
||||||
|
@ -350,7 +359,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||||
{
|
{
|
||||||
CScript t = txTo.vin[i].scriptSig;
|
CScript t = txTo.vin[i].scriptSig;
|
||||||
txTo.vin[i].scriptSig = (CScript() << 11) + t;
|
txTo.vin[i].scriptSig = (CScript() << 11) + t;
|
||||||
BOOST_CHECK(!::AreInputsStandard(txTo, coins));
|
BOOST_CHECK(!::AreInputsStandard(txTo, coins, consensusBranchId));
|
||||||
txTo.vin[i].scriptSig = t;
|
txTo.vin[i].scriptSig = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +372,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||||
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
|
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
|
||||||
txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops);
|
txToNonStd1.vin[0].scriptSig << static_cast<vector<unsigned char> >(sixteenSigops);
|
||||||
|
|
||||||
BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins));
|
BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins, consensusBranchId));
|
||||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
|
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U);
|
||||||
|
|
||||||
CMutableTransaction txToNonStd2;
|
CMutableTransaction txToNonStd2;
|
||||||
|
@ -375,7 +384,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||||
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
|
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
|
||||||
txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops);
|
txToNonStd2.vin[0].scriptSig << static_cast<vector<unsigned char> >(twentySigops);
|
||||||
|
|
||||||
BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins));
|
BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins, consensusBranchId));
|
||||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
|
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "data/script_invalid.json.h"
|
#include "data/script_invalid.json.h"
|
||||||
#include "data/script_valid.json.h"
|
#include "data/script_valid.json.h"
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
|
@ -87,12 +88,13 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu
|
||||||
return txSpend;
|
return txSpend;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message)
|
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, uint32_t consensusBranchId, bool expect, const std::string& message)
|
||||||
{
|
{
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey));
|
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
|
||||||
|
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
|
||||||
CMutableTransaction tx2 = tx;
|
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);
|
BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
|
||||||
#if defined(HAVE_CONSENSUS_LIB)
|
#if defined(HAVE_CONSENSUS_LIB)
|
||||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
@ -187,6 +189,7 @@ private:
|
||||||
std::vector<unsigned char> push;
|
std::vector<unsigned char> push;
|
||||||
std::string comment;
|
std::string comment;
|
||||||
int flags;
|
int flags;
|
||||||
|
uint32_t consensusBranchId;
|
||||||
|
|
||||||
void DoPush()
|
void DoPush()
|
||||||
{
|
{
|
||||||
|
@ -204,7 +207,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_)
|
TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_), consensusBranchId(0)
|
||||||
{
|
{
|
||||||
if (P2SH) {
|
if (P2SH) {
|
||||||
creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL);
|
creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL);
|
||||||
|
@ -236,7 +239,7 @@ public:
|
||||||
|
|
||||||
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32)
|
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32)
|
||||||
{
|
{
|
||||||
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType);
|
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId);
|
||||||
std::vector<unsigned char> vchSig, r, s;
|
std::vector<unsigned char> vchSig, r, s;
|
||||||
uint32_t iter = 0;
|
uint32_t iter = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -288,7 +291,7 @@ public:
|
||||||
{
|
{
|
||||||
TestBuilder copy = *this; // Make a copy so we can rollback the push.
|
TestBuilder copy = *this; // Make a copy so we can rollback the push.
|
||||||
DoPush();
|
DoPush();
|
||||||
DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment);
|
DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, consensusBranchId, expect, comment);
|
||||||
*this = copy;
|
*this = copy;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -576,6 +579,7 @@ BOOST_AUTO_TEST_CASE(script_build)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_valid)
|
BOOST_AUTO_TEST_CASE(script_valid)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
// Read tests from test/data/script_valid.json
|
// Read tests from test/data/script_valid.json
|
||||||
// Format is an array of arrays
|
// Format is an array of arrays
|
||||||
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
|
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
|
||||||
|
@ -599,12 +603,13 @@ BOOST_AUTO_TEST_CASE(script_valid)
|
||||||
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
||||||
unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
|
unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
|
||||||
|
|
||||||
DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest);
|
DoTest(scriptPubKey, scriptSig, scriptflags, consensusBranchId, true, strTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_invalid)
|
BOOST_AUTO_TEST_CASE(script_invalid)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
// Scripts that should evaluate as invalid
|
// Scripts that should evaluate as invalid
|
||||||
UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
|
UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
|
||||||
|
|
||||||
|
@ -624,12 +629,14 @@ BOOST_AUTO_TEST_CASE(script_invalid)
|
||||||
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
CScript scriptPubKey = ParseScript(scriptPubKeyString);
|
||||||
unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
|
unsigned int scriptflags = ParseScriptFlags(test[2].get_str());
|
||||||
|
|
||||||
DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest);
|
DoTest(scriptPubKey, scriptSig, scriptflags, consensusBranchId, false, strTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_PushData)
|
BOOST_AUTO_TEST_CASE(script_PushData)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
|
// Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on
|
||||||
// the stack as the 1-75 opcodes do.
|
// the stack as the 1-75 opcodes do.
|
||||||
static const unsigned char direct[] = { 1, 0x5a };
|
static const unsigned char direct[] = { 1, 0x5a };
|
||||||
|
@ -639,29 +646,29 @@ BOOST_AUTO_TEST_CASE(script_PushData)
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
vector<vector<unsigned char> > directStack;
|
vector<vector<unsigned char> > directStack;
|
||||||
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
|
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
vector<vector<unsigned char> > pushdata1Stack;
|
vector<vector<unsigned char> > pushdata1Stack;
|
||||||
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
|
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
|
||||||
BOOST_CHECK(pushdata1Stack == directStack);
|
BOOST_CHECK(pushdata1Stack == directStack);
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
vector<vector<unsigned char> > pushdata2Stack;
|
vector<vector<unsigned char> > pushdata2Stack;
|
||||||
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
|
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
|
||||||
BOOST_CHECK(pushdata2Stack == directStack);
|
BOOST_CHECK(pushdata2Stack == directStack);
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
vector<vector<unsigned char> > pushdata4Stack;
|
vector<vector<unsigned char> > pushdata4Stack;
|
||||||
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), &err));
|
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err));
|
||||||
BOOST_CHECK(pushdata4Stack == directStack);
|
BOOST_CHECK(pushdata4Stack == directStack);
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
CScript
|
CScript
|
||||||
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction)
|
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, uint32_t consensusBranchId)
|
||||||
{
|
{
|
||||||
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL);
|
uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
|
||||||
CScript result;
|
CScript result;
|
||||||
//
|
//
|
||||||
|
@ -683,15 +690,17 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
CScript
|
CScript
|
||||||
sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
|
sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, uint32_t consensusBranchId)
|
||||||
{
|
{
|
||||||
std::vector<CKey> keys;
|
std::vector<CKey> keys;
|
||||||
keys.push_back(key);
|
keys.push_back(key);
|
||||||
return sign_multisig(scriptPubKey, keys, transaction);
|
return sign_multisig(scriptPubKey, keys, transaction, consensusBranchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
CKey key1, key2, key3;
|
CKey key1, key2, key3;
|
||||||
key1.MakeNewKey(true);
|
key1.MakeNewKey(true);
|
||||||
|
@ -704,24 +713,26 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
|
||||||
CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);
|
CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);
|
||||||
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
|
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
|
||||||
|
|
||||||
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
|
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, consensusBranchId);
|
||||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
txTo12.vout[0].nValue = 2;
|
txTo12.vout[0].nValue = 2;
|
||||||
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
|
|
||||||
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
|
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, consensusBranchId);
|
||||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
|
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
CKey key1, key2, key3, key4;
|
CKey key1, key2, key3, key4;
|
||||||
key1.MakeNewKey(true);
|
key1.MakeNewKey(true);
|
||||||
|
@ -737,61 +748,64 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||||
|
|
||||||
std::vector<CKey> keys;
|
std::vector<CKey> keys;
|
||||||
keys.push_back(key1); keys.push_back(key2);
|
keys.push_back(key1); keys.push_back(key2);
|
||||||
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key1); keys.push_back(key3);
|
keys.push_back(key1); keys.push_back(key3);
|
||||||
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key2); keys.push_back(key3);
|
keys.push_back(key2); keys.push_back(key3);
|
||||||
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
|
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
|
||||||
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
|
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
|
||||||
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
|
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
|
||||||
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
|
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
|
||||||
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
|
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
|
||||||
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
|
||||||
|
|
||||||
keys.clear(); // Must have signatures
|
keys.clear(); // Must have signatures
|
||||||
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
|
||||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
// Test the CombineSignatures function
|
// Test the CombineSignatures function
|
||||||
|
CAmount amount = 0;
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
vector<CKey> keys;
|
vector<CKey> keys;
|
||||||
vector<CPubKey> pubkeys;
|
vector<CPubKey> pubkeys;
|
||||||
|
@ -809,62 +823,62 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||||
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
|
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
|
||||||
CScript& scriptSig = txTo.vin[0].scriptSig;
|
CScript& scriptSig = txTo.vin[0].scriptSig;
|
||||||
|
|
||||||
CScript empty;
|
SignatureData empty;
|
||||||
CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty);
|
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty, consensusBranchId);
|
||||||
BOOST_CHECK(combined.empty());
|
BOOST_CHECK(combined.scriptSig.empty());
|
||||||
|
|
||||||
// Single signature case:
|
// Single signature case:
|
||||||
SignSignature(keystore, txFrom, txTo, 0); // changes scriptSig
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
CScript scriptSigCopy = scriptSig;
|
CScript scriptSigCopy = scriptSig;
|
||||||
// Signing again will give a different, valid signature:
|
// Signing again will give a different, valid signature:
|
||||||
SignSignature(keystore, txFrom, txTo, 0);
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
|
||||||
|
|
||||||
// P2SH, single-signature case:
|
// P2SH, single-signature case:
|
||||||
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
|
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
|
||||||
keystore.AddCScript(pkSingle);
|
keystore.AddCScript(pkSingle);
|
||||||
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
|
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
|
||||||
SignSignature(keystore, txFrom, txTo, 0);
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
scriptSigCopy = scriptSig;
|
scriptSigCopy = scriptSig;
|
||||||
SignSignature(keystore, txFrom, txTo, 0);
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSigCopy || combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
|
||||||
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
|
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
|
||||||
scriptSigCopy = CScript() << OP_0 << static_cast<vector<unsigned char> >(pkSingle);
|
scriptSigCopy = CScript() << OP_0 << static_cast<vector<unsigned char> >(pkSingle);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSigCopy, scriptSig);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, scriptSigCopy);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
|
|
||||||
// Hardest case: Multisig 2-of-3
|
// Hardest case: Multisig 2-of-3
|
||||||
scriptPubKey = GetScriptForMultisig(2, pubkeys);
|
scriptPubKey = GetScriptForMultisig(2, pubkeys);
|
||||||
keystore.AddCScript(scriptPubKey);
|
keystore.AddCScript(scriptPubKey);
|
||||||
SignSignature(keystore, txFrom, txTo, 0);
|
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, scriptSig, empty);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, empty, scriptSig);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
|
||||||
BOOST_CHECK(combined == scriptSig);
|
BOOST_CHECK(combined.scriptSig == scriptSig);
|
||||||
|
|
||||||
// A couple of partially-signed versions:
|
// A couple of partially-signed versions:
|
||||||
vector<unsigned char> sig1;
|
vector<unsigned char> sig1;
|
||||||
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL);
|
uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
BOOST_CHECK(keys[0].Sign(hash1, sig1));
|
BOOST_CHECK(keys[0].Sign(hash1, sig1));
|
||||||
sig1.push_back(SIGHASH_ALL);
|
sig1.push_back(SIGHASH_ALL);
|
||||||
vector<unsigned char> sig2;
|
vector<unsigned char> sig2;
|
||||||
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE);
|
uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, consensusBranchId);
|
||||||
BOOST_CHECK(keys[1].Sign(hash2, sig2));
|
BOOST_CHECK(keys[1].Sign(hash2, sig2));
|
||||||
sig2.push_back(SIGHASH_NONE);
|
sig2.push_back(SIGHASH_NONE);
|
||||||
vector<unsigned char> sig3;
|
vector<unsigned char> sig3;
|
||||||
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE);
|
uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, consensusBranchId);
|
||||||
BOOST_CHECK(keys[2].Sign(hash3, sig3));
|
BOOST_CHECK(keys[2].Sign(hash3, sig3));
|
||||||
sig3.push_back(SIGHASH_SINGLE);
|
sig3.push_back(SIGHASH_SINGLE);
|
||||||
|
|
||||||
|
@ -880,32 +894,34 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||||
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
|
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
|
||||||
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
|
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
|
||||||
|
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial1b);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId);
|
||||||
BOOST_CHECK(combined == partial1a);
|
BOOST_CHECK(combined.scriptSig == partial1a);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1a, partial2a);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId);
|
||||||
BOOST_CHECK(combined == complete12);
|
BOOST_CHECK(combined.scriptSig == complete12);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial1a);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId);
|
||||||
BOOST_CHECK(combined == complete12);
|
BOOST_CHECK(combined.scriptSig == complete12);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial1b, partial2b);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId);
|
||||||
BOOST_CHECK(combined == complete12);
|
BOOST_CHECK(combined.scriptSig == complete12);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial1b);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId);
|
||||||
BOOST_CHECK(combined == complete13);
|
BOOST_CHECK(combined.scriptSig == complete13);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial2a, partial3a);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId);
|
||||||
BOOST_CHECK(combined == complete23);
|
BOOST_CHECK(combined.scriptSig == complete23);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial2b);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId);
|
||||||
BOOST_CHECK(combined == complete23);
|
BOOST_CHECK(combined.scriptSig == complete23);
|
||||||
combined = CombineSignatures(scriptPubKey, txTo, 0, partial3b, partial3a);
|
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId);
|
||||||
BOOST_CHECK(combined == partial3c);
|
BOOST_CHECK(combined.scriptSig == partial3c);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_standard_push)
|
BOOST_AUTO_TEST_CASE(script_standard_push)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
for (int i=0; i<67000; i++) {
|
for (int i=0; i<67000; i++) {
|
||||||
CScript script;
|
CScript script;
|
||||||
script << i;
|
script << i;
|
||||||
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
|
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
|
||||||
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data.");
|
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), consensusBranchId, &err), "Number " << i << " push is not minimal data.");
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -914,7 +930,7 @@ BOOST_AUTO_TEST_CASE(script_standard_push)
|
||||||
CScript script;
|
CScript script;
|
||||||
script << data;
|
script << data;
|
||||||
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
|
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
|
||||||
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data.");
|
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), consensusBranchId, &err), "Length " << i << " push is not minimal data.");
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ void static RandomScript(CScript &script) {
|
||||||
script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
|
script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))];
|
||||||
}
|
}
|
||||||
|
|
||||||
void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
|
void static RandomTransaction(CMutableTransaction &tx, bool fSingle, uint32_t consensusBranchId) {
|
||||||
tx.fOverwintered = insecure_rand() % 2;
|
tx.fOverwintered = insecure_rand() % 2;
|
||||||
if (tx.fOverwintered) {
|
if (tx.fOverwintered) {
|
||||||
// Versions outside known ranges throw an exception during parsing
|
// Versions outside known ranges throw an exception during parsing
|
||||||
|
@ -160,7 +160,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) {
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(tx);
|
CTransaction signTx(tx);
|
||||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
|
||||||
assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL,
|
assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL,
|
||||||
dataToBeSigned.begin(), 32,
|
dataToBeSigned.begin(), 32,
|
||||||
|
@ -173,11 +173,12 @@ BOOST_FIXTURE_TEST_SUITE(sighash_tests, JoinSplitTestingSetup)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(sighash_test)
|
BOOST_AUTO_TEST_CASE(sighash_test)
|
||||||
{
|
{
|
||||||
|
uint32_t overwinterBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
|
||||||
seed_insecure_rand(false);
|
seed_insecure_rand(false);
|
||||||
|
|
||||||
#if defined(PRINT_SIGHASH_JSON)
|
#if defined(PRINT_SIGHASH_JSON)
|
||||||
std::cout << "[\n";
|
std::cout << "[\n";
|
||||||
std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n";
|
std::cout << "\t[\"raw_transaction, script, input_index, hashType, branchId, signature_hash (result)\"],\n";
|
||||||
#endif
|
#endif
|
||||||
int nRandomTests = 50000;
|
int nRandomTests = 50000;
|
||||||
|
|
||||||
|
@ -186,15 +187,16 @@ BOOST_AUTO_TEST_CASE(sighash_test)
|
||||||
#endif
|
#endif
|
||||||
for (int i=0; i<nRandomTests; i++) {
|
for (int i=0; i<nRandomTests; i++) {
|
||||||
int nHashType = insecure_rand();
|
int nHashType = insecure_rand();
|
||||||
|
uint32_t consensusBranchId = insecure_rand() % 2 ? SPROUT_BRANCH_ID : overwinterBranchId;
|
||||||
CMutableTransaction txTo;
|
CMutableTransaction txTo;
|
||||||
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
|
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE, consensusBranchId);
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
RandomScript(scriptCode);
|
RandomScript(scriptCode);
|
||||||
int nIn = insecure_rand() % txTo.vin.size();
|
int nIn = insecure_rand() % txTo.vin.size();
|
||||||
|
|
||||||
uint256 sh, sho;
|
uint256 sh, sho;
|
||||||
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType);
|
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType);
|
||||||
sh = SignatureHash(scriptCode, txTo, nIn, nHashType);
|
sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, consensusBranchId);
|
||||||
#if defined(PRINT_SIGHASH_JSON)
|
#if defined(PRINT_SIGHASH_JSON)
|
||||||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
ss << txTo;
|
ss << txTo;
|
||||||
|
@ -203,7 +205,8 @@ BOOST_AUTO_TEST_CASE(sighash_test)
|
||||||
std::cout << HexStr(ss.begin(), ss.end()) << "\", \"";
|
std::cout << HexStr(ss.begin(), ss.end()) << "\", \"";
|
||||||
std::cout << HexStr(scriptCode) << "\", ";
|
std::cout << HexStr(scriptCode) << "\", ";
|
||||||
std::cout << nIn << ", ";
|
std::cout << nIn << ", ";
|
||||||
std::cout << nHashType << ", \"";
|
std::cout << nHashType << ", ";
|
||||||
|
std::cout << consensusBranchId << ", \"";
|
||||||
std::cout << (txTo.fOverwintered ? sh.GetHex() : sho.GetHex()) << "\"]";
|
std::cout << (txTo.fOverwintered ? sh.GetHex() : sho.GetHex()) << "\"]";
|
||||||
if (i+1 != nRandomTests) {
|
if (i+1 != nRandomTests) {
|
||||||
std::cout << ",";
|
std::cout << ",";
|
||||||
|
@ -236,6 +239,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
||||||
|
|
||||||
std::string raw_tx, raw_script, sigHashHex;
|
std::string raw_tx, raw_script, sigHashHex;
|
||||||
int nIn, nHashType;
|
int nIn, nHashType;
|
||||||
|
uint32_t consensusBranchId;
|
||||||
uint256 sh;
|
uint256 sh;
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
CScript scriptCode = CScript();
|
CScript scriptCode = CScript();
|
||||||
|
@ -246,7 +250,8 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
||||||
raw_script = test[1].get_str();
|
raw_script = test[1].get_str();
|
||||||
nIn = test[2].get_int();
|
nIn = test[2].get_int();
|
||||||
nHashType = test[3].get_int();
|
nHashType = test[3].get_int();
|
||||||
sigHashHex = test[4].get_str();
|
consensusBranchId = test[4].get_int();
|
||||||
|
sigHashHex = test[5].get_str();
|
||||||
|
|
||||||
uint256 sh;
|
uint256 sh;
|
||||||
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
@ -278,7 +283,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
sh = SignatureHash(scriptCode, tx, nIn, nHashType);
|
sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, consensusBranchId);
|
||||||
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
|
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "clientversion.h"
|
#include "clientversion.h"
|
||||||
|
#include "checkqueue.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
@ -15,6 +17,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
|
#include "script/sign.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
|
|
||||||
#include "sodium.h"
|
#include "sodium.h"
|
||||||
|
@ -90,6 +93,8 @@ BOOST_FIXTURE_TEST_SUITE(transaction_tests, JoinSplitTestingSetup)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(tx_valid)
|
BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
// Read tests from test/data/tx_valid.json
|
// Read tests from test/data/tx_valid.json
|
||||||
// Format is an array of arrays
|
// Format is an array of arrays
|
||||||
// Inner arrays are either [ "comment" ]
|
// Inner arrays are either [ "comment" ]
|
||||||
|
@ -147,6 +152,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest + comment);
|
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest + comment);
|
||||||
BOOST_CHECK_MESSAGE(state.IsValid(), comment);
|
BOOST_CHECK_MESSAGE(state.IsValid(), comment);
|
||||||
|
|
||||||
|
PrecomputedTransactionData txdata(tx);
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
{
|
{
|
||||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
||||||
|
@ -155,9 +161,10 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CAmount amount = 0;
|
||||||
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||||
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||||
verify_flags, TransactionSignatureChecker(&tx, i), &err),
|
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err),
|
||||||
strTest + comment);
|
strTest + comment);
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
|
||||||
}
|
}
|
||||||
|
@ -174,6 +181,8 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(tx_invalid)
|
BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
// Read tests from test/data/tx_invalid.json
|
// Read tests from test/data/tx_invalid.json
|
||||||
// Format is an array of arrays
|
// Format is an array of arrays
|
||||||
// Inner arrays are either [ "comment" ]
|
// Inner arrays are either [ "comment" ]
|
||||||
|
@ -230,6 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
|
fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
|
||||||
|
|
||||||
|
PrecomputedTransactionData txdata(tx);
|
||||||
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
|
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
|
||||||
{
|
{
|
||||||
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
|
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());
|
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
|
||||||
|
CAmount amount = 0;
|
||||||
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
|
||||||
verify_flags, TransactionSignatureChecker(&tx, i), &err);
|
verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err);
|
||||||
}
|
}
|
||||||
BOOST_CHECK_MESSAGE(!fValid, strTest + comment);
|
BOOST_CHECK_MESSAGE(!fValid, strTest + comment);
|
||||||
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
|
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
|
||||||
|
@ -389,6 +400,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
auto verifier = libzcash::ProofVerifier::Strict();
|
auto verifier = libzcash::ProofVerifier::Strict();
|
||||||
CMutableTransaction tx;
|
CMutableTransaction tx;
|
||||||
tx.nVersion = 2;
|
tx.nVersion = 2;
|
||||||
|
@ -416,13 +428,14 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||||
jsdesc->nullifiers[0] = GetRandHash();
|
jsdesc->nullifiers[0] = GetRandHash();
|
||||||
jsdesc->nullifiers[1] = GetRandHash();
|
jsdesc->nullifiers[1] = GetRandHash();
|
||||||
|
|
||||||
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
|
BOOST_CHECK(!ContextualCheckTransaction(newTx, state, 0, 100));
|
||||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
|
||||||
|
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(newTx);
|
CTransaction signTx(newTx);
|
||||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
|
||||||
assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL,
|
assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL,
|
||||||
dataToBeSigned.begin(), 32,
|
dataToBeSigned.begin(), 32,
|
||||||
|
@ -430,6 +443,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||||
) == 0);
|
) == 0);
|
||||||
|
|
||||||
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
||||||
|
BOOST_CHECK(ContextualCheckTransaction(newTx, state, 0, 100));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Ensure that values within the joinsplit are well-formed.
|
// Ensure that values within the joinsplit are well-formed.
|
||||||
|
@ -519,6 +533,8 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(test_Get)
|
BOOST_AUTO_TEST_CASE(test_Get)
|
||||||
{
|
{
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
|
|
||||||
CBasicKeyStore keystore;
|
CBasicKeyStore keystore;
|
||||||
CCoinsView coinsDummy;
|
CCoinsView coinsDummy;
|
||||||
CCoinsViewCache coins(&coinsDummy);
|
CCoinsViewCache coins(&coinsDummy);
|
||||||
|
@ -539,16 +555,99 @@ BOOST_AUTO_TEST_CASE(test_Get)
|
||||||
t1.vout[0].nValue = 90*CENT;
|
t1.vout[0].nValue = 90*CENT;
|
||||||
t1.vout[0].scriptPubKey << OP_1;
|
t1.vout[0].scriptPubKey << OP_1;
|
||||||
|
|
||||||
BOOST_CHECK(AreInputsStandard(t1, coins));
|
BOOST_CHECK(AreInputsStandard(t1, coins, consensusBranchId));
|
||||||
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
|
BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT);
|
||||||
|
|
||||||
// Adding extra junk to the scriptSig should make it non-standard:
|
// Adding extra junk to the scriptSig should make it non-standard:
|
||||||
t1.vin[0].scriptSig << OP_11;
|
t1.vin[0].scriptSig << OP_11;
|
||||||
BOOST_CHECK(!AreInputsStandard(t1, coins));
|
BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId));
|
||||||
|
|
||||||
// ... as should not having enough:
|
// ... as should not having enough:
|
||||||
t1.vin[0].scriptSig = CScript();
|
t1.vin[0].scriptSig = CScript();
|
||||||
BOOST_CHECK(!AreInputsStandard(t1, coins));
|
BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
|
||||||
|
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)
|
BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||||
|
|
|
@ -329,6 +329,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
||||||
uint64_t innerUsage = 0;
|
uint64_t innerUsage = 0;
|
||||||
|
|
||||||
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
|
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
|
||||||
|
const int64_t nSpendHeight = GetSpendHeight(mempoolDuplicate);
|
||||||
|
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
list<const CTxMemPoolEntry*> waitingOnDependants;
|
list<const CTxMemPoolEntry*> waitingOnDependants;
|
||||||
|
@ -383,8 +384,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
||||||
waitingOnDependants.push_back(&(*it));
|
waitingOnDependants.push_back(&(*it));
|
||||||
else {
|
else {
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
assert(ContextualCheckInputs(tx, state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL));
|
bool fCheckResult = tx.IsCoinBase() ||
|
||||||
UpdateCoins(tx, state, mempoolDuplicate, 1000000);
|
Consensus::CheckTxInputs(tx, state, mempoolDuplicate, nSpendHeight, Params().GetConsensus());
|
||||||
|
assert(fCheckResult);
|
||||||
|
UpdateCoins(tx, mempoolDuplicate, 1000000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsigned int stepsSinceLastRemove = 0;
|
unsigned int stepsSinceLastRemove = 0;
|
||||||
|
@ -397,8 +400,10 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
|
||||||
stepsSinceLastRemove++;
|
stepsSinceLastRemove++;
|
||||||
assert(stepsSinceLastRemove < waitingOnDependants.size());
|
assert(stepsSinceLastRemove < waitingOnDependants.size());
|
||||||
} else {
|
} else {
|
||||||
assert(ContextualCheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, Params().GetConsensus(), NULL));
|
bool fCheckResult = entry->GetTx().IsCoinBase() ||
|
||||||
UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000);
|
Consensus::CheckTxInputs(entry->GetTx(), state, mempoolDuplicate, nSpendHeight, Params().GetConsensus());
|
||||||
|
assert(fCheckResult);
|
||||||
|
UpdateCoins(entry->GetTx(), mempoolDuplicate, 1000000);
|
||||||
stepsSinceLastRemove = 0;
|
stepsSinceLastRemove = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include "utiltest.h"
|
#include "utiltest.h"
|
||||||
|
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
|
|
||||||
CWalletTx GetValidReceive(ZCJoinSplit& params,
|
CWalletTx GetValidReceive(ZCJoinSplit& params,
|
||||||
const libzcash::SpendingKey& sk, CAmount value,
|
const libzcash::SpendingKey& sk, CAmount value,
|
||||||
bool randomInputs) {
|
bool randomInputs) {
|
||||||
|
@ -45,9 +47,10 @@ CWalletTx GetValidReceive(ZCJoinSplit& params,
|
||||||
mtx.vjoinsplit.push_back(jsdesc);
|
mtx.vjoinsplit.push_back(jsdesc);
|
||||||
|
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(mtx);
|
CTransaction signTx(mtx);
|
||||||
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
|
// Add the signature
|
||||||
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||||
|
@ -129,9 +132,10 @@ CWalletTx GetValidSpend(ZCJoinSplit& params,
|
||||||
mtx.vjoinsplit.push_back(jsdesc);
|
mtx.vjoinsplit.push_back(jsdesc);
|
||||||
|
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
|
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(mtx);
|
CTransaction signTx(mtx);
|
||||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
|
||||||
// Add the signature
|
// Add the signature
|
||||||
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "asyncrpcoperation_sendmany.h"
|
#include "asyncrpcoperation_sendmany.h"
|
||||||
#include "asyncrpcqueue.h"
|
#include "asyncrpcqueue.h"
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -337,6 +338,12 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
||||||
LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total));
|
LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total));
|
||||||
LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee));
|
LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee));
|
||||||
|
|
||||||
|
// Grab the current consensus branch ID
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
consensusBranchId_ = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SCENARIO #1
|
* SCENARIO #1
|
||||||
*
|
*
|
||||||
|
@ -994,7 +1001,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(mtx);
|
CTransaction signTx(mtx);
|
||||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_);
|
||||||
|
|
||||||
// Add the signature
|
// Add the signature
|
||||||
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||||
|
|
|
@ -73,6 +73,7 @@ private:
|
||||||
|
|
||||||
UniValue contextinfo_; // optional data to include in return value from getStatus()
|
UniValue contextinfo_; // optional data to include in return value from getStatus()
|
||||||
|
|
||||||
|
uint32_t consensusBranchId_;
|
||||||
CAmount fee_;
|
CAmount fee_;
|
||||||
int mindepth_;
|
int mindepth_;
|
||||||
std::string fromaddress_;
|
std::string fromaddress_;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "asyncrpcqueue.h"
|
#include "asyncrpcqueue.h"
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -302,12 +303,15 @@ void AsyncRPCOperation_shieldcoinbase::sign_send_raw_transaction(UniValue obj)
|
||||||
|
|
||||||
|
|
||||||
UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) {
|
UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) {
|
||||||
|
uint32_t consensusBranchId;
|
||||||
uint256 anchor;
|
uint256 anchor;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||||
anchor = pcoinsTip->GetBestAnchor();
|
anchor = pcoinsTip->GetBestAnchor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (anchor.IsNull()) {
|
if (anchor.IsNull()) {
|
||||||
throw std::runtime_error("anchor is null");
|
throw std::runtime_error("anchor is null");
|
||||||
}
|
}
|
||||||
|
@ -369,7 +373,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
|
||||||
// Empty output script.
|
// Empty output script.
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(mtx);
|
CTransaction signTx(mtx);
|
||||||
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
|
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
|
||||||
|
|
||||||
// Add the signature
|
// Add the signature
|
||||||
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "amount.h"
|
#include "amount.h"
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -2580,7 +2581,12 @@ UniValue zc_benchmark(const UniValue& params, bool fHelp)
|
||||||
} else if (benchmarktype == "verifyequihash") {
|
} else if (benchmarktype == "verifyequihash") {
|
||||||
sample_times.push_back(benchmark_verify_equihash());
|
sample_times.push_back(benchmark_verify_equihash());
|
||||||
} else if (benchmarktype == "validatelargetx") {
|
} 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") {
|
} else if (benchmarktype == "trydecryptnotes") {
|
||||||
int nAddrs = params[2].get_int();
|
int nAddrs = params[2].get_int();
|
||||||
sample_times.push_back(benchmark_try_decrypt_notes(nAddrs));
|
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.
|
// Empty output script.
|
||||||
CScript scriptCode;
|
CScript scriptCode;
|
||||||
CTransaction signTx(mtx);
|
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
|
// Add the signature
|
||||||
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
#include "coincontrol.h"
|
#include "coincontrol.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -2768,6 +2769,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the current consensus branch ID
|
||||||
|
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
|
||||||
|
|
||||||
// Sign
|
// Sign
|
||||||
int nIn = 0;
|
int nIn = 0;
|
||||||
CTransaction txNewConst(txNew);
|
CTransaction txNewConst(txNew);
|
||||||
|
@ -2775,17 +2779,20 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
|
||||||
{
|
{
|
||||||
bool signSuccess;
|
bool signSuccess;
|
||||||
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
|
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
|
||||||
CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
|
SignatureData sigdata;
|
||||||
if (sign)
|
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
|
else
|
||||||
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes);
|
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);
|
||||||
|
|
||||||
if (!signSuccess)
|
if (!signSuccess)
|
||||||
{
|
{
|
||||||
strFailReason = _("Signing transaction failed");
|
strFailReason = _("Signing transaction failed");
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
UpdateTransaction(txNew, nIn, sigdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
nIn++;
|
nIn++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TX_MULTISIG:
|
case TX_MULTISIG:
|
||||||
{
|
{
|
||||||
// Only consider transactions "mine" if we own ALL the
|
// Only consider transactions "mine" if we own ALL the
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "crypto/equihash.h"
|
#include "crypto/equihash.h"
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
|
@ -221,11 +222,8 @@ double benchmark_verify_equihash()
|
||||||
return timer_stop(tv_start);
|
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
|
// Create priv/pub key
|
||||||
CKey priv;
|
CKey priv;
|
||||||
priv.MakeNewKey(false);
|
priv.MakeNewKey(false);
|
||||||
|
@ -244,26 +242,20 @@ double benchmark_large_tx()
|
||||||
auto orig_tx = CTransaction(m_orig_tx);
|
auto orig_tx = CTransaction(m_orig_tx);
|
||||||
|
|
||||||
CMutableTransaction spending_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();
|
auto input_hash = orig_tx.GetHash();
|
||||||
// Add NUM_INPUTS inputs
|
// Add nInputs inputs
|
||||||
for (size_t i = 0; i < NUM_INPUTS; i++) {
|
for (size_t i = 0; i < nInputs; i++) {
|
||||||
spending_tx.vin.emplace_back(input_hash, 0);
|
spending_tx.vin.emplace_back(input_hash, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign for all the inputs
|
// Sign for all the inputs
|
||||||
for (size_t i = 0; i < NUM_INPUTS; i++) {
|
auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId;
|
||||||
SignSignature(tempKeystore, prevPubKey, spending_tx, i, SIGHASH_ALL);
|
for (size_t i = 0; i < nInputs; i++) {
|
||||||
}
|
SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spending tx has all its inputs signed and does not need to be mutated anymore
|
// 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:
|
// Benchmark signature verification costs:
|
||||||
struct timeval tv_start;
|
struct timeval tv_start;
|
||||||
timer_start(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;
|
ScriptError serror = SCRIPT_ERR_OK;
|
||||||
assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
|
assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
|
||||||
prevPubKey,
|
prevPubKey,
|
||||||
STANDARD_SCRIPT_VERIFY_FLAGS,
|
STANDARD_SCRIPT_VERIFY_FLAGS,
|
||||||
TransactionSignatureChecker(&final_spending_tx, i),
|
TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata),
|
||||||
|
consensusBranchId,
|
||||||
&serror));
|
&serror));
|
||||||
}
|
}
|
||||||
return timer_stop(tv_start);
|
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 std::vector<double> benchmark_solve_equihash_threaded(int nThreads);
|
||||||
extern double benchmark_verify_joinsplit(const JSDescription &joinsplit);
|
extern double benchmark_verify_joinsplit(const JSDescription &joinsplit);
|
||||||
extern double benchmark_verify_equihash();
|
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_try_decrypt_notes(size_t nAddrs);
|
||||||
extern double benchmark_increment_note_witnesses(size_t nTxs);
|
extern double benchmark_increment_note_witnesses(size_t nTxs);
|
||||||
extern double benchmark_connectblock_slow();
|
extern double benchmark_connectblock_slow();
|
||||||
|
|
Loading…
Reference in New Issue