starcoin-framework

Module 0x1::BlockReward

The module provide block rewarding calculation logic.

use 0x1::Account;
use 0x1::CoreAddresses;
use 0x1::Errors;
use 0x1::Event;
use 0x1::RewardConfig;
use 0x1::STC;
use 0x1::Timestamp;
use 0x1::Token;
use 0x1::Treasury;
use 0x1::TreasuryWithdrawDaoProposal;
use 0x1::Vector;

Resource RewardQueue

Queue of rewards distributed to miners.

struct RewardQueue has key
Fields
reward_number: u64
How many block rewards has been handled.
infos: vector<BlockReward::RewardInfo>
informations about the reward distribution.
reward_events: Event::EventHandle<BlockReward::BlockRewardEvent>
event handle used to emit block reward event.

Struct RewardInfo

Reward info of miners.

struct RewardInfo has store
Fields
number: u64
number of the block miner minted.
reward: u128
how many stc rewards.
miner: address
miner who mint the block.
gas_fees: Token::Token<STC::STC>
store the gas fee that users consumed.

Struct BlockRewardEvent

block reward event

struct BlockRewardEvent has drop, store
Fields
block_number: u64
block number
block_reward: u128
STC reward.
gas_fees: u128
gas fees in STC.
miner: address
block miner

Constants

const EAUTHOR_ADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 105;

const EAUTHOR_AUTH_KEY_IS_EMPTY: u64 = 101;

const ECURRENT_NUMBER_IS_WRONG: u64 = 102;

const EMINER_EXIST: u64 = 104;

const EREWARD_NUMBER_IS_WRONG: u64 = 103;

Function initialize

Initialize the module, should be called in genesis.

public fun initialize(account: &signer, reward_delay: u64)
Implementation
public fun initialize(account: &signer, reward_delay: u64) {
    Timestamp::assert_genesis();
    CoreAddresses::assert_genesis_address(account);

    RewardConfig::initialize(account, reward_delay);
    move_to<RewardQueue>(account, RewardQueue {
        reward_number: 0,
        infos: Vector::empty(),
        reward_events: Event::new_event_handle<Self::BlockRewardEvent>(account),
    });
}
Specification
aborts_if !Timestamp::is_genesis();
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
include Config::PublishNewConfigAbortsIf<RewardConfig::RewardConfig>;
include Config::PublishNewConfigEnsures<RewardConfig::RewardConfig>;
aborts_if exists<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
ensures exists<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());

Function process_block_reward

Process the given block rewards.

public fun process_block_reward(account: &signer, current_number: u64, current_reward: u128, current_author: address, _auth_key_vec: vector<u8>, previous_block_gas_fees: Token::Token<STC::STC>)
Implementation
public fun process_block_reward(account: &signer, current_number: u64, current_reward: u128,
                                current_author: address, _auth_key_vec: vector<u8>,
                                previous_block_gas_fees: Token::Token<STC>) acquires RewardQueue {
    CoreAddresses::assert_genesis_address(account);
    if (current_number == 0) {
        Token::destroy_zero(previous_block_gas_fees);
        return
    };

    let rewards = borrow_global_mut<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
    let len = Vector::length(&rewards.infos);
    assert!((current_number == (rewards.reward_number + len + 1)), Errors::invalid_argument(ECURRENT_NUMBER_IS_WRONG));

    // distribute gas fee to last block reward info.
    // if not last block reward info, the passed in gas fee must be zero.
    if (len == 0) {
        Token::destroy_zero(previous_block_gas_fees);
    } else {
        let reward_info = Vector::borrow_mut(&mut rewards.infos, len - 1);
        assert!(current_number == reward_info.number + 1, Errors::invalid_argument(ECURRENT_NUMBER_IS_WRONG));
        Token::deposit(&mut reward_info.gas_fees, previous_block_gas_fees);
    };

    let reward_delay = RewardConfig::reward_delay();
    if (len >= reward_delay) {//pay and remove
        let i = len;
        while (i > 0 && i >= reward_delay) {
            let RewardInfo { number: reward_block_number, reward: block_reward, gas_fees, miner } = Vector::remove(&mut rewards.infos, 0);

            let gas_fee_value = Token::value(&gas_fees);
            let total_reward = gas_fees;
            // add block reward to total.
            if (block_reward > 0) {
                // if no STC in Treasury, BlockReward will been 0.
                let treasury_balance = Treasury::balance<STC>();
                if (treasury_balance < block_reward) {
                    block_reward = treasury_balance;
                };
                if (block_reward > 0) {
                    let reward = TreasuryWithdrawDaoProposal::withdraw_for_block_reward<STC>(account, block_reward);
                    Token::deposit(&mut total_reward, reward);
                };
            };
            // distribute total.
            if (Token::value(&total_reward) > 0) {
                Account::deposit<STC>(miner, total_reward);
            } else {
                Token::destroy_zero(total_reward);
            };
            // emit reward event.
            Event::emit_event<BlockRewardEvent>(
                &mut rewards.reward_events,
                BlockRewardEvent {
                    block_number: reward_block_number,
                    block_reward: block_reward,
                    gas_fees: gas_fee_value,
                    miner,
                }
            );

            rewards.reward_number = rewards.reward_number + 1;
            i = i - 1;
        }
    };

    if (!Account::exists_at(current_author)) {
        Account::create_account_with_address<STC>(current_author);
    };
    let current_info = RewardInfo {
        number: current_number,
        reward: current_reward,
        miner: current_author,
        gas_fees: Token::zero<STC>(),
    };
    Vector::push_back(&mut rewards.infos, current_info);

}
Specification
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if current_number == 0 && Token::value(previous_block_gas_fees) != 0;
aborts_if current_number > 0 && !exists<RewardQueue>(CoreAddresses::GENESIS_ADDRESS());
aborts_if current_number > 0 && (global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).reward_number + Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos) + 1) != current_number;
aborts_if current_number > 0 && !exists<Config::Config<RewardConfig::RewardConfig>>(CoreAddresses::GENESIS_ADDRESS());
let reward_info_length = Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos);
aborts_if current_number > 0 && reward_info_length == 0 && Token::value(previous_block_gas_fees) != 0;
aborts_if current_number > 0 && reward_info_length != 0 && Vector::borrow(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos, reward_info_length - 1).number != current_number - 1;
aborts_if current_number > 0 && Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos) >= global<Config::Config<RewardConfig::RewardConfig>>(CoreAddresses::GENESIS_ADDRESS()).payload.reward_delay
&& (global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).reward_number + 1) != Vector::borrow(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos, 0).number;
aborts_if current_number > 0 && Vector::length(global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).infos) >= global<Config::Config<RewardConfig::RewardConfig>>(CoreAddresses::GENESIS_ADDRESS()).payload.reward_delay
        && (global<RewardQueue>(CoreAddresses::GENESIS_ADDRESS()).reward_number + 1) > max_u64();
aborts_if current_number > 0 && !Account::exists_at(current_author) ;
pragma verify = false;

Module Specification

pragma verify = false;
pragma aborts_if_is_strict = true;