Raven Core  3.0.0
P2P Digital Currency
messages.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2019 The Raven 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 <validation.h>
6 #include <chainparams.h>
7 #include <wallet/wallet.h>
8 #include <script/ismine.h>
9 #include <base58.h>
10 #include "messages.h"
11 #include "messagedb.h"
12 #include <primitives/block.h>
13 
14 
15 std::set<COutPoint> setDirtyMessagesRemove;
16 std::map<COutPoint, CMessage> mapDirtyMessagesAdd;
17 std::map<COutPoint, CMessage> mapDirtyMessagesOrphaned;
18 
19 std::set<std::string> setDirtyChannelsAdd;
20 std::set<std::string> setDirtyChannelsRemove;
21 std::set<std::string> setSubscribedChannelsAskedForFalse;
22 
23 std::set<std::string> setDirtySeenAddressAdd;
24 std::set<std::string> setAddressAskedForFalse;
25 
27 
28 
30 {
31  return (int8_t)status;
32 }
33 
35 {
36  return (MessageStatus)nStatus;
37 }
38 
40 {
41  switch (status) {
42  case MessageStatus::READ: return "READ";
43  case MessageStatus::UNREAD: return "UNREAD";
44  case MessageStatus::ORPHAN: return "ORPHAN";
45  case MessageStatus::EXPIRED: return "EXPIRED";
46  case MessageStatus::SPAM: return "SPAM";
47  case MessageStatus::HIDDEN: return "HIDDEN";
48  default: return "ERROR";
49  }
50 }
51 
53  SetNull();
54 }
55 
56 CMessage::CMessage(const COutPoint& out, const std::string& strName, const std::string& ipfsHash, const int64_t& nExpiredTime, const int64_t& time)
57 {
58  SetNull();
59  this->out = out;
60  this->strName = strName;
61  this->ipfsHash = ipfsHash;
62  this->nExpiredTime = nExpiredTime;
63  this->time = time;
65 }
66 
67 bool IsChannelSubscribed(const std::string &name)
68 {
70  return false;
71 
72  // Check Dirty Cache for newly added channel additions
73  if (setDirtyChannelsAdd.count(name))
74  return true;
75 
76  // Check Dirty Cache for newly removed channels
77  if (setDirtyChannelsRemove.count(name))
78  return false;
79 
80  // Check the Channel Cache and see if it is in the Cache
81  if (pMessageSubscribedChannelsCache->Exists(name))
82  return true;
83 
84  // Check if we have already searched for this before
85  if (setSubscribedChannelsAskedForFalse.count(name))
86  return false;
87 
88  // Check to see if the message database contains the asset
90  pMessageSubscribedChannelsCache->Put(name, 1);
91  return true;
92  }
93 
94  // Help prevent spam and unneeded database reads
96 
97  return false;
98 }
99 
100 bool GetMessage(const COutPoint& out, CMessage& message)
101 {
102  if (!pmessagedb || !pMessagesCache)
103  return false;
104 
105  // Check the dirty add cache
106  if (mapDirtyMessagesAdd.count(out)) {
107  message = mapDirtyMessagesAdd.at(out);
108  return true;
109  }
110 
111  // Check the dirty remove cache
112  if (setDirtyMessagesRemove.count(out))
113  return false;
114 
115  // Check database cache
116  if (pMessagesCache->Exists(out.ToSerializedString())) {
117  message = pMessagesCache->Get(out.ToSerializedString());
118  return true;
119  }
120 
121  // Check the database
122  if (pmessagedb->ReadMessage(out, message)) {
123  pMessagesCache->Put(out.ToSerializedString(), message);
124  return true;
125  }
126 
127  return false;
128 }
129 
130 void AddChannel(const std::string &name)
131 {
132  // Add channel to dirty cache to add
133  setDirtyChannelsAdd.insert(name);
134 
135  // If the channel name is in the dirty remove cache. Remove it so it doesn't get deleted on flush
136  setDirtyChannelsRemove.erase(name);
138 }
139 
140 void RemoveChannel(const std::string &name)
141 {
142  // Add channel to dirty cache to remove
143  setDirtyChannelsRemove.insert(name);
144 
145  // If the channel name is in the dirty add cache. Remove it so it doesn't get added on flush
146  setDirtyChannelsAdd.erase(name);
147 }
148 
149 void AddMessage(const CMessage& message)
150 {
151  // Add message to dirty map cache to add
152  mapDirtyMessagesAdd.insert(std::make_pair(message.out, message));
153 
154  // Remove message Out from dirty set Cache to remove
155  setDirtyMessagesRemove.erase(message.out);
156  mapDirtyMessagesOrphaned.erase(message.out);
157 }
158 
159 void RemoveMessage(const CMessage& message)
160 {
161  RemoveMessage(message.out);
162 }
163 
165 {
166  // Add message out to dirty set Cache to remove
167  setDirtyMessagesRemove.insert(out);
168 
169  // Remove message from map Dirty Message to add
170  mapDirtyMessagesAdd.erase(out);
171  mapDirtyMessagesOrphaned.erase(out);
172 }
173 
175 {
176  CMessage message;
177  if (GetMessage(out, message))
178  OrphanMessage(message);
179 }
180 
181 void OrphanMessage(const CMessage& message)
182 {
183  mapDirtyMessagesOrphaned[message.out] = message;
184 
185  // Remove from other dirty caches
186  mapDirtyMessagesAdd.erase(message.out);
187 }
188 
189 bool ScanForMessageChannels(std::string& strError)
190 {
191  LOCK2(cs_messaging, cs_main);
192 
193  LogPrintf("%s : Start Scanning For Message Channels\n", __func__);
194 
195  if (vpwallets.size() == 0) {
196  strError = "Wallet isn't active on this client. Can't scan for MsgChannels";
197  return false;
198  }
199 
201 
202  while (blockIndex) {
203  CBlock block;
204  if (!ReadBlockFromDisk(block, blockIndex, Params().GetConsensus())) {
205  strError = "Block not found on disk";
206  return false;
207  }
208 
209  for (const auto& tx : block.vtx) {
210 
211  auto ptx = tx.get();
212  if (!ptx) {
213  strError = "Failed to get transaction pointer";
214  return false;
215  }
216 
217  for (auto out : ptx->vout) {
218  int nType = -1;
219  bool fOwner = false;
220  if (vpwallets[0]->IsMine(out) == ISMINE_SPENDABLE) { // Is the out mine
221  if (out.scriptPubKey.IsAssetScript(nType, fOwner)) {
222  CAssetOutputEntry assetData;
223  // Get the asset data from the script
224  if (GetAssetData(out.scriptPubKey, assetData)) {
225  AssetType type;
226  IsAssetNameValid(assetData.assetName, type);
227 
228  if (assetData.type == TX_TRANSFER_ASSET) {
229  if (type == AssetType::MSGCHANNEL || type == AssetType::OWNER) { // Subscribe to any channels or owner tokens you own
230  AddChannel(assetData.assetName);
232  } else if (type == AssetType::ROOT || type == AssetType::SUB) { // Subscribe to any assets you are sent, if they are sent to a new address
233  if (!IsChannelSubscribed(assetData.assetName + OWNER_TAG)) {
234  if (!IsAddressSeen(EncodeDestination(assetData.destination))) {
235  AddChannel(assetData.assetName + OWNER_TAG);
237  }
238  }
239  }
240  } else if (assetData.type == TX_NEW_ASSET || assetData.type == TX_REISSUE_ASSET) {
241  if (fOwner || type == AssetType::MSGCHANNEL) {
242  AddChannel(assetData.assetName);
244  } else if (type == AssetType::ROOT || type == AssetType::SUB || type == AssetType::RESTRICTED) {
245  AddChannel(assetData.assetName + "!");
247  }
248  }
249  } else {
250  LogPrintf("%s : Failed to get GetAssetData call\n", __func__);
251  }
252  }
253  }
254  }
255  }
256  blockIndex = chainActive[blockIndex->nHeight + 1];
257  }
258 
259  LogPrintf("%s : Finished Scanning For Message Channels. Subscribed Messages Channels Found: %u\n", __func__, setDirtyChannelsAdd.size());
260  for (auto item : setDirtyChannelsAdd) {
261  LogPrintf("%s, ",item);
262  }
263  LogPrintf("\n");
264  return true;
265 }
266 
267 bool IsAddressSeen(const std::string &address)
268 {
270  return false;
271 
272  if (setDirtySeenAddressAdd.count(address)) // Check dirty set
273  return true;
274 
275  if (pMessagesSeenAddressCache->Exists(address)) {
276  return true;
277  }
278 
279  if (setAddressAskedForFalse.count(address)) {
280  return false;
281  }
282 
283  if (pmessagechanneldb->ReadUsedAddress(address)) {
284  pMessagesSeenAddressCache->Put(address, 1);
285  return true;
286  }
287 
288  setAddressAskedForFalse.insert(address);
289 
290  return false;
291 }
292 
293 void AddAddressSeen(const std::string &address)
294 {
295  setDirtySeenAddressAdd.insert(address);
296  setSubscribedChannelsAskedForFalse.erase(address);
297 }
298 
300 {
301  // COutPoint: 32 bytes
302  // CNewAsset: Max 80 bytes
303  // CAssetTransfer: Asset Name, CAmount ( 40 bytes)
304  // CReissueAsset: Max 80 bytes
305  // CAmount: 8 bytes
306  // Asset Name: Max 32 bytes
307  // Address: 40 bytes
308  // Block hash: 32 bytes
309  // CTxOut: CAmount + CScript (105 + 8 = 113 bytes)
310  // CMessage: Max 123 Bytes
311 
312 
313  size_t size = 0;
314  // Messages Caches
315  size += 32 * setDirtyMessagesRemove.size(); // COutPoint;
316  size += (32 + 123) * mapDirtyMessagesAdd.size(); // COutPoint -> CMessage
317  size += (32 + 123) * mapDirtyMessagesOrphaned.size(); // COutPoint -> CMessage
318 
319 
320  // Message Channel Caches
321  size += 32 * setDirtyChannelsAdd.size();
322  size += 32 * setDirtyChannelsRemove.size();
323  size += 32 * setSubscribedChannelsAskedForFalse.size();
324 
325  // Address Seen Caches
326  size += 32 * setDirtySeenAddressAdd.size();
327  size += 32 * setAddressAskedForFalse.size();
328 
329  return size;
330 }
331 
332 
334 {
335  std::string str = "";
336  str += "{";
337  str += "\"blockheight\": " + std::to_string(this->blockHeight) + ", ";
338  str += "\"assetname\": \"" + this->assetName + "\", ";
339  str += "\"ipfshash\": \"" + EncodeAssetData(this->ipfsHash) + "\", ";
340  str += "\"expiretime\": " + std::to_string(this->nExpireTime);
341  str += "}";
342 
343  return str;
344 }
std::set< COutPoint > setDirtyMessagesRemove
Definition: messages.cpp:15
void AddChannel(const std::string &name)
Definition: messages.cpp:130
int64_t time
Definition: messages.h:74
Definition: block.h:73
bool GetMessage(const COutPoint &out, CMessage &message)
Definition: messages.cpp:100
size_t GetMessageDirtyCacheSize()
Definition: messages.cpp:299
std::string ToSerializedString() const
Definition: transaction.cpp:19
txnouttype type
Definition: wallet.h:193
CMessageChannelDB * pmessagechanneldb
Global variable that points to the message channel database (protected by cs_main) ...
Definition: validation.cpp:233
CCriticalSection cs_main
Global state.
Definition: validation.cpp:72
std::string createJsonString()
Definition: messages.cpp:333
void SetNull()
Definition: messages.h:81
isminetype IsMine(const CKeyStore &keystore, const CScript &scriptPubKey, SigVersion sigversion)
Definition: ismine.cpp:32
std::vector< CWalletRef > vpwallets
Definition: wallet.cpp:44
bool ReadMyMessageChannel(const std::string &channelname)
Definition: messagedb.cpp:130
MessageStatus
Definition: messages.h:53
MessageStatus status
Definition: messages.h:76
CLRUCache< std::string, int > * pMessageSubscribedChannelsCache
Global variable that points to the subscribed channel LRU Cache (protected by cs_main) ...
Definition: validation.cpp:230
RVN START.
Definition: wallet.h:191
bool GetAssetData(const CScript &script, CAssetOutputEntry &data)
Definition: assets.cpp:3440
bool IsAddressSeen(const std::string &address)
Definition: messages.cpp:267
CLRUCache< std::string, CMessage > * pMessagesCache
Global variable that points to the subscribed channel LRU Cache (protected by cs_main) ...
Definition: validation.cpp:229
bool ReadMessage(const COutPoint &out, CMessage &message)
Definition: messagedb.cpp:22
std::set< std::string > setDirtyChannelsRemove
Definition: messages.cpp:20
#define LOCK2(cs1, cs2)
Definition: sync.h:177
bool IsAssetNameValid(const std::string &name, AssetType &assetType, std::string &error)
Definition: assets.cpp:207
std::set< std::string > setSubscribedChannelsAskedForFalse
Definition: messages.cpp:21
#define LogPrintf(...)
Definition: util.h:149
COutPoint out
Definition: messages.h:71
#define OWNER_TAG
Definition: assets.h:32
CMessageDB * pmessagedb
Global variable that points to the messages database (protected by cs_main)
Definition: validation.cpp:232
std::string assetName
Definition: wallet.h:194
CMessage()
Definition: messages.cpp:52
std::set< std::string > setAddressAskedForFalse
Definition: messages.cpp:24
std::map< COutPoint, CMessage > mapDirtyMessagesOrphaned
Definition: messages.cpp:17
CCriticalSection cs_messaging
Definition: messages.cpp:26
std::string ipfsHash
Definition: messages.h:73
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:75
std::string strName
Definition: messages.h:72
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
void RemoveMessage(const CMessage &message)
Definition: messages.cpp:159
std::map< COutPoint, CMessage > mapDirtyMessagesAdd
Definition: messages.cpp:16
void AddAddressSeen(const std::string &address)
Definition: messages.cpp:293
int8_t IntFromMessageStatus(MessageStatus status)
Definition: messages.cpp:29
AssetType
Definition: assettypes.h:21
int GetAssetActivationHeight() const
Definition: chainparams.h:122
int64_t nExpiredTime
Definition: messages.h:75
std::vector< CTransactionRef > vtx
Definition: block.h:77
std::string EncodeDestination(const CTxDestination &dest)
Definition: base58.cpp:326
bool ScanForMessageChannels(std::string &strError)
Definition: messages.cpp:189
std::string MessageStatusToString(MessageStatus status)
Definition: messages.cpp:39
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:172
const CChainParams & Params()
Return the currently selected parameters.
void AddMessage(const CMessage &message)
Definition: messages.cpp:149
RVN START.
Definition: standard.h:69
void OrphanMessage(const COutPoint &out)
Definition: messages.cpp:174
std::set< std::string > setDirtyChannelsAdd
Definition: messages.cpp:19
MessageStatus MessageStatusFromInt(int8_t nStatus)
Definition: messages.cpp:34
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:185
bool ReadBlockFromDisk(CBlock &block, const CDiskBlockPos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
CTxDestination destination
Definition: wallet.h:195
void RemoveChannel(const std::string &name)
Definition: messages.cpp:140
std::string EncodeAssetData(std::string decoded)
Definition: assets.cpp:3716
CLRUCache< std::string, int > * pMessagesSeenAddressCache
Global variable that points to the address seen LRU Cache (protected by cs_main)
Definition: validation.cpp:231
Wrapped boost mutex: supports recursive locking, but no waiting TODO: We should move away from using ...
Definition: sync.h:92
bool ReadUsedAddress(const std::string &address)
Definition: messagedb.cpp:182
bool IsChannelSubscribed(const std::string &name)
Definition: messages.cpp:67
std::set< std::string > setDirtySeenAddressAdd
Definition: messages.cpp:23