[#74] Return ballot collection functions

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2021-04-29 16:02:33 +03:00 committed by Alex Vanin
parent 0dd9072ca0
commit 7317388b4d
2 changed files with 134 additions and 0 deletions

View file

@ -6,12 +6,28 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/neo"
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
)
type IRNode struct {
PublicKey interop.PublicKey
}
const irListMethod = "innerRingList"
// InnerRingInvoker returns public key of inner ring node that invoked contract.
// Work around for environments without notary support.
func InnerRingInvoker(ir []IRNode) interop.PublicKey {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.PublicKey) {
return node.PublicKey
}
}
return nil
}
// InnerRingNodes return list of inner ring nodes from state validator role
// in side chain.
func InnerRingNodes() []IRNode {
@ -20,6 +36,13 @@ func InnerRingNodes() []IRNode {
return keysToNodes(list)
}
// InnerRingNodesFromNetmap gets list of inner ring through
// calling "innerRingList" method of smart contract.
// Work around for environments without notary support.
func InnerRingNodesFromNetmap(sc interop.Hash160) []IRNode {
return contract.Call(sc, irListMethod, contract.ReadOnly).([]IRNode)
}
// AlphabetNodes return list of alphabet nodes from committee in side chain.
func AlphabetNodes() []IRNode {
list := neo.GetCommittee()

View file

@ -1,11 +1,122 @@
package common
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util"
)
type Ballot struct {
// ID of the voting decision.
ID []byte
// Public keys of already voted inner ring nodes.
Voters []interop.PublicKey
// Height of block with the last vote.
Height int
}
const voteKey = "ballots"
const blockDiff = 20 // change base on performance evaluation
func InitVote(ctx storage.Context) {
SetSerialized(ctx, voteKey, []Ballot{})
}
// Vote adds ballot for the decision with specific 'id' and returns amount
// on unique voters for that decision.
func Vote(ctx storage.Context, id, from []byte) int {
var (
newCandidates []Ballot
candidates = getBallots(ctx)
found = -1
blockHeight = ledger.CurrentIndex()
)
for i := 0; i < len(candidates); i++ {
cnd := candidates[i]
if blockHeight-cnd.Height > blockDiff {
continue
}
if BytesEqual(cnd.ID, id) {
voters := cnd.Voters
for j := range voters {
if BytesEqual(voters[j], from) {
return len(voters)
}
}
voters = append(voters, from)
cnd = Ballot{ID: id, Voters: voters, Height: blockHeight}
found = len(voters)
}
newCandidates = append(newCandidates, cnd)
}
if found < 0 {
voters := []interop.PublicKey{from}
newCandidates = append(newCandidates, Ballot{
ID: id,
Voters: voters,
Height: blockHeight})
found = 1
}
SetSerialized(ctx, voteKey, newCandidates)
return found
}
// RemoveVotes clears ballots of the decision that has been accepted by
// inner ring nodes.
func RemoveVotes(ctx storage.Context, id []byte) {
var (
newCandidates []Ballot
candidates = getBallots(ctx)
)
for i := 0; i < len(candidates); i++ {
cnd := candidates[i]
if !BytesEqual(cnd.ID, id) {
newCandidates = append(newCandidates, cnd)
}
}
SetSerialized(ctx, voteKey, newCandidates)
}
// getBallots returns deserialized slice of vote ballots.
func getBallots(ctx storage.Context) []Ballot {
data := storage.Get(ctx, voteKey)
if data != nil {
return std.Deserialize(data.([]byte)).([]Ballot)
}
return []Ballot{}
}
// BytesEqual compares two slice of bytes by wrapping them into strings,
// which is necessary with new util.Equal interop behaviour, see neo-go#1176.
func BytesEqual(a []byte, b []byte) bool {
return util.Equals(string(a), string(b))
}
// InvokeID returns hashed value of prefix and args concatenation. Used to
// identify different ballots.
func InvokeID(args []interface{}, prefix []byte) []byte {
for i := range args {
arg := args[i].([]byte)
prefix = append(prefix, arg...)
}
return crypto.Sha256(prefix)
}