From d8530284fdd04b01c082987fd19239a51c81a5ac Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Tue, 7 Mar 2023 11:21:11 +0300 Subject: [PATCH] [#7] Remove notary disabled code Signed-off-by: Anton Nikiforov --- CHANGELOG.md | 3 + alphabet/alphabet_contract.go | 98 +++-------- audit/audit_contract.go | 21 +-- balance/balance_contract.go | 154 ++-------------- common/common.go | 26 +++ common/ir.go | 28 --- common/storage.go | 9 - common/vote.go | 149 ---------------- container/container_contract.go | 162 ++--------------- frostfs/config.yml | 2 +- frostfs/doc.go | 10 -- frostfs/frostfs_contract.go | 194 ++------------------- frostfsid/frostfsid_contract.go | 86 +-------- netmap/config.yml | 2 +- netmap/doc.go | 3 +- netmap/netmap_contract.go | 280 +++--------------------------- reputation/reputation_contract.go | 43 +---- subnet/subnet_contract.go | 43 +---- tests/frostfs_test.go | 14 -- 19 files changed, 137 insertions(+), 1190 deletions(-) create mode 100644 common/common.go delete mode 100644 common/vote.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 39e88f7..c960483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ Changelog for FrostFS Contract ### Added ### Changed +### Removed +- Notary disabled code from all contracts (#7) + ### Updated - `neo-go` to `v0.99.4` diff --git a/alphabet/alphabet_contract.go b/alphabet/alphabet_contract.go index 86cbc1c..b8bdd12 100644 --- a/alphabet/alphabet_contract.go +++ b/alphabet/alphabet_contract.go @@ -4,7 +4,6 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-contract/common" "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/native/crypto" "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/neo" @@ -34,6 +33,9 @@ func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) { func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) @@ -41,6 +43,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrNetmap interop.Hash160 addrProxy interop.Hash160 @@ -49,7 +52,7 @@ func _deploy(data interface{}, isUpdate bool) { total int }) - if len(args.addrNetmap) != interop.Hash160Len || !args.notaryDisabled && len(args.addrProxy) != interop.Hash160Len { + if len(args.addrNetmap) != interop.Hash160Len || len(args.addrProxy) != interop.Hash160Len { panic("incorrect length of contract script hash") } @@ -59,13 +62,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, indexKey, args.index) storage.Put(ctx, totalKey, args.total) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.InitVote(ctx) - runtime.Log(args.name + " notary disabled") - } - runtime.Log(args.name + " contract initialized") } @@ -120,15 +116,11 @@ func checkPermission(ir []interop.PublicKey) bool { // and proxy contract. It can be invoked only by an Alphabet node of the Inner Ring. // // To produce GAS, an alphabet contract transfers all available NEO from the contract -// account to itself. If notary is enabled, 50% of the GAS in the contract account +// account to itself. 50% of the GAS in the contract account // are transferred to proxy contract. 43.75% of the GAS are equally distributed // among all Inner Ring nodes. Remaining 6.25% of the GAS stay in the contract. -// -// If notary is disabled, 87.5% of the GAS are equally distributed among all -// Inner Ring nodes. Remaining 12.5% of the GAS stay in the contract. func Emit() { ctx := storage.GetReadOnlyContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) alphabet := common.AlphabetNodes() if !checkPermission(alphabet) { @@ -143,32 +135,23 @@ func Emit() { gasBalance := gas.BalanceOf(contractHash) - if !notaryDisabled { - proxyAddr := storage.Get(ctx, proxyKey).(interop.Hash160) + proxyAddr := storage.Get(ctx, proxyKey).(interop.Hash160) - proxyGas := gasBalance / 2 - if proxyGas == 0 { - panic("no gas to emit") - } - - if !gas.Transfer(contractHash, proxyAddr, proxyGas, nil) { - runtime.Log("could not transfer GAS to proxy contract") - } - - gasBalance -= proxyGas - - runtime.Log("utility token has been emitted to proxy contract") + proxyGas := gasBalance / 2 + if proxyGas == 0 { + panic("no gas to emit") } - var innerRing []interop.PublicKey - - if notaryDisabled { - netmapContract := storage.Get(ctx, netmapKey).(interop.Hash160) - innerRing = common.InnerRingNodesFromNetmap(netmapContract) - } else { - innerRing = common.InnerRingNodes() + if !gas.Transfer(contractHash, proxyAddr, proxyGas, nil) { + runtime.Log("could not transfer GAS to proxy contract") } + gasBalance -= proxyGas + + runtime.Log("utility token has been emitted to proxy contract") + + innerRing := common.InnerRingNodes() + gasPerNode := gasBalance * 7 / 8 / len(innerRing) if gasPerNode != 0 { @@ -192,25 +175,11 @@ func Emit() { // alphabet contracts) should vote for a new committee. func Vote(epoch int, candidates []interop.PublicKey) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) index := index(ctx) name := name(ctx) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("invalid invoker") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) curEpoch := currentEpoch(ctx) if epoch != curEpoch { @@ -220,18 +189,6 @@ func Vote(epoch int, candidates []interop.PublicKey) { candidate := candidates[index%len(candidates)] address := runtime.GetExecutingScriptHash() - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := voteID(epoch, candidates) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - ok := neo.Vote(address, candidate) if ok { runtime.Log(name + ": successfully voted for validator") @@ -240,21 +197,6 @@ func Vote(epoch int, candidates []interop.PublicKey) { } } -func voteID(epoch interface{}, args []interop.PublicKey) []byte { - var ( - result []byte - epochBytes = epoch.([]byte) - ) - - result = append(result, epochBytes...) - - for i := range args { - result = append(result, args[i]...) - } - - return crypto.Sha256(result) -} - // Name returns the Glagolitic name of the contract. func Name() string { ctx := storage.GetReadOnlyContext() diff --git a/audit/audit_contract.go b/audit/audit_contract.go index 5dd6aab..638a76d 100644 --- a/audit/audit_contract.go +++ b/audit/audit_contract.go @@ -44,6 +44,9 @@ const ( func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) @@ -51,6 +54,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrNetmap interop.Hash160 }) @@ -61,12 +65,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, netmapContractKey, args.addrNetmap) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - runtime.Log("audit contract notary disabled") - } - runtime.Log("audit contract initialized") } @@ -90,16 +88,8 @@ func Update(script []byte, manifest []byte, data interface{}) { // in later epochs. func Put(rawAuditResult []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var innerRing []interop.PublicKey - - if notaryDisabled { - netmapContract := storage.Get(ctx, netmapContractKey).(interop.Hash160) - innerRing = common.InnerRingNodesFromNetmap(netmapContract) - } else { - innerRing = common.InnerRingNodes() - } + innerRing := common.InnerRingNodes() hdr := newAuditHeader(rawAuditResult) presented := false @@ -182,7 +172,6 @@ func list(it iterator.Iterator) [][]byte { ignore := [][]byte{ []byte(netmapContractKey), - []byte(notaryDisabledKey), } loop: diff --git a/balance/balance_contract.go b/balance/balance_contract.go index ff9fdb3..8993585 100644 --- a/balance/balance_contract.go +++ b/balance/balance_contract.go @@ -60,6 +60,9 @@ func init() { func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) @@ -67,6 +70,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrNetmap interop.Hash160 addrContainer interop.Hash160 @@ -79,13 +83,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, netmapContractKey, args.addrNetmap) storage.Put(ctx, containerContractKey, args.addrContainer) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.InitVote(ctx) - runtime.Log("balance contract notary disabled") - } - runtime.Log("balance contract initialized") } @@ -146,42 +143,9 @@ func Transfer(from, to interop.Hash160, amount int, data interface{}) bool { // Inner Ring with multisignature. func TransferX(from, to interop.Hash160, amount int, details []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - indirectCall bool - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked from inner ring") - } - - indirectCall = common.FromKnownContract( - ctx, - runtime.GetCallingScriptHash(), - containerContractKey, - ) - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled && !indirectCall { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{from, to, amount}, []byte("transfer")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) result := token.transfer(ctx, from, to, amount, true, details) if !result { @@ -201,23 +165,9 @@ func TransferX(from, to interop.Hash160, amount int, details []byte) { // to a new lock account that won't be used for anything beside Unlock and Burn. func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked from inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) details := common.LockTransferDetails(txDetails) @@ -227,18 +177,6 @@ func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) { Parent: from, } - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{txDetails}, []byte("lock")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - common.SetSerialized(ctx, to, lockAccount) result := token.transfer(ctx, from, to, amount, true, details) @@ -258,21 +196,9 @@ func Lock(txDetails []byte, from, to interop.Hash160, amount, until int) { // It produces Transfer and TransferX notifications. func NewEpoch(epochNum int) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - if notaryDisabled { - indirectCall := common.FromKnownContract( - ctx, - runtime.GetCallingScriptHash(), - netmapContractKey, - ) - if !indirectCall { - panic("this method must be invoked from inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) it := storage.Find(ctx, []byte{}, storage.KeysOnly) for iterator.Next(it) { @@ -305,38 +231,12 @@ func NewEpoch(epochNum int) { // Mint increases total supply of NEP-17 compatible FrostFS token. func Mint(to interop.Hash160, amount int, txDetails []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked from inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) details := common.MintTransferDetails(txDetails) - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{txDetails}, []byte("mint")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - ok := token.transfer(ctx, nil, to, amount, true, details) if !ok { panic("can't transfer assets") @@ -362,38 +262,12 @@ func Mint(to interop.Hash160, amount int, txDetails []byte) { // compatible FrostFS token. func Burn(from interop.Hash160, amount int, txDetails []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked from inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) details := common.BurnTransferDetails(txDetails) - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{txDetails}, []byte("burn")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - ok := token.transfer(ctx, from, nil, amount, true, details) if !ok { panic("can't transfer assets") diff --git a/common/common.go b/common/common.go new file mode 100644 index 0000000..a8cf9c2 --- /dev/null +++ b/common/common.go @@ -0,0 +1,26 @@ +package common + +import ( + "github.com/nspcc-dev/neo-go/pkg/interop/storage" + "github.com/nspcc-dev/neo-go/pkg/interop/util" +) + +const ( + panicMsgForNotaryDisabledEnv = "contract not applicable for notary-disabled environment" +) + +// BytesEqual compares two slices of bytes by wrapping them into strings, +// which is necessary with new util.Equals interop behaviour, see neo-go#1176. +func BytesEqual(a []byte, b []byte) bool { + return util.Equals(string(a), string(b)) +} + +// RmAndCheckNotaryDisabledKey remove notary disabled key from storage and +// panic in notary disabled environment +func RmAndCheckNotaryDisabledKey(data interface{}, key interface{}) { + //TODO(@acid-ant): #9 remove notaryDisabled from args in future version + storage.Delete(storage.GetContext(), key) + if data.([]interface{})[0].(bool) { + panic(panicMsgForNotaryDisabledEnv) + } +} diff --git a/common/ir.go b/common/ir.go index 293f30e..fbc813a 100644 --- a/common/ir.go +++ b/common/ir.go @@ -6,28 +6,12 @@ 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 the public key of the inner ring node that has invoked the contract. -// Work around for environments without notary support. -func InnerRingInvoker(ir []interop.PublicKey) interop.PublicKey { - for i := 0; i < len(ir); i++ { - node := ir[i] - if runtime.CheckWitness(node) { - return node - } - } - - return nil -} - // InnerRingNodes return a list of inner ring nodes from state validator role // in the sidechain. func InnerRingNodes() []interop.PublicKey { @@ -35,18 +19,6 @@ func InnerRingNodes() []interop.PublicKey { return roles.GetDesignatedByRole(roles.NeoFSAlphabet, uint32(blockHeight+1)) } -// InnerRingNodesFromNetmap gets a list of inner ring nodes through -// calling "innerRingList" method of smart contract. -// Work around for environments without notary support. -func InnerRingNodesFromNetmap(sc interop.Hash160) []interop.PublicKey { - nodes := contract.Call(sc, irListMethod, contract.ReadOnly).([]IRNode) - pubs := []interop.PublicKey{} - for i := range nodes { - pubs = append(pubs, nodes[i].PublicKey) - } - return pubs -} - // AlphabetNodes returns a list of alphabet nodes from committee in the sidechain. func AlphabetNodes() []interop.PublicKey { return neo.GetCommittee() diff --git a/common/storage.go b/common/storage.go index caf7ca9..3b9e494 100644 --- a/common/storage.go +++ b/common/storage.go @@ -5,15 +5,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) -func GetList(ctx storage.Context, key interface{}) [][]byte { - data := storage.Get(ctx, key) - if data != nil { - return std.Deserialize(data.([]byte)).([][]byte) - } - - return [][]byte{} -} - // SetSerialized serializes data and puts it into contract storage. func SetSerialized(ctx storage.Context, key interface{}, value interface{}) { data := std.Serialize(value) diff --git a/common/vote.go b/common/vote.go deleted file mode 100644 index 63d10cc..0000000 --- a/common/vote.go +++ /dev/null @@ -1,149 +0,0 @@ -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 the 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 a specific 'id' and returns the amount -// of 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 ( - candidates = getBallots(ctx) - index int - ) - - for i := 0; i < len(candidates); i++ { - cnd := candidates[i] - if BytesEqual(cnd.ID, id) { - index = i - break - } - } - - util.Remove(candidates, index) - SetSerialized(ctx, voteKey, candidates) -} - -// getBallots returns a 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 slices of bytes by wrapping them into strings, -// which is necessary with new util.Equals 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. Iy is 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) -} - -/* - Check if the invocation is made from known container or audit contracts. - This is necessary because calls from these contracts require to do transfer - without signature collection (1 invoke transfer). - - IR1, IR2, IR3, IR4 -(4 invokes)-> [ Container Contract ] -(1 invoke)-> [ Balance Contract ] - - We can do 1 invoke transfer if: - - invokation has happened from inner ring node, - - it is indirect invocation from another smart-contract. - - However, there is a possible attack, when a malicious inner ring node creates - a malicious smart-contract in the morph chain to do indirect call. - - MaliciousIR -(1 invoke)-> [ Malicious Contract ] -(1 invoke)-> [ Balance Contract ] - - To prevent that, we have to allow 1 invoke transfer from authorised well-known - smart-contracts, that will be set up at `Init` method. -*/ - -func FromKnownContract(ctx storage.Context, caller interop.Hash160, key string) bool { - addr := storage.Get(ctx, key).(interop.Hash160) - return BytesEqual(caller, addr) -} diff --git a/container/container_contract.go b/container/container_contract.go index 6601390..03cb65a 100644 --- a/container/container_contract.go +++ b/container/container_contract.go @@ -92,6 +92,9 @@ func OnNEP11Payment(a interop.Hash160, b int, c []byte, d interface{}) { func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) @@ -119,6 +122,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrNetmap interop.Hash160 addrBalance interop.Hash160 @@ -139,13 +143,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, nnsContractKey, args.addrNNS) storage.Put(ctx, nnsRootKey, args.nnsRoot) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.InitVote(ctx) - runtime.Log("container contract notary disabled") - } - // add NNS root for container alias domains registerNiceNameTLD(args.addrNNS, args.nnsRoot) @@ -197,7 +194,6 @@ func PutNamed(container []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte, name, zone string) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) ownerID := ownerFromBinaryContainer(container) containerID := crypto.Sha256(container) @@ -238,26 +234,8 @@ func PutNamed(container []byte, signature interop.Signature, panic("insufficient balance to create container") } - if notaryDisabled { - nodeKey := common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - runtime.Notify("containerPut", container, signature, publicKey, token) - return - } - - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{container, signature, publicKey}, []byte("put")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) // todo: check if new container with unique container id details := common.ContainerFeeTransferDetails(containerID) @@ -336,34 +314,14 @@ func checkNiceNameAvailable(nnsContractAddr interop.Hash160, domain string) bool // If the container doesn't exist, it panics with NotFoundError. func Delete(containerID []byte, signature interop.Signature, token []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) ownerID := getOwnerByID(ctx, containerID) if ownerID == nil { return } - if notaryDisabled { - alphabet := common.AlphabetNodes() - nodeKey := common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - runtime.Notify("containerDelete", containerID, signature, token) - return - } - - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{containerID, signature}, []byte("delete")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) key := append([]byte(nnsHasAliasKey), containerID...) domain := storage.Get(ctx, key).(string) @@ -463,7 +421,6 @@ func List(owner []byte) [][]byte { // If the container doesn't exist, it panics with NotFoundError. func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicKey, token []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) // V2 format // get container ID @@ -476,27 +433,8 @@ func SetEACL(eACL []byte, signature interop.Signature, publicKey interop.PublicK panic(NotFoundError) } - if notaryDisabled { - alphabet := common.AlphabetNodes() - nodeKey := common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - runtime.Notify("setEACL", eACL, signature, publicKey, token) - return - } - - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{eACL}, []byte("setEACL")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) rule := ExtendedACL{ value: eACL, @@ -628,21 +566,9 @@ func IterateContainerSizes(epoch int) iterator.Iterator { // epochNum + 3. It can be invoked only by NewEpoch method of the Netmap contract. func NewEpoch(epochNum int) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - if notaryDisabled { - indirectCall := common.FromKnownContract( - ctx, - runtime.GetCallingScriptHash(), - netmapContractKey, - ) - if !indirectCall { - panic("method must be invoked by inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) cleanupContainers(ctx, epochNum) } @@ -650,36 +576,8 @@ func NewEpoch(epochNum int) { // StartContainerEstimation method produces StartEstimation notification. // It can be invoked only by Alphabet nodes of the Inner Ring. func StartContainerEstimation(epoch int) { - ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("method must be invoked by inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{epoch}, []byte("startEstimation")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) runtime.Notify("StartEstimation", epoch) runtime.Log("notification has been produced") @@ -688,36 +586,8 @@ func StartContainerEstimation(epoch int) { // StopContainerEstimation method produces StopEstimation notification. // It can be invoked only by Alphabet nodes of the Inner Ring. func StopContainerEstimation(epoch int) { - ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("method must be invoked by inner ring") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{epoch}, []byte("stopEstimation")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) runtime.Notify("StopEstimation", epoch) runtime.Log("notification has been produced") diff --git a/frostfs/config.yml b/frostfs/config.yml index 07c56ef..4718ca9 100644 --- a/frostfs/config.yml +++ b/frostfs/config.yml @@ -1,5 +1,5 @@ name: "FrostFS" -safemethods: ["alphabetList", "alphabetAddress", "innerRingCandidates", "config", "listConfig", "version"] +safemethods: ["alphabetAddress", "innerRingCandidates", "config", "listConfig", "version"] permissions: - methods: ["update", "transfer"] events: diff --git a/frostfs/doc.go b/frostfs/doc.go index 99690d6..8a312be 100644 --- a/frostfs/doc.go +++ b/frostfs/doc.go @@ -70,16 +70,6 @@ public keys with the user account (OwnerID). Keys argument is an array of ByteAr - name: keys type: Array -AlphabetUpdate notification. This notification is produced when Alphabet nodes -have updated their lists in the contract. Alphabet argument is an array of ByteArray. It -contains public keys of new alphabet nodes. - - AlphabetUpdate: - - name: id - type: ByteArray - - name: alphabet - type: Array - SetConfig notification. This notification is produced when Alphabet nodes update FrostFS network configuration value. diff --git a/frostfs/frostfs_contract.go b/frostfs/frostfs_contract.go index 26951a2..e7ea5ab 100644 --- a/frostfs/frostfs_contract.go +++ b/frostfs/frostfs_contract.go @@ -5,7 +5,6 @@ import ( "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/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/ledger" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" @@ -48,6 +47,8 @@ var ( func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) @@ -55,6 +56,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrProc interop.Hash160 keys []interop.PublicKey @@ -81,13 +83,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, processingContractKey, args.addrProc) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.InitVote(ctx) - runtime.Log("frostfs contract notary disabled") - } - ln := len(args.config) if ln%2 != 0 { panic("bad configuration") @@ -117,18 +112,6 @@ func Update(script []byte, manifest []byte, data interface{}) { runtime.Log("frostfs contract updated") } -// AlphabetList returns an array of alphabet node keys. It is used in sidechain notary -// disabled environment. -func AlphabetList() []common.IRNode { - ctx := storage.GetReadOnlyContext() - pubs := getAlphabetNodes(ctx) - nodes := []common.IRNode{} - for i := range pubs { - nodes = append(nodes, common.IRNode{PublicKey: pubs[i]}) - } - return nodes -} - // AlphabetAddress returns 2\3n+1 multisignature address of alphabet nodes. // It is used in sidechain notary disabled environment. func AlphabetAddress() interop.Hash160 { @@ -156,43 +139,16 @@ func InnerRingCandidates() []common.IRNode { // This method does not return fee back to the candidate. func InnerRingCandidateRemove(key interop.PublicKey) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) keyOwner := runtime.CheckWitness(key) if !keyOwner { - if notaryDisabled { - alphabet = getAlphabetNodes(ctx) - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked by candidate or alphabet") - } - } else { - multiaddr := AlphabetAddress() - if !runtime.CheckWitness(multiaddr) { - panic("this method must be invoked by candidate or alphabet") - } + multiaddr := AlphabetAddress() + if !runtime.CheckWitness(multiaddr) { + panic("this method must be invoked by candidate or alphabet") } } - if notaryDisabled && !keyOwner { - threshold := len(alphabet)*2/3 + 1 - id := append(key, []byte("delete")...) - hashID := crypto.Sha256(id) - - n := common.Vote(ctx, hashID, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, hashID) - } - prefix := []byte(candidatesKey) stKey := append(prefix, key...) if storage.Get(ctx, stKey) != nil { @@ -285,28 +241,15 @@ func Withdraw(user interop.Hash160, amount int) { } ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) // transfer fee to proxy contract to pay cheque invocation fee := getConfig(ctx, withdrawFeeConfigKey).(int) - if notaryDisabled { - alphabet := getAlphabetNodes(ctx) - for _, node := range alphabet { - processingAddr := contract.CreateStandardAccount(node) + processingAddr := storage.Get(ctx, processingContractKey).(interop.Hash160) - transferred := gas.Transfer(user, processingAddr, fee, []byte{}) - if !transferred { - panic("failed to transfer withdraw fee, aborting") - } - } - } else { - processingAddr := storage.Get(ctx, processingContractKey).(interop.Hash160) - - transferred := gas.Transfer(user, processingAddr, fee, []byte{}) - if !transferred { - panic("failed to transfer withdraw fee, aborting") - } + transferred := gas.Transfer(user, processingAddr, fee, []byte{}) + if !transferred { + panic("failed to transfer withdraw fee, aborting") } // notify alphabet nodes @@ -322,38 +265,11 @@ func Withdraw(user interop.Hash160, amount int) { // // This method produces Cheque notification to burn assets in sidechain. func Cheque(id []byte, user interop.Hash160, amount int, lockAcc []byte) { - ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = getAlphabetNodes(ctx) - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked by alphabet") - } - } else { - multiaddr := AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) from := runtime.GetExecutingScriptHash() - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - transferred := gas.Transfer(from, user, amount, nil) if !transferred { panic("failed to transfer funds, aborting") @@ -403,63 +319,6 @@ func Unbind(user []byte, keys []interop.PublicKey) { runtime.Notify("Unbind", user, keys) } -// AlphabetUpdate updates a list of alphabet nodes with the provided list of -// public keys. It can be invoked only by alphabet nodes. -// -// This method is used in notary disabled sidechain environment. In this case, -// the actual alphabet list should be stored in the FrostFS contract. -func AlphabetUpdate(id []byte, args []interop.PublicKey) { - ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - if len(args) == 0 { - panic("bad arguments") - } - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = getAlphabetNodes(ctx) - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked by alphabet") - } - } else { - multiaddr := AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - newAlphabet := []interop.PublicKey{} - - for i := 0; i < len(args); i++ { - pubKey := args[i] - if len(pubKey) != interop.PublicKeyCompressedLen { - panic("invalid public key in alphabet list") - } - - newAlphabet = append(newAlphabet, pubKey) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - - common.SetSerialized(ctx, alphabetKey, newAlphabet) - - runtime.Notify("AlphabetUpdate", id, newAlphabet) - runtime.Log("alphabet list has been updated") -} - // Config returns configuration value of FrostFS configuration. If the key does // not exists, returns nil. func Config(key []byte) interface{} { @@ -471,34 +330,9 @@ func Config(key []byte) interface{} { // only by Alphabet nodes. func SetConfig(id, key, val []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = getAlphabetNodes(ctx) - nodeKey = common.InnerRingInvoker(alphabet) - if len(key) == 0 { - panic("this method must be invoked by alphabet") - } - } else { - multiaddr := AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } + multiaddr := AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) setConfig(ctx, key, val) diff --git a/frostfsid/frostfsid_contract.go b/frostfsid/frostfsid_contract.go index 7e6bd23..79fb0d5 100644 --- a/frostfsid/frostfsid_contract.go +++ b/frostfsid/frostfsid_contract.go @@ -5,7 +5,6 @@ import ( "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/iterator" - "github.com/nspcc-dev/neo-go/pkg/interop/native/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/native/management" "github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/storage" @@ -31,6 +30,8 @@ const ( func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) @@ -38,6 +39,7 @@ func _deploy(data interface{}, isUpdate bool) { } args := data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrNetmap interop.Hash160 addrContainer interop.Hash160 @@ -50,13 +52,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, netmapContractKey, args.addrNetmap) storage.Put(ctx, containerContractKey, args.addrContainer) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.InitVote(ctx) - runtime.Log("frostfsid contract notary disabled") - } - runtime.Log("frostfsid contract initialized") } @@ -90,41 +85,9 @@ func AddKey(owner []byte, keys []interop.PublicKey) { } ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - indirectCall bool - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("invocation from non inner ring node") - } - - indirectCall = common.FromKnownContract( - ctx, - runtime.GetCallingScriptHash(), - containerContractKey) - - if indirectCall { - threshold := len(alphabet)*2/3 + 1 - id := invokeIDKeys(owner, keys, []byte("add")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) ownerKey := append([]byte{ownerKeysPrefix}, owner...) for i := range keys { @@ -153,34 +116,10 @@ func RemoveKey(owner []byte, keys []interop.PublicKey) { } ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("invocation from non inner ring node") - } - - threshold := len(alphabet)*2/3 + 1 - id := invokeIDKeys(owner, keys, []byte("remove")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } else { - multiaddr := common.AlphabetAddress() - if !runtime.CheckWitness(multiaddr) { - panic("invocation from non inner ring node") - } + multiaddr := common.AlphabetAddress() + if !runtime.CheckWitness(multiaddr) { + panic("invocation from non inner ring node") } ownerKey := append([]byte{ownerKeysPrefix}, owner...) @@ -222,12 +161,3 @@ func getUserInfo(ctx storage.Context, key interface{}) UserInfo { return UserInfo{Keys: pubs} } - -func invokeIDKeys(owner []byte, keys []interop.PublicKey, prefix []byte) []byte { - prefix = append(prefix, owner...) - for i := range keys { - prefix = append(prefix, keys[i]...) - } - - return crypto.Sha256(prefix) -} diff --git a/netmap/config.yml b/netmap/config.yml index b04ecf5..df985cd 100644 --- a/netmap/config.yml +++ b/netmap/config.yml @@ -1,5 +1,5 @@ name: "Netmap" -safemethods: ["innerRingList", "epoch", "netmap", "netmapCandidates", "snapshot", "snapshotByEpoch", "config", "listConfig", "version"] +safemethods: ["epoch", "netmap", "netmapCandidates", "snapshot", "snapshotByEpoch", "config", "listConfig", "version"] permissions: - methods: ["update", "newEpoch"] events: diff --git a/netmap/doc.go b/netmap/doc.go index 549451b..c352699 100644 --- a/netmap/doc.go +++ b/netmap/doc.go @@ -2,8 +2,7 @@ Netmap contract is a contract deployed in FrostFS sidechain. Netmap contract stores and manages FrostFS network map, Storage node candidates -and epoch number counter. In notary disabled environment, contract also stores -a list of Inner Ring node keys. +and epoch number counter. # Contract notifications diff --git a/netmap/netmap_contract.go b/netmap/netmap_contract.go index 7d4600e..8601093 100644 --- a/netmap/netmap_contract.go +++ b/netmap/netmap_contract.go @@ -5,7 +5,6 @@ import ( "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/iterator" - "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/management" "github.com/nspcc-dev/neo-go/pkg/interop/native/std" @@ -71,7 +70,10 @@ var ( func _deploy(data interface{}, isUpdate bool) { ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + var args = data.(struct { + //TODO(@acid-ant): #9 remove notaryDisabled in future version notaryDisabled bool addrBalance interop.Hash160 addrContainer interop.Hash160 @@ -115,14 +117,6 @@ func _deploy(data interface{}, isUpdate bool) { storage.Put(ctx, balanceContractKey, args.addrBalance) storage.Put(ctx, containerContractKey, args.addrContainer) - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.SetSerialized(ctx, innerRingKey, args.keys) - common.InitVote(ctx) - runtime.Log("netmap contract notary disabled") - } - runtime.Log("netmap contract initialized") } @@ -138,62 +132,6 @@ func Update(script []byte, manifest []byte, data interface{}) { runtime.Log("netmap contract updated") } -// InnerRingList method returns a slice of structures that contains the public key of -// an Inner Ring node. It should be used in notary disabled environment only. -// -// If notary is enabled, look to NeoFSAlphabet role in native RoleManagement -// contract of the sidechain. -func InnerRingList() []common.IRNode { - ctx := storage.GetReadOnlyContext() - pubs := getIRNodes(ctx) - nodes := []common.IRNode{} - for i := range pubs { - nodes = append(nodes, common.IRNode{PublicKey: pubs[i]}) - } - return nodes -} - -// UpdateInnerRing method updates a list of Inner Ring node keys. It should be used -// only in notary disabled environment. It can be invoked only by Alphabet nodes. -// -// If notary is enabled, update NeoFSAlphabet role in native RoleManagement -// contract of the sidechain. Use notary service to collect multisignature. -func UpdateInnerRing(keys []interop.PublicKey) { - ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked by alphabet nodes") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := keysID(keys, []byte("updateIR")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - - runtime.Log("inner ring list updated") - common.SetSerialized(ctx, innerRingKey, keys) -} - // AddPeerIR accepts Alphabet calls in the notary-enabled contract setting and // behaves similar to AddPeer in the notary-disabled one. // @@ -201,10 +139,6 @@ func UpdateInnerRing(keys []interop.PublicKey) { // AddPeerIR MUST be called by the Alphabet member only. func AddPeerIR(nodeInfo []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - if notaryDisabled { - panic("AddPeerIR should only be called in notary-enabled environment") - } common.CheckAlphabetWitness(common.AlphabetAddress()) @@ -217,77 +151,13 @@ func AddPeerIR(nodeInfo []byte) { } // AddPeer accepts information about the network map candidate in the FrostFS -// binary protocol format, identifies the caller and behaves depending on different -// conditions listed below. -// -// Contract settings: -// -// (1) notary-enabled -// (2) notary-disabled -// -// Callers: -// -// (a) candidate himself, if node's public key corresponds to the signer -// (b) Alphabet member -// (c) others -// -// AddPeer case-by-case behavior: -// -// (1a) does nothing -// (1b) panics. Notice that AddPeerIR MUST be used for this purpose. -// (2a) throws AddPeer notification with the provided BLOB -// (2b) accepts Alphabet vote. If the threshold of votes is reached, adds -// new element to the candidate set, and throws AddPeerSuccess notification. -// (c) panics -// -// Candidate MUST call AddPeer with "online" state in its descriptor. Alphabet -// members MUST NOT call AddPeer with any other states. +// binary protocol format and does nothing. Keep method because storage node +// creates a notary transaction with this method, which produces a notary +// notification (implicit here). func AddPeer(nodeInfo []byte) { - ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - } - - // V2 format - publicKey := nodeInfo[2:35] // offset:2, len:33 - - // If notary is enabled or caller is not an alphabet node, - // just emit the notification for alphabet. - if !notaryDisabled || len(nodeKey) == 0 { - common.CheckWitness(publicKey) - if notaryDisabled { - runtime.Notify("AddPeer", nodeInfo) - } - return - } - - candidate := Node{ - BLOB: nodeInfo, - State: NodeStateOnline, - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - rawCandidate := std.Serialize(candidate) - id := crypto.Sha256(rawCandidate) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - - addToNetmap(ctx, publicKey, candidate) + // V2 format - offset:2, len:33 + common.CheckWitness(nodeInfo[2:35]) + return } // updates state of the network map candidate by its public key in the contract @@ -310,13 +180,8 @@ func updateCandidateState(ctx storage.Context, publicKey interop.PublicKey, stat } // UpdateState accepts new state to be assigned to network map candidate -// identified by the given public key, identifies the signer and behaves -// depending on different conditions listed below. -// -// Contract settings: -// -// (1) notary-enabled -// (2) notary-disabled +// identified by the given public key, identifies the signer. +// Applicable only for notary-enabled environment. // // Signers: // @@ -327,13 +192,10 @@ func updateCandidateState(ctx storage.Context, publicKey interop.PublicKey, stat // // UpdateState case-by-case behavior: // -// (1a) panics -// (1b) like (1a) -// (1ab) updates candidate's state in the contract storage (*), and throws +// (a) panics +// (b) panics +// (ab) updates candidate's state in the contract storage (*), and throws // UpdateStateSuccess with the provided key and new state -// (2a) throws UpdateState notification with the provided key and new state -// (2b) accepts Alphabet vote. If the threshold of votes is reached, behaves -// like (1ab). // (c) panics // // (*) Candidate is removed from the candidate set if state is NodeStateOffline. @@ -349,33 +211,9 @@ func UpdateState(state NodeState, publicKey interop.PublicKey) { } ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - if notaryDisabled { - alphabet := common.AlphabetNodes() - nodeKey := common.InnerRingInvoker(alphabet) - - // If caller is not an alphabet node, - // just emit the notification for alphabet. - if len(nodeKey) == 0 { - common.CheckWitness(publicKey) - runtime.Notify("UpdateState", state, publicKey) - return - } - - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{state, publicKey}, []byte("update")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } else { - common.CheckWitness(publicKey) - common.CheckAlphabetWitness(common.AlphabetAddress()) - } + common.CheckWitness(publicKey) + common.CheckAlphabetWitness(common.AlphabetAddress()) updateCandidateState(ctx, publicKey, state) } @@ -388,10 +226,6 @@ func UpdateState(state NodeState, publicKey interop.PublicKey) { // UpdateStateIR MUST be called by the Alphabet member only. func UpdateStateIR(state NodeState, publicKey interop.PublicKey) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - if notaryDisabled { - panic("UpdateStateIR should only be called in notary-enabled environment") - } common.CheckAlphabetWitness(common.AlphabetAddress()) @@ -409,35 +243,9 @@ func UpdateStateIR(state NodeState, publicKey interop.PublicKey) { // It produces NewEpoch notification. func NewEpoch(epochNum int) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("this method must be invoked by inner ring nodes") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{epochNum}, []byte("epoch")) - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) currentEpoch := storage.Get(ctx, snapshotEpoch).(int) if epochNum <= currentEpoch { @@ -634,34 +442,9 @@ func Config(key []byte) interface{} { // only by Alphabet nodes. func SetConfig(id, key, val []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - panic("invoked by non inner ring node") - } - } else { - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } - - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) setConfig(ctx, key, val) @@ -784,26 +567,3 @@ func cleanup(ctx storage.Context, epoch int) { containerContractAddr := storage.Get(ctx, containerContractKey).(interop.Hash160) contract.Call(containerContractAddr, cleanupEpochMethod, contract.All, epoch) } - -func getIRNodes(ctx storage.Context) []interop.PublicKey { - data := storage.Get(ctx, innerRingKey) - if data != nil { - return std.Deserialize(data.([]byte)).([]interop.PublicKey) - } - - return []interop.PublicKey{} -} - -func keysID(args []interop.PublicKey, prefix []byte) []byte { - var ( - result []byte - ) - - result = append(result, prefix...) - - for i := range args { - result = append(result, args[i]...) - } - - return crypto.Sha256(result) -} diff --git a/reputation/reputation_contract.go b/reputation/reputation_contract.go index 4e6104c..2055204 100644 --- a/reputation/reputation_contract.go +++ b/reputation/reputation_contract.go @@ -18,7 +18,7 @@ const ( ) func _deploy(data interface{}, isUpdate bool) { - ctx := storage.GetContext() + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) if isUpdate { args := data.([]interface{}) @@ -26,17 +26,6 @@ func _deploy(data interface{}, isUpdate bool) { return } - args := data.(struct { - notaryDisabled bool - }) - - // initialize the way to collect signatures - storage.Put(ctx, notaryDisabledKey, args.notaryDisabled) - if args.notaryDisabled { - common.InitVote(ctx) - runtime.Log("reputation contract notary disabled") - } - runtime.Log("reputation contract initialized") } @@ -60,40 +49,14 @@ func Update(script []byte, manifest []byte, data interface{}) { // Value contains a stable marshaled structure of DataAuditResult. func Put(epoch int, peerID []byte, value []byte) { ctx := storage.GetContext() - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - var ( // for invocation collection without notary - alphabet []interop.PublicKey - nodeKey []byte - alphabetCall bool - ) - - if notaryDisabled { - alphabet = common.AlphabetNodes() - nodeKey = common.InnerRingInvoker(alphabet) - alphabetCall = len(nodeKey) != 0 - } else { - multiaddr := common.AlphabetAddress() - alphabetCall = runtime.CheckWitness(multiaddr) - } - - if !alphabetCall { + multiaddr := common.AlphabetAddress() + if !runtime.CheckWitness(multiaddr) { runtime.Notify("reputationPut", epoch, peerID, value) return } id := storageID(epoch, peerID) - if notaryDisabled { - threshold := len(alphabet)*2/3 + 1 - - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } - key := getReputationKey(reputationCountPrefix, id) rawCnt := storage.Get(ctx, key) cnt := 0 diff --git a/subnet/subnet_contract.go b/subnet/subnet_contract.go index 3d87b14..fdd3f74 100644 --- a/subnet/subnet_contract.go +++ b/subnet/subnet_contract.go @@ -27,14 +27,6 @@ const ( ErrInvalidUser = "invalid user" // ErrInvalidNode is thrown when node has invalid format. ErrInvalidNode = "invalid node key" - // ErrNodeAdmNotExist is thrown when node admin is not found. - ErrNodeAdmNotExist = "node admin not found" - // ErrClientAdmNotExist is thrown when client admin is not found. - ErrClientAdmNotExist = "client admin not found" - // ErrNodeNotExist is thrown when node is not found. - ErrNodeNotExist = "node not found" - // ErrUserNotExist is thrown when user is not found. - ErrUserNotExist = "user not found" // ErrAccessDenied is thrown when operation is denied for caller. ErrAccessDenied = "access denied" ) @@ -57,18 +49,13 @@ const ( // _deploy function sets up initial list of inner ring public keys. func _deploy(data interface{}, isUpdate bool) { + common.RmAndCheckNotaryDisabledKey(data, notaryDisabledKey) + if isUpdate { args := data.([]interface{}) common.CheckVersion(args[len(args)-1].(int)) return } - - args := data.(struct { - notaryDisabled bool - }) - - ctx := storage.GetContext() - storage.Put(ctx, []byte{notaryDisabledKey}, args.notaryDisabled) } // Update method updates contract source code and manifest. It can be invoked @@ -99,30 +86,10 @@ func Put(id []byte, ownerKey interop.PublicKey, info []byte) { panic(ErrAlreadyExists) } - notaryDisabled := storage.Get(ctx, notaryDisabledKey).(bool) - if notaryDisabled { - alphabet := common.AlphabetNodes() - nodeKey := common.InnerRingInvoker(alphabet) - if len(nodeKey) == 0 { - common.CheckWitness(ownerKey) - runtime.Notify("Put", id, ownerKey, info) - return - } + common.CheckOwnerWitness(ownerKey) - threshold := len(alphabet)*2/3 + 1 - id := common.InvokeID([]interface{}{ownerKey, info}, []byte("put")) - n := common.Vote(ctx, id, nodeKey) - if n < threshold { - return - } - - common.RemoveVotes(ctx, id) - } else { - common.CheckOwnerWitness(ownerKey) - - multiaddr := common.AlphabetAddress() - common.CheckAlphabetWitness(multiaddr) - } + multiaddr := common.AlphabetAddress() + common.CheckAlphabetWitness(multiaddr) storage.Put(ctx, stKey, ownerKey) stKey[0] = infoPrefix diff --git a/tests/frostfs_test.go b/tests/frostfs_test.go index ec72765..a9b59d2 100644 --- a/tests/frostfs_test.go +++ b/tests/frostfs_test.go @@ -79,20 +79,6 @@ func newFrostFSInvoker(t *testing.T, n int, config ...interface{}) (*neotest.Con return e.CommitteeInvoker(h).WithSigners(alphabet), alphabet, pubs } -func TestFrostFS_AlphabetList(t *testing.T) { - const alphabetSize = 4 - - e, _, pubs := newFrostFSInvoker(t, alphabetSize) - arr := make([]stackitem.Item, len(pubs)) - for i := range arr { - arr[i] = stackitem.NewStruct([]stackitem.Item{ - stackitem.NewByteArray(pubs[i].Bytes()), - }) - } - - e.Invoke(t, stackitem.NewArray(arr), "alphabetList") -} - func TestFrostFS_InnerRingCandidate(t *testing.T) { e, _, _ := newFrostFSInvoker(t, 4, frostfs.CandidateFeeConfigKey, int64(10))