forked from TrueCloudLab/frostfs-contract
[#74] neofs: Check alphabet multi signature and don't use ballots
Ballots are inefficient to collect invocations of contract methods. Instead contract can check multi signature collected outside of the contract, e.g. with notary service. Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
be6c280032
commit
086b4c632c
1 changed files with 26 additions and 73 deletions
|
@ -36,7 +36,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
"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/iterator"
|
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||||
|
@ -98,7 +97,6 @@ func Init(owner interop.PublicKey, args []interop.PublicKey) bool {
|
||||||
|
|
||||||
// initialize all storage slices
|
// initialize all storage slices
|
||||||
common.SetSerialized(ctx, alphabetKey, irList)
|
common.SetSerialized(ctx, alphabetKey, irList)
|
||||||
common.InitVote(ctx)
|
|
||||||
common.SetSerialized(ctx, candidatesKey, []common.IRNode{})
|
common.SetSerialized(ctx, candidatesKey, []common.IRNode{})
|
||||||
|
|
||||||
storage.Put(ctx, common.OwnerKey, owner)
|
storage.Put(ctx, common.OwnerKey, owner)
|
||||||
|
@ -145,22 +143,9 @@ func InnerRingCandidates() []common.IRNode {
|
||||||
func InnerRingCandidateRemove(key interop.PublicKey) bool {
|
func InnerRingCandidateRemove(key interop.PublicKey) bool {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
if !runtime.CheckWitness(key) {
|
multiaddr := AlphabetAddress()
|
||||||
alphabet := getNodes(ctx, alphabetKey)
|
if !runtime.CheckWitness(key) && !runtime.CheckWitness(multiaddr) {
|
||||||
threshold := len(alphabet)*2/3 + 1
|
panic("irCandidateRemove: this method must be invoked by candidate or alphabet")
|
||||||
|
|
||||||
nodeKey := common.InnerRingInvoker(alphabet)
|
|
||||||
if len(nodeKey) == 0 {
|
|
||||||
panic("irCandidateRemove: invoked by non alphabet node")
|
|
||||||
}
|
|
||||||
|
|
||||||
id := append(key, []byte("delete")...)
|
|
||||||
hashID := crypto.Sha256(id)
|
|
||||||
|
|
||||||
n := common.Vote(ctx, hashID, nodeKey)
|
|
||||||
if n < threshold {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := []common.IRNode{} // it is explicit declaration of empty slice, not nil
|
nodes := []common.IRNode{} // it is explicit declaration of empty slice, not nil
|
||||||
|
@ -185,7 +170,7 @@ func InnerRingCandidateAdd(key interop.PublicKey) bool {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
if !runtime.CheckWitness(key) {
|
if !runtime.CheckWitness(key) {
|
||||||
panic("irCandidateAdd: you should be the owner of the public key")
|
panic("irCandidateAdd: this method must be invoked by candidate")
|
||||||
}
|
}
|
||||||
|
|
||||||
c := common.IRNode{PublicKey: key}
|
c := common.IRNode{PublicKey: key}
|
||||||
|
@ -287,20 +272,11 @@ func Withdraw(user []byte, amount int) bool {
|
||||||
// Cheque sends gas assets back to the user if they were successfully
|
// Cheque sends gas assets back to the user if they were successfully
|
||||||
// locked in NeoFS balance contract.
|
// locked in NeoFS balance contract.
|
||||||
func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) bool {
|
func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) bool {
|
||||||
ctx := storage.GetContext()
|
multiaddr := AlphabetAddress()
|
||||||
alphabet := getNodes(ctx, alphabetKey)
|
if !runtime.CheckWitness(multiaddr) {
|
||||||
threshold := len(alphabet)*2/3 + 1
|
panic("cheque: this method must be invoked by alphabet")
|
||||||
|
|
||||||
hashID := crypto.Sha256(id)
|
|
||||||
|
|
||||||
key := common.InnerRingInvoker(alphabet)
|
|
||||||
if len(key) == 0 {
|
|
||||||
panic("cheque: invoked by non alphabet node")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n := common.Vote(ctx, hashID, key)
|
|
||||||
if n >= threshold {
|
|
||||||
common.RemoveVotes(ctx, hashID)
|
|
||||||
from := runtime.GetExecutingScriptHash()
|
from := runtime.GetExecutingScriptHash()
|
||||||
|
|
||||||
transferred := gas.Transfer(from, user, amount, nil)
|
transferred := gas.Transfer(from, user, amount, nil)
|
||||||
|
@ -310,7 +286,6 @@ func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) bool {
|
||||||
|
|
||||||
runtime.Log("cheque: funds have been transferred")
|
runtime.Log("cheque: funds have been transferred")
|
||||||
runtime.Notify("Cheque", id, user, amount, lockAcc)
|
runtime.Notify("Cheque", id, user, amount, lockAcc)
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -360,12 +335,9 @@ func AlphabetUpdate(chequeID []byte, args []interop.PublicKey) bool {
|
||||||
panic("alphabetUpdate: bad arguments")
|
panic("alphabetUpdate: bad arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
alphabet := getNodes(ctx, alphabetKey)
|
multiaddr := AlphabetAddress()
|
||||||
threshold := len(alphabet)*2/3 + 1
|
if !runtime.CheckWitness(multiaddr) {
|
||||||
|
panic("alphabetUpdate: this method must be invoked by alphabet")
|
||||||
key := common.InnerRingInvoker(alphabet)
|
|
||||||
if len(key) == 0 {
|
|
||||||
panic("innerRingUpdate: invoked by non alphabet node")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newAlphabet := []common.IRNode{}
|
newAlphabet := []common.IRNode{}
|
||||||
|
@ -381,17 +353,10 @@ func AlphabetUpdate(chequeID []byte, args []interop.PublicKey) bool {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
hashID := crypto.Sha256(chequeID)
|
|
||||||
|
|
||||||
n := common.Vote(ctx, hashID, key)
|
|
||||||
if n >= threshold {
|
|
||||||
common.RemoveVotes(ctx, hashID)
|
|
||||||
|
|
||||||
common.SetSerialized(ctx, alphabetKey, newAlphabet)
|
common.SetSerialized(ctx, alphabetKey, newAlphabet)
|
||||||
|
|
||||||
runtime.Notify("AlphabetUpdate", chequeID, newAlphabet)
|
runtime.Notify("AlphabetUpdate", chequeID, newAlphabet)
|
||||||
runtime.Log("alphabetUpdate: alphabet list has been updated")
|
runtime.Log("alphabetUpdate: alphabet list has been updated")
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -406,27 +371,15 @@ func Config(key []byte) interface{} {
|
||||||
func SetConfig(id, key, val []byte) bool {
|
func SetConfig(id, key, val []byte) bool {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
|
|
||||||
// check if it is alphabet invocation
|
multiaddr := AlphabetAddress()
|
||||||
alphabet := getNodes(ctx, alphabetKey)
|
if !runtime.CheckWitness(multiaddr) {
|
||||||
threshold := len(alphabet)*2/3 + 1
|
panic("setConfig: this method must be invoked by alphabet")
|
||||||
|
|
||||||
nodeKey := common.InnerRingInvoker(alphabet)
|
|
||||||
if len(nodeKey) == 0 {
|
|
||||||
panic("setConfig: invoked by non alphabet node")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vote for new configuration value
|
|
||||||
hashID := crypto.Sha256(id)
|
|
||||||
|
|
||||||
n := common.Vote(ctx, hashID, nodeKey)
|
|
||||||
if n >= threshold {
|
|
||||||
common.RemoveVotes(ctx, hashID)
|
|
||||||
|
|
||||||
setConfig(ctx, key, val)
|
setConfig(ctx, key, val)
|
||||||
|
|
||||||
runtime.Notify("SetConfig", id, key, val)
|
runtime.Notify("SetConfig", id, key, val)
|
||||||
runtime.Log("setConfig: configuration has been updated")
|
runtime.Log("setConfig: configuration has been updated")
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue