@@ -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+
380429SmartContractQueryResult 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 )) {
0 commit comments