massa-factory-worker/factory.md
The massa-factory crate will be responsible for:
The factory module will function in separate, independent threads.
The factory controller will allow acting on the factory from other modules:
The factory will need to call other modules:
The factory module will maintain its own absolute clock based on genesis_timestamp, t0 and thread_count.
The block creation slot (period, thread) will be at time genesis_timestamp + (t0*period) + ((thread*t0)/thread_count)).
Since double-staking is penalized and could happen on node reboot, a safety measure is to wait 2 periods (2*t0) after the program starts before beginning block production.
We ignore block creation slots for which S.period == 0 (genesis blocks).
At every block creation slot, the block creation thread will read selector draws at that slot to check whether one of the staking keys was selected to produce the block. If the address linked to a stored staking key was selected, launch the block production process below.
The production of a block B at slot S happens in steps:
best_parents which will be the parents set inside the headerBlockId of B's parent in B's threadremaining_gas = MAX_BLOCk_GAS which is the remaining gas in the blockremaining_space = MAX_BLOCK_SIZE which is the remaining operation space in the block in bytesbalance_cache: Map<Address, Amount> = Default::default() which is a cache of balanceexcluded_ops: Set<OperationId> which is the list of operations to excludeexcluded_ops by asking the execution execution module for the list of operations that have been executed previously in B's threadstart_time = MassaTime::now(0) which is the time when we started producing the blockMassaTime::now(0).saturating_sub(start_time) > MAX_BLOCK_PRODUCTION_MILLIS, it means we have spent too much time in this loop => break loopS, remaining_gas, remaining_space, excluded_opsexcluded_ops with the obtained batchop in the ordered batch:
op.get_gas_usage() > remaining_gas, it means that there is not enough remaining block gas to execute the operation => continue loopop.serialized_version.len() > remaining_space, it means that there is not enough remaining space to include the operation => continue loopop's creator address is not in balance_cache, ask execution for the balance of op.creator and insert it inside balance_cachebalance_cache[op.creator_addr] < op.fee + op.get_gas_coins(), it means that the sender cannot pay for the fees => continue loopremaining_gas -= op.get_gas_usage()remaining_space -= op.serialized_version.len()balance_cache[op.creator_addr] -= (op.fee + op.get_gas_coins())consensus with the block ID for processingconsensus will send it further to protocol for propagation if it was properly integrated in the graphEndorsement production is slightly different from the one we have currently. Endorsement production should happen in a separate thread compared to block creation.
Endorsements that endorse slot S=(period, thread) will be produced at endorsement tick genesis_timestamp + (t0*period) + ((thread*t0)/thread_count)) + (t0/2).
This is indeed a half-period lag in order to incentivize timely block and endorsement propagation.
Since double-staking is penalized and could happen on node reboot, a safety measure is to wait 1 period (2*t0) after the program starts before beginning endorsement production.
At every block creation slot, the block creation thread will read selector draws at that slot to check whether one of the staking keys was selected to produce the block. If the address linked to a stored staking key was selected, launch the block production process below.
At each endorsement time tick encorsing slot S, we do the following:
B of the blockclique at slot S
endo that is supposed to be created by address A and to endorse the block B:
B.id at slot S, signed with Astorage and protocol for propagation