[#19] alphabet: Check epoch value in Vote method

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2020-12-07 15:53:11 +03:00 committed by Alex Vanin
parent 24b7bc5c77
commit a8d55d9166
8 changed files with 182 additions and 134 deletions

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,8 +34,6 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded
threshold = totalAlphabetContracts * 2 / 3 + 1 threshold = totalAlphabetContracts * 2 / 3 + 1
voteKey = "ballots" voteKey = "ballots"
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )

View file

@ -2,7 +2,6 @@ package alphabetcontract
import ( import (
"github.com/nspcc-dev/neo-go/pkg/interop/binary" "github.com/nspcc-dev/neo-go/pkg/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/interop/blockchain"
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
@ -17,9 +16,9 @@ type (
} }
ballot struct { ballot struct {
id []byte // id of the voting decision id []byte // hash of validators list
n [][]byte // already voted inner ring nodes n [][]byte // already voted inner ring nodes
block int // block with the last vote height int // height is an neofs epoch when ballot was registered
} }
) )
@ -35,9 +34,7 @@ const (
netmapContractKey = "netmapScriptHash" netmapContractKey = "netmapScriptHash"
blockDiff = 20 // amount of blocks when ballot get discarded threshold = totalAlphabetContracts * 2 / 3 + 1
threshold = totalAlphabetContracts*2/3 + 1
voteKey = "ballots" voteKey = "ballots"
totalAlphabetContracts = 7 totalAlphabetContracts = 7
@ -91,6 +88,11 @@ func irList() []irNode {
return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode) return engine.AppCall(netmapContractAddr, "innerRingList").([]irNode)
} }
func currentEpoch() int {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
return engine.AppCall(netmapContractAddr, "epoch").(int)
}
func checkPermission(ir []irNode) bool { func checkPermission(ir []irNode) bool {
if len(ir) <= index { if len(ir) <= index {
return false return false
@ -153,8 +155,13 @@ func Vote(epoch int, candidates [][]byte) {
panic("invalid invoker") panic("invalid invoker")
} }
curEpoch := currentEpoch()
if epoch != curEpoch {
panic("invalid epoch")
}
id := voteID(epoch, candidates) id := voteID(epoch, candidates)
n := vote(ctx, id, key) n := vote(ctx, curEpoch, id, key)
if n >= threshold { if n >= threshold {
candidate := candidates[index%len(candidates)] candidate := candidates[index%len(candidates)]
@ -178,12 +185,11 @@ func Name() string {
return name return name
} }
func vote(ctx storage.Context, id, from []byte) int { func vote(ctx storage.Context, epoch int, id, from []byte) int {
var ( var (
newCandidates []ballot newCandidates []ballot
candidates = getBallots(ctx) candidates = getBallots(ctx)
found = -1 found = -1
blockHeight = blockchain.GetHeight()
) )
for i := 0; i < len(candidates); i++ { for i := 0; i < len(candidates); i++ {
@ -198,12 +204,12 @@ func vote(ctx storage.Context, id, from []byte) int {
} }
voters = append(voters, from) voters = append(voters, from)
cnd = ballot{id: id, n: voters, block: blockHeight} cnd = ballot{id: id, n: voters, height: epoch}
found = len(voters) found = len(voters)
} }
// do not add old ballots, they are invalid // add only valid ballots with current epochs
if blockHeight-cnd.block <= blockDiff { if cnd.height == epoch {
newCandidates = append(newCandidates, cnd) newCandidates = append(newCandidates, cnd)
} }
} }
@ -211,9 +217,9 @@ func vote(ctx storage.Context, id, from []byte) int {
if found < 0 { if found < 0 {
voters := [][]byte{from} voters := [][]byte{from}
newCandidates = append(newCandidates, ballot{ newCandidates = append(newCandidates, ballot{
id: id, id: id,
n: voters, n: voters,
block: blockHeight}) height: epoch})
found = 1 found = 1
} }
@ -259,7 +265,7 @@ func bytesEqual(a []byte, b []byte) bool {
func voteID(epoch interface{}, args [][]byte) []byte { func voteID(epoch interface{}, args [][]byte) []byte {
var ( var (
result []byte result []byte
epochBytes = epoch.([]byte) epochBytes = epoch.([]byte)
) )