1 // Copyright (c) 2018-2020 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <interfaces/chain.h>
6
7 #include <chain.h>
8 #include <chainparams.h>
9 #include <interfaces/handler.h>
10 #include <interfaces/wallet.h>
11 #include <net.h>
12 #include <net_processing.h>
13 #include <node/coin.h>
14 #include <node/context.h>
15 #include <node/transaction.h>
16 #include <policy/fees.h>
17 #include <policy/policy.h>
18 #include <policy/rbf.h>
19 #include <policy/settings.h>
20 #include <primitives/block.h>
21 #include <primitives/transaction.h>
22 #include <rpc/protocol.h>
23 #include <rpc/server.h>
24 #include <shutdown.h>
25 #include <sync.h>
26 #include <timedata.h>
27 #include <txmempool.h>
28 #include <ui_interface.h>
29 #include <uint256.h>
30 #include <univalue.h>
31 #include <util/system.h>
32 #include <validation.h>
33 #include <validationinterface.h>
34
35 #include <memory>
36 #include <utility>
37
38 namespace interfaces {
39 namespace {
40
41 class LockImpl : public Chain::Lock, public UniqueLock<RecursiveMutex>
42 {
getHeight()43 Optional<int> getHeight() override
44 {
45 LockAssertion lock(::cs_main);
46 int height = ::ChainActive().Height();
47 if (height >= 0) {
48 return height;
49 }
50 return nullopt;
51 }
getBlockHeight(const uint256 & hash)52 Optional<int> getBlockHeight(const uint256& hash) override
53 {
54 LockAssertion lock(::cs_main);
55 CBlockIndex* block = LookupBlockIndex(hash);
56 if (block && ::ChainActive().Contains(block)) {
57 return block->nHeight;
58 }
59 return nullopt;
60 }
getBlockHash(int height)61 uint256 getBlockHash(int height) override
62 {
63 LockAssertion lock(::cs_main);
64 CBlockIndex* block = ::ChainActive()[height];
65 assert(block != nullptr);
66 return block->GetBlockHash();
67 }
getBlockTime(int height)68 int64_t getBlockTime(int height) override
69 {
70 LockAssertion lock(::cs_main);
71 CBlockIndex* block = ::ChainActive()[height];
72 assert(block != nullptr);
73 return block->GetBlockTime();
74 }
getBlockMedianTimePast(int height)75 int64_t getBlockMedianTimePast(int height) override
76 {
77 LockAssertion lock(::cs_main);
78 CBlockIndex* block = ::ChainActive()[height];
79 assert(block != nullptr);
80 return block->GetMedianTimePast();
81 }
haveBlockOnDisk(int height)82 bool haveBlockOnDisk(int height) override
83 {
84 LockAssertion lock(::cs_main);
85 CBlockIndex* block = ::ChainActive()[height];
86 return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
87 }
findFirstBlockWithTimeAndHeight(int64_t time,int height,uint256 * hash)88 Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override
89 {
90 LockAssertion lock(::cs_main);
91 CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height);
92 if (block) {
93 if (hash) *hash = block->GetBlockHash();
94 return block->nHeight;
95 }
96 return nullopt;
97 }
findPruned(int start_height,Optional<int> stop_height)98 Optional<int> findPruned(int start_height, Optional<int> stop_height) override
99 {
100 LockAssertion lock(::cs_main);
101 if (::fPruneMode) {
102 CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip();
103 while (block && block->nHeight >= start_height) {
104 if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
105 return block->nHeight;
106 }
107 block = block->pprev;
108 }
109 }
110 return nullopt;
111 }
findFork(const uint256 & hash,Optional<int> * height)112 Optional<int> findFork(const uint256& hash, Optional<int>* height) override
113 {
114 LockAssertion lock(::cs_main);
115 const CBlockIndex* block = LookupBlockIndex(hash);
116 const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr;
117 if (height) {
118 if (block) {
119 *height = block->nHeight;
120 } else {
121 height->reset();
122 }
123 }
124 if (fork) {
125 return fork->nHeight;
126 }
127 return nullopt;
128 }
getTipLocator()129 CBlockLocator getTipLocator() override
130 {
131 LockAssertion lock(::cs_main);
132 return ::ChainActive().GetLocator();
133 }
findLocatorFork(const CBlockLocator & locator)134 Optional<int> findLocatorFork(const CBlockLocator& locator) override
135 {
136 LockAssertion lock(::cs_main);
137 if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) {
138 return fork->nHeight;
139 }
140 return nullopt;
141 }
checkFinalTx(const CTransaction & tx)142 bool checkFinalTx(const CTransaction& tx) override
143 {
144 LockAssertion lock(::cs_main);
145 return CheckFinalTx(tx);
146 }
getImmatureStakes()147 std::map<COutPoint, uint32_t> getImmatureStakes() override
148 {
149 LockAssertion lock(::cs_main);
150 return GetImmatureStakes();
151 }
152
153 using UniqueLock::UniqueLock;
154 };
155
156 class NotificationsProxy : public CValidationInterface
157 {
158 public:
NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)159 explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications)
160 : m_notifications(std::move(notifications)) {}
161 virtual ~NotificationsProxy() = default;
TransactionAddedToMempool(const CTransactionRef & tx)162 void TransactionAddedToMempool(const CTransactionRef& tx) override
163 {
164 m_notifications->transactionAddedToMempool(tx);
165 }
TransactionRemovedFromMempool(const CTransactionRef & tx,MemPoolRemovalReason reason)166 void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason) override
167 {
168 m_notifications->transactionRemovedFromMempool(tx, reason);
169 }
BlockConnected(const std::shared_ptr<const CBlock> & block,const CBlockIndex * index)170 void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
171 {
172 m_notifications->blockConnected(*block, index->nHeight);
173 }
BlockDisconnected(const std::shared_ptr<const CBlock> & block,const CBlockIndex * index)174 void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
175 {
176 m_notifications->blockDisconnected(*block, index->nHeight);
177 }
UpdatedBlockTip(const CBlockIndex * index,const CBlockIndex * fork_index,bool is_ibd)178 void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
179 {
180 m_notifications->updatedBlockTip();
181 }
ChainStateFlushed(const CBlockLocator & locator)182 void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); }
183 std::shared_ptr<Chain::Notifications> m_notifications;
184 };
185
186 class NotificationsHandlerImpl : public Handler
187 {
188 public:
NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)189 explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications)
190 : m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications)))
191 {
192 RegisterSharedValidationInterface(m_proxy);
193 }
~NotificationsHandlerImpl()194 ~NotificationsHandlerImpl() override { disconnect(); }
disconnect()195 void disconnect() override
196 {
197 if (m_proxy) {
198 UnregisterSharedValidationInterface(m_proxy);
199 m_proxy.reset();
200 }
201 }
202 std::shared_ptr<NotificationsProxy> m_proxy;
203 };
204
205 class RpcHandlerImpl : public Handler
206 {
207 public:
RpcHandlerImpl(const CRPCCommand & command)208 explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
209 {
210 m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
211 if (!m_wrapped_command) return false;
212 try {
213 return m_wrapped_command->actor(request, result, last_handler);
214 } catch (const UniValue& e) {
215 // If this is not the last handler and a wallet not found
216 // exception was thrown, return false so the next handler can
217 // try to handle the request. Otherwise, reraise the exception.
218 if (!last_handler) {
219 const UniValue& code = e["code"];
220 if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) {
221 return false;
222 }
223 }
224 throw;
225 }
226 };
227 ::tableRPC.appendCommand(m_command.name, &m_command);
228 }
229
disconnect()230 void disconnect() override final
231 {
232 if (m_wrapped_command) {
233 m_wrapped_command = nullptr;
234 ::tableRPC.removeCommand(m_command.name, &m_command);
235 }
236 }
237
~RpcHandlerImpl()238 ~RpcHandlerImpl() override { disconnect(); }
239
240 CRPCCommand m_command;
241 const CRPCCommand* m_wrapped_command;
242 };
243
244 class ChainImpl : public Chain
245 {
246 public:
ChainImpl(NodeContext & node)247 explicit ChainImpl(NodeContext& node) : m_node(node) {}
lock(bool try_lock)248 std::unique_ptr<Chain::Lock> lock(bool try_lock) override
249 {
250 auto lock = MakeUnique<LockImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
251 if (try_lock && lock && !*lock) return {};
252 std::unique_ptr<Chain::Lock> result = std::move(lock); // Temporary to avoid CWG 1579
253 return result;
254 }
findBlock(const uint256 & hash,CBlock * block,int64_t * time,int64_t * time_max)255 bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
256 {
257 CBlockIndex* index;
258 {
259 LOCK(cs_main);
260 index = LookupBlockIndex(hash);
261 if (!index) {
262 return false;
263 }
264 if (time) {
265 *time = index->GetBlockTime();
266 }
267 if (time_max) {
268 *time_max = index->GetBlockTimeMax();
269 }
270 }
271 if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
272 block->SetNull();
273 }
274 return true;
275 }
findCoins(std::map<COutPoint,Coin> & coins)276 void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); }
guessVerificationProgress(const uint256 & block_hash)277 double guessVerificationProgress(const uint256& block_hash) override
278 {
279 LOCK(cs_main);
280 return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash));
281 }
isRBFOptIn(const CTransaction & tx)282 RBFTransactionState isRBFOptIn(const CTransaction& tx) override
283 {
284 LOCK(::mempool.cs);
285 return IsRBFOptIn(tx, ::mempool);
286 }
hasDescendantsInMempool(const uint256 & txid)287 bool hasDescendantsInMempool(const uint256& txid) override
288 {
289 LOCK(::mempool.cs);
290 auto it = ::mempool.GetIter(txid);
291 return it && (*it)->GetCountWithDescendants() > 1;
292 }
broadcastTransaction(const CTransactionRef & tx,const CAmount & max_tx_fee,bool relay,std::string & err_string)293 bool broadcastTransaction(const CTransactionRef& tx,
294 const CAmount& max_tx_fee,
295 bool relay,
296 std::string& err_string) override
297 {
298 const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
299 // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
300 // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
301 // that Chain clients do not need to know about.
302 return TransactionError::OK == err;
303 }
getTransactionAncestry(const uint256 & txid,size_t & ancestors,size_t & descendants)304 void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override
305 {
306 ::mempool.GetTransactionAncestry(txid, ancestors, descendants);
307 }
getPackageLimits(unsigned int & limit_ancestor_count,unsigned int & limit_descendant_count)308 void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override
309 {
310 limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
311 limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
312 }
checkChainLimits(const CTransactionRef & tx)313 bool checkChainLimits(const CTransactionRef& tx) override
314 {
315 LockPoints lp;
316 CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp);
317 CTxMemPool::setEntries ancestors;
318 auto limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
319 auto limit_ancestor_size = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000;
320 auto limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
321 auto limit_descendant_size = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000;
322 std::string unused_error_string;
323 LOCK(::mempool.cs);
324 return ::mempool.CalculateMemPoolAncestors(entry, ancestors, limit_ancestor_count, limit_ancestor_size,
325 limit_descendant_count, limit_descendant_size, unused_error_string);
326 }
estimateSmartFee(int num_blocks,bool conservative,FeeCalculation * calc)327 CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
328 {
329 return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative);
330 }
estimateMaxBlocks()331 unsigned int estimateMaxBlocks() override
332 {
333 return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
334 }
mempoolMinFee()335 CFeeRate mempoolMinFee() override
336 {
337 return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
338 }
relayMinFee()339 CFeeRate relayMinFee() override { return ::minRelayTxFee; }
relayIncrementalFee()340 CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
relayDustFee()341 CFeeRate relayDustFee() override { return ::dustRelayFee; }
havePruned()342 bool havePruned() override
343 {
344 LOCK(cs_main);
345 return ::fHavePruned;
346 }
isReadyToBroadcast()347 bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
isInitialBlockDownload()348 bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
shutdownRequested()349 bool shutdownRequested() override { return ShutdownRequested(); }
getAdjustedTime()350 int64_t getAdjustedTime() override { return GetAdjustedTime(); }
initMessage(const std::string & message)351 void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
initWarning(const std::string & message)352 void initWarning(const std::string& message) override { InitWarning(message); }
initError(const std::string & message)353 void initError(const std::string& message) override { InitError(message); }
showProgress(const std::string & title,int progress,bool resume_possible)354 void showProgress(const std::string& title, int progress, bool resume_possible) override
355 {
356 ::uiInterface.ShowProgress(title, progress, resume_possible);
357 }
handleNotifications(std::shared_ptr<Notifications> notifications)358 std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override
359 {
360 return MakeUnique<NotificationsHandlerImpl>(std::move(notifications));
361 }
waitForNotificationsIfTipChanged(const uint256 & old_tip)362 void waitForNotificationsIfTipChanged(const uint256& old_tip) override
363 {
364 if (!old_tip.IsNull()) {
365 LOCK(::cs_main);
366 if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return;
367 }
368 SyncWithValidationInterfaceQueue();
369 }
handleRpc(const CRPCCommand & command)370 std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
371 {
372 return MakeUnique<RpcHandlerImpl>(command);
373 }
rpcEnableDeprecated(const std::string & method)374 bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); }
rpcRunLater(const std::string & name,std::function<void ()> fn,int64_t seconds)375 void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override
376 {
377 RPCRunLater(name, std::move(fn), seconds);
378 }
rpcSerializationFlags()379 int rpcSerializationFlags() override { return RPCSerializationFlags(); }
requestMempoolTransactions(Notifications & notifications)380 void requestMempoolTransactions(Notifications& notifications) override
381 {
382 LOCK2(::cs_main, ::mempool.cs);
383 for (const CTxMemPoolEntry& entry : ::mempool.mapTx) {
384 notifications.transactionAddedToMempool(entry.GetSharedTx());
385 }
386 }
387 NodeContext& m_node;
388 };
389 } // namespace
390
MakeChain(NodeContext & node)391 std::unique_ptr<Chain> MakeChain(NodeContext& node) { return MakeUnique<ChainImpl>(node); }
392
393 } // namespace interfaces
394