Use RPC calls to check bitcoin blocks are valid and confirmed

This commit is contained in:
Matt Corallo 2014-12-06 14:38:47 -08:00 committed by Gregory Sanders
parent 7c9a06de5a
commit c94ee2b4e0
12 changed files with 122 additions and 13 deletions

View file

@ -267,6 +267,7 @@ libbitcoin_consensus_a_SOURCES = \
arith_uint256.h \
bloom.cpp \
bloom.h \
callrpc.cpp \
consensus/merkle.cpp \
consensus/merkle.h \
consensus/params.h \
@ -282,6 +283,7 @@ libbitcoin_consensus_a_SOURCES = \
primitives/transaction.h \
pubkey.cpp \
pubkey.h \
rpc/protocol.cpp \
script/bitcoinconsensus.cpp \
script/interpreter.cpp \
script/interpreter.h \
@ -289,6 +291,7 @@ libbitcoin_consensus_a_SOURCES = \
script/script.h \
script/script_error.cpp \
script/script_error.h \
support/events.cpp \
serialize.h \
tinyformat.h \
uint256.cpp \
@ -325,7 +328,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/lockedpool.cpp \
@ -389,7 +392,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)
@ -424,7 +427,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 #
@ -438,7 +441,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

View file

@ -154,7 +154,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

View file

@ -76,10 +76,11 @@ static void http_error_cb(enum evhttp_request_error err, void *ctx)
}
#endif
UniValue CallRPC(const std::string& strMethod, const UniValue& params)
UniValue CallRPC(const std::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());
// Obtain event base
raii_event_base base = obtain_event_base();
@ -149,3 +150,37 @@ UniValue CallRPC(const std::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;
}

View file

@ -6,10 +6,15 @@
#ifndef BITCOIN_CALLRPC_H
#define BITCOIN_CALLRPC_H
#include "rpc/client.h"
#include "rpc/protocol.h"
#include "uint256.h"
#include <string>
#include <stdexcept>
#include <univalue.h>
//#include <univalue.h>
#include "univalue/include/univalue.h"
static const bool DEFAULT_NAMED=false;
static const char DEFAULT_RPCCONNECT[] = "127.0.0.1";
@ -29,6 +34,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

View file

@ -65,7 +65,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;

View file

@ -6,7 +6,7 @@
#ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H
#include <univalue.h>
#include "univalue/include/univalue.h"
/** Convert positional arguments to command-specific RPC representation */
UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);

View file

@ -12,7 +12,8 @@
#include <string>
#include <boost/filesystem.hpp>
#include <univalue.h>
#include "univalue/include/univalue.h"
//#include <univalue.h>
//! HTTP status codes
enum HTTPStatusCode

View file

@ -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<vector<unsigned char> >& 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<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
vector<vector<unsigned char> > stack;

View file

@ -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<unsigned char> &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<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL);

View file

@ -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;

View file

@ -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;

33
src/support/events.cpp Normal file
View file

@ -0,0 +1,33 @@
// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "events.h"
raii_event_base obtain_event_base() {
auto result = raii_event_base(event_base_new());
if (!result.get())
throw std::runtime_error("cannot create event_base");
return result;
}
raii_event obtain_event(struct event_base* base, evutil_socket_t s, short events, event_callback_fn cb, void* arg) {
return raii_event(event_new(base, s, events, cb, arg));
}
raii_evhttp obtain_evhttp(struct event_base* base) {
return raii_evhttp(evhttp_new(base));
}
raii_evhttp_request obtain_evhttp_request(void(*cb)(struct evhttp_request *, void *), void *arg) {
return raii_evhttp_request(evhttp_request_new(cb, arg));
}
raii_evhttp_connection obtain_evhttp_connection_base(struct event_base* base, std::string host, uint16_t port) {
auto result = raii_evhttp_connection(evhttp_connection_base_new(base, NULL, host.c_str(), port));
if (!result.get())
throw std::runtime_error("create connection failed");
return result;
}