Merge pull request #98 from z-classic/revert-zencash-exploit

Revert ZenCash Exploit
This commit is contained in:
Joshua Yabut 2017-07-10 00:24:25 -04:00 committed by GitHub
commit 20d4581134
6 changed files with 14 additions and 57 deletions

View File

@ -449,8 +449,8 @@ zcash_cli_LDADD = \
# #
# zcash-tx binary # # zcash-tx binary #
zcash_tx_SOURCES = bitcoin-tx.cpp script/standard.cpp zcash_tx_SOURCES = bitcoin-tx.cpp
zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES) -DZCASH_TX zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
zcash_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) zcash_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS if TARGET_WINDOWS

View File

@ -5,7 +5,6 @@ noinst_PROGRAMS += zcash-gtest
# test_checktransaction.cpp MUST be before # test_checktransaction.cpp MUST be before
# any test that calls SelectParams(). # any test that calls SelectParams().
zcash_gtest_SOURCES = \ zcash_gtest_SOURCES = \
script/standard.cpp \
gtest/main.cpp \ gtest/main.cpp \
gtest/utils.cpp \ gtest/utils.cpp \
gtest/test_checktransaction.cpp \ gtest/test_checktransaction.cpp \
@ -42,7 +41,7 @@ zcash_gtest_SOURCES += \
wallet/gtest/test_wallet.cpp wallet/gtest/test_wallet.cpp
endif endif
zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES) -DZCASH_TX zcash_gtest_CPPFLAGS = -DMULTICORE -fopenmp -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DSTATIC $(BITCOIN_INCLUDES)
zcash_gtest_LDADD = -lgtest -lgmock $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ 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) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1)

View File

@ -40,7 +40,6 @@ RAW_TEST_FILES = test/data/alertTests.raw
GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h) GENERATED_TEST_FILES = $(JSON_TEST_FILES:.json=.json.h) $(RAW_TEST_FILES:.raw=.raw.h)
BITCOIN_TESTS =\ BITCOIN_TESTS =\
script/standard.cpp \
test/arith_uint256_tests.cpp \ test/arith_uint256_tests.cpp \
test/bignum.h \ test/bignum.h \
test/addrman_tests.cpp \ test/addrman_tests.cpp \
@ -100,7 +99,7 @@ BITCOIN_TESTS += \
endif endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) 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) -DZCASH_TX test_test_bitcoin_CPPFLAGS = -fopenmp $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \ 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) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
if ENABLE_WALLET if ENABLE_WALLET

View File

@ -380,8 +380,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
} }
case OP_NOP5: case OP_NOP5:
{ {
// 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() == 2) {
if (stack.size() == 3) {
popstack(stack); popstack(stack);
popstack(stack); popstack(stack);
} }

View File

@ -5,7 +5,6 @@
#include "script/standard.h" #include "script/standard.h"
#include "main.h"
#include "pubkey.h" #include "pubkey.h"
#include "script/script.h" #include "script/script.h"
#include "util.h" #include "util.h"
@ -27,9 +26,12 @@ const char* GetTxnOutputType(txnouttype t)
{ {
case TX_NONSTANDARD: return "nonstandard"; case TX_NONSTANDARD: return "nonstandard";
case TX_PUBKEY: return "pubkey"; case TX_PUBKEY: return "pubkey";
case TX_PUBKEY_REPLAY: return "pubkeyreplay";
case TX_PUBKEYHASH: return "pubkeyhash"; case TX_PUBKEYHASH: return "pubkeyhash";
case TX_PUBKEYHASH_REPLAY: return "pubkeyhashreplay";
case TX_SCRIPTHASH: return "scripthash"; case TX_SCRIPTHASH: return "scripthash";
case TX_MULTISIG: return "multisig"; case TX_MULTISIG: return "multisig";
case TX_MULTISIG_REPLAY: return "multisigreplay";
case TX_NULL_DATA: return "nulldata"; case TX_NULL_DATA: return "nulldata";
} }
return NULL; return NULL;
@ -46,15 +48,15 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
{ {
// Standard tx, sender provides pubkey, receiver adds signature // 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, CScript() << OP_PUBKEY << OP_CHECKSIG));
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5)); mTemplates.insert(make_pair(TX_PUBKEY_REPLAY, CScript() << OP_PUBKEY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey // 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, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5)); mTemplates.insert(make_pair(TX_PUBKEYHASH_REPLAY, 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 // 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, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5)); mTemplates.insert(make_pair(TX_MULTISIG_REPLAY, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
// Empty, provably prunable, data-carrying output // Empty, provably prunable, data-carrying output
if (GetBoolArg("-datacarrier", true)) if (GetBoolArg("-datacarrier", true))
@ -72,9 +74,6 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
return true; return true;
} }
// OP_CHECKBLOCKATHEIGHT parameters
vector<unsigned char> vchBlockHash, vchBlockHeight;
// Scan templates // Scan templates
const CScript& script1 = scriptPubKey; const CScript& script1 = scriptPubKey;
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates) BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
@ -149,52 +148,10 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
} }
else if (opcode2 == OP_SMALLDATA) else if (opcode2 == OP_SMALLDATA)
{ {
// Possible values of OP_CHECKBLOCKATHEIGHT parameters
if (vch1.size() <= sizeof(int))
vchBlockHeight = vch1;
else
vchBlockHash = vch1;
// small pushdata, <= nMaxDatacarrierBytes // small pushdata, <= nMaxDatacarrierBytes
if (vch1.size() > nMaxDatacarrierBytes) if (vch1.size() > nMaxDatacarrierBytes)
break; 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) else if (opcode1 != opcode2 || vch1 != vch2)
{ {
// Others must match exactly // Others must match exactly

View File

@ -62,9 +62,12 @@ enum txnouttype
TX_NONSTANDARD, TX_NONSTANDARD,
// 'standard' transaction types: // 'standard' transaction types:
TX_PUBKEY, TX_PUBKEY,
TX_PUBKEY_REPLAY,
TX_PUBKEYHASH, TX_PUBKEYHASH,
TX_PUBKEYHASH_REPLAY,
TX_SCRIPTHASH, TX_SCRIPTHASH,
TX_MULTISIG, TX_MULTISIG,
TX_MULTISIG_REPLAY,
TX_NULL_DATA, TX_NULL_DATA,
}; };