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 binary #
|
||||||
zcash_tx_SOURCES = bitcoin-tx.cpp
|
zcash_tx_SOURCES = bitcoin-tx.cpp script/standard.cpp
|
||||||
zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
|
zcash_tx_CPPFLAGS = $(BITCOIN_INCLUDES) -DZCASH_TX
|
||||||
zcash_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
zcash_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
|
||||||
|
|
||||||
if TARGET_WINDOWS
|
if TARGET_WINDOWS
|
||||||
|
|
|
@ -5,6 +5,7 @@ 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 \
|
||||||
|
@ -41,7 +42,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)
|
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) \
|
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)
|
||||||
|
|
|
@ -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)
|
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 \
|
||||||
|
@ -99,7 +100,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)
|
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) \
|
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
|
||||||
|
|
|
@ -380,7 +380,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
|
||||||
}
|
}
|
||||||
case OP_NOP5:
|
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);
|
||||||
popstack(stack);
|
popstack(stack);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#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"
|
||||||
|
@ -26,12 +27,9 @@ 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;
|
||||||
|
@ -48,15 +46,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_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
|
// 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_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
|
// 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_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
|
// Empty, provably prunable, data-carrying output
|
||||||
if (GetBoolArg("-datacarrier", true))
|
if (GetBoolArg("-datacarrier", true))
|
||||||
|
@ -74,6 +72,9 @@ 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)
|
||||||
|
@ -148,10 +149,52 @@ 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
|
||||||
|
|
|
@ -62,12 +62,9 @@ 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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue