mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-15 12:51:00 +02:00
Use RPC calls to check bitcoin blocks are valid and confirmed
This commit is contained in:
parent
7c9a06de5a
commit
c94ee2b4e0
12 changed files with 122 additions and 13 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
33
src/support/events.cpp
Normal 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;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue