From eca4077baa3fa60082f9a78becf583edbed3328c 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/callrpc.cpp | 29 +++++++++++++++++++++++++++-- src/callrpc.h | 4 +++- src/script/interpreter.cpp | 14 +++++++++++++- src/script/interpreter.h | 14 ++++++++++++++ src/script/script_error.cpp | 2 ++ src/script/script_error.h | 1 + src/script/standard.h | 3 ++- 7 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/callrpc.cpp b/src/callrpc.cpp index ba11f57fee..f3d5f44f2d 100644 --- a/src/callrpc.cpp +++ b/src/callrpc.cpp @@ -10,7 +10,7 @@ using namespace json_spirit; #define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */ -Object CallRPC(const string& strMethod, const Array& params) +Object CallRPC(const string& strMethod, const Array& params, string port) { if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "") throw runtime_error(strprintf( @@ -27,7 +27,9 @@ Object CallRPC(const string& strMethod, const Array& params) SSLIOStreamDevice d(sslStream, fUseSSL); iostreams::stream< SSLIOStreamDevice > stream(d); - const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort()))); + if (port == "") + port = GetArg("-rpcport", itostr(BaseParams().RPCPort())); + const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), port); if (!fConnected) throw CConnectionFailed("couldn't connect to server"); @@ -67,3 +69,26 @@ Object CallRPC(const string& strMethod, const Array& params) return reply; } + +bool IsConfirmedBitcoinBlock(const uint256& hash, int nMinConfirmationDepth) +{ + try { + Array params; + params.push_back(hash.GetHex()); + Object reply = CallRPC("getblock", params, GetArg("-rpcconnectport", "18332")); + if (find_value(reply, "error").type() != null_type) + return false; + Value result = find_value(reply, "result"); + if (result.type() != obj_type) + return false; + result = find_value(result.get_obj(), "confirmations"); + return result.type() == int_type && 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 b962d58345..d7565c37c2 100644 --- a/src/callrpc.h +++ b/src/callrpc.h @@ -8,6 +8,7 @@ #include "rpcclient.h" #include "rpcprotocol.h" +#include "uint256.h" #include @@ -25,6 +26,7 @@ public: }; -json_spirit::Object CallRPC(const std::string& strMethod, const json_spirit::Array& params); +json_spirit::Object CallRPC(const std::string& strMethod, const json_spirit::Array& params, std::string port=""); +bool IsConfirmedBitcoinBlock(const uint256& hash, int nMinConfirmationDepth); #endif // BITCOIN_CALLRPC_H diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 27efd63dbf..cb6f6b6caa 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -8,6 +8,9 @@ #include #define FEDERATED_PEG_SIDECHAIN_ONLY +#ifdef FEDERATED_PEG_SIDECHAIN_ONLY +#include "callrpc.h" +#endif #include "primitives/transaction.h" #include "crypto/ripemd160.h" @@ -23,6 +26,7 @@ #include "streams.h" #include "uint256.h" #include "utilstrencodings.h" +#include "util.h" using namespace std; @@ -1285,7 +1289,8 @@ bool EvalScript(vector >& stack, const CScript& script, un return set_error(serror, SCRIPT_ERR_WITHDRAW_VERIFY_SECONDSCRIPT); #ifdef FEDERATED_PEG_SIDECHAIN_ONLY - //TODO: Check that we're spending from a valid, buried bitcoin block + if (!GetBoolArg("-blindtrust", true) && !checker.IsConfirmedBitcoinBlock(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 @@ -1712,6 +1717,13 @@ CAmount TransactionSignatureChecker::GetValueInPrevIn() const return nInMinusOneValue; } +#ifdef FEDERATED_PEG_SIDECHAIN_ONLY +bool TransactionSignatureChecker::IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements) const +{ + return ::IsConfirmedBitcoinBlock(hash, fConservativeConfirmationRequirements ? 10 : 8); +} +#endif + bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index bcb6ab53c5..8bbda18285 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -82,6 +82,9 @@ enum // Execute sidechain-related opcodes instead of treating them as NOPs SCRIPT_VERIFY_WITHDRAW = (1U << 11), + + // Dirty hack to require a higher bar of bitcoin block confirmation in mempool + SCRIPT_VERIFY_INCREASE_CONFIRMATIONS_REQUIRED = (1U << 12) }; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); @@ -117,6 +120,14 @@ public: return -1; } +#define FEDERATED_PEG_SIDECHAIN_ONLY +#ifdef FEDERATED_PEG_SIDECHAIN_ONLY + virtual bool IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements) const + { + return false; + } +#endif + virtual ~BaseSignatureChecker() {} }; @@ -157,6 +168,9 @@ public: CAmount GetValueIn() const; CAmount GetValueInPrevIn() const; CAmount GetTransactionFee() const; +#ifdef FEDERATED_PEG_SIDECHAIN_ONLY + bool IsConfirmedBitcoinBlock(const uint256& hash, bool fConservativeConfirmationRequirements) const; +#endif }; bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 08760a89a9..3505500279 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -79,6 +79,8 @@ const char* ScriptErrorString(const ScriptError serror) return "Withdraw proof validation failed - locktime was not set correctly"; case SCRIPT_ERR_WITHDRAW_VERIFY_SECONDSCRIPT: return "Withdraw proof validation failed - second script validation failed"; + case SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED: + return "Withdraw proof validation failed - lock block was not sufficiently confirmed on sending chain"; case SCRIPT_ERR_REORG_VERIFY_FORMAT: return "Reorg/Fraud proof validation failed - invalid proof format"; case SCRIPT_ERR_REORG_VERIFY_FRAUD_BLOCK: diff --git a/src/script/script_error.h b/src/script/script_error.h index a982c90891..58fda930ab 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -58,6 +58,7 @@ typedef enum ScriptError_t SCRIPT_ERR_WITHDRAW_VERIFY_OUTPUT, SCRIPT_ERR_WITHDRAW_VERIFY_LOCKTIME, SCRIPT_ERR_WITHDRAW_VERIFY_SECONDSCRIPT, + SCRIPT_ERR_WITHDRAW_VERIFY_BLOCKCONFIRMED, SCRIPT_ERR_REORG_VERIFY_FORMAT, SCRIPT_ERR_REORG_VERIFY_FRAUD_BLOCK, SCRIPT_ERR_REORG_VERIFY_FRAUD_ORIG_BLOCK, diff --git a/src/script/standard.h b/src/script/standard.h index 3d2c47f114..65eb5be83b 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -51,7 +51,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY SCRIPT_VERIFY_NULLDUMMY | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS | SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | - SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; + SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | + 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;