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