Auto merge of #4227 - str4d:2074-scripts-1, r=str4d
Bitcoin script PRs 1 Cherry-picked from the following upstream PRs: - bitcoin/bitcoin#6335 - bitcoin/bitcoin#6424 - bitcoin/bitcoin#11058 - bitcoin/bitcoin#12460 - bitcoin/bitcoin#13194 Part of #2074.
This commit is contained in:
commit
63c3d1ec94
|
@ -157,6 +157,7 @@ BITCOIN_CORE_H = \
|
||||||
netbase.h \
|
netbase.h \
|
||||||
noui.h \
|
noui.h \
|
||||||
policy/fees.h \
|
policy/fees.h \
|
||||||
|
policy/policy.h \
|
||||||
pow.h \
|
pow.h \
|
||||||
prevector.h \
|
prevector.h \
|
||||||
primitives/block.h \
|
primitives/block.h \
|
||||||
|
@ -255,6 +256,7 @@ libbitcoin_server_a_SOURCES = \
|
||||||
net.cpp \
|
net.cpp \
|
||||||
noui.cpp \
|
noui.cpp \
|
||||||
policy/fees.cpp \
|
policy/fees.cpp \
|
||||||
|
policy/policy.cpp \
|
||||||
pow.cpp \
|
pow.cpp \
|
||||||
rest.cpp \
|
rest.cpp \
|
||||||
rpc/blockchain.cpp \
|
rpc/blockchain.cpp \
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "core_io.h"
|
#include "core_io.h"
|
||||||
#include "key_io.h"
|
#include "key_io.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#ifndef BITCOIN_CONSENSUS_CONSENSUS_H
|
#ifndef BITCOIN_CONSENSUS_CONSENSUS_H
|
||||||
#define BITCOIN_CONSENSUS_CONSENSUS_H
|
#define BITCOIN_CONSENSUS_CONSENSUS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/** The minimum allowed block version (network rule) */
|
/** The minimum allowed block version (network rule) */
|
||||||
static const int32_t MIN_BLOCK_VERSION = 4;
|
static const int32_t MIN_BLOCK_VERSION = 4;
|
||||||
/** The minimum allowed transaction version (network rule) */
|
/** The minimum allowed transaction version (network rule) */
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "metrics.h"
|
#include "metrics.h"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "rpc/server.h"
|
#include "rpc/server.h"
|
||||||
#include "rpc/register.h"
|
#include "rpc/register.h"
|
||||||
#include "script/standard.h"
|
#include "script/standard.h"
|
||||||
|
|
143
src/main.cpp
143
src/main.cpp
|
@ -13,6 +13,7 @@
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "checkpoints.h"
|
#include "checkpoints.h"
|
||||||
#include "checkqueue.h"
|
#include "checkqueue.h"
|
||||||
|
#include "consensus/consensus.h"
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "deprecation.h"
|
#include "deprecation.h"
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
#include "merkleblock.h"
|
#include "merkleblock.h"
|
||||||
#include "metrics.h"
|
#include "metrics.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "txmempool.h"
|
#include "txmempool.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
|
@ -671,79 +673,6 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRE
|
||||||
return nEvicted;
|
return nEvicted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IsStandardTx(const CTransaction& tx, string& reason, const CChainParams& chainparams, const int nHeight)
|
|
||||||
{
|
|
||||||
bool overwinterActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER);
|
|
||||||
bool saplingActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING);
|
|
||||||
|
|
||||||
if (saplingActive) {
|
|
||||||
// Sapling standard rules apply
|
|
||||||
if (tx.nVersion > CTransaction::SAPLING_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::SAPLING_MIN_CURRENT_VERSION) {
|
|
||||||
reason = "sapling-version";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (overwinterActive) {
|
|
||||||
// Overwinter standard rules apply
|
|
||||||
if (tx.nVersion > CTransaction::OVERWINTER_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::OVERWINTER_MIN_CURRENT_VERSION) {
|
|
||||||
reason = "overwinter-version";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Sprout standard rules apply
|
|
||||||
if (tx.nVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION) {
|
|
||||||
reason = "version";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
|
||||||
{
|
|
||||||
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
|
|
||||||
// keys. (remember the 520 byte limit on redeemScript size) That works
|
|
||||||
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
|
|
||||||
// bytes of scriptSig, which we round off to 1650 bytes for some minor
|
|
||||||
// future-proofing. That's also enough to spend a 20-of-20
|
|
||||||
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
|
|
||||||
// considered standard)
|
|
||||||
if (txin.scriptSig.size() > 1650) {
|
|
||||||
reason = "scriptsig-size";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!txin.scriptSig.IsPushOnly()) {
|
|
||||||
reason = "scriptsig-not-pushonly";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int nDataOut = 0;
|
|
||||||
txnouttype whichType;
|
|
||||||
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
|
|
||||||
if (!::IsStandard(txout.scriptPubKey, whichType)) {
|
|
||||||
reason = "scriptpubkey";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (whichType == TX_NULL_DATA)
|
|
||||||
nDataOut++;
|
|
||||||
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
|
|
||||||
reason = "bare-multisig";
|
|
||||||
return false;
|
|
||||||
} else if (txout.IsDust(::minRelayTxFee)) {
|
|
||||||
reason = "dust";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only one OP_RETURN txout is permitted
|
|
||||||
if (nDataOut > 1) {
|
|
||||||
reason = "multi-op-return";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
|
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
|
||||||
{
|
{
|
||||||
if (tx.nLockTime == 0)
|
if (tx.nLockTime == 0)
|
||||||
|
@ -800,74 +729,6 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
|
||||||
return IsFinalTx(tx, nBlockHeight, nBlockTime);
|
return IsFinalTx(tx, nBlockHeight, nBlockTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check transaction inputs to mitigate two
|
|
||||||
* potential denial-of-service attacks:
|
|
||||||
*
|
|
||||||
* 1. scriptSigs with extra data stuffed into them,
|
|
||||||
* not consumed by scriptPubKey (or P2SH script)
|
|
||||||
* 2. P2SH scripts with a crazy number of expensive
|
|
||||||
* CHECKSIG/CHECKMULTISIG operations
|
|
||||||
*/
|
|
||||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId)
|
|
||||||
{
|
|
||||||
if (tx.IsCoinBase())
|
|
||||||
return true; // Coinbases don't use vin normally
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
|
||||||
{
|
|
||||||
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
|
|
||||||
|
|
||||||
vector<vector<unsigned char> > vSolutions;
|
|
||||||
txnouttype whichType;
|
|
||||||
// get the scriptPubKey corresponding to this input:
|
|
||||||
const CScript& prevScript = prev.scriptPubKey;
|
|
||||||
if (!Solver(prevScript, whichType, vSolutions))
|
|
||||||
return false;
|
|
||||||
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
|
|
||||||
if (nArgsExpected < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Transactions with extra stuff in their scriptSigs are
|
|
||||||
// non-standard. Note that this EvalScript() call will
|
|
||||||
// be quick, because if there are any operations
|
|
||||||
// beside "push data" in the scriptSig
|
|
||||||
// IsStandardTx() will have already returned false
|
|
||||||
// and this method isn't called.
|
|
||||||
vector<vector<unsigned char> > stack;
|
|
||||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (whichType == TX_SCRIPTHASH)
|
|
||||||
{
|
|
||||||
if (stack.empty())
|
|
||||||
return false;
|
|
||||||
CScript subscript(stack.back().begin(), stack.back().end());
|
|
||||||
vector<vector<unsigned char> > vSolutions2;
|
|
||||||
txnouttype whichType2;
|
|
||||||
if (Solver(subscript, whichType2, vSolutions2))
|
|
||||||
{
|
|
||||||
int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
|
|
||||||
if (tmpExpected < 0)
|
|
||||||
return false;
|
|
||||||
nArgsExpected += tmpExpected;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Any other Script with less than 15 sigops OK:
|
|
||||||
unsigned int sigops = subscript.GetSigOpCount(true);
|
|
||||||
// ... extra data left on the stack after execution is OK, too:
|
|
||||||
return (sigops <= MAX_P2SH_SIGOPS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.size() != (unsigned int)nArgsExpected)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int GetLegacySigOpCount(const CTransaction& tx)
|
unsigned int GetLegacySigOpCount(const CTransaction& tx)
|
||||||
{
|
{
|
||||||
unsigned int nSigOps = 0;
|
unsigned int nSigOps = 0;
|
||||||
|
|
38
src/main.h
38
src/main.h
|
@ -14,7 +14,6 @@
|
||||||
#include "chain.h"
|
#include "chain.h"
|
||||||
#include "chainparams.h"
|
#include "chainparams.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "consensus/consensus.h"
|
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "primitives/block.h"
|
#include "primitives/block.h"
|
||||||
|
@ -54,21 +53,12 @@ class PrecomputedTransactionData;
|
||||||
|
|
||||||
struct CNodeStateStats;
|
struct CNodeStateStats;
|
||||||
|
|
||||||
/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
|
|
||||||
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SIZE;
|
|
||||||
static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
|
|
||||||
/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
|
|
||||||
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = DEFAULT_BLOCK_MAX_SIZE / 2;
|
|
||||||
/** Default for accepting alerts from the P2P network. */
|
/** Default for accepting alerts from the P2P network. */
|
||||||
static const bool DEFAULT_ALERTS = true;
|
static const bool DEFAULT_ALERTS = true;
|
||||||
/** Minimum alert priority for enabling safe mode. */
|
/** Minimum alert priority for enabling safe mode. */
|
||||||
static const int ALERT_PRIORITY_SAFE_MODE = 4000;
|
static const int ALERT_PRIORITY_SAFE_MODE = 4000;
|
||||||
/** Maximum reorg length we will accept before we shut down and alert the user. */
|
/** Maximum reorg length we will accept before we shut down and alert the user. */
|
||||||
static const unsigned int MAX_REORG_LENGTH = COINBASE_MATURITY - 1;
|
static const unsigned int MAX_REORG_LENGTH = COINBASE_MATURITY - 1;
|
||||||
/** Maximum number of signature check operations in an IsStandard() P2SH script */
|
|
||||||
static const unsigned int MAX_P2SH_SIGOPS = 15;
|
|
||||||
/** The maximum number of sigops we're willing to relay/mine in a single tx */
|
|
||||||
static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
|
|
||||||
/** Default for -minrelaytxfee, minimum relay fee for transactions */
|
/** Default for -minrelaytxfee, minimum relay fee for transactions */
|
||||||
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100;
|
static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 100;
|
||||||
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
|
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
|
||||||
|
@ -119,10 +109,6 @@ static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
|
||||||
|
|
||||||
static const bool DEFAULT_TESTSAFEMODE = false;
|
static const bool DEFAULT_TESTSAFEMODE = false;
|
||||||
|
|
||||||
// Sanity check the magic numbers when we change them
|
|
||||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
|
||||||
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE);
|
|
||||||
|
|
||||||
#define equihash_parameters_acceptable(N, K) \
|
#define equihash_parameters_acceptable(N, K) \
|
||||||
((CBlockHeader::HEADER_SIZE + equihash_solution_size(N, K))*MAX_HEADERS_RESULTS < \
|
((CBlockHeader::HEADER_SIZE + equihash_solution_size(N, K))*MAX_HEADERS_RESULTS < \
|
||||||
MAX_PROTOCOL_MESSAGE_LENGTH-1000)
|
MAX_PROTOCOL_MESSAGE_LENGTH-1000)
|
||||||
|
@ -313,25 +299,6 @@ struct CNodeStateStats {
|
||||||
|
|
||||||
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
|
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
|
||||||
|
|
||||||
/**
|
|
||||||
* Check transaction inputs, and make sure any
|
|
||||||
* pay-to-script-hash transactions are evaluating IsStandard scripts
|
|
||||||
*
|
|
||||||
* Why bother? To avoid denial-of-service attacks; an attacker
|
|
||||||
* can submit a standard HASH... OP_EQUAL transaction,
|
|
||||||
* which will get accepted into blocks. The redemption
|
|
||||||
* script can be anything; an attacker could use a very
|
|
||||||
* expensive-to-check-upon-redemption script like:
|
|
||||||
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for standard transaction types
|
|
||||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
|
||||||
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
|
||||||
*/
|
|
||||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, 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
|
||||||
* @return number of sigops this transaction's outputs will produce when spent
|
* @return number of sigops this transaction's outputs will produce when spent
|
||||||
|
@ -373,11 +340,6 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight);
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
|
bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
|
||||||
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
|
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
|
||||||
|
|
||||||
/** Check for standard transaction types
|
|
||||||
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
|
|
||||||
*/
|
|
||||||
bool IsStandardTx(const CTransaction& tx, std::string& reason, const CChainParams& chainparams, int nHeight = 0);
|
|
||||||
|
|
||||||
namespace Consensus {
|
namespace Consensus {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "metrics.h"
|
#include "metrics.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic
|
||||||
|
|
||||||
|
#include "policy/policy.h"
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include "tinyformat.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "utilstrencodings.h"
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check transaction inputs to mitigate two
|
||||||
|
* potential denial-of-service attacks:
|
||||||
|
*
|
||||||
|
* 1. scriptSigs with extra data stuffed into them,
|
||||||
|
* not consumed by scriptPubKey (or P2SH script)
|
||||||
|
* 2. P2SH scripts with very many expensive
|
||||||
|
* CHECKSIG/CHECKMULTISIG operations
|
||||||
|
*
|
||||||
|
* Check transaction inputs, and make sure any
|
||||||
|
* pay-to-script-hash transactions are evaluating IsStandard scripts
|
||||||
|
*
|
||||||
|
* Why bother? To avoid denial-of-service attacks; an attacker
|
||||||
|
* can submit a standard HASH... OP_EQUAL transaction,
|
||||||
|
* which will get accepted into blocks. The redemption
|
||||||
|
* script can be anything; an attacker could use a very
|
||||||
|
* expensive-to-check-upon-redemption script like:
|
||||||
|
* DUP CHECKSIG DROP ... repeated 100 times... OP_1
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||||
|
{
|
||||||
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
|
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (whichType == TX_MULTISIG)
|
||||||
|
{
|
||||||
|
unsigned char m = vSolutions.front()[0];
|
||||||
|
unsigned char n = vSolutions.back()[0];
|
||||||
|
// Support up to x-of-3 multisig txns as standard
|
||||||
|
if (n < 1 || n > 3)
|
||||||
|
return false;
|
||||||
|
if (m < 1 || m > n)
|
||||||
|
return false;
|
||||||
|
} else if (whichType == TX_NULL_DATA &&
|
||||||
|
(!GetBoolArg("-datacarrier", true) || scriptPubKey.size() > nMaxDatacarrierBytes))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return whichType != TX_NONSTANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsStandardTx(const CTransaction& tx, std::string& reason, const CChainParams& chainparams, const int nHeight)
|
||||||
|
{
|
||||||
|
bool overwinterActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_OVERWINTER);
|
||||||
|
bool saplingActive = chainparams.GetConsensus().NetworkUpgradeActive(nHeight, Consensus::UPGRADE_SAPLING);
|
||||||
|
|
||||||
|
if (saplingActive) {
|
||||||
|
// Sapling standard rules apply
|
||||||
|
if (tx.nVersion > CTransaction::SAPLING_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::SAPLING_MIN_CURRENT_VERSION) {
|
||||||
|
reason = "sapling-version";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (overwinterActive) {
|
||||||
|
// Overwinter standard rules apply
|
||||||
|
if (tx.nVersion > CTransaction::OVERWINTER_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::OVERWINTER_MIN_CURRENT_VERSION) {
|
||||||
|
reason = "overwinter-version";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Sprout standard rules apply
|
||||||
|
if (tx.nVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION || tx.nVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION) {
|
||||||
|
reason = "version";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||||
|
{
|
||||||
|
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
|
||||||
|
// keys. (remember the 520 byte limit on redeemScript size) That works
|
||||||
|
// out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
|
||||||
|
// bytes of scriptSig, which we round off to 1650 bytes for some minor
|
||||||
|
// future-proofing. That's also enough to spend a 20-of-20
|
||||||
|
// CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
|
||||||
|
// considered standard)
|
||||||
|
if (txin.scriptSig.size() > 1650) {
|
||||||
|
reason = "scriptsig-size";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!txin.scriptSig.IsPushOnly()) {
|
||||||
|
reason = "scriptsig-not-pushonly";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int nDataOut = 0;
|
||||||
|
txnouttype whichType;
|
||||||
|
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
|
||||||
|
if (!::IsStandard(txout.scriptPubKey, whichType)) {
|
||||||
|
reason = "scriptpubkey";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whichType == TX_NULL_DATA)
|
||||||
|
nDataOut++;
|
||||||
|
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
|
||||||
|
reason = "bare-multisig";
|
||||||
|
return false;
|
||||||
|
} else if (txout.IsDust(::minRelayTxFee)) {
|
||||||
|
reason = "dust";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only one OP_RETURN txout is permitted
|
||||||
|
if (nDataOut > 1) {
|
||||||
|
reason = "multi-op-return";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId)
|
||||||
|
{
|
||||||
|
if (tx.IsCoinBase())
|
||||||
|
return true; // Coinbases don't use vin normally
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||||
|
{
|
||||||
|
const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
|
||||||
|
|
||||||
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
|
txnouttype whichType;
|
||||||
|
// get the scriptPubKey corresponding to this input:
|
||||||
|
const CScript& prevScript = prev.scriptPubKey;
|
||||||
|
if (!Solver(prevScript, whichType, vSolutions))
|
||||||
|
return false;
|
||||||
|
int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
|
||||||
|
if (nArgsExpected < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Transactions with extra stuff in their scriptSigs are
|
||||||
|
// non-standard. Note that this EvalScript() call will
|
||||||
|
// be quick, because if there are any operations
|
||||||
|
// beside "push data" in the scriptSig
|
||||||
|
// IsStandardTx() will have already returned false
|
||||||
|
// and this method isn't called.
|
||||||
|
std::vector<std::vector<unsigned char> > stack;
|
||||||
|
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (whichType == TX_SCRIPTHASH)
|
||||||
|
{
|
||||||
|
if (stack.empty())
|
||||||
|
return false;
|
||||||
|
CScript subscript(stack.back().begin(), stack.back().end());
|
||||||
|
std::vector<std::vector<unsigned char> > vSolutions2;
|
||||||
|
txnouttype whichType2;
|
||||||
|
if (Solver(subscript, whichType2, vSolutions2))
|
||||||
|
{
|
||||||
|
int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
|
||||||
|
if (tmpExpected < 0)
|
||||||
|
return false;
|
||||||
|
nArgsExpected += tmpExpected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Any other Script with less than 15 sigops OK:
|
||||||
|
unsigned int sigops = subscript.GetSigOpCount(true);
|
||||||
|
// ... extra data left on the stack after execution is OK, too:
|
||||||
|
return (sigops <= MAX_P2SH_SIGOPS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack.size() != (unsigned int)nArgsExpected)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
|
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_POLICY_H
|
||||||
|
#define BITCOIN_POLICY_H
|
||||||
|
|
||||||
|
#include "consensus/consensus.h"
|
||||||
|
#include "script/interpreter.h"
|
||||||
|
#include "script/standard.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CChainParams;
|
||||||
|
class CCoinsViewCache;
|
||||||
|
|
||||||
|
/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
|
||||||
|
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = MAX_BLOCK_SIZE;
|
||||||
|
static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
|
||||||
|
/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
|
||||||
|
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = DEFAULT_BLOCK_MAX_SIZE / 2;
|
||||||
|
/** Maximum number of signature check operations in an IsStandard() P2SH script */
|
||||||
|
static const unsigned int MAX_P2SH_SIGOPS = 15;
|
||||||
|
/** The maximum number of sigops we're willing to relay/mine in a single tx */
|
||||||
|
static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
|
||||||
|
/**
|
||||||
|
* Standard script verification flags that standard transactions will comply
|
||||||
|
* with. However scripts violating these flags may still be present in valid
|
||||||
|
* blocks and we must accept those blocks.
|
||||||
|
*/
|
||||||
|
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||||
|
// SCRIPT_VERIFY_DERSIG is always enforced
|
||||||
|
SCRIPT_VERIFY_STRICTENC |
|
||||||
|
SCRIPT_VERIFY_MINIMALDATA |
|
||||||
|
SCRIPT_VERIFY_NULLDUMMY |
|
||||||
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
||||||
|
SCRIPT_VERIFY_CLEANSTACK |
|
||||||
|
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
||||||
|
SCRIPT_VERIFY_LOW_S;
|
||||||
|
|
||||||
|
/** For convenience, standard but not mandatory verify flags. */
|
||||||
|
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||||
|
|
||||||
|
// Sanity check the magic numbers when we change them
|
||||||
|
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_MAX_SIZE <= MAX_BLOCK_SIZE);
|
||||||
|
BOOST_STATIC_ASSERT(DEFAULT_BLOCK_PRIORITY_SIZE <= DEFAULT_BLOCK_MAX_SIZE);
|
||||||
|
|
||||||
|
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
||||||
|
/**
|
||||||
|
* Check for standard transaction types
|
||||||
|
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
|
||||||
|
*/
|
||||||
|
bool IsStandardTx(const CTransaction& tx, std::string& reason, const CChainParams& chainparams, int nHeight = 0);
|
||||||
|
/**
|
||||||
|
* Check for standard transaction types
|
||||||
|
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||||
|
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
||||||
|
*/
|
||||||
|
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId);
|
||||||
|
|
||||||
|
#endif // BITCOIN_POLICY_H
|
13
src/pubkey.h
13
src/pubkey.h
|
@ -33,10 +33,10 @@ public:
|
||||||
/**
|
/**
|
||||||
* secp256k1:
|
* secp256k1:
|
||||||
*/
|
*/
|
||||||
static const unsigned int PUBLIC_KEY_SIZE = 65;
|
static constexpr unsigned int PUBLIC_KEY_SIZE = 65;
|
||||||
static const unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
|
static constexpr unsigned int COMPRESSED_PUBLIC_KEY_SIZE = 33;
|
||||||
static const unsigned int SIGNATURE_SIZE = 72;
|
static constexpr unsigned int SIGNATURE_SIZE = 72;
|
||||||
static const unsigned int COMPACT_SIGNATURE_SIZE = 65;
|
static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65;
|
||||||
/**
|
/**
|
||||||
* see www.keylength.com
|
* see www.keylength.com
|
||||||
* script supports up to 75 for single byte push
|
* script supports up to 75 for single byte push
|
||||||
|
@ -70,6 +70,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
bool static ValidSize(const std::vector<unsigned char> &vch) {
|
||||||
|
return vch.size() > 0 && GetLen(vch[0]) == vch.size();
|
||||||
|
}
|
||||||
|
|
||||||
//! Construct an invalid public key.
|
//! Construct an invalid public key.
|
||||||
CPubKey()
|
CPubKey()
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "merkleblock.h"
|
#include "merkleblock.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "primitives/transaction.h"
|
#include "primitives/transaction.h"
|
||||||
#include "rpc/server.h"
|
#include "rpc/server.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
|
|
|
@ -65,17 +65,17 @@ static inline void popstack(vector<valtype>& stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
||||||
if (vchPubKey.size() < 33) {
|
if (vchPubKey.size() < CPubKey::COMPRESSED_PUBLIC_KEY_SIZE) {
|
||||||
// Non-canonical public key: too short
|
// Non-canonical public key: too short
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (vchPubKey[0] == 0x04) {
|
if (vchPubKey[0] == 0x04) {
|
||||||
if (vchPubKey.size() != 65) {
|
if (vchPubKey.size() != CPubKey::PUBLIC_KEY_SIZE) {
|
||||||
// Non-canonical public key: invalid length for uncompressed key
|
// Non-canonical public key: invalid length for uncompressed key
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
|
} else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
|
||||||
if (vchPubKey.size() != 33) {
|
if (vchPubKey.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE) {
|
||||||
// Non-canonical public key: invalid length for compressed key
|
// Non-canonical public key: invalid length for compressed key
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,11 +143,6 @@ const char* GetOpName(opcodetype opcode)
|
||||||
|
|
||||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||||
|
|
||||||
// Note:
|
|
||||||
// The template matching params OP_SMALLDATA/etc are defined in opcodetype enum
|
|
||||||
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
|
|
||||||
// Script, just let the default: case deal with them.
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "OP_UNKNOWN";
|
return "OP_UNKNOWN";
|
||||||
}
|
}
|
||||||
|
@ -223,9 +218,8 @@ bool CScript::IsPayToScriptHash() const
|
||||||
(*this)[22] == OP_EQUAL);
|
(*this)[22] == OP_EQUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CScript::IsPushOnly() const
|
bool CScript::IsPushOnly(const_iterator pc) const
|
||||||
{
|
{
|
||||||
const_iterator pc = begin();
|
|
||||||
while (pc < end())
|
while (pc < end())
|
||||||
{
|
{
|
||||||
opcodetype opcode;
|
opcodetype opcode;
|
||||||
|
@ -241,6 +235,11 @@ bool CScript::IsPushOnly() const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CScript::IsPushOnly() const
|
||||||
|
{
|
||||||
|
return this->IsPushOnly(begin());
|
||||||
|
}
|
||||||
|
|
||||||
// insightexplorer
|
// insightexplorer
|
||||||
CScript::ScriptType CScript::GetType() const
|
CScript::ScriptType CScript::GetType() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -171,14 +171,6 @@ enum opcodetype
|
||||||
OP_NOP9 = 0xb8,
|
OP_NOP9 = 0xb8,
|
||||||
OP_NOP10 = 0xb9,
|
OP_NOP10 = 0xb9,
|
||||||
|
|
||||||
|
|
||||||
// template matching params
|
|
||||||
OP_SMALLDATA = 0xf9,
|
|
||||||
OP_SMALLINTEGER = 0xfa,
|
|
||||||
OP_PUBKEYS = 0xfb,
|
|
||||||
OP_PUBKEYHASH = 0xfd,
|
|
||||||
OP_PUBKEY = 0xfe,
|
|
||||||
|
|
||||||
OP_INVALIDOPCODE = 0xff,
|
OP_INVALIDOPCODE = 0xff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -579,6 +571,7 @@ public:
|
||||||
uint160 AddressHash() const;
|
uint160 AddressHash() const;
|
||||||
|
|
||||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||||
|
bool IsPushOnly(const_iterator pc) const;
|
||||||
bool IsPushOnly() const;
|
bool IsPushOnly() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
|
|
||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
|
|
||||||
#include "primitives/transaction.h"
|
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
|
#include "primitives/transaction.h"
|
||||||
#include "script/standard.h"
|
#include "script/standard.h"
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
||||||
|
|
|
@ -35,29 +35,55 @@ const char* GetTxnOutputType(txnouttype t)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static bool MatchPayToPubkey(const CScript& script, valtype& pubkey)
|
||||||
* Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
|
|
||||||
*/
|
|
||||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
|
|
||||||
{
|
{
|
||||||
// Templates
|
if (script.size() == CPubKey::PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) {
|
||||||
static multimap<txnouttype, CScript> mTemplates;
|
pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::PUBLIC_KEY_SIZE + 1);
|
||||||
if (mTemplates.empty())
|
return CPubKey::ValidSize(pubkey);
|
||||||
{
|
|
||||||
// Standard tx, sender provides pubkey, receiver adds signature
|
|
||||||
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
|
|
||||||
|
|
||||||
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
|
|
||||||
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
|
|
||||||
|
|
||||||
// Sender provides N pubkeys, receivers provides M signatures
|
|
||||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
|
||||||
|
|
||||||
// Empty, provably prunable, data-carrying output
|
|
||||||
if (GetBoolArg("-datacarrier", true))
|
|
||||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN << OP_SMALLDATA));
|
|
||||||
mTemplates.insert(make_pair(TX_NULL_DATA, CScript() << OP_RETURN));
|
|
||||||
}
|
}
|
||||||
|
if (script.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 2 && script[0] == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE && script.back() == OP_CHECKSIG) {
|
||||||
|
pubkey = valtype(script.begin() + 1, script.begin() + CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1);
|
||||||
|
return CPubKey::ValidSize(pubkey);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MatchPayToPubkeyHash(const CScript& script, valtype& pubkeyhash)
|
||||||
|
{
|
||||||
|
if (script.size() == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG) {
|
||||||
|
pubkeyhash = valtype(script.begin () + 3, script.begin() + 23);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test for "small positive integer" script opcodes - OP_1 through OP_16. */
|
||||||
|
static constexpr bool IsSmallInteger(opcodetype opcode)
|
||||||
|
{
|
||||||
|
return opcode >= OP_1 && opcode <= OP_16;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MatchMultisig(const CScript& script, unsigned int& required, std::vector<valtype>& pubkeys)
|
||||||
|
{
|
||||||
|
opcodetype opcode;
|
||||||
|
valtype data;
|
||||||
|
CScript::const_iterator it = script.begin();
|
||||||
|
if (script.size() < 1 || script.back() != OP_CHECKMULTISIG) return false;
|
||||||
|
|
||||||
|
if (!script.GetOp(it, opcode, data) || !IsSmallInteger(opcode)) return false;
|
||||||
|
required = CScript::DecodeOP_N(opcode);
|
||||||
|
while (script.GetOp(it, opcode, data) && CPubKey::ValidSize(data)) {
|
||||||
|
pubkeys.emplace_back(std::move(data));
|
||||||
|
}
|
||||||
|
if (!IsSmallInteger(opcode)) return false;
|
||||||
|
unsigned int keys = CScript::DecodeOP_N(opcode);
|
||||||
|
if (pubkeys.size() != keys || keys < required) return false;
|
||||||
|
return (it + 1 == script.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
|
||||||
|
{
|
||||||
|
vSolutionsRet.clear();
|
||||||
|
|
||||||
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
||||||
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
||||||
|
@ -69,90 +95,37 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan templates
|
// Provably prunable, data-carrying output
|
||||||
const CScript& script1 = scriptPubKey;
|
//
|
||||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
// So long as script passes the IsUnspendable() test and all but the first
|
||||||
{
|
// byte passes the IsPushOnly() test we don't care what exactly is in the
|
||||||
const CScript& script2 = tplate.second;
|
// script.
|
||||||
vSolutionsRet.clear();
|
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
|
||||||
|
typeRet = TX_NULL_DATA;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
opcodetype opcode1, opcode2;
|
std::vector<unsigned char> data;
|
||||||
vector<unsigned char> vch1, vch2;
|
if (MatchPayToPubkey(scriptPubKey, data)) {
|
||||||
|
typeRet = TX_PUBKEY;
|
||||||
|
vSolutionsRet.push_back(std::move(data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Compare
|
if (MatchPayToPubkeyHash(scriptPubKey, data)) {
|
||||||
CScript::const_iterator pc1 = script1.begin();
|
typeRet = TX_PUBKEYHASH;
|
||||||
CScript::const_iterator pc2 = script2.begin();
|
vSolutionsRet.push_back(std::move(data));
|
||||||
while (true)
|
return true;
|
||||||
{
|
}
|
||||||
if (pc1 == script1.end() && pc2 == script2.end())
|
|
||||||
{
|
|
||||||
// Found a match
|
|
||||||
typeRet = tplate.first;
|
|
||||||
if (typeRet == TX_MULTISIG)
|
|
||||||
{
|
|
||||||
// Additional checks for TX_MULTISIG:
|
|
||||||
unsigned char m = vSolutionsRet.front()[0];
|
|
||||||
unsigned char n = vSolutionsRet.back()[0];
|
|
||||||
if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
|
||||||
break;
|
|
||||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Template matching opcodes:
|
unsigned int required;
|
||||||
if (opcode2 == OP_PUBKEYS)
|
std::vector<std::vector<unsigned char>> keys;
|
||||||
{
|
if (MatchMultisig(scriptPubKey, required, keys)) {
|
||||||
while (vch1.size() >= 33 && vch1.size() <= 65)
|
typeRet = TX_MULTISIG;
|
||||||
{
|
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
|
||||||
vSolutionsRet.push_back(vch1);
|
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
|
||||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
|
||||||
break;
|
return true;
|
||||||
}
|
|
||||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
|
||||||
break;
|
|
||||||
// Normal situation is to fall through
|
|
||||||
// to other if/else statements
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opcode2 == OP_PUBKEY)
|
|
||||||
{
|
|
||||||
if (vch1.size() < 33 || vch1.size() > 65)
|
|
||||||
break;
|
|
||||||
vSolutionsRet.push_back(vch1);
|
|
||||||
}
|
|
||||||
else if (opcode2 == OP_PUBKEYHASH)
|
|
||||||
{
|
|
||||||
if (vch1.size() != sizeof(uint160))
|
|
||||||
break;
|
|
||||||
vSolutionsRet.push_back(vch1);
|
|
||||||
}
|
|
||||||
else if (opcode2 == OP_SMALLINTEGER)
|
|
||||||
{ // Single-byte small integer pushed onto vSolutions
|
|
||||||
if (opcode1 == OP_0 ||
|
|
||||||
(opcode1 >= OP_1 && opcode1 <= OP_16))
|
|
||||||
{
|
|
||||||
char n = (char)CScript::DecodeOP_N(opcode1);
|
|
||||||
vSolutionsRet.push_back(valtype(1, n));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (opcode2 == OP_SMALLDATA)
|
|
||||||
{
|
|
||||||
// small pushdata, <= nMaxDatacarrierBytes
|
|
||||||
if (vch1.size() > nMaxDatacarrierBytes)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
|
||||||
{
|
|
||||||
// Others must match exactly
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vSolutionsRet.clear();
|
vSolutionsRet.clear();
|
||||||
|
@ -181,26 +154,6 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
|
||||||
{
|
|
||||||
vector<valtype> vSolutions;
|
|
||||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (whichType == TX_MULTISIG)
|
|
||||||
{
|
|
||||||
unsigned char m = vSolutions.front()[0];
|
|
||||||
unsigned char n = vSolutions.back()[0];
|
|
||||||
// Support up to x-of-3 multisig txns as standard
|
|
||||||
if (n < 1 || n > 3)
|
|
||||||
return false;
|
|
||||||
if (m < 1 || m > n)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return whichType != TX_NONSTANDARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||||
{
|
{
|
||||||
vector<valtype> vSolutions;
|
vector<valtype> vSolutions;
|
||||||
|
|
|
@ -27,8 +27,19 @@ public:
|
||||||
CScriptID(const uint160& in) : uint160(in) {}
|
CScriptID(const uint160& in) : uint160(in) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int MAX_OP_RETURN_RELAY = 80; //!< bytes
|
/**
|
||||||
|
* Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
|
||||||
|
* +2 for the pushdata opcodes.
|
||||||
|
*/
|
||||||
|
static const unsigned int MAX_OP_RETURN_RELAY = 83;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data carrying output is an unspendable output containing data. The script
|
||||||
|
* type is designated as TX_NULL_DATA.
|
||||||
|
*/
|
||||||
extern bool fAcceptDatacarrier;
|
extern bool fAcceptDatacarrier;
|
||||||
|
|
||||||
|
/** Maximum size of TX_NULL_DATA scripts that this node considers standard. */
|
||||||
extern unsigned nMaxDatacarrierBytes;
|
extern unsigned nMaxDatacarrierBytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,24 +52,6 @@ extern unsigned nMaxDatacarrierBytes;
|
||||||
*/
|
*/
|
||||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||||
|
|
||||||
/**
|
|
||||||
* Standard script verification flags that standard transactions will comply
|
|
||||||
* with. However scripts violating these flags may still be present in valid
|
|
||||||
* blocks and we must accept those blocks.
|
|
||||||
*/
|
|
||||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
|
||||||
// SCRIPT_VERIFY_DERSIG is always enforced
|
|
||||||
SCRIPT_VERIFY_STRICTENC |
|
|
||||||
SCRIPT_VERIFY_MINIMALDATA |
|
|
||||||
SCRIPT_VERIFY_NULLDUMMY |
|
|
||||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
|
|
||||||
SCRIPT_VERIFY_CLEANSTACK |
|
|
||||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
|
|
||||||
SCRIPT_VERIFY_LOW_S;
|
|
||||||
|
|
||||||
/** For convenience, standard but not mandatory verify flags. */
|
|
||||||
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
|
||||||
|
|
||||||
enum txnouttype
|
enum txnouttype
|
||||||
{
|
{
|
||||||
TX_NONSTANDARD,
|
TX_NONSTANDARD,
|
||||||
|
@ -67,7 +60,7 @@ enum txnouttype
|
||||||
TX_PUBKEYHASH,
|
TX_PUBKEYHASH,
|
||||||
TX_SCRIPTHASH,
|
TX_SCRIPTHASH,
|
||||||
TX_MULTISIG,
|
TX_MULTISIG,
|
||||||
TX_NULL_DATA,
|
TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
|
||||||
};
|
};
|
||||||
|
|
||||||
class CNoDestination {
|
class CNoDestination {
|
||||||
|
@ -88,16 +81,49 @@ typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
|
||||||
/** Check whether a CTxDestination is a CNoDestination. */
|
/** Check whether a CTxDestination is a CNoDestination. */
|
||||||
bool IsValidDestination(const CTxDestination& dest);
|
bool IsValidDestination(const CTxDestination& dest);
|
||||||
|
|
||||||
|
/** Get the name of a txnouttype as a C string, or nullptr if unknown. */
|
||||||
const char* GetTxnOutputType(txnouttype t);
|
const char* GetTxnOutputType(txnouttype t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a scriptPubKey and identify script type for standard scripts. If
|
||||||
|
* successful, returns script type and parsed pubkeys or hashes, depending on
|
||||||
|
* the type. For example, for a P2SH script, vSolutionsRet will contain the
|
||||||
|
* script hash, for P2PKH it will contain the key hash, etc.
|
||||||
|
*
|
||||||
|
* @param[in] scriptPubKey Script to parse
|
||||||
|
* @param[out] typeRet The script type
|
||||||
|
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
|
||||||
|
* @return True if script matches standard template
|
||||||
|
*/
|
||||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
||||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
||||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
|
||||||
|
/**
|
||||||
|
* Parse a standard scriptPubKey for the destination address. Assigns result to
|
||||||
|
* the addressRet parameter and returns true if successful. For multisig
|
||||||
|
* scripts, instead use ExtractDestinations. Currently only works for P2PK,
|
||||||
|
* P2PKH, and P2SH scripts.
|
||||||
|
*/
|
||||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a standard scriptPubKey with one or more destination addresses. For
|
||||||
|
* multisig scripts, this populates the addressRet vector with the pubkey IDs
|
||||||
|
* and nRequiredRet with the n required to spend. For other destinations,
|
||||||
|
* addressRet is populated with a single value and nRequiredRet is set to 1.
|
||||||
|
* Returns true if successful.
|
||||||
|
*/
|
||||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
|
||||||
|
* script for a CKeyID destination, a P2SH script for a CScriptID, and an empty
|
||||||
|
* script for CNoDestination.
|
||||||
|
*/
|
||||||
CScript GetScriptForDestination(const CTxDestination& dest);
|
CScript GetScriptForDestination(const CTxDestination& dest);
|
||||||
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
|
CScript GetScriptForRawPubKey(const CPubKey& pubkey);
|
||||||
|
|
||||||
|
/** Generate a multisig script. */
|
||||||
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
||||||
|
|
||||||
// insightexplorer
|
// insightexplorer
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "consensus/upgrades.h"
|
#include "consensus/upgrades.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "policy/policy.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
#include "script/script_error.h"
|
#include "script/script_error.h"
|
||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
|
@ -776,12 +777,29 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||||
BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
|
BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
|
||||||
|
|
||||||
// 80-byte TX_NULL_DATA (standard)
|
// MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||||
|
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
|
||||||
BOOST_CHECK(IsStandardTx(t, reason, chainparams));
|
BOOST_CHECK(IsStandardTx(t, reason, chainparams));
|
||||||
|
|
||||||
// 81-byte TX_NULL_DATA (non-standard)
|
// MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
||||||
|
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
|
||||||
|
BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
|
||||||
|
|
||||||
|
// Data payload can be encoded in any way...
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("");
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason, chainparams));
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("00") << ParseHex("01");
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason, chainparams));
|
||||||
|
// OP_RESERVED *is* considered to be a PUSHDATA type opcode by IsPushOnly()!
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RESERVED << -1 << 0 << ParseHex("01") << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12 << 13 << 14 << 15 << 16;
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason, chainparams));
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << 0 << ParseHex("01") << 2 << ParseHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
BOOST_CHECK(IsStandardTx(t, reason, chainparams));
|
||||||
|
|
||||||
|
// ...so long as it only contains PUSHDATA's
|
||||||
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_RETURN;
|
||||||
BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
|
BOOST_CHECK(!IsStandardTx(t, reason, chainparams));
|
||||||
|
|
||||||
// TX_NULL_DATA w/o PUSHDATA
|
// TX_NULL_DATA w/o PUSHDATA
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "key_io.h"
|
#include "key_io.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "rpc/protocol.h"
|
#include "rpc/protocol.h"
|
||||||
#include "rpc/server.h"
|
#include "rpc/server.h"
|
||||||
#include "script/script.h"
|
#include "script/script.h"
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "consensus/validation.h"
|
#include "consensus/validation.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
|
#include "policy/policy.h"
|
||||||
#include "pow.h"
|
#include "pow.h"
|
||||||
#include "rpc/server.h"
|
#include "rpc/server.h"
|
||||||
#include "script/sign.h"
|
#include "script/sign.h"
|
||||||
|
|
Loading…
Reference in New Issue