public void MultiVote(Address from, string subject, PollVote[] choices)
        {
            Runtime.Expect(_pollMap.ContainsKey <string>(subject), "invalid poll subject");

            Runtime.Expect(choices.Length > 0, "invalid number of choices");

            var poll = FetchPoll(subject);

            Runtime.Expect(poll.state == PollState.Active, "poll not active");

            switch (poll.kind)
            {
            case ConsensusKind.Validators:
                Runtime.Expect(Runtime.Nexus.IsKnownValidator(from), "must be primary or secondary validator");
                var primaryValidators = Runtime.Nexus.GetPrimaryValidatorCount();
                Runtime.Expect(primaryValidators >= 2, "not enough primary validators");
                break;

            case ConsensusKind.Masters:
                Runtime.Expect(Runtime.Nexus.IsStakeMaster(from), "must be stake master");
                var masters = Runtime.CallContext(Nexus.StakeContractName, nameof(StakeContract.GetMasterCount), from).AsNumber();

                break;
            }

            Runtime.Expect(choices.Length <= poll.choicesPerUser, "too many choices");

            Runtime.Expect(IsWitness(from), "invalid witness");

            var        presences = _presences.Get <Address, StorageList>(from);
            var        count     = presences.Count();
            int        index     = -1;
            BigInteger round     = 0;

            for (int i = 0; i < count; i++)
            {
                var presence = presences.Get <PollPresence>(i);
                if (presence.subject == subject)
                {
                    index = -1;
                    round = presence.round;
                    break;
                }
            }

            if (index >= 0)
            {
                Runtime.Expect(round < poll.round, "already voted");
            }

            BigInteger votingPower;

            if (poll.kind == ConsensusKind.Community)
            {
                votingPower = Runtime.CallContext(Nexus.StakeContractName, nameof(StakeContract.GetAddressVotingPower), from).AsNumber();
            }
            else
            {
                votingPower = 100;
            }

            Runtime.Expect(votingPower > 0, "not enough voting power");

            for (int i = 0; i < choices.Length; i++)
            {
                var votes = (votingPower * choices[i].percentage) / 100;
                Runtime.Expect(votes > 0, "choice percentage is too low");

                var targetIndex = (int)choices[i].index;
                poll.entries[targetIndex].votes += votes;
            }

            poll.totalVotes += 1;
            _pollMap.Set <string, ConsensusPoll>(subject, poll);

            // finally add this voting round to the presences list
            var temp = new PollPresence()
            {
                subject = subject,
                round   = poll.round,
            };

            if (index >= 0)
            {
                presences.Replace <PollPresence>(index, temp);
            }
            else
            {
                presences.Add(temp);
            }

            Runtime.Notify(EventKind.PollVote, from, subject);
        }
        public void MultiVote(Address from, string subject, PollVote[] choices)
        {
            Runtime.Expect(_pollMap.ContainsKey <string>(subject), "invalid subject");

            Runtime.Expect(choices.Length > 0, "invalid number of choices");

            var poll = FetchPoll(subject);

            Runtime.Expect(poll.state == PollState.Active, "poll not active");

            Runtime.Expect(choices.Length <= poll.votesPerUser, "too many choices");

            Runtime.Expect(IsWitness(from), "invalid witness");

            var        presences = _presences.Get <Address, StorageList>(from);
            var        count     = presences.Count();
            int        index     = -1;
            BigInteger round     = 0;

            for (int i = 0; i < count; i++)
            {
                var presence = presences.Get <PollPresence>(i);
                if (presence.subject == subject)
                {
                    index = -1;
                    round = presence.round;
                    break;
                }
            }

            if (index >= 0)
            {
                Runtime.Expect(round < poll.round, "already voted");
            }

            BigInteger votingPower;

            if (poll.kind == ConsensusKind.Validators)
            {
                votingPower = 100;
            }
            else
            {
                votingPower = (BigInteger)Runtime.CallContext("energy", "GetAddressVotingPower", from);
            }

            Runtime.Expect(votingPower > 0, "not enough voting power");

            for (int i = 0; i < choices.Length; i++)
            {
                var votes = (votingPower * choices[i].percentage) / 100;
                Runtime.Expect(votes > 0, "choice percentage is too low");

                var targetIndex = (int)choices[i].index;
                poll.entries[targetIndex].votes += votes;
            }

            poll.totalVotes += 1;
            _pollMap.Set <string, ConsensusPoll>(subject, poll);

            // finally add this voting round to the presences list
            var temp = new PollPresence()
            {
                subject = subject,
                round   = poll.round,
            };

            if (index >= 0)
            {
                presences.Replace <PollPresence>(index, temp);
            }
            else
            {
                presences.Add(temp);
            }

            Runtime.Notify(EventKind.PollVote, from, subject);
        }