Skip to content

Commit bcc5531

Browse files
authored
Merge pull request #758 from qubic/release/release-278
* Adds Oracles to the core * Remove dependency from QBAY and NOSTROMO to QUOTTERY datetime * Solves issue with Unions for non-MSVC * Fix revenue of computors to 100% due to potential mid-epoch updates * Increase ADDITION_SOLUTION_THRESHOLD_DEFAULT to 74196
2 parents 6770887 + 92a3eee commit bcc5531

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+6836
-677
lines changed

doc/contracts_proposals.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ struct QUTIL
120120
// Your code should set the state variable that the proposal is about to the accepted value.
121121
// This can be done as in this example taken from QUTIL:
122122
123-
switch (input.proposal.variableOptions.variable)
123+
switch (input.proposal.data.variableOptions.variable)
124124
{
125125
case 0:
126126
state.smt1InvocationFee = input.acceptedValue;
@@ -348,7 +348,7 @@ PRIVATE_PROCEDURE_WITH_LOCALS(FinalizeShareholderStateVarProposals)
348348
if (locals.p.acceptedOption <= 0)
349349
continue;
350350

351-
locals.p.acceptedValue = locals.p.proposal.variableOptions.value;
351+
locals.p.acceptedValue = locals.p.proposal.data.variableOptions.value;
352352

353353
CALL(FinalizeShareholderProposalSetStateVar, locals.p, output);
354354
}
@@ -376,8 +376,8 @@ PUBLIC_PROCEDURE(SetShareholderProposal)
376376
{
377377
// check proposal input and fees
378378
if (qpi.invocationReward() < setProposalFeeVarOrValue || (input.epoch
379-
&& (input.type != ProposalTypes::VariableYesNo || input.variableOptions.variable >= numFeeStateVariables
380-
|| input.variableOptions.value < 0)))
379+
&& (input.type != ProposalTypes::VariableYesNo || input.data.variableOptions.variable >= numFeeStateVariables
380+
|| input.data.variableOptions.value < 0)))
381381
{
382382
// error -> reimburse invocation reward
383383
qpi.transfer(qpi.invocator(), qpi.invocationReward());

doc/protocol.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ The network message types are defined in a single `enum` in [src/network_message
1313
The type number is the identifier used in `RequestResponseHeader` (defined in `header.h`).
1414
The type number is usually available from the network message type via the `static constexpr unsigned char type()` method.
1515

16+
17+
## List of special transaction types
18+
19+
Transactions with destination `NULL_ID` (32 bytes all-zero) are handled by the system.
20+
The following transaction types (`tx->inputType`) are defined:
21+
22+
- Vote counter transaction, type 1, defined in `src/vote_counter.h`.
23+
- `MiningSolutionTransaction`, type 2, defined in `src/mining/mining.h`.
24+
- `FileHeaderTransaction`, type 3, defined in `src/files/files.h`.
25+
- `FileFragmentTransactionPrefix`, type 4, defined in `src/files/files.h`.
26+
- `FileTrailerTransaction`, type 5, defined in `src/files/files.h`.
27+
- `OracleReplyCommitTransactionPrefix`, type 6, defined in `src/oracle_core/oracle_transactions.h`.
28+
- `OracleReplyRevealTransactionPrefix`, type 7, defined in `src/oracle_core/oracle_transactions.h`.
29+
- `CustomMiningSolutionTransaction`, type 8, defined in `src/mining/mining.h`.
30+
- `ExecutionFeeReportTransactionPrefix`, type 9, defined in `src/network_messages/execution_fees.h`.
31+
- `OracleUserQueryTransactionPrefix`, type 10, defined in `src/oracle_core/oracle_transactions.h`.
32+
33+
1634
## Peer Sharing
1735

1836
Peers are identified by IPv4 addresses in context of peer sharing.

src/Qubic.vcxproj

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<ClInclude Include="contract_core\qpi_collection_impl.h" />
6363
<ClInclude Include="contract_core\qpi_ipo_impl.h" />
6464
<ClInclude Include="contract_core\qpi_mining_impl.h" />
65+
<ClInclude Include="contract_core\qpi_oracle_impl.h" />
6566
<ClInclude Include="contract_core\qpi_spectrum_impl.h" />
6667
<ClInclude Include="contract_core\qpi_system_impl.h" />
6768
<ClInclude Include="contract_core\qpi_hash_map_impl.h" />
@@ -92,13 +93,20 @@
9293
<ClInclude Include="network_messages\execution_fees.h" />
9394
<ClInclude Include="network_messages\header.h" />
9495
<ClInclude Include="network_messages\logging.h" />
96+
<ClInclude Include="network_messages\oracles.h" />
9597
<ClInclude Include="network_messages\public_peers.h" />
9698
<ClInclude Include="network_messages\special_command.h" />
9799
<ClInclude Include="network_messages\system_info.h" />
98100
<ClInclude Include="network_messages\tick.h" />
99101
<ClInclude Include="network_messages\transactions.h" />
100-
<ClInclude Include="oracles\oracle_machines.h" />
101-
<ClInclude Include="oracles\Price.h" />
102+
<ClInclude Include="oracle_core\core_om_network_messages.h" />
103+
<ClInclude Include="oracle_core\net_msg_impl.h" />
104+
<ClInclude Include="oracle_core\oracle_engine.h" />
105+
<ClInclude Include="oracle_core\oracle_interfaces_def.h" />
106+
<ClInclude Include="oracle_core\oracle_transactions.h" />
107+
<ClInclude Include="oracle_core\snapshot_files.h" />
108+
<ClInclude Include="oracle_interfaces\Mock.h" />
109+
<ClInclude Include="oracle_interfaces\Price.h" />
102110
<ClInclude Include="platform\assert.h" />
103111
<ClInclude Include="platform\concurrency.h" />
104112
<ClInclude Include="four_q.h" />
@@ -110,6 +118,7 @@
110118
<ClInclude Include="platform\file_io.h" />
111119
<ClInclude Include="platform\console_logging.h" />
112120
<ClInclude Include="platform\common_types.h" />
121+
<ClInclude Include="platform\memory_util.h" />
113122
<ClInclude Include="platform\profiling.h" />
114123
<ClInclude Include="platform\quorum_value.h" />
115124
<ClInclude Include="platform\random.h" />
@@ -123,7 +132,6 @@
123132
<ClInclude Include="score.h" />
124133
<ClInclude Include="platform\m256.h" />
125134
<ClInclude Include="platform\memory.h" />
126-
<ClInclude Include="platform\memory-util.h" />
127135
<ClInclude Include="score_cache.h" />
128136
<ClInclude Include="spectrum\special_entities.h" />
129137
<ClInclude Include="spectrum\spectrum.h" />

src/Qubic.vcxproj.filters

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,6 @@
182182
<ClInclude Include="contracts\ComputorControlledFund.h">
183183
<Filter>contracts</Filter>
184184
</ClInclude>
185-
<ClInclude Include="oracles\Price.h">
186-
<Filter>oracles</Filter>
187-
</ClInclude>
188-
<ClInclude Include="oracles\oracle_machines.h">
189-
<Filter>oracles</Filter>
190-
</ClInclude>
191185
<ClInclude Include="files\files.h">
192186
<Filter>files</Filter>
193187
</ClInclude>
@@ -230,7 +224,6 @@
230224
<ClInclude Include="contracts\TestExampleB.h">
231225
<Filter>contracts</Filter>
232226
</ClInclude>
233-
<ClInclude Include="platform\memory-util.h" />
234227
<ClInclude Include="ticking\ticking.h">
235228
<Filter>ticking</Filter>
236229
</ClInclude>
@@ -315,12 +308,42 @@
315308
<ClInclude Include="contract_core\pre_qpi_def.h">
316309
<Filter>contract_core</Filter>
317310
</ClInclude>
311+
<ClInclude Include="oracle_core\oracle_engine.h">
312+
<Filter>oracle_core</Filter>
313+
</ClInclude>
314+
<ClInclude Include="oracle_core\core_om_network_messages.h">
315+
<Filter>oracle_core</Filter>
316+
</ClInclude>
317+
<ClInclude Include="oracle_core\oracle_interfaces_def.h">
318+
<Filter>oracle_core</Filter>
319+
</ClInclude>
320+
<ClInclude Include="oracle_core\oracle_transactions.h">
321+
<Filter>oracle_core</Filter>
322+
</ClInclude>
323+
<ClInclude Include="oracle_interfaces\Price.h">
324+
<Filter>oracle_interfaces</Filter>
325+
</ClInclude>
326+
<ClInclude Include="platform\memory_util.h">
327+
<Filter>platform</Filter>
328+
</ClInclude>
329+
<ClInclude Include="contract_core\qpi_oracle_impl.h">
330+
<Filter>contract_core</Filter>
331+
</ClInclude>
318332
<ClInclude Include="network_messages\network_message_type.h">
319333
<Filter>network_messages</Filter>
320334
</ClInclude>
335+
<ClInclude Include="network_messages\oracles.h">
336+
<Filter>network_messages</Filter>
337+
</ClInclude>
338+
<ClInclude Include="oracle_core\net_msg_impl.h">
339+
<Filter>oracle_core</Filter>
340+
</ClInclude>
321341
<ClInclude Include="contract_core\execution_time_accumulator.h">
322342
<Filter>contract_core</Filter>
323343
</ClInclude>
344+
<ClInclude Include="oracle_interfaces\Mock.h">
345+
<Filter>oracle_interfaces</Filter>
346+
</ClInclude>
324347
<ClInclude Include="mining\score_common.h">
325348
<Filter>mining</Filter>
326349
</ClInclude>
@@ -336,6 +359,12 @@
336359
<ClInclude Include="contracts\qRWA.h">
337360
<Filter>contracts</Filter>
338361
</ClInclude>
362+
<ClInclude Include="contracts\SupplyWatcher_old.h">
363+
<Filter>contracts</Filter>
364+
</ClInclude>
365+
<ClInclude Include="oracle_core\snapshot_files.h">
366+
<Filter>oracle_core</Filter>
367+
</ClInclude>
339368
</ItemGroup>
340369
<ItemGroup>
341370
<Filter Include="platform">
@@ -356,9 +385,6 @@
356385
<Filter Include="addons">
357386
<UniqueIdentifier>{d409258b-a63c-443f-8c7a-918c14f192a6}</UniqueIdentifier>
358387
</Filter>
359-
<Filter Include="oracles">
360-
<UniqueIdentifier>{74ae36a2-d776-43e9-a6b9-f41412f5fdd2}</UniqueIdentifier>
361-
</Filter>
362388
<Filter Include="files">
363389
<UniqueIdentifier>{ed6ee181-230c-46ac-91bd-234b9081e36f}</UniqueIdentifier>
364390
</Filter>
@@ -377,10 +403,16 @@
377403
<Filter Include="spectrum">
378404
<UniqueIdentifier>{2f27aed7-b9b8-4b8c-a70a-90f18385b167}</UniqueIdentifier>
379405
</Filter>
406+
<Filter Include="oracle_interfaces">
407+
<UniqueIdentifier>{ec5bb5e9-cc03-4d2f-bbe4-40d60c3df1c8}</UniqueIdentifier>
408+
</Filter>
409+
<Filter Include="oracle_core">
410+
<UniqueIdentifier>{a42dd6f2-617c-4fbc-b3ec-f51975e5c447}</UniqueIdentifier>
411+
</Filter>
380412
</ItemGroup>
381413
<ItemGroup>
382414
<MASM Include="platform\custom_stack.asm">
383415
<Filter>platform</Filter>
384416
</MASM>
385417
</ItemGroup>
386-
</Project>
418+
</Project>

src/contract_core/contract_def.h

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
#include "contracts/qpi.h"
1616
#include "qpi_proposal_voting.h"
1717

18+
// make interfaces to oracles available for all contracts
19+
#include "oracle_core/oracle_interfaces_def.h"
20+
1821
#define QX_CONTRACT_INDEX 1
1922
#define CONTRACT_INDEX QX_CONTRACT_INDEX
2023
#define CONTRACT_STATE_TYPE QX
@@ -479,10 +482,55 @@ static void initializeContracts()
479482
REGISTER_CONTRACT_FUNCTIONS_AND_PROCEDURES(TESTEXD);
480483

481484
// fill execution fee reserves for test contracts
482-
setContractFeeReserve(TESTEXA_CONTRACT_INDEX, 10000);
483-
setContractFeeReserve(TESTEXB_CONTRACT_INDEX, 10000);
484-
setContractFeeReserve(TESTEXC_CONTRACT_INDEX, 10000);
485-
setContractFeeReserve(TESTEXD_CONTRACT_INDEX, 10000);
485+
setContractFeeReserve(TESTEXA_CONTRACT_INDEX, 100000000000);
486+
setContractFeeReserve(TESTEXB_CONTRACT_INDEX, 100000000000);
487+
setContractFeeReserve(TESTEXC_CONTRACT_INDEX, 100000000000);
488+
setContractFeeReserve(TESTEXD_CONTRACT_INDEX, 100000000000);
486489
#endif
487490
}
488491

492+
// Class for registering and looking up user procedures independently of input type, for example for notifications
493+
class UserProcedureRegistry
494+
{
495+
public:
496+
struct UserProcedureData
497+
{
498+
USER_PROCEDURE procedure;
499+
unsigned int contractIndex;
500+
unsigned int localsSize;
501+
unsigned short inputSize;
502+
unsigned short outputSize;
503+
};
504+
505+
void init()
506+
{
507+
setMemory(*this, 0);
508+
}
509+
510+
bool add(unsigned int procedureId, const UserProcedureData& data)
511+
{
512+
const unsigned int cnt = (unsigned int)idToIndex.population();
513+
if (cnt >= idToIndex.capacity())
514+
return false;
515+
516+
copyMemory(userProcData[cnt], data);
517+
idToIndex.set(procedureId, cnt);
518+
519+
return true;
520+
}
521+
522+
const UserProcedureData* get(unsigned int procedureId) const
523+
{
524+
unsigned int idx;
525+
if (!idToIndex.get(procedureId, idx))
526+
return nullptr;
527+
return userProcData + idx;
528+
}
529+
530+
protected:
531+
UserProcedureData userProcData[MAX_CONTRACT_PROCEDURES_REGISTERED];
532+
QPI::HashMap<unsigned int, unsigned int, MAX_CONTRACT_PROCEDURES_REGISTERED> idToIndex;
533+
};
534+
535+
// For registering and looking up user procedures independently of input type (for notifications), initialized by initContractExec()
536+
GLOBAL_VAR_DECL UserProcedureRegistry* userProcedureRegistry GLOBAL_VAR_INIT(nullptr);

src/contract_core/contract_exec.h

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ static bool initContractExec()
192192
if (!contractActionTracker.allocBuffer())
193193
return false;
194194

195+
if (!allocPoolWithErrorLog(L"userProcedureRegistry", sizeof(*userProcedureRegistry), (void**)&userProcedureRegistry, __LINE__))
196+
{
197+
return false;
198+
}
199+
userProcedureRegistry->init();
200+
195201
return true;
196202
}
197203

@@ -218,6 +224,9 @@ static void deinitContractExec()
218224
freePool(contractStateChangeFlags);
219225
}
220226

227+
if (userProcedureRegistry)
228+
freePool(userProcedureRegistry);
229+
221230
contractActionTracker.freeBuffer();
222231
}
223232

@@ -917,6 +926,16 @@ void QPI::QpiContextForInit::__registerUserProcedure(USER_PROCEDURE userProcedur
917926
contractUserProcedureLocalsSizes[_currentContractIndex][inputType] = localsSize;
918927
}
919928

929+
void QPI::QpiContextForInit::__registerUserProcedureNotification(USER_PROCEDURE userProcedure, unsigned int procedureId, unsigned short inputSize, unsigned short outputSize, unsigned int localsSize) const
930+
{
931+
ASSERT(userProcedureRegistry);
932+
if (!userProcedureRegistry->add(procedureId, { userProcedure, _currentContractIndex, localsSize, inputSize, outputSize }))
933+
{
934+
#if !defined(NDEBUG)
935+
addDebugMessage(L"__registerUserProcedureNotification() failed. You should increase MAX_CONTRACT_PROCEDURES_REGISTERED.");
936+
#endif
937+
}
938+
}
920939

921940

922941
// QPI context used to call contract system procedure from qubic core (contract processor)
@@ -1266,15 +1285,6 @@ struct QpiContextUserFunctionCall : public QPI::QpiContextFunctionCall
12661285
};
12671286

12681287

1269-
struct UserProcedureNotification
1270-
{
1271-
unsigned int contractIndex;
1272-
USER_PROCEDURE procedure;
1273-
const void* inputPtr;
1274-
unsigned short inputSize;
1275-
unsigned int localsSize;
1276-
};
1277-
12781288
// QPI context used to call contract user procedure as a notification from qubic core (contract processor).
12791289
// This means, it isn't triggered by a transaction, but following an event after having setup the notification
12801290
// callback in the contract code.
@@ -1283,16 +1293,16 @@ struct UserProcedureNotification
12831293
// The procedure pointer, the expected inputSize, and the expected localsSize, which are passed via
12841294
// UserProcedureNotification, must be consistent. The code using notifications is responible for ensuring that.
12851295
// Use cases:
1286-
// - oracle notifications (managed by oracleEngine)
1296+
// - oracle notifications (managed by oracleEngine and userProcedureRegistry)
12871297
struct QpiContextUserProcedureNotificationCall : public QPI::QpiContextProcedureCall
12881298
{
1289-
QpiContextUserProcedureNotificationCall(const UserProcedureNotification& notification) : QPI::QpiContextProcedureCall(notif.contractIndex, NULL_ID, 0, USER_PROCEDURE_NOTIFICATION_CALL), notif(notification)
1299+
QpiContextUserProcedureNotificationCall(const UserProcedureRegistry::UserProcedureData& notification) : QPI::QpiContextProcedureCall(notification.contractIndex, NULL_ID, 0, USER_PROCEDURE_NOTIFICATION_CALL), notif(notification)
12901300
{
12911301
contractActionTracker.init();
12921302
}
12931303

12941304
// Run user procedure notification
1295-
void call()
1305+
void call(const void* inputPtr)
12961306
{
12971307
ASSERT(_currentContractIndex < contractCount);
12981308

@@ -1330,7 +1340,7 @@ struct QpiContextUserProcedureNotificationCall : public QPI::QpiContextProcedure
13301340
__qpiAbort(ContractErrorAllocInputOutputFailed);
13311341
}
13321342
char* locals = input + notif.inputSize;
1333-
copyMem(input, notif.inputPtr, notif.inputSize);
1343+
copyMem(input, inputPtr, notif.inputSize);
13341344
setMem(locals, notif.localsSize, 0);
13351345

13361346
// call user procedure
@@ -1353,5 +1363,5 @@ struct QpiContextUserProcedureNotificationCall : public QPI::QpiContextProcedure
13531363
}
13541364

13551365
private:
1356-
const UserProcedureNotification& notif;
1366+
const UserProcedureRegistry::UserProcedureData& notif;
13571367
};

src/contract_core/execution_time_accumulator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class ExecutionTimeAccumulator
5959
math_lib::sadd(contractExecutionTimePerPhase[contractExecutionTimeActiveArrayIndex][contractIndex], timeMicroSeconds);
6060
RELEASE(lock);
6161

62-
#if !defined(NDEBUG) && !defined(NO_UEFI)
62+
#if !defined(NDEBUG) && !defined(NO_UEFI) && 0
6363
CHAR16 dbgMsgBuf[128];
6464
setText(dbgMsgBuf, L"Execution time added for contract ");
6565
appendNumber(dbgMsgBuf, contractIndex, FALSE);

src/contract_core/pre_qpi_def.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ constexpr unsigned short MAX_NESTED_CONTRACT_CALLS = 10;
2727
// Size of the contract action tracker, limits the number of transfers that one contract call can execute.
2828
constexpr unsigned long long CONTRACT_ACTION_TRACKER_SIZE = 16 * 1024 * 1024;
2929

30+
// Maximum number of contract procedures that may be registered, e.g. for user procedure notifications
31+
constexpr unsigned int MAX_CONTRACT_PROCEDURES_REGISTERED = 16 * 1024;
32+
3033

3134
static void __beginFunctionOrProcedure(const unsigned int); // TODO: more human-readable form of function ID?
3235
static void __endFunctionOrProcedure(const unsigned int);

0 commit comments

Comments
 (0)