Skip to content

Latest commit

 

History

History
273 lines (186 loc) · 8.69 KB

tip-271.md

File metadata and controls

273 lines (186 loc) · 8.69 KB
tip: 271
title: Vote for SR in Smart Contract
author: yanghang8612<[email protected]>
status: Last Call
type: Standards Track
category: VM
created: 2021-06-01

Simple Summary

To provide vote related operations in TVM.

Abstract

VoteWitness & WithdrawReward operations in system contract are introduced, smart contract can vote for witness and get reward from the system.

Motivation

Common user can vote for activated witness to share the block reward. However, non-privatekey accounts, like smart contracts, can not get benefit from this incentive mechanism.

Meanwhile, after TIP-157 activating on the mainnet, smart contracts can freeze their balance to get resources include tron power. But this part of resources can not be used because there is no vote related instructions in TVM.

So this TIP aims to implement the incentive voting functionalities for smart contracts. On one hand, smart contracts will take fully advantage of their balance. For example, voting witness, keeping the network safe, sharing the block reward. On the other hand, developer could write some special voting contracts to provide a new way to vote witness for common user which is different from system voting contract. These voting contracts may be more complex to system voting contract and provide more attractive and unique voting feature.

Specifications

New instructions

0xd8: VOTEWITNESS

The VOTE takes 4 operands pop up from stack:

tronPowerArrayLength: witness address array offset.

tronPowerArrayOffset: witness address array size.

witnessAddressArrayLength: tron power number array offset.

witnessAddressArrayOffset: tron power number array size.

TVM will get witness array from memory by using witnessOffset and witnessSize.

TVM will get tron power array from memory by using tronPowerOffset and tronPowerSize.

Execute vote function and push 0 to stack if fail, push 1 otherwize.

0xd9: WITHDRAWREWARD

The WITHDRAWREWARD takes no operand pop up from stack.

Execute withdraw function and push 0 to stack if fail, push 1 otherwise.

New precompile contracts

0x1000005: RewardBalance

The RewardBalance takes no operand pop up from stack.

Execute query reward function and push reward balance to stack.

0x1000006: IsSrCandidate

The IsSrCandidate takes 1 operand pop up from stack:

targetAddress: target account address.

Push 0 if target address is not a witness, otherwise push 1.

0x1000007: VoteCount

The VoteCount takes 2 operand pop up from stack:

voteAddress: vote account address.

targetAddress: target account address.

Execute query vote count function and push vote count to stack.

0x1000008: UsedVoteCount

The UsedVoteCount takes 1 operand pop up from stack:

voteAddress: vote account address.

Execute query total used vote count function.

0x1000009: ReceivedVoteCount

The ReceviedVoteCount takes 1 operand pop up from stack:

receivedAddress: witness address.

Excute query witness total received vote count.

0x100000a: TotalVoteCount

The TotalVoteCount takes 1 operand pop up from stack:

voteAddress: vote account address.

Execute query total vote count function.

Solidity Example

contract TestVote {

    /**
     * @dev Contract can accept value while creating.
     */
    constructor() public payable {
    }

    /**
     * @dev Freeze `amount` balance of contract to get resource for `receiver` 
     * which type is `res` (0 for bandwidth, 1 for energy).
     *
     * below situations can cause `revert` excepiton:
     * 1. `amount` is greater than long.max_value or contract balance
     * 2. `amount` is less than 10e6 sun (1 trx)
     * 3. `res` is not zero or one
     * 4. `receiver` is contract address (exclude this contract)
     */
    function freeze(address payable receiver, uint amount, uint res) external {
        receiver.freeze(amount, res);
    }

    /**
     * @dev Unfreeze specific balance to get corresponding balance.You can use 
     * `receiver' and 'res'  (0 for bandwidth, 1 for energy) parameters to 
     * unfreeze specific balance.
     *
     * below situations can cause `revert` excepiton:
     * 1. `res` is not zero or one
     * 1. frozen relationship between contract and `receiver` does not exist
     * 2. it is not time to unfreeze the specific balance
     */
    function unfreeze(address payable receiver, uint res) external {
        receiver.unfreeze(res);
    }

    /**
     * @dev Vote witness in `srList` array and every witness will get correspond 
     * tron power in `tpList` array.
     *
     * below situations can cause `revert` excepiton:
     * 1. `srList` array length and `tpList` array length are different
     * 2. array length are greater than MAX_VOTE_NUMBER (30)
     * 3. there are normal account address in `srList` array
     * 4. there are negative value in 'tpList' array
     * 5. total needed tron power is greater than current owned tron power of contract
     */
    function voteWitness(address[] calldata srList, uint[] calldata tpList) external {
        vote(srList, tpList);
    }

    /**
     * @dev Withdraw all allowance and reward to contract balance. Return actually withdraw amount.
     *
     * below situations can cause `revert` excepiton:
     * 1. contract address is in witness list of genesis block
     * 2. sum of contract balance and reward overflow long (8 bytes)
     */
    function withdrawReward() external returns(uint) {
        return withdrawreward();
    }

    /**
     * @dev query all allowance and reward of contract account. Return contract's all allowance.
     */
    function queryRewardBalance() external view returns(uint) {
        return rewardBalance();
    }

    /**
     * @dev Judge whether the address is a candidate address.If the address is a candidate address,
     * return `true`, or return `false`.    
     */
    function isWitness(address sr) external view returns(bool) {
        return isSrCandidate(sr);
    }

    /**
     * @dev Query vote count of `from` votes for `to`. Return corresponding vote count (tron-power, 1 trx = 1 tron-power).    
     */
    function queryVoteCount(address from, address to) external view returns(uint) {
        return voteCount(from, to);
    }

    /**
     * @dev Query total vote count of `owner`. Return owner's total vote count (tron-power, 1 trx = 1 tron-power).    
     */
    function queryTotalVoteCount(address owner) external view returns(uint) {
        return totalVoteCount(owner);
    }

     /**
     * @dev Query `owner` recevied vote count. Return owner's received vote count (tron-power, 1 trx = 1 tron-power).    
     */
    function queryReceivedVoteCount(address owner) external view returns(uint) {
        return receivedVoteCount(owner);
    }

    /**
     * @dev Query `owner` used vote count. Return owner's used vote count (tron-power, 1 trx = 1 tron-power).
     */
    function queryUsedVoteCount(address owner) external view returns(uint) {
        return usedVoteCount(owner);
    }

    /**
     * @dev Execute self destruct and transfer all balance and asset of contract to target address.
     *
     * below situations can cause `revert` excepiton:
     * 1. there are still delegated frozen balance for other account address
     */
    function killme(address payable target) external {
        selfdestruct(target);
    }
}

Notice

For vote(address[], uint[]), if array length in memory does not match the parameter length, a ByteExecutionException will throw.

For vote(address[], uint[]), if address array length and uint array length is different, a revert exception will throw.

For withdrawreward(), withdraw all rewards to contract balance.

Both vote(address[], uint[]) and withdrawreward() will change the state of storage, so they can not be executed in static context (a static context can only be created by staticcall now). Otherwise, a StaticCallModificationException will throw.

New reward calculation algorithm

See author`s blog for more details of the algorithm at Read the docs

Rationale

Tier

VOTEWITNESS: tier.ExtTier

WITHDRAWREWARD: tier.ExtTier

Energy cost

Instructions

VOTEWITNESS: 30000 energy

WITHDRAWREWARD: 20000 energy

Precomplie contracts

RewardBalance: 500 energy

IsSrCandidate: 20 energy

VoteCount: 500 energy

UsedVoteCount: 20 energy

ReceivedVoteCount: 20 energy

TotalVoteCount: 20 energy

Selfdestruct

If contract still has votes and unwithdrawed reward, selfdestruct will auto clear votes and withdraw allowance and reward to contract balance. There may be some rewards of current cycle that can never be withdrawed.