[#42] Share InnerRingInvoker function between contracts

Define IRNode structure in common package. Replace innerRingInvoker function
in common package and export it. Reuse this function in all contracts.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-02-02 21:26:34 +03:00 committed by Alex Vanin
parent dd0768aaeb
commit 3395a886fc
7 changed files with 86 additions and 166 deletions

View file

@ -10,12 +10,6 @@ import (
"github.com/nspcc-dev/neofs-contract/common"
)
type (
irNode struct {
key []byte
}
)
const (
// native gas token script hash
gasHash = "\xfb\xed\xfe\x2e\xd2\x22\x65\x92\xb6\x48\xc4\xda\x97\xb9\xc9\xcd\x5d\xc1\xa6\xa6"
@ -84,9 +78,9 @@ func balance(hash string, addr []byte) int {
return balance.(int)
}
func irList() []irNode {
func irList() []common.IRNode {
netmapContractAddr := storage.Get(ctx, netmapKey).([]byte)
return contract.Call(netmapContractAddr, "innerRingList").([]irNode)
return contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
}
func currentEpoch() int {
@ -106,7 +100,7 @@ func total() int {
return storage.Get(ctx, totalKey).(int)
}
func checkPermission(ir []irNode) bool {
func checkPermission(ir []common.IRNode) bool {
index := index() // read from contract memory
if len(ir) <= index {
@ -114,24 +108,7 @@ func checkPermission(ir []irNode) bool {
}
node := ir[index]
return runtime.CheckWitness(node.key)
}
func innerRingInvoker(ir []irNode) []byte {
amountOfContracts := total() // read from contract memory
for i := 0; i < len(ir); i++ {
if i >= amountOfContracts {
return nil
}
node := ir[i]
if runtime.CheckWitness(node.key) {
return node.key
}
}
return nil
return runtime.CheckWitness(node.PublicKey)
}
func Emit() bool {
@ -155,7 +132,7 @@ func Emit() bool {
for i := range innerRingKeys {
node := innerRingKeys[i]
address := contract.CreateStandardAccount(node.key)
address := contract.CreateStandardAccount(node.PublicKey)
_ = contract.Call([]byte(gasHash), "transfer", contractHash, address, gasPerNode, nil)
}
@ -170,7 +147,7 @@ func Vote(epoch int, candidates [][]byte) {
index := index()
name := name()
key := innerRingInvoker(innerRingKeys)
key := common.InnerRingInvoker(innerRingKeys)
if len(key) == 0 {
panic("invalid invoker")
}

View file

@ -11,10 +11,6 @@ import (
)
type (
irNode struct {
key []byte
}
// Token holds all token info.
Token struct {
// Ticker symbol
@ -114,10 +110,10 @@ func TransferX(from, to interop.Hash160, amount int, details []byte) bool {
)
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("transferX: this method must be invoked from inner ring")
}
@ -150,10 +146,10 @@ func TransferX(from, to interop.Hash160, amount int, details []byte) bool {
func Lock(txID []byte, from, to interop.Hash160, amount, until int) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("lock: this method must be invoked from inner ring")
}
@ -188,10 +184,10 @@ func Lock(txID []byte, from, to interop.Hash160, amount, until int) bool {
func NewEpoch(epochNum int) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("epochNum: this method must be invoked from inner ring")
}
@ -227,10 +223,10 @@ func NewEpoch(epochNum int) bool {
func Mint(to interop.Hash160, amount int, details []byte) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("burn: this method must be invoked from inner ring")
}
@ -258,10 +254,10 @@ func Mint(to interop.Hash160, amount int, details []byte) bool {
func Burn(from interop.Hash160, amount int, details []byte) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("burn: this method must be invoked from inner ring")
}
@ -381,17 +377,6 @@ func isUsableAddress(addr interop.Hash160) bool {
return false
}
func innerRingInvoker(ir []irNode) []byte {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.key) {
return node.key
}
}
return nil
}
func getAccount(ctx storage.Context, key interface{}) Account {
data := storage.Get(ctx, key)
if data != nil {

View file

@ -1,6 +1,9 @@
package common
import "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
import (
"github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
)
func InvokeID(args []interface{}, prefix []byte) []byte {
for i := range args {
@ -10,3 +13,19 @@ func InvokeID(args []interface{}, prefix []byte) []byte {
return crypto.SHA256(prefix)
}
type IRNode struct {
PublicKey []byte
}
// InnerRingInvoker returns public key of inner ring node that invoked contract.
func InnerRingInvoker(ir []IRNode) []byte {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.PublicKey) {
return node.PublicKey
}
}
return nil
}

View file

@ -12,10 +12,6 @@ import (
)
type (
irNode struct {
key []byte
}
storageNode struct {
info []byte
}
@ -87,7 +83,7 @@ func Init(addrNetmap, addrBalance, addrID []byte) {
func Put(container, signature, publicKey []byte) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
offset := int(container[1])
@ -98,7 +94,7 @@ func Put(container, signature, publicKey []byte) bool {
// If invoked from storage node, ignore it.
// Inner ring will find tx, validate it and send it again.
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
// check provided key
if !isSignedByOwnerKey(container, signature, ownerID, publicKey) {
@ -126,7 +122,7 @@ func Put(container, signature, publicKey []byte) bool {
for i := 0; i < len(innerRing); i++ {
node := innerRing[i]
to := contract.CreateStandardAccount(node.key)
to := contract.CreateStandardAccount(node.PublicKey)
tx := contract.Call(balanceContractAddr, "transferX",
from,
@ -154,7 +150,7 @@ func Put(container, signature, publicKey []byte) bool {
func Delete(containerID, signature []byte) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
ownerID := getOwnerByID(ctx, containerID)
@ -164,7 +160,7 @@ func Delete(containerID, signature []byte) bool {
// If invoked from storage node, ignore it.
// Inner ring will find tx, validate it and send it again.
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
// check provided key
neofsIDContractAddr := storage.Get(ctx, neofsIDContractKey).([]byte)
@ -341,10 +337,10 @@ func ListContainerSizes(epoch int) [][]byte {
func ProcessEpoch(epochNum int) {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("processEpoch: this method must be invoked from inner ring")
}
@ -365,10 +361,10 @@ func ProcessEpoch(epochNum int) {
func StartContainerEstimation(epoch int) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("startEstimation: only inner ring nodes can invoke this")
}
@ -389,10 +385,10 @@ func StartContainerEstimation(epoch int) bool {
func StopContainerEstimation(epoch int) bool {
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("stopEstimation: only inner ring nodes can invoke this")
}
@ -472,17 +468,6 @@ func remove(ctx storage.Context, key interface{}, value []byte) int {
return ln
}
func innerRingInvoker(ir []irNode) []byte {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.key) {
return node.key
}
}
return nil
}
func getList(ctx storage.Context, key interface{}) [][]byte {
data := storage.Get(ctx, key)
if data != nil {

View file

@ -43,10 +43,6 @@ import (
)
type (
node struct {
pub []byte
}
cheque struct {
id []byte
}
@ -102,7 +98,7 @@ func Init(args [][]byte) bool {
panic("neofs: contract already deployed")
}
var irList []node
var irList []common.IRNode
if len(args) < 3 {
panic("neofs: at least three inner ring keys must be provided")
@ -113,13 +109,13 @@ func Init(args [][]byte) bool {
if len(pub) != publicKeySize {
panic("neofs: incorrect public key length")
}
irList = append(irList, node{pub: pub})
irList = append(irList, common.IRNode{PublicKey: pub})
}
// initialize all storage slices
common.SetSerialized(ctx, innerRingKey, irList)
common.InitVote(ctx)
common.SetSerialized(ctx, candidatesKey, []node{})
common.SetSerialized(ctx, candidatesKey, []common.IRNode{})
common.SetSerialized(ctx, cashedChequesKey, []cheque{})
runtime.Log("neofs: contract initialized")
@ -128,12 +124,12 @@ func Init(args [][]byte) bool {
}
// InnerRingList returns array of inner ring node keys.
func InnerRingList() []node {
func InnerRingList() []common.IRNode {
return getInnerRingNodes(ctx, innerRingKey)
}
// InnerRingCandidates returns array of inner ring candidate node keys.
func InnerRingCandidates() []node {
func InnerRingCandidates() []common.IRNode {
return getInnerRingNodes(ctx, candidatesKey)
}
@ -143,12 +139,12 @@ func InnerRingCandidateRemove(key []byte) bool {
panic("irCandidateRemove: you should be the owner of the public key")
}
nodes := []node{} // it is explicit declaration of empty slice, not nil
nodes := []common.IRNode{} // it is explicit declaration of empty slice, not nil
candidates := getInnerRingNodes(ctx, candidatesKey)
for i := range candidates {
c := candidates[i]
if !common.BytesEqual(c.pub, key) {
if !common.BytesEqual(c.PublicKey, key) {
nodes = append(nodes, c)
} else {
runtime.Log("irCandidateRemove: candidate has been removed")
@ -166,7 +162,7 @@ func InnerRingCandidateAdd(key []byte) bool {
panic("irCandidateAdd: you should be the owner of the public key")
}
c := node{pub: key}
c := common.IRNode{PublicKey: key}
candidates := getInnerRingNodes(ctx, candidatesKey)
list, ok := addNode(candidates, c)
@ -274,7 +270,7 @@ func Cheque(id, user []byte, amount int, lockAcc []byte) bool {
cashedCheques := getCashedCheques(ctx)
hashID := crypto.SHA256(id)
irKey := innerRingInvoker(irList)
irKey := common.InnerRingInvoker(irList)
if len(irKey) == 0 {
panic("cheque: invoked by non inner ring node")
}
@ -353,7 +349,7 @@ func InnerRingUpdate(chequeID []byte, args [][]byte) bool {
irList := getInnerRingNodes(ctx, innerRingKey)
threshold := len(irList)/3*2 + 1
irKey := innerRingInvoker(irList)
irKey := common.InnerRingInvoker(irList)
if len(irKey) == 0 {
panic("innerRingUpdate: invoked by non inner ring node")
}
@ -369,7 +365,7 @@ func InnerRingUpdate(chequeID []byte, args [][]byte) bool {
oldNodes := 0
candidates := getInnerRingNodes(ctx, candidatesKey)
newIR := []node{}
newIR := []common.IRNode{}
loop:
for i := 0; i < len(args); i++ {
@ -381,7 +377,7 @@ loop:
// find key in actual inner ring list
for j := 0; j < len(irList); j++ {
n := irList[j]
if common.BytesEqual(n.pub, key) {
if common.BytesEqual(n.PublicKey, key) {
newIR = append(newIR, n)
oldNodes++
@ -427,7 +423,7 @@ func IsInnerRing(key []byte) bool {
for i := range irList {
node := irList[i]
if common.BytesEqual(node.pub, key) {
if common.BytesEqual(node.PublicKey, key) {
return true
}
}
@ -446,7 +442,7 @@ func SetConfig(id, key, val []byte) bool {
irList := getInnerRingNodes(ctx, innerRingKey)
threshold := len(irList)/3*2 + 1
irKey := innerRingInvoker(irList)
irKey := common.InnerRingInvoker(irList)
if len(irKey) == 0 {
panic("setConfig: invoked by non inner ring node")
}
@ -523,26 +519,14 @@ func Version() int {
return version
}
// innerRingInvoker returns public key of inner ring node that invoked contract.
func innerRingInvoker(ir []node) []byte {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.pub) {
return node.pub
}
}
return nil
}
// getInnerRingNodes returns deserialized slice of inner ring nodes from storage.
func getInnerRingNodes(ctx storage.Context, key string) []node {
func getInnerRingNodes(ctx storage.Context, key string) []common.IRNode {
data := storage.Get(ctx, key)
if data != nil {
return binary.Deserialize(data.([]byte)).([]node)
return binary.Deserialize(data.([]byte)).([]common.IRNode)
}
return []node{}
return []common.IRNode{}
}
// getInnerRingNodes returns deserialized slice of used cheques.
@ -587,9 +571,9 @@ func addCheque(lst []cheque, c cheque) ([]cheque, bool) {
// addNode returns slice of nodes with appended node 'n' and bool flag
// that set to false if node 'n' is already presented in the slice 'lst'.
func addNode(lst []node, n node) ([]node, bool) {
func addNode(lst []common.IRNode, n common.IRNode) ([]common.IRNode, bool) {
for i := 0; i < len(lst); i++ {
if common.BytesEqual(n.pub, lst[i].pub) {
if common.BytesEqual(n.PublicKey, lst[i].PublicKey) {
return nil, false
}
}
@ -602,14 +586,14 @@ func addNode(lst []node, n node) ([]node, bool) {
// rmNodeByKey returns slice of nodes without node with key 'k',
// slices of nodes 'add' with node with key 'k' and bool flag,
// that set to false if node with a key 'k' does not exists in the slice 'lst'.
func rmNodeByKey(lst, add []node, k []byte) ([]node, []node, bool) {
func rmNodeByKey(lst, add []common.IRNode, k []byte) ([]common.IRNode, []common.IRNode, bool) {
var (
flag bool
newLst = []node{} // it is explicit declaration of empty slice, not nil
newLst = []common.IRNode{} // it is explicit declaration of empty slice, not nil
)
for i := 0; i < len(lst); i++ {
if common.BytesEqual(k, lst[i].pub) {
if common.BytesEqual(k, lst[i].PublicKey) {
add = append(add, lst[i])
flag = true
} else {

View file

@ -10,10 +10,6 @@ import (
)
type (
irNode struct {
key []byte
}
UserInfo struct {
Keys [][]byte
}
@ -64,10 +60,10 @@ func AddKey(owner []byte, keys [][]byte) bool {
}
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("addKey: invocation from non inner ring node")
}
@ -118,10 +114,10 @@ func RemoveKey(owner []byte, keys [][]byte) bool {
}
netmapContractAddr := storage.Get(ctx, netmapContractKey).([]byte)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]irNode)
innerRing := contract.Call(netmapContractAddr, "innerRingList").([]common.IRNode)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("removeKey: invocation from non inner ring node")
}
@ -186,17 +182,6 @@ func getUserInfo(ctx storage.Context, key interface{}) UserInfo {
return UserInfo{Keys: [][]byte{}}
}
func innerRingInvoker(ir []irNode) []byte {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.key) {
return node.key
}
}
return nil
}
func invokeIDKeys(owner []byte, keys [][]byte, prefix []byte) []byte {
prefix = append(prefix, owner...)
for i := range keys {

View file

@ -10,10 +10,6 @@ import (
)
type (
irNode struct {
key []byte
}
storageNode struct {
info []byte
}
@ -70,11 +66,11 @@ func Init(keys [][]byte) {
panic("netmap: contract already initialized")
}
var irList []irNode
var irList []common.IRNode
for i := 0; i < len(keys); i++ {
key := keys[i]
irList = append(irList, irNode{key: key})
irList = append(irList, common.IRNode{PublicKey: key})
}
common.SetSerialized(ctx, innerRingKey, irList)
@ -91,7 +87,7 @@ func Init(keys [][]byte) {
runtime.Log("netmap contract initialized")
}
func InnerRingList() []irNode {
func InnerRingList() []common.IRNode {
return getIRNodes(ctx)
}
@ -99,16 +95,16 @@ func UpdateInnerRing(keys [][]byte) bool {
innerRing := getIRNodes(ctx)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("updateInnerRing: this method must be invoked by inner ring nodes")
}
var irList []irNode
var irList []common.IRNode
for i := 0; i < len(keys); i++ {
key := keys[i]
irList = append(irList, irNode{key: key})
irList = append(irList, common.IRNode{PublicKey: key})
}
rawIRList := binary.Serialize(irList)
@ -130,7 +126,7 @@ func AddPeer(nodeInfo []byte) bool {
innerRing := getIRNodes(ctx)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
publicKey := nodeInfo[2:35] // offset:2, len:33
if !runtime.CheckWitness(publicKey) {
@ -172,7 +168,7 @@ func UpdateState(state int, publicKey []byte) bool {
innerRing := getIRNodes(ctx)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
if !runtime.CheckWitness(publicKey) {
panic("updateState: witness check failed")
@ -205,7 +201,7 @@ func NewEpoch(epochNum int) bool {
innerRing := getIRNodes(ctx)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("newEpoch: this method must be invoked by inner ring nodes")
}
@ -279,7 +275,7 @@ func SetConfig(id, key, val []byte) bool {
innerRing := getIRNodes(ctx)
threshold := len(innerRing)/3*2 + 1
irKey := innerRingInvoker(innerRing)
irKey := common.InnerRingInvoker(innerRing)
if len(irKey) == 0 {
panic("setConfig: invoked by non inner ring node")
}
@ -340,17 +336,6 @@ func Version() int {
return version
}
func innerRingInvoker(ir []irNode) []byte {
for i := 0; i < len(ir); i++ {
node := ir[i]
if runtime.CheckWitness(node.key) {
return node.key
}
}
return nil
}
func addToNetmap(ctx storage.Context, n storageNode) []netmapNode {
var (
newNode = n.info
@ -412,13 +397,13 @@ func filterNetmap(ctx storage.Context, st nodeState) []storageNode {
return result
}
func getIRNodes(ctx storage.Context) []irNode {
func getIRNodes(ctx storage.Context) []common.IRNode {
data := storage.Get(ctx, innerRingKey)
if data != nil {
return binary.Deserialize(data.([]byte)).([]irNode)
return binary.Deserialize(data.([]byte)).([]common.IRNode)
}
return []irNode{}
return []common.IRNode{}
}
func getNetmapNodes(ctx storage.Context) []netmapNode {