Skip to content

Commit 235b105

Browse files
committed
implement another layer of cache for query smart contract
1 parent 61e5809 commit 235b105

File tree

8 files changed

+102
-71
lines changed

8 files changed

+102
-71
lines changed

GlobalVar.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ struct GlobalState {
8787
bool allowCheckInQubicGlobal = true;
8888

8989
std::atomic_bool gStopFlag;
90+
91+
TimedCacheMap<>* TCM;
9092
};
9193

9294
// Safe, lazy singleton accessor avoids static init order issues.

RESTAPI/ApiHelpers.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,21 +362,70 @@ static bool parseHexInput(const std::string& inputDataHex, std::vector<uint8_t>&
362362
return true;
363363
}
364364

365-
SmartContractQueryResult checkSmartContractResult(uint32_t nonce) {
365+
m256i makeHashQuerySC(uint32_t scIndex, uint32_t funcNumber, const std::string& inputDataHex)
366+
{
367+
m256i digest{};
368+
std::vector<uint8_t> nonceData;
369+
nonceData.reserve(sizeof(uint32_t) * 2 + inputDataHex.size());
370+
371+
// Append scIndex and funcNumber
372+
nonceData.insert(nonceData.end(),
373+
reinterpret_cast<uint8_t *>(&scIndex),
374+
reinterpret_cast<uint8_t *>(&scIndex) + sizeof(uint32_t));
375+
nonceData.insert(nonceData.end(),
376+
reinterpret_cast<uint8_t *>(&funcNumber),
377+
reinterpret_cast<uint8_t *>(&funcNumber) + sizeof(uint32_t));
378+
379+
// Append input hex data
380+
nonceData.insert(nonceData.end(), inputDataHex.begin(), inputDataHex.end());
381+
382+
// Calculate K12 hash
383+
KangarooTwelve(nonceData.data(), nonceData.size(), digest.m256i_u8, 32);
384+
return digest;
385+
}
386+
387+
SmartContractQueryResult checkSmartContractResult(uint32_t nonce, uint32_t scIndex,
388+
uint32_t funcNumber, const std::string& inputDataHex)
389+
{
366390
SmartContractQueryResult result;
367391
result.nonce = nonce;
368392

369393
std::vector<uint8_t> out;
370394
if (responseSCData.get(nonce, out)) {
371395
result.success = true;
372396
result.data = bytesToHex(out.data(), out.size());
397+
398+
m256i hash = ApiHelpers::makeHashQuerySC(scIndex, funcNumber, inputDataHex);
399+
gTCM->add(hash, out);
373400
} else {
374401
result.pending = true;
375402
}
376403

377404
return result;
378405
}
379406

407+
// Non-blocking enqueue: send a SC query and return immediately
408+
bool enqueueSmartContractRequest(uint32_t nonce, uint32_t scIndex, uint32_t funcNumber, const uint8_t* data, uint32_t dataSize)
409+
{
410+
std::vector<uint8_t> vdata(dataSize + sizeof(RequestContractFunction) + sizeof(RequestResponseHeader));
411+
RequestContractFunction rcf{};
412+
rcf.contractIndex = scIndex;
413+
rcf.inputSize = dataSize;
414+
rcf.inputType = funcNumber;
415+
416+
auto header = (RequestResponseHeader*)vdata.data();
417+
header->setType(RequestContractFunction::type);
418+
header->setSize(dataSize + sizeof(RequestResponseHeader) + sizeof(RequestContractFunction));
419+
header->setDejavu(nonce);
420+
421+
memcpy(vdata.data() + sizeof(RequestResponseHeader), &rcf, sizeof(RequestResponseHeader));
422+
if (dataSize)
423+
memcpy(vdata.data() + sizeof(RequestResponseHeader) + sizeof(RequestContractFunction), data, dataSize);
424+
425+
// fire-and-forget to SC thread
426+
return MRB_SC.EnqueuePacket(vdata.data());
427+
}
428+
380429
SmartContractQueryResult querySmartContract(uint32_t nonce, uint32_t scIndex,
381430
uint32_t funcNumber, const std::string& inputDataHex) {
382431
SmartContractQueryResult result;
@@ -396,6 +445,18 @@ SmartContractQueryResult querySmartContract(uint32_t nonce, uint32_t scIndex,
396445
return result;
397446
}
398447

448+
// cache level 2
449+
{
450+
m256i digest{};
451+
digest = makeHashQuerySC(scIndex, funcNumber, inputDataHex);
452+
if (gTCM->tryGet(digest, out))
453+
{
454+
result.success = true;
455+
result.data = bytesToHex(out.data(), out.size());
456+
return result;
457+
}
458+
}
459+
399460
// Parse input data
400461
std::vector<uint8_t> dataBytes;
401462
if (!parseHexInput(inputDataHex, dataBytes, result.error)) {

RESTAPI/ApiHelpers.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,11 @@ SmartContractQueryResult querySmartContract(uint32_t nonce, uint32_t scIndex,
135135
// Check if a smart contract query result is available (by nonce)
136136
// @param nonce: unique identifier for the query
137137
// @return SmartContractQueryResult with response data if available
138-
SmartContractQueryResult checkSmartContractResult(uint32_t nonce);
138+
SmartContractQueryResult checkSmartContractResult(uint32_t nonce, uint32_t scIndex,
139+
uint32_t funcNumber, const std::string& inputDataHex);
139140

141+
// @return K12 of scIndex funcNumber and inputDataHex
142+
m256i makeHashQuerySC(uint32_t scIndex, uint32_t funcNumber, const std::string& inputDataHex);
140143
// ============================================================================
141144
// Utility Functions
142145
// ============================================================================

RESTAPI/RESTServer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,9 +559,9 @@ namespace {
559559
auto pollResultPtr = std::make_shared<std::function<void()>>();
560560
std::weak_ptr<std::function<void()>> pollResultWeak = pollResultPtr;
561561

562-
*pollResultPtr = [nonce, sharedCallback, attemptCount, startTime, loop, pollResultWeak]() {
562+
*pollResultPtr = [nonce, sharedCallback, attemptCount, startTime, loop, pollResultWeak, scIndex, funcNumber, data]() {
563563
// Check for result using shared helper
564-
SmartContractQueryResult result = ApiHelpers::checkSmartContractResult(nonce);
564+
SmartContractQueryResult result = ApiHelpers::checkSmartContractResult(nonce, scIndex, funcNumber, data);
565565

566566
if (result.success) {
567567
Json::Value root;

RESTAPI/bobAPI.cpp

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,6 @@ static std::string toHex(const std::vector<uint8_t>& data) {
2121
return ss.str();
2222
}
2323

24-
// Non-blocking enqueue: send a SC query and return immediately
25-
bool enqueueSmartContractRequest(uint32_t nonce, uint32_t scIndex, uint32_t funcNumber, const uint8_t* data, uint32_t dataSize)
26-
{
27-
std::vector<uint8_t> vdata(dataSize + sizeof(RequestContractFunction) + sizeof(RequestResponseHeader));
28-
RequestContractFunction rcf{};
29-
rcf.contractIndex = scIndex;
30-
rcf.inputSize = dataSize;
31-
rcf.inputType = funcNumber;
32-
33-
auto header = (RequestResponseHeader*)vdata.data();
34-
header->setType(RequestContractFunction::type);
35-
header->setSize(dataSize + sizeof(RequestResponseHeader) + sizeof(RequestContractFunction));
36-
header->setDejavu(nonce);
37-
38-
memcpy(vdata.data() + sizeof(RequestResponseHeader), &rcf, sizeof(RequestResponseHeader));
39-
if (dataSize)
40-
memcpy(vdata.data() + sizeof(RequestResponseHeader) + sizeof(RequestContractFunction), data, dataSize);
41-
42-
// fire-and-forget to SC thread
43-
return MRB_SC.EnqueuePacket(vdata.data());
44-
}
45-
4624
std::string bobGetBalance(const char* identity)
4725
{
4826
if (!identity) return "{\"error\": \"Wrong identity format\"}";
@@ -543,49 +521,6 @@ std::string bobGetStatus()
543521
"}";
544522
}
545523

546-
std::string querySmartContract(uint32_t nonce, uint32_t scIndex, uint32_t funcNumber, uint8_t* data, uint32_t dataSize)
547-
{
548-
// Preserve existing sync API for backwards compatibility,
549-
// but avoid blocking the thread for long: do a single immediate check, else enqueue and return pending.
550-
std::vector<uint8_t> dataOut;
551-
Json::Value root;
552-
553-
if (responseSCData.get(nonce, dataOut)) {
554-
root["nonce"] = nonce;
555-
root["data"] = toHex(dataOut);
556-
} else {
557-
enqueueSmartContractRequest(nonce, scIndex, funcNumber, data, dataSize);
558-
root["error"] = "pending";
559-
root["message"] = "Query enqueued; try again shortly with the same nonce";
560-
}
561-
562-
Json::FastWriter writer;
563-
return writer.write(root);
564-
}
565-
566-
567-
std::string broadcastTransaction(uint8_t* txDataWithHeader, int size)
568-
{
569-
auto tx = (Transaction*)(txDataWithHeader+sizeof(RequestResponseHeader));
570-
if (tx->inputSize + sizeof(Transaction) + sizeof(RequestResponseHeader) + SIGNATURE_SIZE != size)
571-
{
572-
return "{\"error\": \"Invalid size\"}";
573-
}
574-
m256i digest{};
575-
uint8_t* signature = txDataWithHeader + sizeof(RequestResponseHeader) + sizeof(Transaction) + tx->inputSize;
576-
KangarooTwelve(reinterpret_cast<const uint8_t *>(tx), size - sizeof(RequestResponseHeader) - SIGNATURE_SIZE, digest.m256i_u8, 32);
577-
if (!verify(tx->sourcePublicKey, digest.m256i_u8, signature))
578-
{
579-
return "{\"error\": \"Invalid signature\"}";
580-
}
581-
MRB_SC.EnqueuePacket(txDataWithHeader);
582-
KangarooTwelve(reinterpret_cast<const uint8_t *>(tx), size - sizeof(RequestResponseHeader), digest.m256i_u8, 32);
583-
char hash[64]={0};
584-
getIdentityFromPublicKey(digest.m256i_u8, hash, true);
585-
std::string txHash(hash);
586-
return "{\"txHash\": \"" + txHash + "\"}";
587-
}
588-
589524
std::string bobGetEpochInfo(uint16_t epoch)
590525
{
591526
auto info = ApiHelpers::getEpochInfo(epoch);

SpecialBufferStructs.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,11 @@ class TimedCacheMap {
215215
*/
216216
void add(m256i key, std::vector<uint8_t> value) {
217217
std::lock_guard<std::mutex> lock(mtx_);
218-
218+
if (data_map_.find(key) != data_map_.end())
219+
{
220+
// already exist
221+
return;
222+
}
219223
// If at capacity and key doesn't exist, remove oldest
220224
if (data_map_.size() >= L && data_map_.find(key) == data_map_.end()) {
221225
remove_oldest();
@@ -255,7 +259,7 @@ class TimedCacheMap {
255259
* @param sz Reference to int that will contain the size (will be set to 0 if not found)
256260
* @return true if key was found and data copied, false otherwise
257261
*/
258-
bool tryGet(m256i key, uint8_t*& ptr, int& sz) {
262+
bool tryGetRaw(m256i key, uint8_t*& ptr, int& sz) {
259263
std::lock_guard<std::mutex> lock(mtx_);
260264

261265
auto it = data_map_.find(key);
@@ -281,6 +285,26 @@ class TimedCacheMap {
281285
return false;
282286
}
283287

288+
/**
289+
* @brief Tries to retrieve a value from the cache into a vector.
290+
* @param key The m256i key to search for
291+
* @param value Reference to vector that will be populated with the data
292+
* @return true if key was found and data copied, false otherwise
293+
*/
294+
bool tryGet(m256i key, std::vector<uint8_t>& value) {
295+
std::lock_guard<std::mutex> lock(mtx_);
296+
297+
auto it = data_map_.find(key);
298+
if (it == data_map_.end()) {
299+
value.clear();
300+
return false;
301+
}
302+
303+
value = it->second.data;
304+
return true;
305+
}
306+
307+
284308
/**
285309
* @brief Returns the current number of elements in the cache.
286310
*/

bob.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ int runBob(int argc, char *argv[])
230230
set_this_thread_name("indexer");
231231
indexVerifiedTicks();
232232
});
233+
gTCM = new TimedCacheMap<>();
233234
auto sc_thread = std::thread([&](){
234235
set_this_thread_name("sc");
235236
querySmartContractThread(connPool);
@@ -359,7 +360,11 @@ int runBob(int argc, char *argv[])
359360
Logger::get()->info("Exited LogEventRequestTrustedNodes thread");
360361
indexer_thread.join();
361362
Logger::get()->info("Exited indexer thread");
363+
362364
sc_thread.join();
365+
delete gTCM;
366+
Logger::get()->info("Exited SC thread");
367+
363368
if (log_event_verifier_thread.joinable())
364369
{
365370
log_event_verifier_thread.join();

shim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,4 @@
5959
#define gStopFlag (GS().gStopFlag)
6060
#define gStartTimeUnix (GS().startTimeUnix)
6161
#define gAllowCheckInQubicGlobal (GS().allowCheckInQubicGlobal)
62+
#define gTCM (GS().TCM)

0 commit comments

Comments
 (0)