1 // Copyright (c) 2014-2017 Daniel Kraft
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 <names/common.h>
6
7 #include <script/names.h>
8
9 bool fNameHistory = false;
10
11 /* ************************************************************************** */
12 /* CNameData. */
13
14 void
fromScript(unsigned h,const COutPoint & out,const CNameScript & script)15 CNameData::fromScript (unsigned h, const COutPoint& out,
16 const CNameScript& script)
17 {
18 assert (script.isAnyUpdate ());
19 value = script.getOpValue ();
20 nHeight = h;
21 prevout = out;
22 addr = script.getAddress ();
23 }
24
25 /* ************************************************************************** */
26 /* CNameIterator. */
27
~CNameIterator()28 CNameIterator::~CNameIterator ()
29 {
30 /* Nothing to be done here. This may be overwritten by
31 subclasses if they need a destructor. */
32 }
33
34 /* ************************************************************************** */
35 /* CNameCacheNameIterator. */
36
37 class CCacheNameIterator : public CNameIterator
38 {
39
40 private:
41
42 /** Reference to cache object that is used. */
43 const CNameCache& cache;
44
45 /** Base iterator to combine with the cache. */
46 CNameIterator* base;
47
48 /** Whether or not the base iterator has more entries. */
49 bool baseHasMore;
50 /** "Next" name of the base iterator. */
51 valtype baseName;
52 /** "Next" data of the base iterator. */
53 CNameData baseData;
54
55 /** Iterator of the cache's entries. */
56 CNameCache::EntryMap::const_iterator cacheIter;
57
58 /* Call the base iterator's next() routine to fill in the internal
59 "cache" for the next entry. This already skips entries that are
60 marked as deleted in the cache. */
61 void advanceBaseIterator ();
62
63 public:
64
65 /**
66 * Construct the iterator. This takes ownership of the base iterator.
67 * @param c The cache object to use.
68 * @param b The base iterator.
69 */
70 CCacheNameIterator (const CNameCache& c, CNameIterator* b);
71
72 /* Destruct, this deletes also the base iterator. */
73 ~CCacheNameIterator ();
74
75 /* Implement iterator methods. */
76 void seek (const valtype& name);
77 bool next (valtype& name, CNameData& data);
78
79 };
80
CCacheNameIterator(const CNameCache & c,CNameIterator * b)81 CCacheNameIterator::CCacheNameIterator (const CNameCache& c, CNameIterator* b)
82 : cache(c), base(b)
83 {
84 /* Add a seek-to-start to ensure that everything is consistent. This call
85 may be superfluous if we seek to another position afterwards anyway,
86 but it should also not hurt too much. */
87 seek (valtype ());
88 }
89
~CCacheNameIterator()90 CCacheNameIterator::~CCacheNameIterator ()
91 {
92 delete base;
93 }
94
95 void
advanceBaseIterator()96 CCacheNameIterator::advanceBaseIterator ()
97 {
98 assert (baseHasMore);
99 do
100 baseHasMore = base->next (baseName, baseData);
101 while (baseHasMore && cache.isDeleted (baseName));
102 }
103
104 void
seek(const valtype & start)105 CCacheNameIterator::seek (const valtype& start)
106 {
107 cacheIter = cache.entries.lower_bound (start);
108 base->seek (start);
109
110 baseHasMore = true;
111 advanceBaseIterator ();
112 }
113
114 bool
next(valtype & name,CNameData & data)115 CCacheNameIterator::next (valtype& name, CNameData& data)
116 {
117 /* Exit early if no more data is available in either the cache
118 nor the base iterator. */
119 if (!baseHasMore && cacheIter == cache.entries.end ())
120 return false;
121
122 /* Determine which source to use for the next. */
123 bool useBase;
124 if (!baseHasMore)
125 useBase = false;
126 else if (cacheIter == cache.entries.end ())
127 useBase = true;
128 else
129 {
130 /* A special case is when both iterators are equal. In this case,
131 we want to use the cached version. We also have to advance
132 the base iterator. */
133 if (baseName == cacheIter->first)
134 advanceBaseIterator ();
135
136 /* Due to advancing the base iterator above, it may happen that
137 no more base entries are present. Handle this gracefully. */
138 if (!baseHasMore)
139 useBase = false;
140 else
141 {
142 assert (baseName != cacheIter->first);
143
144 CNameCache::NameComparator cmp;
145 useBase = cmp (baseName, cacheIter->first);
146 }
147 }
148
149 /* Use the correct source now and advance it. */
150 if (useBase)
151 {
152 name = baseName;
153 data = baseData;
154 advanceBaseIterator ();
155 }
156 else
157 {
158 name = cacheIter->first;
159 data = cacheIter->second;
160 ++cacheIter;
161 }
162
163 return true;
164 }
165
166 /* ************************************************************************** */
167 /* CNameCache. */
168
169 bool
get(const valtype & name,CNameData & data) const170 CNameCache::get (const valtype& name, CNameData& data) const
171 {
172 const EntryMap::const_iterator i = entries.find (name);
173 if (i == entries.end ())
174 return false;
175
176 data = i->second;
177 return true;
178 }
179
180 void
set(const valtype & name,const CNameData & data)181 CNameCache::set (const valtype& name, const CNameData& data)
182 {
183 const std::set<valtype>::iterator di = deleted.find (name);
184 if (di != deleted.end ())
185 deleted.erase (di);
186
187 const EntryMap::iterator ei = entries.find (name);
188 if (ei != entries.end ())
189 ei->second = data;
190 else
191 entries.insert (std::make_pair (name, data));
192 }
193
194 void
remove(const valtype & name)195 CNameCache::remove (const valtype& name)
196 {
197 const EntryMap::iterator ei = entries.find (name);
198 if (ei != entries.end ())
199 entries.erase (ei);
200
201 deleted.insert (name);
202 }
203
204 CNameIterator*
iterateNames(CNameIterator * base) const205 CNameCache::iterateNames (CNameIterator* base) const
206 {
207 return new CCacheNameIterator (*this, base);
208 }
209
210 bool
getHistory(const valtype & name,CNameHistory & res) const211 CNameCache::getHistory (const valtype& name, CNameHistory& res) const
212 {
213 assert (fNameHistory);
214
215 const std::map<valtype, CNameHistory>::const_iterator i = history.find (name);
216 if (i == history.end ())
217 return false;
218
219 res = i->second;
220 return true;
221 }
222
223 void
setHistory(const valtype & name,const CNameHistory & data)224 CNameCache::setHistory (const valtype& name, const CNameHistory& data)
225 {
226 assert (fNameHistory);
227
228 const std::map<valtype, CNameHistory>::iterator ei = history.find (name);
229 if (ei != history.end ())
230 ei->second = data;
231 else
232 history.insert (std::make_pair (name, data));
233 }
234
235 void
updateNamesForHeight(unsigned nHeight,std::set<valtype> & names) const236 CNameCache::updateNamesForHeight (unsigned nHeight,
237 std::set<valtype>& names) const
238 {
239 /* Seek in the map of cached entries to the first one corresponding
240 to our height. */
241
242 const ExpireEntry seekEntry(nHeight, valtype ());
243 std::map<ExpireEntry, bool>::const_iterator it;
244
245 for (it = expireIndex.lower_bound (seekEntry); it != expireIndex.end (); ++it)
246 {
247 const ExpireEntry& cur = it->first;
248 assert (cur.nHeight >= nHeight);
249 if (cur.nHeight > nHeight)
250 break;
251
252 if (it->second)
253 names.insert (cur.name);
254 else
255 names.erase (cur.name);
256 }
257 }
258
259 void
addExpireIndex(const valtype & name,unsigned height)260 CNameCache::addExpireIndex (const valtype& name, unsigned height)
261 {
262 const ExpireEntry entry(height, name);
263 expireIndex[entry] = true;
264 }
265
266 void
removeExpireIndex(const valtype & name,unsigned height)267 CNameCache::removeExpireIndex (const valtype& name, unsigned height)
268 {
269 const ExpireEntry entry(height, name);
270 expireIndex[entry] = false;
271 }
272
273 void
apply(const CNameCache & cache)274 CNameCache::apply (const CNameCache& cache)
275 {
276 for (EntryMap::const_iterator i = cache.entries.begin ();
277 i != cache.entries.end (); ++i)
278 set (i->first, i->second);
279
280 for (std::set<valtype>::const_iterator i = cache.deleted.begin ();
281 i != cache.deleted.end (); ++i)
282 remove (*i);
283
284 for (std::map<valtype, CNameHistory>::const_iterator i
285 = cache.history.begin (); i != cache.history.end (); ++i)
286 setHistory (i->first, i->second);
287
288 for (std::map<ExpireEntry, bool>::const_iterator i
289 = cache.expireIndex.begin (); i != cache.expireIndex.end (); ++i)
290 expireIndex[i->first] = i->second;
291 }
292