From 183e00bdfdc2287024c461bd1784855b8434b40b Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 6 Dec 2014 14:38:47 -0800 Subject: [PATCH] Use RPC calls to check bitcoin blocks are valid and confirmed --- src/Makefile.am | 10 ++++++---- src/Makefile.test.include | 2 +- src/callrpc.cpp | 39 +++++++++++++++++++++++++++++++++++-- src/callrpc.h | 7 ++++++- src/policy/policy.h | 3 ++- src/script/interpreter.cpp | 19 +++++++++++++++++- src/script/interpreter.h | 10 ++++++++++ src/script/script_error.cpp | 2 ++ src/script/script_error.h | 1 + 9 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 7e1af1c69d..2dcdcee950 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -250,6 +250,7 @@ libbitcoin_consensus_a_SOURCES = \ amount.h \ arith_uint256.cpp \ arith_uint256.h \ + callrpc.cpp \ consensus/merkle.cpp \ consensus/merkle.h \ consensus/params.h \ @@ -266,6 +267,7 @@ libbitcoin_consensus_a_SOURCES = \ primitives/transaction.h \ pubkey.cpp \ pubkey.h \ + rpc/protocol.cpp \ script/bitcoinconsensus.cpp \ script/interpreter.cpp \ script/interpreter.h \ @@ -307,7 +309,7 @@ libbitcoin_common_a_SOURCES = \ # util: shared between all executables. # This library *must* be included to make sure that the glibc # backward-compatibility objects and their sanity checks are linked. -libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/pagelocker.cpp \ @@ -369,7 +371,7 @@ bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPN # bitcoin-cli binary # bitcoin_cli_SOURCES = bitcoin-cli.cpp -bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) +bitcoin_cli_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) bitcoin_cli_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) @@ -404,7 +406,7 @@ bitcoin_tx_LDADD = \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) -bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) +bitcoin_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS) # # bitcoinconsensus library # @@ -418,7 +420,7 @@ endif libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 1:0:0 $(RELDFLAGS) libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1) -libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL +libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL -DBITCOIN_SCRIPT_NO_CALLRPC libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) endif diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 27e7694748..697ea0a511 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -110,7 +110,7 @@ if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif -test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) +test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_LIBS) test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static if ENABLE_ZMQ diff --git a/src/callrpc.cpp b/src/callrpc.cpp index ebf7ddfe74..15f1693031 100644 --- a/src/callrpc.cpp +++ b/src/callrpc.cpp @@ -43,10 +43,11 @@ static void http_request_done(struct evhttp_request *req, void *ctx) } } -UniValue CallRPC(const string& strMethod, const UniValue& params) +UniValue CallRPC(const string& strMethod, const UniValue& params, int port) { std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); - int port = GetArg("-rpcport", BaseParams().RPCPort()); + if (port < 0) + port = GetArg("-rpcport", BaseParams().RPCPort()); // Create event base struct event_base *base = event_base_new(); // TODO RAII @@ -120,3 +121,37 @@ UniValue CallRPC(const string& strMethod, const UniValue& params) return reply; } + +bool IsConfirmedBitcoinBlock(const uint256& genesishash, const uint256& hash, int nMinConfirmationDepth) +{ + try { + UniValue params(UniValue::VARR); + params.push_back(UniValue(0)); + UniValue reply = CallRPC("getblockhash", params, GetArg("-rpcconnectport", 18332)); + if (!find_value(reply, "error").isNull()) + return false; + UniValue result = find_value(reply, "result"); + if (!result.isStr()) + return false; + if (result.get_str() != genesishash.GetHex()) + return false; + + params = UniValue(UniValue::VARR); + params.push_back(hash.GetHex()); + reply = CallRPC("getblock", params, GetArg("-rpcconnectport", 18332)); + if (!find_value(reply, "error").isNull()) + return false; + result = find_value(reply, "result"); + if (!result.isObject()) + return false; + result = find_value(result.get_obj(), "confirmations"); + return result.isNum() && result.get_int64() >= nMinConfirmationDepth; + } catch (CConnectionFailed& e) { + LogPrintf("ERROR: Lost connection to bitcoind RPC, you will want to restart after fixing this!\n"); + return false; + } catch (...) { + LogPrintf("ERROR: Failure connecting to bitcoind RPC, you will want to restart after fixing this!\n"); + return false; + } + return true; +} diff --git a/src/callrpc.h b/src/callrpc.h index 79a91274ef..2efb74748b 100644 --- a/src/callrpc.h +++ b/src/callrpc.h @@ -6,6 +6,10 @@ #ifndef BITCOIN_CALLRPC_H #define BITCOIN_CALLRPC_H +#include "rpc/client.h" +#include "rpc/protocol.h" +#include "uint256.h" + #include #include @@ -28,6 +32,7 @@ public: }; -UniValue CallRPC(const std::string& strMethod, const UniValue& params); +UniValue CallRPC(const std::string& strMethod, const UniValue& params, int port=-1); +bool IsConfirmedBitcoinBlock(const uint256& genesishash, const uint256& hash, int nMinConfirmationDepth); #endif // BITCOIN_CALLRPC_H diff --git a/src/policy/policy.h b/src/policy/policy.h index 814e6c0b6f..1f5edb4fe2 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -55,7 +55,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM | - SCRIPT_VERIFY_WITNESS_PUBKEYTYPE; + SCRIPT_VERIFY_WITNESS_PUBKEYTYPE | + SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED; /** 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; diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 88afb99d52..b5fbe1e1ac 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -20,6 +20,11 @@ #include "streams.h" #include "uint256.h" #include "utilstrencodings.h" +#include "util.h" + +#ifndef BITCOIN_SCRIPT_NO_CALLRPC +#include "callrpc.h" +#endif using namespace std; @@ -1211,7 +1216,10 @@ bool EvalScript(vector >& stack, const CScript& script, un if (withdrawOutput.scriptPubKey != expectedWithdrawScriptPubKey) return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT); - //TODO: Check that we're spending from a valid, buried bitcoin block +#ifndef BITCOIN_SCRIPT_NO_CALLRPC + if (!GetBoolArg("-blindtrust", true) && !checker.IsConfirmedBitcoinBlock(genesishash, merkleBlock.header.GetHash(), flags & SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED)) + return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED); +#endif } catch (std::exception& e) { // Probably invalid encoding of something which was deserialized return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_FORMAT); @@ -1582,6 +1590,15 @@ CAmount TransactionSignatureChecker::GetValueInPrevIn() const return amountPreviousInput; } +bool TransactionSignatureChecker::IsConfirmedBitcoinBlock(const uint256& genesishash, const uint256& hash, bool fConservativeConfirmationRequirements) const +{ +#ifndef BITCOIN_SCRIPT_NO_CALLRPC + return ::IsConfirmedBitcoinBlock(genesishash, hash, fConservativeConfirmationRequirements ? 10 : 8); +#else + return true; +#endif +} + static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { vector > stack; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 8f6d4cb51b..ebca53dae7 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -111,6 +111,10 @@ enum // Execute sidechain-related opcodes instead of treating them as NOPs // SCRIPT_VERIFY_WITHDRAW = (1U << 16), + + // Dirty hack to require a higher bar of bitcoin block confirmation in mempool + // + SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED = (1U << 17) }; bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); @@ -161,6 +165,11 @@ public: return -1; } + virtual bool IsConfirmedBitcoinBlock(const uint256& genesishash, const uint256& hash, bool fConservativeConfirmationRequirements) const + { + return false; + } + virtual ~BaseSignatureChecker() {} }; @@ -203,6 +212,7 @@ public: COutPoint GetPrevOut() const; CAmount GetValueIn() const; CAmount GetValueInPrevIn() const; + bool IsConfirmedBitcoinBlock(const uint256& genesishash, const uint256& hash, bool fConservativeConfirmationRequirements) const; }; bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 47bc0192ec..f29f5ad084 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -95,6 +95,8 @@ const char* ScriptErrorString(const ScriptError serror) return "Withdraw proof validation failed - locking transaction misformatted"; case SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT: return "Withdraw proof validation failed - output does not match expected"; + case SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED: + return "Withdraw proof validation failed - lock block was not sufficiently confirmed on sending chain"; case SCRIPT_ERR_UNKNOWN_ERROR: case SCRIPT_ERR_ERROR_COUNT: default: break; diff --git a/src/script/script_error.h b/src/script/script_error.h index 51e6e335c5..2e10e32bac 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -69,6 +69,7 @@ typedef enum ScriptError_t SCRIPT_ERR_WITHDRAW_VERIFY_BLOCK, SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTX, SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT, + SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED, SCRIPT_ERR_ERROR_COUNT } ScriptError;