Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
391060a
Implement qpi.getOracleQuery() and tests
philippwerner Dec 16, 2025
7ca5294
Implement oracle reply commit transaction
philippwerner Dec 17, 2025
aea387c
OracleEngine: add lock for mutal exclusion
philippwerner Dec 23, 2025
95745e5
Refactor: move global tick storage instance to header
philippwerner Jan 5, 2026
a90d567
Create/process reveal tx + notify contract
philippwerner Jan 5, 2026
38f2be1
Change contract notifications to use registry
philippwerner Jan 6, 2026
defb91b
Implement notifications in oracleEngine
philippwerner Jan 6, 2026
2e58367
Implement timeouts in oracle engine
philippwerner Jan 6, 2026
dac80f7
Integrate oracle engine in qubic.cpp
philippwerner Jan 6, 2026
54fe7cc
Reduce OracleQueryMetadata size from 80 to 72 bytes
philippwerner Jan 6, 2026
f3c85d5
Implement first RequestOracleData features
philippwerner Jan 6, 2026
fcecda7
Merge branch 'develop' into feature/2025-12-15-contract-one-time-orac…
philippwerner Jan 6, 2026
45e7b62
Merge branch 'feature/2025-12-09-oracle-machine' into feature/2025-12…
philippwerner Jan 6, 2026
a1c4cfe
Revert "virtual memory test: add deinit filesystem"
Franziska-Mueller Jan 7, 2026
681bf58
Merge pull request #710 from qubic/develop (Release v1.273.0)
Franziska-Mueller Jan 7, 2026
017c75f
Add oracle interface Mock
philippwerner Jan 7, 2026
6f020e2
set START_NETWORK_FROM_SCRATCH to 1
Franziska-Mueller Jan 7, 2026
674639d
Add char enum to conveniently init id from string
philippwerner Jan 7, 2026
c195c22
Set TESTEXC regular price query to value supported by OM
philippwerner Jan 7, 2026
ea7bef4
TESTEXC: Add query/notification to mack oracle interface
philippwerner Jan 7, 2026
90b92f9
QIP fix: bug on moving the remaining amount for the next epoch (#712)
TakaYuPP Jan 7, 2026
507c30c
Add Smart Contract qRWA for QMINE ecosystem (#703)
mundusakhan Jan 12, 2026
1290107
qRWA: change construction epoch from 198 to 197 (as confirmed with Eko)
Franziska-Mueller Jan 12, 2026
e9293e7
add NO_QRWA toggle
Franziska-Mueller Jan 12, 2026
9e53369
update params for epoch 196 / v1.274.0
Franziska-Mueller Jan 12, 2026
feb6a05
Fix bug in processRequestOracleData()
philippwerner Jan 12, 2026
57cd01c
enable contract execution fee deduction
Franziska-Mueller Jan 13, 2026
e03d235
Merge pull request #715 from qubic/develop (Release v1.274.0)
Franziska-Mueller Jan 14, 2026
87d2cdb
Revert "add NO_QRWA toggle"
Franziska-Mueller Jan 14, 2026
9ca8c9c
QIP: remove one-time fix for epoch 196
Franziska-Mueller Jan 14, 2026
6ed5a51
QRaffle fix: incorrect shareholder info (#717)
TakaYuPP Jan 15, 2026
2b90e06
Fix compiler compatibility issue
philippwerner Jan 16, 2026
0678ff4
OracleMock: show stats.
cyber-pc Jan 8, 2026
3fe22d5
Add logging of oracle query status changes
philippwerner Jan 9, 2026
030f993
Fix uninitialized padding in log items
philippwerner Jan 9, 2026
851dc98
TESTEXC: Log in oracle notification procedures
philippwerner Jan 9, 2026
8d2ec92
Fix status type in OracleNotificationInpuut
philippwerner Jan 9, 2026
b118bc1
Fix ASSERT in logging
philippwerner Jan 9, 2026
3a955c3
Fix loop in processOracleReplyCommitTransaction()
philippwerner Jan 13, 2026
6138676
Fix bug in processRequestOracleData()
philippwerner Jan 13, 2026
79464ba
Fix deadlock in processRequestOracleData()
philippwerner Jan 13, 2026
7f1770f
Add important reminder about debug logging
philippwerner Jan 16, 2026
0a3182a
Implement more oracle query QPI functions
philippwerner Jan 16, 2026
b2b03bb
Log avg tick count until oracle reply tx get executed
philippwerner Jan 16, 2026
cebab8f
Set oracle reply tx publication offsets
philippwerner Jan 13, 2026
9c47cc2
Add debug output to oracle query pipeline
philippwerner Jan 9, 2026
f902702
More oracle query stats and request/response for those
philippwerner Jan 19, 2026
565af82
Fix typo in oracle query stats struct
philippwerner Jan 19, 2026
b612d06
QIP: not transfer the share management during the ICO & fixing the bu…
TakaYuPP Jan 19, 2026
211f36a
Extend and fix stats
philippwerner Jan 19, 2026
c2cf9c1
Add addition mining algorithm (#716)
cyber-pc Jan 19, 2026
5967b25
update params for epoch 197 / v1.275.0
Franziska-Mueller Jan 19, 2026
d2cd554
QBay fix: qbay gtest bug (#719)
TakaYuPP Jan 19, 2026
bd18b89
Update ADDITION_SOLUTION_THRESHOLD_DEFAULT.
cyber-pc Jan 20, 2026
d769317
update new initial tick
Franziska-Mueller Jan 21, 2026
ae90be2
Merge branch 'main' into develop
Franziska-Mueller Jan 21, 2026
e89a2f5
qRWA: Fix dividend routing (#722)
mundusakhan Jan 23, 2026
4c1b820
IPO QDuel (#705)
N-010 Jan 26, 2026
70ab46a
Adjust SWATCH burn mechanism for infrastructure contracts (#723)
fnordspace Jan 26, 2026
9ce65cb
add OLD_SWATCH toggle
Franziska-Mueller Jan 26, 2026
28ddf32
add NO_QDUEL toggle
Franziska-Mueller Jan 26, 2026
141b7d3
IPO QThirtyFour (#684)
N-010 Jan 26, 2026
fa20bdf
add NO_QRP and NO_QTF toggles
Franziska-Mueller Jan 26, 2026
9b044a9
Fix reorgBuffer race condition (#724)
philippwerner Jan 27, 2026
b08fadf
update params for epoch 198 / v1.276.0
Franziska-Mueller Jan 27, 2026
7336dfd
Merge branch 'develop' into feature/2025-12-09-oracle-machine
philippwerner Jan 27, 2026
5a6a1fe
Merge branch 'feature/2025-12-09-oracle-machine' into feature/2025-12…
philippwerner Jan 27, 2026
038d5e3
Fix oracle-related use cases of reorgBuffer
philippwerner Jan 26, 2026
014641a
Improve debug output
philippwerner Jan 19, 2026
a37f5c5
Fix oracle stats network message
philippwerner Jan 19, 2026
4043127
Set oracle reply commit publication offset to 4
philippwerner Jan 19, 2026
18da209
Save/load snapshot of all oracle engine data
philippwerner Jan 19, 2026
0ad7918
Disable pendingTxsPool.add() debug output...
philippwerner Jan 20, 2026
dc2d839
Improve oracle status output (to console)
philippwerner Jan 20, 2026
7ff1a1e
Fix typos
philippwerner Jan 23, 2026
bfc3acd
Delete all oracle queries in beginEpoch()
philippwerner Jan 26, 2026
59691d0
Oracle engine snapshot loading and consistency check
philippwerner Jan 23, 2026
fbfcf69
Improve output + checks (mainly snapshots)
philippwerner Jan 26, 2026
7ee406e
Disable some debug output of pendingTxsPool
philippwerner Jan 26, 2026
2f0a2e5
Fix name clash in FourQ
philippwerner Jan 27, 2026
faac34c
Improve connection between node and OM. (#725)
cyber-pc Jan 27, 2026
78c526d
remove all toggles for code that depended on proposals
Franziska-Mueller Jan 28, 2026
bf03309
Add ability to adjust multipler of each mining algo's solution. (#721)
cyber-pc Jan 28, 2026
d873107
Implement RequestOracleData::requestAllQueryIdsByTick
philippwerner Jan 29, 2026
2f82271
Remove oracle status flags that don't add to status
philippwerner Jan 29, 2026
2664d56
Solve issues with anonymous unions in non-MSVC
philippwerner Jan 30, 2026
cdf2f99
Update docs
philippwerner Jan 30, 2026
841852e
Merge branch 'refactor/2026-01-30-solve-anonymous-union-issues' into …
philippwerner Jan 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions doc/contracts_proposals.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ struct QUTIL
// Your code should set the state variable that the proposal is about to the accepted value.
// This can be done as in this example taken from QUTIL:

switch (input.proposal.variableOptions.variable)
switch (input.proposal.data.variableOptions.variable)
{
case 0:
state.smt1InvocationFee = input.acceptedValue;
Expand Down Expand Up @@ -348,7 +348,7 @@ PRIVATE_PROCEDURE_WITH_LOCALS(FinalizeShareholderStateVarProposals)
if (locals.p.acceptedOption <= 0)
continue;

locals.p.acceptedValue = locals.p.proposal.variableOptions.value;
locals.p.acceptedValue = locals.p.proposal.data.variableOptions.value;

CALL(FinalizeShareholderProposalSetStateVar, locals.p, output);
}
Expand Down Expand Up @@ -376,8 +376,8 @@ PUBLIC_PROCEDURE(SetShareholderProposal)
{
// check proposal input and fees
if (qpi.invocationReward() < setProposalFeeVarOrValue || (input.epoch
&& (input.type != ProposalTypes::VariableYesNo || input.variableOptions.variable >= numFeeStateVariables
|| input.variableOptions.value < 0)))
&& (input.type != ProposalTypes::VariableYesNo || input.data.variableOptions.variable >= numFeeStateVariables
|| input.data.variableOptions.value < 0)))
{
// error -> reimburse invocation reward
qpi.transfer(qpi.invocator(), qpi.invocationReward());
Expand Down
10 changes: 10 additions & 0 deletions src/Qubic.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
<ClInclude Include="common_buffers.h" />
<ClInclude Include="contracts\ComputorControlledFund.h" />
<ClInclude Include="contracts\Qdraw.h" />
<ClInclude Include="contracts\qRWA.h" />
<ClInclude Include="contracts\Qswap.h" />
<ClInclude Include="contracts\RandomLottery.h" />
<ClInclude Include="contracts\QDuel.h" />
<ClInclude Include="contracts\SupplyWatcher.h" />
<ClInclude Include="contracts\EmptyTemplate.h" />
<ClInclude Include="contracts\GeneralQuorumProposal.h" />
Expand All @@ -44,6 +46,8 @@
<ClInclude Include="contracts\QRaffle.h" />
<ClInclude Include="contracts\QBond.h" />
<ClInclude Include="contracts\QIP.h" />
<ClInclude Include="contracts\QReservePool.h" />
<ClInclude Include="contracts\QThirtyFour.h" />
<ClInclude Include="contracts\TestExampleA.h" />
<ClInclude Include="contracts\TestExampleB.h" />
<ClInclude Include="contracts\TestExampleC.h" />
Expand All @@ -70,6 +74,10 @@
<ClInclude Include="logging\logging.h" />
<ClInclude Include="logging\net_msg_impl.h" />
<ClInclude Include="mining\mining.h" />
<ClInclude Include="mining\score_addition.h" />
<ClInclude Include="mining\score_common.h" />
<ClInclude Include="mining\score_engine.h" />
<ClInclude Include="mining\score_hyperidentity.h" />
<ClInclude Include="network_core\peers.h" />
<ClInclude Include="network_core\tcp4.h" />
<ClInclude Include="network_messages\all.h" />
Expand All @@ -96,6 +104,8 @@
<ClInclude Include="oracle_core\oracle_engine.h" />
<ClInclude Include="oracle_core\oracle_interfaces_def.h" />
<ClInclude Include="oracle_core\oracle_transactions.h" />
<ClInclude Include="oracle_core\snapshot_files.h" />
<ClInclude Include="oracle_interfaces\Mock.h" />
<ClInclude Include="oracle_interfaces\Price.h" />
<ClInclude Include="platform\assert.h" />
<ClInclude Include="platform\concurrency.h" />
Expand Down
33 changes: 33 additions & 0 deletions src/Qubic.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@
<ClInclude Include="contracts\RandomLottery.h">
<Filter>contracts</Filter>
</ClInclude>
<ClInclude Include="contracts\QReservePool.h">
<Filter>contracts</Filter>
</ClInclude>
<ClInclude Include="contracts\QThirtyFour.h">
<Filter>contracts</Filter>
</ClInclude>
<ClInclude Include="contracts\QDuel.h">
<Filter>contracts</Filter>
</ClInclude>
<ClInclude Include="contract_core\pre_qpi_def.h">
<Filter>contract_core</Filter>
</ClInclude>
Expand Down Expand Up @@ -332,6 +341,30 @@
<ClInclude Include="contract_core\execution_time_accumulator.h">
<Filter>contract_core</Filter>
</ClInclude>
<ClInclude Include="oracle_interfaces\Mock.h">
<Filter>oracle_interfaces</Filter>
</ClInclude>
<ClInclude Include="mining\score_common.h">
<Filter>mining</Filter>
</ClInclude>
<ClInclude Include="mining\score_engine.h">
<Filter>mining</Filter>
</ClInclude>
<ClInclude Include="mining\score_hyperidentity.h">
<Filter>mining</Filter>
</ClInclude>
<ClInclude Include="mining\score_addition.h">
<Filter>mining</Filter>
</ClInclude>
<ClInclude Include="contracts\qRWA.h">
<Filter>contracts</Filter>
</ClInclude>
<ClInclude Include="contracts\SupplyWatcher_old.h">
<Filter>contracts</Filter>
</ClInclude>
<ClInclude Include="oracle_core\snapshot_files.h">
<Filter>oracle_core</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="platform">
Expand Down
5 changes: 3 additions & 2 deletions src/assets/assets.h
Original file line number Diff line number Diff line change
Expand Up @@ -793,8 +793,8 @@ static void assetsEndEpoch()
ACQUIRE(universeLock);

// rebuild asset hash map, getting rid of all elements with zero shares
AssetRecord* reorgAssets = (AssetRecord*)reorgBuffer;
setMem(reorgAssets, ASSETS_CAPACITY * sizeof(AssetRecord), 0);
AssetRecord* reorgAssets = (AssetRecord*)commonBuffers.acquireBuffer(universeSizeInBytes);
setMem(reorgAssets, universeSizeInBytes, 0);
for (unsigned int i = 0; i < ASSETS_CAPACITY; i++)
{
if (assets[i].varStruct.possession.type == POSSESSION
Expand Down Expand Up @@ -874,6 +874,7 @@ static void assetsEndEpoch()
}
}
copyMem(assets, reorgAssets, ASSETS_CAPACITY * sizeof(AssetRecord));
commonBuffers.releaseBuffer(reorgAssets);

setMem(assetChangeFlags, ASSETS_CAPACITY / 8, 0xFF);

Expand Down
201 changes: 178 additions & 23 deletions src/common_buffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,200 @@
#include "platform/global_var.h"
#include "platform/memory_util.h"
#include "platform/assert.h"
#include "platform/concurrency.h"

#include "network_messages/entity.h"
#include "network_messages/assets.h"
#include "contract_core/pre_qpi_def.h"
#include "contracts/math_lib.h"


constexpr unsigned long long spectrumSizeInBytes = SPECTRUM_CAPACITY * sizeof(EntityRecord);
constexpr unsigned long long universeSizeInBytes = ASSETS_CAPACITY * sizeof(AssetRecord);
// TODO: check that max contract state size does not exceed size of spectrum or universe
constexpr unsigned long long reorgBufferSize = (spectrumSizeInBytes >= universeSizeInBytes) ? spectrumSizeInBytes : universeSizeInBytes;
constexpr unsigned long long defaultCommonBuffersSize = math_lib::max(MAX_CONTRACT_STATE_SIZE, math_lib::max(spectrumSizeInBytes, universeSizeInBytes));

// Buffer used for reorganizing spectrum and universe hash maps, currently also used as scratchpad buffer for contracts
// Buffer(s) used for:
// - reorganizing spectrum and universe hash maps (tick processor)
// - scratchpad buffer used internally in QPI::Collection, QPI::HashMap, QPI::HashSet,
// QPI::ProposalAndVotingByShareholders
// (often used in contract processor which does not run concurrently with tick processor, but now also used outside
// of contracts, e.g. pendingTxsPool.add() running in request processor may trigger Collection::_rebuild() which
// uses scratchpad)
// - building oracle transactions in processTick() in tick processor
// - calculateStableComputorIndex() in tick processor
// - saving and loading of logging state
// - DustBurnLogger used in increaseEnergy() in tick / contract processor
// Must be large enough to fit any contract, full spectrum, and full universe!
// No locking! Can be used in tick processor or contract processor.
// May be only used in main processor if tick/contract processor is paused or not started yet.
GLOBAL_VAR_DECL void* reorgBuffer GLOBAL_VAR_INIT(nullptr);
class CommonBuffers
{
public:
// Allocate common buffers. With count > 1, multiple buffers may be used concurrently. The maximum buffer size
// that can be acquired is given by size.
bool init(unsigned int count, unsigned long long size = defaultCommonBuffersSize)
{
if (!count || !size)
return false;

// soft limit, just to detect mistakes in usage like init(sizeof(Object))
ASSERT(count < 16);

// memory layout of buffer: sub buffer pointers | sub buffer locks | sub buffer 1 | sub buffer 2 | ...
unsigned char* buffer = nullptr;
const unsigned long long ptrSize = count * sizeof(unsigned char*);
const unsigned long long lockSize = (count + 7) / 8;
const unsigned long long bufSize = count * size;

if (!allocPoolWithErrorLog(L"commonBuffers", ptrSize + lockSize + bufSize, (void**)&buffer, __LINE__))
{
return false;
}

static bool initCommonBuffers()
{
if (!allocPoolWithErrorLog(L"reorgBuffer", reorgBufferSize, (void**)&reorgBuffer, __LINE__))
bufferCount = count;
subBufferSize = size;
subBufferPtr = (unsigned char**)buffer;
subBufferLock = (volatile char*)(buffer + ptrSize);
unsigned char* subBuf = buffer + ptrSize + lockSize;
for (unsigned int i = 0; i < count; ++i)
{
subBufferPtr[i] = subBuf;
subBuf += size;
}

return true;
}

// Free common buffers.
void deinit()
{
return false;
if (subBufferPtr)
{
freePool(subBufferPtr);
subBufferPtr = nullptr;
subBufferLock = nullptr;
subBufferSize = 0;
bufferCount = 0;
waitingCount = 0;
maxWaitingCount = 0;
invalidReleaseCount = 0;
}
}

return true;
}

static void deinitCommonBuffers()
{
if (reorgBuffer)
// Get buffer of given size.
// Returns nullptr if size is too big. Otherwise may block until buffer is available.
// Does not init buffer! Buffer needs to be released with releaseBuffer() after use.
void* acquireBuffer(unsigned long long size)
{
ASSERT(subBufferLock && subBufferPtr);
#if !defined(NO_UEFI)
ASSERT(size <= subBufferSize);
#endif
if (size > subBufferSize)
return nullptr;

// shortcut for default case
if (TRY_ACQUIRE(subBufferLock[0]))
{
return subBufferPtr[0];
}

long cnt = _InterlockedIncrement(&waitingCount);
if (maxWaitingCount < cnt)
maxWaitingCount = cnt;

unsigned int i = 0;
BEGIN_WAIT_WHILE(TRY_ACQUIRE(subBufferLock[i]) == false)
{
++i;
if (i >= bufferCount)
i = 0;
}
END_WAIT_WHILE();

_InterlockedDecrement(&waitingCount);

return subBufferPtr[i];
}

// Release buffer that was acquired with acquireBuffer() before.
void releaseBuffer(void* buffer)
{
ASSERT(subBufferLock && subBufferPtr && buffer);

// shortcut for default case
if (subBufferPtr[0] == buffer)
{
if (subBufferLock[0])
RELEASE(subBufferLock[0]);
else
++invalidReleaseCount;
return;
}

// find buffer
unsigned int bufferIdx = 1;
while (bufferIdx < bufferCount && subBufferPtr[bufferIdx] != buffer)
++bufferIdx;

// invalid pointer passed?
#if !defined(NO_UEFI)
ASSERT(bufferIdx < bufferCount);
ASSERT(subBufferLock[bufferIdx]);
#endif
if (bufferIdx >= bufferCount || !subBufferLock[bufferIdx])
{
++invalidReleaseCount;
return;
}

// release buffer
RELEASE(subBufferLock[bufferIdx]);
}

// Heuristics how many processors were waiting for a buffer in parallel (for deciding the count of buffers)
long getMaxWaitingProcessorCount() const
{
return maxWaitingCount;
}

// Counter of invalid release calls as an indicator if debugging is needed
long getInvalidReleaseCount() const
{
freePool(reorgBuffer);
reorgBuffer = nullptr;
return invalidReleaseCount;
}

// Returns number of buffers currently acquired
unsigned int acquiredBuffers() const
{
unsigned int count = 0;
for (unsigned int i = 0; i < bufferCount; ++i)
if (subBufferLock[i])
++count;
return count;
}

protected:
unsigned char** subBufferPtr = nullptr;
volatile char* subBufferLock = nullptr;
unsigned long long subBufferSize = 0;
unsigned int bufferCount = 0;
volatile long waitingCount = 0;
long maxWaitingCount = 0;
long invalidReleaseCount = 0;
};


GLOBAL_VAR_DECL CommonBuffers commonBuffers;


static void* __acquireScratchpad(unsigned long long size, bool initZero = true)
{
void* ptr = commonBuffers.acquireBuffer(size);
if (ptr && initZero)
setMem(ptr, size, 0);
return ptr;
}

static void* __scratchpad(unsigned long long sizeToMemsetZero)
static void __releaseScratchpad(void* ptr)
{
ASSERT(sizeToMemsetZero <= reorgBufferSize);
if (sizeToMemsetZero)
setMem(reorgBuffer, sizeToMemsetZero, 0);
return reorgBuffer;
commonBuffers.releaseBuffer(ptr);
}
Loading