From dd0768aaebc9d68f9234cd671c31ddf4029477af Mon Sep 17 00:00:00 2001
From: Leonard Lyubich <leonard@nspcc.ru>
Date: Tue, 2 Feb 2021 20:42:05 +0300
Subject: [PATCH] [#42] Share InvokeID between contracts

Replace invokeID to common package and export it.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
---
 balance/balance_contract.go     | 20 +++++---------------
 common/invoke.go                | 12 ++++++++++++
 container/container_contract.go | 19 +++++--------------
 neofsid/neofsid_contract.go     |  9 ---------
 netmap/netmap_contract.go       | 15 +++------------
 5 files changed, 25 insertions(+), 50 deletions(-)
 create mode 100644 common/invoke.go

diff --git a/balance/balance_contract.go b/balance/balance_contract.go
index 398f616..ac7b1ce 100644
--- a/balance/balance_contract.go
+++ b/balance/balance_contract.go
@@ -4,7 +4,6 @@ import (
 	"github.com/nspcc-dev/neo-go/pkg/interop"
 	"github.com/nspcc-dev/neo-go/pkg/interop/binary"
 	"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/iterator"
 	"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
 	"github.com/nspcc-dev/neo-go/pkg/interop/storage"
@@ -128,7 +127,7 @@ func TransferX(from, to interop.Hash160, amount int, details []byte) bool {
 		n = threshold
 		runtime.Log("transferX: processed indirect invoke")
 	} else {
-		hashTxID = invokeID([]interface{}{from, to, amount}, []byte("transfer"))
+		hashTxID = common.InvokeID([]interface{}{from, to, amount}, []byte("transfer"))
 		n = common.Vote(ctx, hashTxID, irKey)
 	}
 
@@ -159,7 +158,7 @@ func Lock(txID []byte, from, to interop.Hash160, amount, until int) bool {
 		panic("lock: this method must be invoked from inner ring")
 	}
 
-	hashTxID := invokeID([]interface{}{txID, from, to, amount, until}, []byte("lock"))
+	hashTxID := common.InvokeID([]interface{}{txID, from, to, amount, until}, []byte("lock"))
 
 	n := common.Vote(ctx, hashTxID, irKey)
 	if n >= threshold {
@@ -197,7 +196,7 @@ func NewEpoch(epochNum int) bool {
 		panic("epochNum: this method must be invoked from inner ring")
 	}
 
-	epochID := invokeID([]interface{}{epochNum}, []byte("epoch"))
+	epochID := common.InvokeID([]interface{}{epochNum}, []byte("epoch"))
 
 	n := common.Vote(ctx, epochID, irKey)
 	if n >= threshold {
@@ -236,7 +235,7 @@ func Mint(to interop.Hash160, amount int, details []byte) bool {
 		panic("burn: this method must be invoked from inner ring")
 	}
 
-	mintID := invokeID([]interface{}{to, amount, details}, []byte("mint"))
+	mintID := common.InvokeID([]interface{}{to, amount, details}, []byte("mint"))
 
 	n := common.Vote(ctx, mintID, irKey)
 	if n >= threshold {
@@ -267,7 +266,7 @@ func Burn(from interop.Hash160, amount int, details []byte) bool {
 		panic("burn: this method must be invoked from inner ring")
 	}
 
-	burnID := invokeID([]interface{}{from, amount, details}, []byte("burn"))
+	burnID := common.InvokeID([]interface{}{from, amount, details}, []byte("burn"))
 
 	n := common.Vote(ctx, burnID, irKey)
 	if n >= threshold {
@@ -402,15 +401,6 @@ func getAccount(ctx storage.Context, key interface{}) Account {
 	return Account{}
 }
 
-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 invocation made from known container or audit contracts.
    This is necessary because calls from these contracts require to do transfer
diff --git a/common/invoke.go b/common/invoke.go
new file mode 100644
index 0000000..6dfe0fd
--- /dev/null
+++ b/common/invoke.go
@@ -0,0 +1,12 @@
+package common
+
+import "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
+
+func InvokeID(args []interface{}, prefix []byte) []byte {
+	for i := range args {
+		arg := args[i].([]byte)
+		prefix = append(prefix, arg...)
+	}
+
+	return crypto.SHA256(prefix)
+}
diff --git a/container/container_contract.go b/container/container_contract.go
index 89084c2..186bc63 100644
--- a/container/container_contract.go
+++ b/container/container_contract.go
@@ -117,7 +117,7 @@ func Put(container, signature, publicKey []byte) bool {
 	from := walletToScripHash(ownerID)
 	balanceContractAddr := storage.Get(ctx, balanceContractKey).([]byte)
 	containerFee := contract.Call(netmapContractAddr, "config", containerFeeKey).(int)
-	hashCandidate := invokeID([]interface{}{container, signature, publicKey}, []byte("put"))
+	hashCandidate := common.InvokeID([]interface{}{container, signature, publicKey}, []byte("put"))
 
 	n := common.Vote(ctx, hashCandidate, irKey)
 	if n >= threshold {
@@ -178,7 +178,7 @@ func Delete(containerID, signature []byte) bool {
 		return true
 	}
 
-	hashCandidate := invokeID([]interface{}{containerID, signature}, []byte("delete"))
+	hashCandidate := common.InvokeID([]interface{}{containerID, signature}, []byte("delete"))
 
 	n := common.Vote(ctx, hashCandidate, irKey)
 	if n >= threshold {
@@ -350,7 +350,7 @@ func ProcessEpoch(epochNum int) {
 	}
 
 	candidates := keysToDelete(epochNum)
-	epochID := invokeID([]interface{}{epochNum}, []byte("epoch"))
+	epochID := common.InvokeID([]interface{}{epochNum}, []byte("epoch"))
 
 	n := common.Vote(ctx, epochID, irKey)
 	if n >= threshold {
@@ -373,7 +373,7 @@ func StartContainerEstimation(epoch int) bool {
 		panic("startEstimation: only inner ring nodes can invoke this")
 	}
 
-	hashCandidate := invokeID([]interface{}{epoch}, []byte("startEstimation"))
+	hashCandidate := common.InvokeID([]interface{}{epoch}, []byte("startEstimation"))
 
 	n := common.Vote(ctx, hashCandidate, irKey)
 	if n >= threshold {
@@ -397,7 +397,7 @@ func StopContainerEstimation(epoch int) bool {
 		panic("stopEstimation: only inner ring nodes can invoke this")
 	}
 
-	hashCandidate := invokeID([]interface{}{epoch}, []byte("stopEstimation"))
+	hashCandidate := common.InvokeID([]interface{}{epoch}, []byte("stopEstimation"))
 
 	n := common.Vote(ctx, hashCandidate, irKey)
 	if n >= threshold {
@@ -531,15 +531,6 @@ func verifySignature(msg, sig []byte, keys [][]byte) bool {
 	return false
 }
 
-func invokeID(args []interface{}, prefix []byte) []byte {
-	for i := range args {
-		arg := args[i].([]byte)
-		prefix = append(prefix, arg...)
-	}
-
-	return crypto.SHA256(prefix)
-}
-
 func getOwnerByID(ctx storage.Context, id []byte) []byte {
 	owners := getList(ctx, ownersKey)
 	for i := 0; i < len(owners); i++ {
diff --git a/neofsid/neofsid_contract.go b/neofsid/neofsid_contract.go
index c40fb13..c12e84f 100644
--- a/neofsid/neofsid_contract.go
+++ b/neofsid/neofsid_contract.go
@@ -197,15 +197,6 @@ func innerRingInvoker(ir []irNode) []byte {
 	return nil
 }
 
-func invokeID(args []interface{}, prefix []byte) []byte {
-	for i := range args {
-		arg := args[i].([]byte)
-		prefix = append(prefix, arg...)
-	}
-
-	return crypto.SHA256(prefix)
-}
-
 func invokeIDKeys(owner []byte, keys [][]byte, prefix []byte) []byte {
 	prefix = append(prefix, owner...)
 	for i := range keys {
diff --git a/netmap/netmap_contract.go b/netmap/netmap_contract.go
index bc2b6e3..10e1f4e 100644
--- a/netmap/netmap_contract.go
+++ b/netmap/netmap_contract.go
@@ -185,7 +185,7 @@ func UpdateState(state int, publicKey []byte) bool {
 	case offlineState:
 		newNetmap := removeFromNetmap(ctx, publicKey)
 
-		hashID := invokeID([]interface{}{publicKey}, []byte("delete"))
+		hashID := common.InvokeID([]interface{}{publicKey}, []byte("delete"))
 		n := common.Vote(ctx, hashID, irKey)
 		if n >= threshold {
 			runtime.Log("updateState: remove storage node from the network map")
@@ -218,7 +218,7 @@ func NewEpoch(epochNum int) bool {
 	data0snapshot := getSnapshot(ctx, snapshot0Key)
 	dataOnlineState := filterNetmap(ctx, onlineState)
 
-	hashID := invokeID([]interface{}{epochNum}, []byte("epoch"))
+	hashID := common.InvokeID([]interface{}{epochNum}, []byte("epoch"))
 
 	n := common.Vote(ctx, hashID, irKey)
 	if n >= threshold {
@@ -285,7 +285,7 @@ func SetConfig(id, key, val []byte) bool {
 	}
 
 	// check unique id of the operation
-	hashID := invokeID([]interface{}{id, key, val}, []byte("config"))
+	hashID := common.InvokeID([]interface{}{id, key, val}, []byte("config"))
 	n := common.Vote(ctx, hashID, irKey)
 
 	if n >= threshold {
@@ -452,12 +452,3 @@ func setConfig(ctx storage.Context, key, val interface{}) {
 
 	storage.Put(ctx, storageKey, val)
 }
-
-func invokeID(args []interface{}, prefix []byte) []byte {
-	for i := range args {
-		arg := args[i].([]byte)
-		prefix = append(prefix, arg...)
-	}
-
-	return crypto.SHA256(prefix)
-}