evm-tokenvote

Voting machine using ERC20 tokens as votes.
Info | Log | Files | Refs | README

test_base.py (11668B)


      1 # standard imports
      2 import unittest
      3 import logging
      4 import os
      5 from chainlib.eth.nonce import RPCNonceOracle
      6 from chainlib.eth.tx import receipt
      7 from chainlib.eth.block import block_latest
      8 from hexathon import same as same_hex
      9 from eth_erc20 import ERC20
     10 from giftable_erc20_token import GiftableToken
     11 
     12 # local imports
     13 from evm_tokenvote.unittest import TestEvmVoteProposal
     14 from evm_tokenvote.unittest.base import hash_of_foo
     15 from evm_tokenvote import Voter
     16 from evm_tokenvote import ProposalState
     17 
     18 
     19 logging.basicConfig(level=logging.DEBUG)
     20 logg = logging.getLogger()
     21 
     22 class TestVoteBase(TestEvmVoteProposal):
     23 
     24     def test_propose(self):
     25         c = Voter(self.chain_spec)
     26         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
     27         r = self.rpc.do(o)
     28         proposal = c.parse_proposal(r)
     29         self.assertTrue(same_hex(proposal.description_digest, hash_of_foo))
     30         self.assertEqual(proposal.supply, self.supply)
     31         self.assertEqual(proposal.total, 0)
     32         self.assertEqual(proposal.block_deadline, self.proposal_block_height + 100)
     33         self.assertEqual(proposal.target_vote_ppm, 500000)
     34         self.assertTrue(same_hex(proposal.proposer, self.ivan))
     35         self.assertEqual(proposal.state, ProposalState.INIT)
     36 
     37         o = c.current_proposal(self.voter_address, sender_address=self.accounts[0])
     38         r = self.rpc.do(o)
     39         proposal = c.parse_proposal(r)
     40         self.assertTrue(same_hex(proposal.description_digest, hash_of_foo))
     41         self.assertEqual(proposal.supply, self.supply)
     42         self.assertEqual(proposal.total, 0)
     43         self.assertEqual(proposal.block_deadline, self.proposal_block_height + 100)
     44         self.assertEqual(proposal.target_vote_ppm, 500000)
     45         self.assertTrue(same_hex(proposal.proposer, self.ivan))
     46         self.assertEqual(proposal.state, ProposalState.INIT)
     47 
     48 
     49 
     50     def test_vote(self):
     51         nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
     52         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
     53         (tx_hash, o) = c.vote(self.voter_address, self.alice, 10)
     54         self.rpc.do(o)
     55         o = receipt(tx_hash)
     56         r = self.rpc.do(o)
     57         self.assertEqual(r['status'], 0)
     58 
     59         nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
     60         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
     61         (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.alice, 100)
     62         self.rpc.do(o)
     63 
     64         nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
     65         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
     66         o = c.get_proposal(self.voter_address, 0, sender_address=self.alice)
     67         r = self.rpc.do(o)
     68         proposal = c.parse_proposal(r)
     69         self.assertEqual(proposal.total, 0)
     70 
     71         # vote does not work without approval
     72         (tx_hash, o) = c.vote(self.voter_address, self.alice, 10)
     73         self.rpc.do(o)
     74         o = receipt(tx_hash)
     75         r = self.rpc.do(o)
     76         self.assertEqual(r['status'], 0)
     77 
     78         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
     79         (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, 100)
     80         self.rpc.do(o)
     81 
     82         # vote can be called multiple times (up to balance)
     83         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
     84         (tx_hash, o) = c.vote(self.voter_address, self.alice, 10)
     85         self.rpc.do(o)
     86         o = receipt(tx_hash)
     87         r = self.rpc.do(o)
     88         self.assertEqual(r['status'], 1)
     89 
     90         (tx_hash, o) = c.vote(self.voter_address, self.alice, 90)
     91         self.rpc.do(o)
     92         o = receipt(tx_hash)
     93         r = self.rpc.do(o)
     94         self.assertEqual(r['status'], 1)
     95 
     96         # vote total is updated
     97         o = c.get_proposal(self.voter_address, 0, sender_address=self.alice)
     98         r = self.rpc.do(o)
     99         proposal = c.parse_proposal(r)
    100         self.assertEqual(proposal.total, 100)
    101 
    102         # fail because all votes used
    103         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    104         (tx_hash, o) = c.vote(self.voter_address, self.alice, 1)
    105         self.rpc.do(o)
    106         o = receipt(tx_hash)
    107         r = self.rpc.do(o)
    108         self.assertEqual(r['status'], 0)
    109 
    110 
    111     def test_vote_win(self):
    112         half_supply = self.initial_supply / 2
    113         nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
    114         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    115         (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.alice, half_supply)
    116         self.rpc.do(o)
    117 
    118         nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
    119         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    120         (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.bob, half_supply)
    121         self.rpc.do(o)
    122 
    123         nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
    124         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    125         (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, half_supply)
    126         self.rpc.do(o)
    127 
    128         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    129         (tx_hash, o) = c.vote(self.voter_address, self.alice, half_supply - 1)
    130         self.rpc.do(o)
    131 
    132         # no majority and deadline not reached
    133         nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
    134         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    135         (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
    136         self.rpc.do(o)
    137         o = receipt(tx_hash)
    138         r = self.rpc.do(o)
    139         self.assertEqual(r['status'], 0)
    140 
    141         nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
    142         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    143         (tx_hash, o) = c.vote(self.voter_address, self.alice, 1)
    144         self.rpc.do(o)
    145 
    146         self.backend.mine_blocks(100)
    147 
    148         # majority, but not cancel, we care about deadline
    149         nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
    150         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    151         (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
    152         self.rpc.do(o)
    153         o = receipt(tx_hash)
    154         r = self.rpc.do(o)
    155         self.assertEqual(r['status'], 1)
    156 
    157         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
    158         r = self.rpc.do(o)
    159         proposal = c.parse_proposal(r)
    160         self.assertEqual(proposal.state & ProposalState.INIT, ProposalState.INIT)
    161 
    162         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    163         (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
    164         self.rpc.do(o)
    165         o = receipt(tx_hash)
    166         r = self.rpc.do(o)
    167         self.assertEqual(r['status'], 1)
    168 
    169         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
    170         r = self.rpc.do(o)
    171         proposal = c.parse_proposal(r)
    172         self.assertEqual(proposal.state & ProposalState.SCANNED, ProposalState.SCANNED)
    173 
    174         (tx_hash, o) = c.finalize_vote(self.voter_address, self.trent)
    175         self.rpc.do(o)
    176         o = receipt(tx_hash)
    177         r = self.rpc.do(o)
    178         self.assertEqual(r['status'], 1)
    179 
    180         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
    181         r = self.rpc.do(o)
    182         proposal = c.parse_proposal(r)
    183         self.assertEqual(proposal.state & ProposalState.FINAL, ProposalState.FINAL)
    184         self.assertEqual(proposal.state & ProposalState.INSUFFICIENT, 0)
    185         self.assertEqual(proposal.state & ProposalState.TIED, 0)
    186         self.assertEqual(proposal.state & ProposalState.SUPPLYCHANGE, 0)
    187 
    188 
    189     def test_vote_insufficient(self):
    190         half_supply = self.initial_supply / 2
    191         nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
    192         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    193         (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.alice, half_supply)
    194         self.rpc.do(o)
    195 
    196         nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
    197         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    198         (tx_hash, o) = c.transfer(self.address, self.accounts[0], self.bob, half_supply)
    199         self.rpc.do(o)
    200 
    201         nonce_oracle = RPCNonceOracle(self.alice, conn=self.conn)
    202         c = ERC20(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    203         (tx_hash, o) = c.approve(self.address, self.alice, self.voter_address, half_supply)
    204         self.rpc.do(o)
    205 
    206         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    207         (tx_hash, o) = c.vote(self.voter_address, self.alice, half_supply - 1)
    208         self.rpc.do(o)
    209 
    210         o = block_latest()
    211         now_block_height = self.rpc.do(o)
    212         need_blocks = self.proposal_block_height + 100 - now_block_height + 1
    213         self.backend.mine_blocks(need_blocks)
    214 
    215         nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
    216         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    217         (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
    218         self.rpc.do(o)
    219         o = receipt(tx_hash)
    220         r = self.rpc.do(o)
    221         self.assertEqual(r['status'], 1)
    222 
    223         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
    224         r = self.rpc.do(o)
    225         proposal = c.parse_proposal(r)
    226         self.assertEqual(proposal.state & ProposalState.SCANNED, ProposalState.SCANNED)
    227 
    228         (tx_hash, o) = c.finalize_vote(self.voter_address, self.trent)
    229         self.rpc.do(o)
    230         o = receipt(tx_hash)
    231         r = self.rpc.do(o)
    232         self.assertEqual(r['status'], 1)
    233 
    234         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
    235         r = self.rpc.do(o)
    236         proposal = c.parse_proposal(r)
    237         self.assertEqual(proposal.state & ProposalState.FINAL, ProposalState.FINAL)
    238         self.assertEqual(proposal.state & ProposalState.INSUFFICIENT, ProposalState.INSUFFICIENT)
    239         self.assertEqual(proposal.state & ProposalState.TIED, 0)
    240         self.assertEqual(proposal.state & ProposalState.SUPPLYCHANGE, 0)
    241 
    242 
    243     def test_proposal_ok_supplychange(self):
    244         nonce_oracle = RPCNonceOracle(self.accounts[0], conn=self.conn)
    245         c = GiftableToken(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    246         (tx_hash, o) = c.mint_to(self.address, self.accounts[0], self.alice, 1)
    247         self.rpc.do(o)
    248 
    249         o = block_latest()
    250         now_block_height = self.rpc.do(o)
    251         need_blocks = self.proposal_block_height + 100 - now_block_height + 1
    252         self.backend.mine_blocks(need_blocks)
    253 
    254         nonce_oracle = RPCNonceOracle(self.trent, conn=self.conn)
    255         c = Voter(self.chain_spec, signer=self.signer, nonce_oracle=nonce_oracle)
    256         (tx_hash, o) = c.scan(self.voter_address, self.trent, 0, 0)
    257         self.rpc.do(o)
    258 
    259         (tx_hash, o) = c.finalize_vote(self.voter_address, self.trent)
    260         self.rpc.do(o)
    261         o = receipt(tx_hash)
    262         r = self.rpc.do(o)
    263         self.assertEqual(r['status'], 1)
    264 
    265         o = c.get_proposal(self.voter_address, 0, sender_address=self.accounts[0])
    266         r = self.rpc.do(o)
    267         proposal = c.parse_proposal(r)
    268         self.assertEqual(proposal.state & ProposalState.FINAL, ProposalState.FINAL)
    269         self.assertEqual(proposal.state & ProposalState.SUPPLYCHANGE, ProposalState.SUPPLYCHANGE)
    270         self.assertEqual(proposal.state & ProposalState.CANCELLED, 0)
    271 
    272 
    273 if __name__ == '__main__':
    274     unittest.main()