Add replay protection. Bugfix.
This commit is contained in:
parent
7348fcce47
commit
0d9afc87eb
|
@ -449,8 +449,8 @@ zcash_cli_LDADD = \
|
|||
#
|
||||
|
||||
# zcash-tx binary #
|
||||
zcash_tx_SOURCES = bitcoin-tx.cpp
|
||||
zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
|
||||
zcash_tx_SOURCES = bitcoin-tx.cpp script/standard.cpp
|
||||
zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES) -DZCASH_TX
|
||||
zcash_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||
|
||||
if TARGET_WINDOWS
|
||||
|
|
|
@ -5,6 +5,7 @@ noinst_PROGRAMS += zcash-gtest
|
|||
# test_checktransaction.cpp MUST be before
|
||||
# any test that calls SelectParams().
|
||||
zcash_gtest_SOURCES = \
|
||||
script/standard.cpp \
|
||||
gtest/main.cpp \
|
||||
gtest/utils.cpp \
|
||||
gtest/test_checktransaction.cpp \
|
||||
|
@ -41,7 +42,7 @@ zcash_gtest_SOURCES += \
|
|||
wallet/gtest/test_wallet.cpp
|
||||
endif
|
||||
|
||||
zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
|
||||
zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) -DZCASH_TX
|
||||
|
||||
zcash_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)
|
||||
|
|
|
@ -40,6 +40,7 @@ RAW_TEST_FILES = test/data/alertTests.raw
|
|||
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
|
||||
|
||||
BITCOIN_TESTS =\
|
||||
script/standard.cpp \
|
||||
test/arith_uint256_tests.cpp \
|
||||
test/bignum.h \
|
||||
test/addrman_tests.cpp \
|
||||
|
@ -99,7 +100,7 @@ BITCOIN_TESTS += \
|
|||
endif
|
||||
|
||||
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||
test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
|
||||
test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS) -DZCASH_TX
|
||||
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||
if ENABLE_WALLET
|
||||
|
|
|
@ -380,7 +380,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
|||
}
|
||||
case OP_NOP5:
|
||||
{
|
||||
if (stack.size() == 2) {
|
||||
// If it is OP_CHECKBLOCKATHEIGHT then there are should be 3 args in stack: 2 params and 1 ret value from the prev opcode
|
||||
if (stack.size() == 3) {
|
||||
popstack(stack);
|
||||
popstack(stack);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "script/standard.h"
|
||||
|
||||
#include "main.h"
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
|
@ -26,12 +27,9 @@ const char* GetTxnOutputType(txnouttype t)
|
|||
{
|
||||
case TX_NONSTANDARD: return "nonstandard";
|
||||
case TX_PUBKEY: return "pubkey";
|
||||
case TX_PUBKEY_REPLAY: return "pubkeyreplay";
|
||||
case TX_PUBKEYHASH: return "pubkeyhash";
|
||||
case TX_PUBKEYHASH_REPLAY: return "pubkeyhashreplay";
|
||||
case TX_SCRIPTHASH: return "scripthash";
|
||||
case TX_MULTISIG: return "multisig";
|
||||
case TX_MULTISIG_REPLAY: return "multisigreplay";
|
||||
case TX_NULL_DATA: return "nulldata";
|
||||
}
|
||||
return NULL;
|
||||
|
@ -48,15 +46,15 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||
{
|
||||
// Standard tx, sender provides pubkey, receiver adds signature
|
||||
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
|
||||
mTemplates.insert(make_pair(TX_PUBKEY_REPLAY, CScript() << OP_PUBKEY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
|
||||
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
|
||||
|
||||
// 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));
|
||||
mTemplates.insert(make_pair(TX_PUBKEYHASH_REPLAY, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
|
||||
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
|
||||
|
||||
// Sender provides N pubkeys, receivers provides M signatures
|
||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
||||
mTemplates.insert(make_pair(TX_MULTISIG_REPLAY, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
|
||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
|
||||
|
||||
// Empty, provably prunable, data-carrying output
|
||||
if (GetBoolArg("-datacarrier", true))
|
||||
|
@ -74,6 +72,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||
return true;
|
||||
}
|
||||
|
||||
// OP_CHECKBLOCKATHEIGHT parameters
|
||||
vector<unsigned char> vchBlockHash, vchBlockHeight;
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||
|
@ -148,10 +149,52 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
|||
}
|
||||
else if (opcode2 == OP_SMALLDATA)
|
||||
{
|
||||
// Possible values of OP_CHECKBLOCKATHEIGHT parameters
|
||||
if (vch1.size() <= sizeof(int))
|
||||
vchBlockHeight = vch1;
|
||||
else
|
||||
vchBlockHash = vch1;
|
||||
|
||||
// small pushdata, <= nMaxDatacarrierBytes
|
||||
if (vch1.size() > nMaxDatacarrierBytes)
|
||||
break;
|
||||
}
|
||||
else if (opcode2 == OP_NOP5)
|
||||
{
|
||||
// Full-fledged implementation of the OP_CHECKBLOCKATHEIGHT opcode for verification of vout's
|
||||
|
||||
#ifndef ZCASH_TX // This is a workaround. zcash-tx does not have access to chain state so no replay protection is possible
|
||||
|
||||
if (vchBlockHeight.size() == 0 || vchBlockHash.size() == 0)
|
||||
{
|
||||
LogPrintf("%s: %s: OP_CHECKBLOCKATHEIGHT verification failed. Bad params.", __FILE__, __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
const int32_t nHeight = CScriptNum(vchBlockHeight, true, sizeof(int)).getint();
|
||||
|
||||
if (nHeight < 0 || nHeight > chainActive.Height())
|
||||
{
|
||||
LogPrintf("%s: %s: OP_CHECKBLOCKATHEIGHT verification failed. Transaction is non-final. Referenced height: %d", __FILE__, __func__, nHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
CBlockIndex* pblockindex = chainActive[nHeight];
|
||||
|
||||
vector<unsigned char> vchCompareTo(pblockindex->GetBlockHash().begin(), pblockindex->GetBlockHash().end());
|
||||
vchCompareTo.erase(vchCompareTo.begin(), vchCompareTo.end() - vchBlockHash.size());
|
||||
|
||||
if (vchCompareTo != vchBlockHash)
|
||||
{
|
||||
LogPrintf("%s: %s: OP_CHECKBLOCKATHEIGHT verification failed. vout block height: %d", __FILE__, __func__, nHeight);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (opcode1 != opcode2 || vch1 != vch2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
||||
{
|
||||
// Others must match exactly
|
||||
|
|
|
@ -62,12 +62,9 @@ enum txnouttype
|
|||
TX_NONSTANDARD,
|
||||
// 'standard' transaction types:
|
||||
TX_PUBKEY,
|
||||
TX_PUBKEY_REPLAY,
|
||||
TX_PUBKEYHASH,
|
||||
TX_PUBKEYHASH_REPLAY,
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_MULTISIG_REPLAY,
|
||||
TX_NULL_DATA,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue