mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-04 18:55:49 +00:00
re-write of governance hook, compiling but untested
This commit is contained in:
@@ -125,6 +125,13 @@ hook_param(
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
otxn_param(
|
||||
uint32_t write_ptr,
|
||||
uint32_t write_len,
|
||||
uint32_t read_ptr,
|
||||
uint32_t read_len);
|
||||
|
||||
extern int64_t
|
||||
hook_param_set(
|
||||
uint32_t read_ptr,
|
||||
|
||||
433
hook/govern.c
433
hook/govern.c
@@ -3,328 +3,386 @@
|
||||
if (!(x))\
|
||||
rollback(SBUF("Govern: Assertion failed."),__LINE__);
|
||||
|
||||
#define INIT_MEMBER_COUNT 5
|
||||
#define MAX_MEMBER_COUNT 20
|
||||
#define INIT_AMOUNT 50000000000000ULL // 50MM
|
||||
#define SEAT_COUNT 20
|
||||
|
||||
// test accounts only, must be replaced with real accounts prior to launch
|
||||
uint8_t initial_members[] =
|
||||
{
|
||||
// the first 12 bytes of each is padding to allow a reverse key
|
||||
// to be easily set for the account id
|
||||
#define HOOK_MAX 10 // maximum number of hooks on an account
|
||||
|
||||
// acc 0 - rJmkqLL4mqrc9kbP5Ztkq4TvVamYNetedp
|
||||
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U, 0x00U, 0x00U,
|
||||
0xC2U,0xF1U,0x07U,0xE6U,0xE8U,0x64U,0xD3U,0x90U,0x6DU,0x0AU,
|
||||
0x08U,0x84U,0x46U,0xFDU,0xDFU,0x8AU,0x7BU,0x2FU,0x56U,0x9CU,
|
||||
/**
|
||||
* Xahau Governance Hook
|
||||
*
|
||||
* Hook Parameters:
|
||||
* Parameter Name: {'I', 'M', 'C'}
|
||||
* Parameter Value: Initial Member Count <1 byte>
|
||||
*
|
||||
* Parameter Name: {'I', 'D', 'A'}
|
||||
* Parameter Value: Initial Distribution Amount to each initial member <8 byte BE drops>
|
||||
*
|
||||
* Parameter Name: {'I', 'R', 'R'}
|
||||
* Parameter Value: Initial Reward Rate <8 byte XFL fraction between 0 and 1, LE>
|
||||
*
|
||||
* Parameter Name: {'I', 'R', 'D'}
|
||||
* Parameter Value: Initial Reward Delay <8 byte LE int seconds between rewards>
|
||||
*
|
||||
* Parameter Name: {'I', 'S', '\0'}
|
||||
* Parameter Value: Initial seat #0's member's 20 byte Account ID.
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* Hook State:
|
||||
* State Key: {0..0, 'M', 'C'}
|
||||
* State Data: Current member count <1 byte>
|
||||
*
|
||||
* State Key: {0..0, 'R', 'R'}
|
||||
* State Data: Current reward rate <8 byte LE XFL>
|
||||
*
|
||||
* State Key: {0..0, 'R', 'D'}
|
||||
* State Data: Current reward delay <8 byte LE int>
|
||||
*
|
||||
* State Key: {0..0, '\0 + seat id'}
|
||||
* State Data: 20 byte account ID for the member who occupies this seat. If absent unoccupied.
|
||||
*
|
||||
* State Key: {0..0, <20 byte account id>}
|
||||
* State Data: Seat number this member occupies <1 byte>
|
||||
*
|
||||
* State Key: {'V', 'H|R|M' <topic type>, '\0 + topic id', 0..0, <member accid>}
|
||||
* State Data: A vote by a member for a topic and topic data
|
||||
*
|
||||
* State Key: {'C', 'H|R|M' <topic type>, '\0 + topic id', 0*, <front truncated topic data>}
|
||||
* State Data: The number of members who have voted for that topic data and topic combination <1 byte>
|
||||
*
|
||||
* Hook Invocation:
|
||||
* ttINVOKE:
|
||||
* First time:
|
||||
* Behaviour: Setup hook, fund initial accounts, end (accept).
|
||||
*
|
||||
* Subsequent:
|
||||
* Behaviour: Vote on a topic, if the votes meet the topic vote threshold, action the topic.
|
||||
*
|
||||
* Parameter Name: {'T'}
|
||||
* Parameter Value: The topic to vote on <2 bytes>
|
||||
* { 'S|H' (seat, hook), '\0 + topic id' }, or
|
||||
* { 'R' (reward), 'R|D' (rate, delay) }
|
||||
*
|
||||
* Parameter Name: {'V'}
|
||||
* Parameter Value: The data to vote for this topic (accid, hook hash, reward rate/delay)
|
||||
**/
|
||||
|
||||
// acc 1 - rEVGdPT6ACPPcXGNwNeeYYtoRTKFaqhEi4
|
||||
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U, 0x00U, 0x00U,
|
||||
0x9EU,0xEAU,0x73U,0xF5U,0xF0U,0x62U,0x7EU,0x69U,0x39U,0x7EU,
|
||||
0xC7U,0x2EU,0x9AU,0x3CU,0x78U,0x04U,0xC0U,0xF2U,0xBFU,0x69U,
|
||||
#define SVAR(x) x, sizeof(x)
|
||||
|
||||
// acc 2 - rJi1kZsQthVqVPLmQdTmG8AtiAKk26J9ST
|
||||
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U, 0x00U, 0x00U,
|
||||
0xC3U,0xE8U,0xE2U,0x9AU,0xB6U,0x28U,0x47U,0x27U,0x5CU,0xEDU,
|
||||
0x36U,0xEBU,0xF4U,0xE9U,0x28U,0xDCU,0x25U,0xA0U,0x7FU,0x24U,
|
||||
|
||||
// acc 3 - rHm34nx2QSJKXhe32NiNbsnrUSeZqDZMkg
|
||||
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U, 0x00U, 0x00U,
|
||||
0xB7U,0xDAU,0x76U,0x2DU,0xB9U,0x90U,0x2EU,0x85U,0x19U,0x96U,
|
||||
0x66U,0xB2U,0xE6U,0xC3U,0x00U,0x9CU,0x5EU,0x27U,0x57U,0x69U,
|
||||
|
||||
// acc 4 - rLc3URyuFpTqBAcPFK5J7c73h488ew79dH
|
||||
0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U,0x00U, 0x00U, 0x00U,
|
||||
0xD7U,0x0EU,0xF4U,0xD5U,0x02U,0x1CU,0x7CU,0x64U,0x6AU,0x98U,
|
||||
0xE8U,0x4FU,0x60U,0xFEU,0xD3U,0x64U,0xA0U,0x04U,0x45U,0x32U,
|
||||
};
|
||||
|
||||
// this is the xfl for 0.00333333333
|
||||
uint8_t initial_reward[] = // on key FF, 0..0
|
||||
{
|
||||
0x53U,0xCBU,0xD7U,0xA6U,0x25U,0x0DU,0x78U,0x80U
|
||||
};
|
||||
|
||||
uint8_t key[32];
|
||||
uint8_t account_field[32];
|
||||
uint8_t zero[32];
|
||||
|
||||
#define DONE()\
|
||||
#define DONE(x)\
|
||||
{\
|
||||
accept(0,0,(uint32_t)__LINE__);\
|
||||
accept(SVAR(x),(uint32_t)__LINE__);\
|
||||
}
|
||||
|
||||
#define TRACELINE()\
|
||||
{\
|
||||
uint8_t out[4];\
|
||||
out[0] = (__LINE__ >> 24U) & 0xFFU;\
|
||||
out[1] = (__LINE__ >> 16U) & 0xFFU;\
|
||||
out[2] = (__LINE__ >> 8U) & 0xFFU;\
|
||||
out[3] = (__LINE__ >> 0U) & 0xFFU;\
|
||||
trace(SBUF("Line upto:"), out, 4, 1);\
|
||||
}
|
||||
#define NOPE(x)\
|
||||
rollback(SBUF(x), __LINE__);
|
||||
|
||||
int64_t hook(uint32_t r)
|
||||
{
|
||||
_g(1,1);
|
||||
|
||||
uint8_t ttbuf[2];
|
||||
int64_t br = otxn_field(SBUF(ttbuf), sfTransactionType);
|
||||
uint32_t txntype = ((uint32_t)(ttbuf[0]) << 16U) + ((uint32_t)(ttbuf[1]));
|
||||
|
||||
if (txntype != 99) // ttINVOKE
|
||||
DONE();
|
||||
if (otxn_type() != 99) // ttINVOKE
|
||||
DONE("Governance: Passing non-Invoke txn. HookOn should be changed to avoid this.");
|
||||
|
||||
// get the account id
|
||||
ASSERT(otxn_field(account_field + 12, 20, sfAccount) == 20);
|
||||
uint8_t account_field[32];
|
||||
otxn_field(account_field + 12, 20, sfAccount);
|
||||
|
||||
uint8_t hook_accid[20];
|
||||
hook_account(SBUF(hook_accid));
|
||||
|
||||
// start of hook proper
|
||||
|
||||
|
||||
int64_t member_count = state(0,0, SBUF(key));
|
||||
// state key 0..0 contains the member count
|
||||
int64_t member_count = state(0,0, "MC", 2);
|
||||
|
||||
TRACEVAR(member_count);
|
||||
|
||||
// initial execution, setup hook
|
||||
if (member_count == DOESNT_EXIST)
|
||||
{
|
||||
etxn_reserve(INIT_MEMBER_COUNT);
|
||||
// gather hook parameters
|
||||
|
||||
int64_t imc, ida, irr, ird;
|
||||
if (hook_param(SVAR(imc), "IMC", 3) < 0)
|
||||
NOPE("Governance: Initial Member Count Parameter missing (IMC).");
|
||||
|
||||
if (hook_param(SVAR(ida), "IDA", 3) < 0)
|
||||
NOPE("Governance: Initial Distribution Amount Prameter missing (IDA).");
|
||||
|
||||
if (hook_param(SVAR(irr), "IRR", 3) < 0)
|
||||
NOPE("Governance: Initial Reward Rate Parameter missing (IRR).");
|
||||
|
||||
if (hook_param(SVAR(ird), "IRD", 3) < 0)
|
||||
NOPE("Governance: Initial Reward Delay Parameter miss (IRD).");
|
||||
|
||||
// sanity check parameters
|
||||
if (imc == 0)
|
||||
NOPE("Governance: Initial Member Count must be > 0.");
|
||||
|
||||
if (imc > SEAT_COUNT)
|
||||
NOPE("Governance: Initial Member Count must be <= Seat Count (20).");
|
||||
|
||||
if (ird == 0)
|
||||
NOPE("Governance: Initial Reward Delay must be > 0.");
|
||||
|
||||
etxn_reserve(imc);
|
||||
|
||||
// set member count
|
||||
int8_t imc = INIT_MEMBER_COUNT;
|
||||
ASSERT(state_set(&imc, 1, SBUF(key))); // member count is on the zero key
|
||||
ASSERT(state_set(SBUF(imc), "MC", 2));
|
||||
|
||||
// set reward rate
|
||||
key[0] = 0xFFU;
|
||||
ASSERT(state_set(SBUF(initial_reward), SBUF(key))); // interest rate is on the the FF, 0...0 key
|
||||
key[0] = 0;
|
||||
ASSERT(state_set(SVAR(irr), "RR", 2));
|
||||
|
||||
// set reward delay
|
||||
ASSERT(state_set(SVAR(ird), "RD", 2));
|
||||
|
||||
for (uint32_t i = 0; GUARD(INIT_MEMBER_COUNT), i < INIT_MEMBER_COUNT; ++i)
|
||||
for (uint8_t i = 0; GUARD(SEAT_COUNT), i < imc; ++i)
|
||||
{
|
||||
key[31] = i+1;
|
||||
uint8_t member_acc[20];
|
||||
uint8_t member_pkey[3] = {'I', 'S', i};
|
||||
if (hook_param(SBUF(member_acc), member_pkey, 3) != 20)
|
||||
NOPE("Governance: One or more initial member account ID's is missing");
|
||||
|
||||
// 0... X where X is member id started from 1
|
||||
// maps to the member's account ID
|
||||
// reverse key
|
||||
ASSERT(state_set(initial_members + (i * 32) + 12, 20, SBUF(key)) == 20);
|
||||
ASSERT(state_set(SBUF(member_acc), SVAR(i)) == 20);
|
||||
|
||||
// 0, 0... ACCOUNT ID maps to member_id (as above)
|
||||
// forward key
|
||||
ASSERT(state_set(key + 31, 1, initial_members + (i * 32), 32) == 1);
|
||||
ASSERT(state_set(SVAR(i), SBUF(member_acc)) == 1);
|
||||
|
||||
// emit initial
|
||||
uint8_t tx[PREPARE_PAYMENT_SIMPLE_SIZE];
|
||||
PREPARE_PAYMENT_SIMPLE(tx, INIT_AMOUNT, (initial_members + (i * 32) + 12), 0, 0);
|
||||
PREPARE_PAYMENT_SIMPLE(tx, ida, member_acc, 0, 0);
|
||||
|
||||
// emit the transaction
|
||||
uint8_t emithash[32];
|
||||
int64_t emit_result = emit(SBUF(emithash), SBUF(tx));
|
||||
ASSERT(emit_result > 0);
|
||||
TRACEVAR(emit_result);
|
||||
|
||||
}
|
||||
|
||||
DONE();
|
||||
DONE("Governance: Setup completed successfully.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// outgoing txns allowed
|
||||
if (BUFFER_EQUAL_20(hook_accid, account_field + 12))
|
||||
DONE();
|
||||
|
||||
|
||||
|
||||
DONE("Goverance: Passing outgoing txn.");
|
||||
|
||||
// otherwise a normal execution (not initial)
|
||||
// first let's check if the invoking party is a member
|
||||
|
||||
int64_t member_id = state(0,0,SBUF(account_field));
|
||||
ASSERT(member_id >= 0);
|
||||
int64_t member_id = state(0,0,account_field + 12, 20);
|
||||
if (member_id < 0)
|
||||
NOPE("Governance: You are not currently a governance member.");
|
||||
|
||||
// the only thing you can do is vote for a topic
|
||||
// the only thing a member can do is vote for a topic
|
||||
// so lets process their vote
|
||||
ASSERT(otxn_slot(1) == 1);
|
||||
ASSERT(slot_subfield(1, sfHookParameters, 2) == 2);
|
||||
// first parameter must contain the topic as key and the topic data as value
|
||||
ASSERT(slot_subarray(2, 0, 2) == 2);
|
||||
ASSERT(slot_subfield(2, sfHookParameterName, 3) == 3);
|
||||
ASSERT(slot_subfield(2, sfHookParameterValue, 4) == 4);
|
||||
|
||||
// { 'S|H|R', '\0 + topicid' }
|
||||
uint8_t topic[2];
|
||||
int64_t result = otxn_param(SBUF(topic), "T", 1);
|
||||
if (result != 2 || (
|
||||
topic[0] != 'S' && // topic type: seat
|
||||
topic[0] != 'H' && // topic type: hook
|
||||
topic[0] != 'R')) // topic type: reward
|
||||
NOPE("Governance: Valid TOPIC must be specified as otxn parameter.");
|
||||
|
||||
|
||||
if (topic[0] == 'S' && topic[1] > (SEAT_COUNT - 1) )
|
||||
NOPE("Governance: Valid seat topics are 0 through 19.");
|
||||
|
||||
if (topic[0] == 'H' && topic[1] > HOOK_MAX)
|
||||
NOPE("Governance: Valid hook topics are 0 through 9.");
|
||||
|
||||
if (topic[0] == 'R' && topic[1] != 'R' && topic[1] != 'D')
|
||||
NOPE("Governance: Valid reward topics are R (rate) and D (delay).");
|
||||
|
||||
uint8_t dump[1024];
|
||||
uint64_t dumpsize = slot(SBUF(dump), 4);
|
||||
trace(SBUF("dump"), dump, dumpsize, 1);
|
||||
|
||||
int64_t topic = slot(0,0, 3) & 0xFFU; // there's a high "size" byte because it's a VL
|
||||
TRACEVAR(topic);
|
||||
ASSERT(topic >= 1 && topic <= 25);
|
||||
|
||||
|
||||
uint8_t topic_data_buffer[44]; // this gives us some bytes on the front to play with to avoid buffer copies
|
||||
uint8_t* topic_data = topic_data_buffer + 12;;
|
||||
uint8_t topic_data[32];
|
||||
uint8_t topic_size =
|
||||
topic == 1 ? 8 :
|
||||
topic >= 2 && topic <= 5 ? 32 : 20;
|
||||
topic[0] == 'R' ? 8 : // reward topics are an 8 byte int/xfl
|
||||
topic[0] == 'H' ? 32 : // hook topics are a 32 byte hook hash
|
||||
20; // account topics are a 20 byte account ID
|
||||
|
||||
// reuse account_field to record vote
|
||||
account_field[0] = topic;
|
||||
uint8_t padding = 32 - topic_size;
|
||||
|
||||
// read canidate from ttINVOKE parameter
|
||||
ASSERT(slot(topic_data - 1, topic_size + 1, 4) == topic_size + 1);
|
||||
*(topic_data - 1) = 0; // this is the size byte for the VL
|
||||
result = otxn_param(topic_data + padding, topic_size, "V", 1);
|
||||
if (result != topic_size)
|
||||
NOPE("Governance: Missing or incorrect size of VOTE data for TOPIC type.");
|
||||
|
||||
|
||||
// get previous vote if any on this topic (1-25)
|
||||
|
||||
// reuse account_field to create vote key
|
||||
account_field[0] = 'V';
|
||||
account_field[1] = topic[0];
|
||||
account_field[2] = topic[1];
|
||||
|
||||
// get their previous vote if any on this topic
|
||||
uint8_t previous_topic_data[32];
|
||||
int64_t previous_topic_size = state(previous_topic_data, topic_size, SBUF(account_field));
|
||||
|
||||
// write vote to voting key
|
||||
ASSERT(state_set(topic_data, topic_size, SBUF(account_field)) == topic_size);
|
||||
int64_t previous_topic_size = state(previous_topic_data + padding, topic_size, SBUF(account_field));
|
||||
|
||||
// check if the vote they're making has already been cast before,
|
||||
// if it is identical to their existing vote for this topic then just end with tesSUCCESS
|
||||
if (previous_topic_size == topic_size && BUFFER_EQUAL_32(previous_topic_data, topic_data))
|
||||
DONE();
|
||||
DONE("Governance: Your vote is already cast this way for this topic.");
|
||||
|
||||
|
||||
// execution to here means the vote is different
|
||||
// we might have to decrement the old voting if they voted previously
|
||||
// and we will have to increment the new voting
|
||||
|
||||
|
||||
// decrement old counter
|
||||
// write vote to their voting key
|
||||
ASSERT(state_set(topic_data, topic_size, SBUF(account_field)) == topic_size);
|
||||
|
||||
// decrement old vote counter for this option
|
||||
if (previous_topic_size > 0)
|
||||
{
|
||||
uint8_t votes = 0;
|
||||
previous_topic_data[31] = topic;
|
||||
// override the first two bytes to turn it into a vote count key
|
||||
previous_topic_data[0] = 'C';
|
||||
previous_topic_data[1] = topic[0];
|
||||
previous_topic_data[2] = topic[1];
|
||||
|
||||
if (state(&votes, 1, SBUF(previous_topic_data)) && votes > 0)
|
||||
{
|
||||
votes--;
|
||||
ASSERT(state_set(&votes, 1, SBUF(previous_topic_data)));
|
||||
// delete the state entry if votes hit zero
|
||||
ASSERT(state_set(votes == 0 ? 0 : &votes, votes == 0 ? 0 : 1, SBUF(previous_topic_data)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// increment new counter
|
||||
// increment new counter
|
||||
uint8_t votes = 0;
|
||||
uint8_t last_byte = *(topic_data + 31);
|
||||
*(topic_data + 31) = topic;
|
||||
state(&votes, 1, topic_data, 32);
|
||||
votes++;
|
||||
ASSERT(state_set(&votes, 1, topic_data, 32));
|
||||
*(topic_data + 31) = last_byte;
|
||||
{
|
||||
// we're going to clobber the topic data to turn it into a vote count key
|
||||
// so store the first bytes
|
||||
uint64_t saved_data = *((uint64_t*)topic_data);
|
||||
topic_data[0] = 'C';
|
||||
topic_data[1] = topic[0];
|
||||
topic_data[2] = topic[1];
|
||||
|
||||
|
||||
// set this flag if the topic data is all zeros, it's important in some cases
|
||||
state(&votes, 1, SBUF(topic_data));
|
||||
votes++;
|
||||
ASSERT(state_set(&votes, 1, SBUF(topic_data)));
|
||||
|
||||
// restore the saved bytes
|
||||
*((uint64_t*)topic_data) = saved_data;
|
||||
}
|
||||
|
||||
|
||||
// set this flag if the topic data is all zeros
|
||||
uint8_t zero[32];
|
||||
int topic_data_zero = BUFFER_EQUAL_32(topic_data, zero);
|
||||
|
||||
TRACEVAR(topic_data_zero);
|
||||
TRACEVAR(votes);
|
||||
TRACEVAR(member_count);
|
||||
TRACEVAR(topic);
|
||||
|
||||
trace(SBUF("topic"), topic, 2, 1);
|
||||
|
||||
// now check if we hit threshold
|
||||
if (votes == member_count || // 100% required for topics 1 - 5 (interest rate, hooks0-3)
|
||||
(topic > 5 && votes >= (member_count * 0.8))) // 80% required for membership voting
|
||||
if (votes < (topic[0] == 'M' ? (member_count * 0.8) : member_count))
|
||||
DONE("Governance: Vote recorded. Not yet enough votes to action.");
|
||||
|
||||
// 100%/80% threshold as needed is reached
|
||||
// action vote
|
||||
|
||||
TRACESTR("Actioning votes");
|
||||
|
||||
// RH UPTO:
|
||||
switch (topic[0])
|
||||
{
|
||||
// 100%/80% threshold as needed is reached
|
||||
// action vote
|
||||
|
||||
TRACESTR("Actioning votes");
|
||||
|
||||
if (topic == 1)
|
||||
case 'R':
|
||||
{
|
||||
// change reward %
|
||||
key[0] = 0xFFU;
|
||||
ASSERT(state_set(topic_data, 8, SBUF(key))); // interest rate is on the the FF, 0...0 key
|
||||
// reward topics
|
||||
ASSERT(state_set(topic_data, 8, SBUF(topic))); // interest rate is on the the FF, 0...0 key
|
||||
if (topic[1] == 'R')
|
||||
DONE("Governance: Reward rate change actioned!");
|
||||
|
||||
DONE("Governance: Reward delay change actioned!");
|
||||
}
|
||||
else if (topic <= 5)
|
||||
|
||||
case 'H':
|
||||
{
|
||||
// set hook hash
|
||||
uint8_t pos = topic - 2;
|
||||
|
||||
// hook topics
|
||||
|
||||
// first get the hook ledget object
|
||||
uint8_t keylet[34];
|
||||
ASSERT(util_keylet(SBUF(keylet), KEYLET_HOOK, SBUF(hook_accid), 0,0,0,0) == 34);
|
||||
ASSERT(slot_set(SBUF(keylet), 5) == 5);
|
||||
util_keylet(SBUF(keylet), KEYLET_HOOK, SBUF(hook_accid), 0,0,0,0);
|
||||
slot_set(SBUF(keylet), 5);
|
||||
|
||||
// now get the hooks array
|
||||
ASSERT(slot_subfield(5, sfHooks, 6) == 6);
|
||||
slot_subfield(5, sfHooks, 6);
|
||||
|
||||
// now check the entry
|
||||
if (slot_subarray(6, pos, 7) == 7)
|
||||
if (slot_subarray(6, topic[1], 7) == 7)
|
||||
{
|
||||
// it exists
|
||||
// check if its identical
|
||||
uint8_t existing_hook[32];
|
||||
ASSERT(slot_subfield(7, sfHookHash, 8) == 8);
|
||||
slot_subfield(7, sfHookHash, 8);
|
||||
ASSERT(slot(SBUF(existing_hook), 8) == 32);
|
||||
|
||||
// if it is then do nothing
|
||||
if (BUFFER_EQUAL_32(existing_hook, topic_data))
|
||||
DONE();
|
||||
DONE("Goverance: Target hook is already the same as actioned hook.");
|
||||
}
|
||||
|
||||
// generate the hook definition keylet
|
||||
ASSERT(util_keylet(SBUF(keylet), KEYLET_HOOK_DEFINITION, topic_data, 32, 0,0,0,0) == 34);
|
||||
util_keylet(SBUF(keylet), KEYLET_HOOK_DEFINITION, topic_data, 32, 0,0,0,0);
|
||||
|
||||
// check if the ledger contains such a hook definition
|
||||
ASSERT(slot_set(SBUF(keylet), 9) == 9);
|
||||
if (slot_set(SBUF(keylet), 9) != 9)
|
||||
NOPE("Goverance: Hook Hash doesn't exist on ledger while actioning hook.");
|
||||
|
||||
// it does so now we can do the emit
|
||||
etxn_reserve(1);
|
||||
|
||||
// RH UPTO: do hookset emit
|
||||
|
||||
uint8_t* hookhash =
|
||||
topic_data_zero
|
||||
? ((uint8_t*)0xFFFFFFFFU) // if the topic data is all zero then it's a delete operation
|
||||
: topic_data; // otherwise it's an install operation
|
||||
|
||||
uint8_t* h[4] =
|
||||
{
|
||||
pos == 0 ? hookhash : 0,
|
||||
pos == 1 ? hookhash : 0,
|
||||
pos == 2 ? hookhash : 0,
|
||||
pos == 3 ? hookhash : 0
|
||||
};
|
||||
|
||||
uint8_t* h[10];
|
||||
h[topic[1]] = hookhash;
|
||||
|
||||
uint8_t emit_buf[1024];
|
||||
uint32_t emit_size = 0;
|
||||
PREPARE_HOOKSET(emit_buf, sizeof(emit_buf), h[0], h[1], h[2], h[3], emit_size);
|
||||
PREPARE_HOOKSET(emit_buf, sizeof(emit_buf), h, emit_size);
|
||||
|
||||
uint8_t emithash[32];
|
||||
int64_t emit_result = emit(SBUF(emithash), emit_buf, emit_size);
|
||||
|
||||
TRACEVAR(emit_result);
|
||||
|
||||
if (emit_result != emit_size)
|
||||
NOPE("Governance: Emit failed during hook actioning.");
|
||||
|
||||
DONE("Governance: Hook actioned.");
|
||||
}
|
||||
else
|
||||
|
||||
case 'S':
|
||||
{
|
||||
// add / change member
|
||||
key[31] = topic - 6;
|
||||
|
||||
|
||||
uint8_t previous_member[32];
|
||||
int previous_present = (state(previous_member + 12, 20, SBUF(key)) == 20);
|
||||
int previous_present = (state(previous_member + 12, 20, topic[1], 1) == 20);
|
||||
|
||||
if (previous_present && !topic_data_zero)
|
||||
{
|
||||
// we will not change member count, we're adding a member and removing a member
|
||||
|
||||
// pass
|
||||
}
|
||||
else
|
||||
{
|
||||
// decrement member count
|
||||
ASSERT(member_count > 0); // just bail out if the last member is trying to self remove
|
||||
|
||||
// adjust member count
|
||||
if (previous_present)
|
||||
member_count--;
|
||||
else
|
||||
member_count++;
|
||||
|
||||
ASSERT(member_count > 0); // just bail out if the last member is trying to self remove
|
||||
|
||||
ASSERT(state_set(&member_count, 1, SBUF(zero)) == 1);
|
||||
}
|
||||
@@ -332,27 +390,37 @@ int64_t hook(uint32_t r)
|
||||
// we need to garbage collect all their votes
|
||||
if (previous_present)
|
||||
{
|
||||
for (int i = 1; GUARD(25), i <= 25; ++i)
|
||||
previous_member[0] = 'V';
|
||||
|
||||
for (int i = 1; GUARD(32), i < 32; ++i)
|
||||
{
|
||||
previous_member[0] = i;
|
||||
previous_member[1] = i < 2 ? 'R' : i < 12 ? 'H' : 'S';
|
||||
previous_member[2] = i < 2 ? i : i < 12 ? i - 2 : i - 12;
|
||||
|
||||
uint8_t vote_key[32];
|
||||
if (state(SBUF(vote_key), SBUF(previous_member)) == 32)
|
||||
{
|
||||
uint8_t vote_count = 0;
|
||||
|
||||
// find and decrement the vote counter
|
||||
vote_key[0] = 'C';
|
||||
vote_key[1] = previous_member[1];
|
||||
vote_key[2] = previous_member[2];
|
||||
if (state(&vote_count, 1, SBUF(vote_key)) == 1)
|
||||
{
|
||||
// if we're down to 1 vote then delete state
|
||||
if (vote_count <= 1)
|
||||
{
|
||||
ASSERT(state_set(0,0, SBUF(vote_key)) == 0);
|
||||
}
|
||||
else
|
||||
else // otherwise decrement
|
||||
{
|
||||
vote_count--;
|
||||
ASSERT(state_set(&vote_count, 1, SBUF(vote_key)) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// delete the entry
|
||||
// delete the vote entry
|
||||
ASSERT(state_set(0,0, SBUF(previous_member)) == 0);
|
||||
}
|
||||
}
|
||||
@@ -362,16 +430,15 @@ int64_t hook(uint32_t r)
|
||||
{
|
||||
// add the new member
|
||||
// reverse key
|
||||
key[31] = topic - 6;
|
||||
ASSERT(state_set(topic_data, 20, SBUF(key)) == 20);
|
||||
ASSERT(state_set(topic_data, 20, topic[1], 1) == 20);
|
||||
|
||||
// forward key
|
||||
ASSERT(state_set(key + 31, 1, topic_data_buffer, 32) == 20);
|
||||
ASSERT(state_set(topic[1], 1, SBUF(topic_data)) == 20);
|
||||
}
|
||||
|
||||
// done!
|
||||
DONE("Governance: Action member change.");
|
||||
}
|
||||
}
|
||||
|
||||
DONE();
|
||||
|
||||
rollback(SBUF("Governance: Internal logic error."), __LINE__);
|
||||
}
|
||||
|
||||
16
hook/macro.h
16
hook/macro.h
@@ -539,7 +539,7 @@ int out_len = 0;\
|
||||
*buf_out++ = 0xE1U;\
|
||||
}
|
||||
|
||||
#define PREPARE_HOOKSET(buf_out_master, maxlen, hash0, hash1, hash2, hash3, sizeout)\
|
||||
#define PREPARE_HOOKSET(buf_out_master, maxlen, h, sizeout)\
|
||||
{\
|
||||
uint8_t* buf_out = (buf_out_master); \
|
||||
uint8_t acc[20]; \
|
||||
@@ -558,10 +558,16 @@ int out_len = 0;\
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, remaining_size); \
|
||||
buf_out += edlen; \
|
||||
*buf_out++ = 0xFBU; /* hook array start */ \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, hash0); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, hash1); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, hash2); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, hash3); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[0]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[1]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[2]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[3]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[4]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[5]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[6]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[7]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[8]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[9]); \
|
||||
*buf_out++ = 0xF1U; /* hook array end */ \
|
||||
sizeout = (buf_out - (buf_out_master)); \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, sizeout); \
|
||||
|
||||
Reference in New Issue
Block a user