forked from TrueCloudLab/frostfs-contract
[#74] Return ballot collection functions
Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
0dd9072ca0
commit
7317388b4d
2 changed files with 134 additions and 0 deletions
23
common/ir.go
23
common/ir.go
|
@ -6,12 +6,28 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
"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/neo"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/roles"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IRNode struct {
|
type IRNode struct {
|
||||||
PublicKey interop.PublicKey
|
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
|
// InnerRingNodes return list of inner ring nodes from state validator role
|
||||||
// in side chain.
|
// in side chain.
|
||||||
func InnerRingNodes() []IRNode {
|
func InnerRingNodes() []IRNode {
|
||||||
|
@ -20,6 +36,13 @@ func InnerRingNodes() []IRNode {
|
||||||
return keysToNodes(list)
|
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.
|
// AlphabetNodes return list of alphabet nodes from committee in side chain.
|
||||||
func AlphabetNodes() []IRNode {
|
func AlphabetNodes() []IRNode {
|
||||||
list := neo.GetCommittee()
|
list := neo.GetCommittee()
|
||||||
|
|
111
common/vote.go
111
common/vote.go
|
@ -1,11 +1,122 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
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"
|
"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,
|
// BytesEqual compares two slice of bytes by wrapping them into strings,
|
||||||
// which is necessary with new util.Equal interop behaviour, see neo-go#1176.
|
// which is necessary with new util.Equal interop behaviour, see neo-go#1176.
|
||||||
func BytesEqual(a []byte, b []byte) bool {
|
func BytesEqual(a []byte, b []byte) bool {
|
||||||
return util.Equals(string(a), string(b))
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue