1 // Copyright (c) 2018 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 <primitives/block.h>
10 #include <sync.h>
11 #include <txmempool.h>
12 #include <uint256.h>
13 #include <util/system.h>
14 #include <validation.h>
15
16 #include <memory>
17 #include <utility>
18
19 namespace interfaces {
20 namespace {
21
22 class LockImpl : public Chain::Lock
23 {
getHeight()24 Optional<int> getHeight() override
25 {
26 int height = ::chainActive.Height();
27 if (height >= 0) {
28 return height;
29 }
30 return nullopt;
31 }
getBlockHeight(const uint256 & hash)32 Optional<int> getBlockHeight(const uint256& hash) override
33 {
34 CBlockIndex* block = LookupBlockIndex(hash);
35 if (block && ::chainActive.Contains(block)) {
36 return block->nHeight;
37 }
38 return nullopt;
39 }
getBlockDepth(const uint256 & hash)40 int getBlockDepth(const uint256& hash) override
41 {
42 const Optional<int> tip_height = getHeight();
43 const Optional<int> height = getBlockHeight(hash);
44 return tip_height && height ? *tip_height - *height + 1 : 0;
45 }
getBlockHash(int height)46 uint256 getBlockHash(int height) override
47 {
48 CBlockIndex* block = ::chainActive[height];
49 assert(block != nullptr);
50 return block->GetBlockHash();
51 }
getBlockTime(int height)52 int64_t getBlockTime(int height) override
53 {
54 CBlockIndex* block = ::chainActive[height];
55 assert(block != nullptr);
56 return block->GetBlockTime();
57 }
getBlockMedianTimePast(int height)58 int64_t getBlockMedianTimePast(int height) override
59 {
60 CBlockIndex* block = ::chainActive[height];
61 assert(block != nullptr);
62 return block->GetMedianTimePast();
63 }
haveBlockOnDisk(int height)64 bool haveBlockOnDisk(int height) override
65 {
66 CBlockIndex* block = ::chainActive[height];
67 return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
68 }
findFirstBlockWithTime(int64_t time,uint256 * hash)69 Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
70 {
71 CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
72 if (block) {
73 if (hash) *hash = block->GetBlockHash();
74 return block->nHeight;
75 }
76 return nullopt;
77 }
findFirstBlockWithTimeAndHeight(int64_t time,int height)78 Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height) override
79 {
80 // TODO: Could update CChain::FindEarliestAtLeast() to take a height
81 // parameter and use it with std::lower_bound() to make this
82 // implementation more efficient and allow combining
83 // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one
84 // method.
85 for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) {
86 if (block->GetBlockTime() >= time) {
87 return block->nHeight;
88 }
89 }
90 return nullopt;
91 }
findPruned(int start_height,Optional<int> stop_height)92 Optional<int> findPruned(int start_height, Optional<int> stop_height) override
93 {
94 if (::fPruneMode) {
95 CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip();
96 while (block && block->nHeight >= start_height) {
97 if ((block->nStatus & BLOCK_HAVE_DATA) == 0) {
98 return block->nHeight;
99 }
100 block = block->pprev;
101 }
102 }
103 return nullopt;
104 }
findFork(const uint256 & hash,Optional<int> * height)105 Optional<int> findFork(const uint256& hash, Optional<int>* height) override
106 {
107 const CBlockIndex* block = LookupBlockIndex(hash);
108 const CBlockIndex* fork = block ? ::chainActive.FindFork(block) : nullptr;
109 if (height) {
110 if (block) {
111 *height = block->nHeight;
112 } else {
113 height->reset();
114 }
115 }
116 if (fork) {
117 return fork->nHeight;
118 }
119 return nullopt;
120 }
isPotentialTip(const uint256 & hash)121 bool isPotentialTip(const uint256& hash) override
122 {
123 if (::chainActive.Tip()->GetBlockHash() == hash) return true;
124 CBlockIndex* block = LookupBlockIndex(hash);
125 return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
126 }
getTipLocator()127 CBlockLocator getTipLocator() override { return ::chainActive.GetLocator(); }
findLocatorFork(const CBlockLocator & locator)128 Optional<int> findLocatorFork(const CBlockLocator& locator) override
129 {
130 LockAnnotation lock(::cs_main);
131 if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
132 return fork->nHeight;
133 }
134 return nullopt;
135 }
136 };
137
138 class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
139 {
140 using UniqueLock::UniqueLock;
141 };
142
143 class ChainImpl : public Chain
144 {
145 public:
lock(bool try_lock)146 std::unique_ptr<Chain::Lock> lock(bool try_lock) override
147 {
148 auto result = MakeUnique<LockingStateImpl>(::cs_main, "cs_main", __FILE__, __LINE__, try_lock);
149 if (try_lock && result && !*result) return {};
150 // std::move necessary on some compilers due to conversion from
151 // LockingStateImpl to Lock pointer
152 return std::move(result);
153 }
assumeLocked()154 std::unique_ptr<Chain::Lock> assumeLocked() override { return MakeUnique<LockImpl>(); }
findBlock(const uint256 & hash,CBlock * block,int64_t * time,int64_t * time_max)155 bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override
156 {
157 CBlockIndex* index;
158 {
159 LOCK(cs_main);
160 index = LookupBlockIndex(hash);
161 if (!index) {
162 return false;
163 }
164 if (time) {
165 *time = index->GetBlockTime();
166 }
167 if (time_max) {
168 *time_max = index->GetBlockTimeMax();
169 }
170 }
171 if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) {
172 block->SetNull();
173 }
174 return true;
175 }
guessVerificationProgress(const uint256 & block_hash)176 double guessVerificationProgress(const uint256& block_hash) override
177 {
178 LOCK(cs_main);
179 return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash));
180 }
requestMempoolTransactions(std::function<void (const CTransactionRef &)> fn)181 void requestMempoolTransactions(std::function<void(const CTransactionRef&)> fn) override
182 {
183 LOCK2(::cs_main, ::mempool.cs);
184 for (const CTxMemPoolEntry& entry : ::mempool.mapTx) {
185 fn(entry.GetSharedTx());
186 }
187 }
188 };
189
190 } // namespace
191
MakeChain()192 std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
193
194 } // namespace interfaces
195