nodeos_voting_test.py 9.8 KB
Newer Older
1 2
#!/usr/bin/env python3

3
from testUtils import Utils
4
import testUtils
5 6 7 8
from Cluster import Cluster
from WalletMgr import WalletMgr
from Node import Node
from TestHelper import TestHelper
9 10

import decimal
11
import math
12 13 14 15 16 17 18
import re

###############################################################
# nodeos_voting_test
# --dump-error-details <Upon error print etc/eosio/node_*/config.ini and var/lib/node_*/stderr.log to stdout>
# --keep-logs <Don't delete var/lib/node_* folders upon test completion>
###############################################################
19 20
class ProducerToNode:
    map={}
21

22 23 24 25 26 27 28
    @staticmethod
    def populate(node, num):
        for prod in node.producers:
            ProducerToNode.map[prod]=num
            Utils.Print("Producer=%s for nodeNum=%s" % (prod,num))

def isValidBlockProducer(prodsActive, blockNum, node):
29
    blockProducer=node.getBlockProducerByNum(blockNum)
30 31 32 33 34
    if blockProducer not in prodsActive:
        return False
    return prodsActive[blockProducer]

def validBlockProducer(prodsActive, prodsSeen, blockNum, node):
35
    blockProducer=node.getBlockProducerByNum(blockNum)
36 37
    if blockProducer not in prodsActive:
        Utils.cmdError("unexpected block producer %s at blockNum=%s" % (blockProducer,blockNum))
38
        Utils.errorExit("Failed because of invalid block producer")
39 40
    if not prodsActive[blockProducer]:
        Utils.cmdError("block producer %s for blockNum=%s not elected, belongs to node %s" % (blockProducer, blockNum, ProducerToNode.map[blockProducer]))
41
        Utils.errorExit("Failed because of incorrect block producer")
42 43 44 45 46 47 48
    prodsSeen[blockProducer]=True

def setActiveProducers(prodsActive, activeProducers):
    for prod in prodsActive:
        prodsActive[prod]=prod in activeProducers

def verifyProductionRounds(trans, node, prodsActive, rounds):
49
    blockNum=node.getNextCleanProductionCycle(trans)
50 51 52 53 54
    Utils.Print("Validating blockNum=%s" % (blockNum))

    temp=Utils.Debug
    Utils.Debug=False
    Utils.Print("FIND VALID BLOCK PRODUCER")
55
    blockProducer=node.getBlockProducerByNum(blockNum)
56 57 58 59
    lastBlockProducer=blockProducer
    adjust=False
    while not isValidBlockProducer(prodsActive, blockNum, node):
        adjust=True
60
        blockProducer=node.getBlockProducerByNum(blockNum)
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
        if lastBlockProducer!=blockProducer:
            Utils.Print("blockProducer=%s for blockNum=%s is for node=%s" % (blockProducer, blockNum, ProducerToNode.map[blockProducer]))
        lastBlockProducer=blockProducer
        blockNum+=1

    Utils.Print("VALID BLOCK PRODUCER")
    saw=0
    sawHigh=0
    startingFrom=blockNum
    doPrint=0
    invalidCount=0
    while adjust:
        invalidCount+=1
        if lastBlockProducer==blockProducer:
            saw+=1;
        else:
            if saw>=12:
                startingFrom=blockNum
                if saw>12:
                    Utils.Print("ERROR!!!!!!!!!!!!!!      saw=%s, blockProducer=%s, blockNum=%s" % (saw,blockProducer,blockNum))
                break
            else:
                if saw > sawHigh:
                    sawHigh = saw
                    Utils.Print("sawHigh=%s" % (sawHigh))
                if doPrint < 5:
                    doPrint+=1
                    Utils.Print("saw=%s, blockProducer=%s, blockNum=%s" % (saw,blockProducer,blockNum))
                lastBlockProducer=blockProducer
                saw=1
91
        blockProducer=node.getBlockProducerByNum(blockNum)
92 93 94 95 96 97 98 99 100 101 102 103 104 105
        blockNum+=1

    if adjust:
        blockNum-=1

    Utils.Print("ADJUSTED %s blocks" % (invalidCount-1))

    prodsSeen=None
    Utils.Print("Verify %s complete rounds of all producers producing" % (rounds))
    for i in range(0, rounds):
        prodsSeen={}
        lastBlockProducer=None
        for j in range(0, 21):
            # each new set of 12 blocks should have a different blockProducer 
106
            if lastBlockProducer is not None and lastBlockProducer==node.getBlockProducerByNum(blockNum):
107
                Utils.cmdError("expected blockNum %s to be produced by any of the valid producers except %s" % (blockNum, lastBlockProducer))
108
                Utils.errorExit("Failed because of incorrect block producer order")
109 110

            # make sure that the next set of 12 blocks all have the same blockProducer
111
            lastBlockProducer=node.getBlockProducerByNum(blockNum)
112 113
            for k in range(0, 12):
                validBlockProducer(prodsActive, prodsSeen, blockNum, node1)
114
                blockProducer=node.getBlockProducerByNum(blockNum)
115 116 117 118 119 120
                if lastBlockProducer!=blockProducer:
                    printStr=""
                    newBlockNum=blockNum-18
                    for l in range(0,36):
                        printStr+="%s" % (newBlockNum)
                        printStr+=":"
121
                        newBlockProducer=node.getBlockProducerByNum(newBlockNum)
122 123 124 125
                        printStr+="%s" % (newBlockProducer)
                        printStr+="  "
                        newBlockNum+=1
                    Utils.cmdError("expected blockNum %s (started from %s) to be produced by %s, but produded by %s: round=%s, prod slot=%s, prod num=%s - %s" % (blockNum, startingFrom, lastBlockProducer, blockProducer, i, j, k, printStr))
126
                    Utils.errorExit("Failed because of incorrect block producer order")
127 128 129 130 131 132
                blockNum+=1

    # make sure that we have seen all 21 producers
    prodsSeenKeys=prodsSeen.keys()
    if len(prodsSeenKeys)!=21:
        Utils.cmdError("only saw %s producers of expected 21. At blockNum %s only the following producers were seen: %s" % (len(prodsSeenKeys), blockNum, ",".join(prodsSeenKeys)))
133
        Utils.errorExit("Failed because of missing block producers")
134 135 136 137 138 139

    Utils.Debug=temp


Print=Utils.Print
errorExit=Utils.errorExit
140 141 142

from core_symbol import CORE_SYMBOL

143 144
args = TestHelper.parse_args({"--prod-count","--dump-error-details","--keep-logs","-v","--leave-running","--clean-run",
                              "--p2p-plugin","--wallet-port"})
145 146 147 148 149 150 151 152
Utils.Debug=args.v
totalNodes=4
cluster=Cluster(walletd=True)
dumpErrorDetails=args.dump_error_details
keepLogs=args.keep_logs
dontKill=args.leave_running
prodCount=args.prod_count
killAll=args.clean_run
P
Paul Calabrese 已提交
153
p2pPlugin=args.p2p_plugin
154
walletPort=args.wallet_port
155

156
walletMgr=WalletMgr(True, port=walletPort)
157 158 159
testSuccessful=False
killEosInstances=not dontKill
killWallet=not dontKill
160

161
WalletdName=Utils.EosWalletName
162
ClientName="cleos"
163 164

try:
165
    TestHelper.printSystemInfo("BEGIN")
166
    cluster.setWalletMgr(walletMgr)
167 168 169 170

    cluster.killall(allInstances=killAll)
    cluster.cleanup()
    Print("Stand up cluster")
171
    if cluster.launch(prodCount=prodCount, onlyBios=False, pnodes=totalNodes, totalNodes=totalNodes, totalProducers=totalNodes*21, p2pPlugin=p2pPlugin, useBiosBootFile=False) is False:
172
        Utils.cmdError("launcher")
173
        Utils.errorExit("Failed to stand up eos cluster.")
174 175 176 177 178 179

    Print("Validating system accounts after bootstrap")
    cluster.validateAccounts(None)

    accounts=cluster.createAccountKeys(5)
    if accounts is None:
180
        Utils.errorExit("FAILURE - create keys")
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    accounts[0].name="tester111111"
    accounts[1].name="tester222222"
    accounts[2].name="tester333333"
    accounts[3].name="tester444444"
    accounts[4].name="tester555555"

    testWalletName="test"

    Print("Creating wallet \"%s\"." % (testWalletName))
    testWallet=walletMgr.create(testWalletName, [cluster.eosioAccount,accounts[0],accounts[1],accounts[2],accounts[3],accounts[4]])

    for _, account in cluster.defProducerAccounts.items():
        walletMgr.importKey(account, testWallet, ignoreDupKeyWarning=True)

    Print("Wallet \"%s\" password=%s." % (testWalletName, testWallet.password.encode("utf-8")))

    for i in range(0, totalNodes):
        node=cluster.getNode(i)
        node.producers=Cluster.parseProducers(i)
        for prod in node.producers:
201
            trans=node.regproducer(cluster.defProducerAccounts[prod], "http::/mysite.com", 0, waitForTransBlock=False, exitOnError=True)
202 203 204 205 206 207 208 209 210 211

    node0=cluster.getNode(0)
    node1=cluster.getNode(1)
    node2=cluster.getNode(2)
    node3=cluster.getNode(3)

    node=node0
    # create accounts via eosio as otherwise a bid is needed
    for account in accounts:
        Print("Create new account %s via %s" % (account.name, cluster.eosioAccount.name))
212
        trans=node.createInitializeAccount(account, cluster.eosioAccount, stakedDeposit=0, waitForTransBlock=False, stakeNet=1000, stakeCPU=1000, buyRAM=1000, exitOnError=True)
213 214
        transferAmount="100000000.0000 {0}".format(CORE_SYMBOL)
        Print("Transfer funds %s from account %s to %s" % (transferAmount, cluster.eosioAccount.name, account.name))
215
        node.transferFunds(cluster.eosioAccount, account, transferAmount, "test transfer")
216
        trans=node.delegatebw(account, 20000000.0000, 20000000.0000, waitForTransBlock=True, exitOnError=True)
217 218 219 220 221 222 223 224 225 226 227 228

    # containers for tracking producers
    prodsActive={}
    for i in range(0, 4):
        node=cluster.getNode(i)
        ProducerToNode.populate(node, i)
        for prod in node.producers:
            prodsActive[prod]=False

    #first account will vote for node0 producers, all others will vote for node1 producers
    node=node0
    for account in accounts:
229
        trans=node.vote(account, node.producers, waitForTransBlock=True)
230 231 232 233 234 235 236 237 238 239
        node=node1

    setActiveProducers(prodsActive, node1.producers)

    verifyProductionRounds(trans, node2, prodsActive, 2)

    # test shifting all 21 away from one node to another
    # first account will vote for node2 producers, all others will vote for node3 producers
    node1
    for account in accounts:
240
        trans=node.vote(account, node.producers, waitForTransBlock=True)
241 242 243 244 245
        node=node2

    setActiveProducers(prodsActive, node2.producers)

    verifyProductionRounds(trans, node1, prodsActive, 2)
246

247
    testSuccessful=True
248
finally:
249
    TestHelper.shutdown(cluster, walletMgr, testSuccessful, killEosInstances, killWallet, keepLogs, killAll, dumpErrorDetails)
250 251

exit(0)