Add system config methods

NeoFS contract will contain installation parameters
for storage network such as max object size, epoch
duration, etc.
This commit is contained in:
alexvanin 2020-07-16 18:59:49 +03:00
parent 058e39dcf1
commit 8c7bcea436

View file

@ -6,6 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/contract" "github.com/nspcc-dev/neo-go/pkg/interop/contract"
"github.com/nspcc-dev/neo-go/pkg/interop/crypto" "github.com/nspcc-dev/neo-go/pkg/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/engine" "github.com/nspcc-dev/neo-go/pkg/interop/engine"
"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/runtime"
"github.com/nspcc-dev/neo-go/pkg/interop/storage" "github.com/nspcc-dev/neo-go/pkg/interop/storage"
"github.com/nspcc-dev/neo-go/pkg/interop/util" "github.com/nspcc-dev/neo-go/pkg/interop/util"
@ -25,11 +26,17 @@ type (
cheque struct { cheque struct {
id []byte id []byte
} }
record struct {
key []byte
val []byte
}
) )
const ( const (
tokenHash = "\x3b\x7d\x37\x11\xc6\xf0\xcc\xf9\xb1\xdc\xa9\x03\xd1\xbf\xa1\xd8\x96\xf1\x23\x8c" tokenHash = "\x3b\x7d\x37\x11\xc6\xf0\xcc\xf9\xb1\xdc\xa9\x03\xd1\xbf\xa1\xd8\x96\xf1\x23\x8c"
innerRingCandidateFee = 100 * 1_0000_0000 // 100 Fixed8 Gas defaultCandidateFee = 100 * 1_0000_0000 // 100 Fixed8 Gas
candidateFeeConfigKey = "InnerRingCandidateFee"
version = 2 version = 2
innerRingKey = "innerring" innerRingKey = "innerring"
voteKey = "ballots" voteKey = "ballots"
@ -40,6 +47,10 @@ const (
minInnerRingSize = 3 minInnerRingSize = 3
) )
var (
configPrefix = []byte("config")
)
func Main(op string, args []interface{}) interface{} { func Main(op string, args []interface{}) interface{} {
// The trigger determines whether this smart-contract is being // The trigger determines whether this smart-contract is being
// run in 'verification' or 'application' mode. // run in 'verification' or 'application' mode.
@ -143,7 +154,8 @@ func Main(op string, args []interface{}) interface{} {
from := contract.CreateStandardAccount(key) from := contract.CreateStandardAccount(key)
to := runtime.GetExecutingScriptHash() to := runtime.GetExecutingScriptHash()
params := []interface{}{from, to, innerRingCandidateFee} fee := getConfig(ctx, candidateFeeConfigKey).(int)
params := []interface{}{from, to, fee}
transferred := engine.AppCall([]byte(tokenHash), "transfer", params).(bool) transferred := engine.AppCall([]byte(tokenHash), "transfer", params).(bool)
if !transferred { if !transferred {
@ -369,6 +381,91 @@ func Main(op string, args []interface{}) interface{} {
} }
return false return false
case "Config":
if len(args) != 1 {
panic("config: bad arguments")
}
key := args[0].([]byte)
return getConfig(ctx, key)
case "SetConfig":
if len(args) != 3 {
panic("setConfig: bad arguments")
}
// check if it is inner ring invocation
irList := getInnerRingNodes(ctx, innerRingKey)
threshold := len(irList)/3*2 + 1
irKey := innerRingInvoker(irList)
if len(irKey) == 0 {
panic("setConfig: invoked by non inner ring node")
}
// check unique id of the operation
id := args[0].([]byte)
c := cheque{id: id}
cashedCheques := getCashedCheques(ctx)
chequesList, ok := addCheque(cashedCheques, c)
if !ok {
panic("setConfig: non unique id")
}
// vote for new configuration value
hashID := crypto.SHA256(id)
n := vote(ctx, hashID, irKey)
if n >= threshold {
removeVotes(ctx, hashID)
key := args[1]
val := args[2]
setConfig(ctx, key, val)
setSerialized(ctx, cashedChequesKey, chequesList)
runtime.Notify("SetConfig", id, key, val)
runtime.Log("setConfig: configuration has been updated")
}
return true
case "ListConfig":
var config []record
it := storage.Find(ctx, configPrefix)
for iterator.Next(it) {
key := iterator.Key(it).([]byte)
val := iterator.Value(it).([]byte)
r := record{key: key[len(configPrefix):], val: val}
config = append(config, r)
}
return config
case "InitConfig":
if getConfig(ctx, candidateFeeConfigKey) != nil {
panic("neofs: configuration already installed")
}
ln := len(args)
if ln%2 != 0 {
panic("initConfig: bad arguments")
}
setConfig(ctx, candidateFeeConfigKey, defaultCandidateFee)
for i := 0; i < ln/2; i++ {
key := args[i*2]
val := args[i*2+1]
setConfig(ctx, key, val)
}
runtime.Log("neofs: config has been installed")
return true
case "Version": case "Version":
return version return version
} }
@ -598,6 +695,22 @@ func getBallots(ctx storage.Context) []ballot {
return []ballot{} return []ballot{}
} }
// getConfig returns installed neofs configuration value or nil if it is not set.
func getConfig(ctx storage.Context, key interface{}) interface{} {
postfix := key.([]byte)
storageKey := append(configPrefix, postfix...)
return storage.Get(ctx, storageKey)
}
// setConfig sets neofs configuration value in the contract storage.
func setConfig(ctx storage.Context, key, val interface{}) {
postfix := key.([]byte)
storageKey := append(configPrefix, postfix...)
storage.Put(ctx, storageKey, val)
}
// addCheque returns slice of cheques with appended cheque 'c' and bool flag // addCheque returns slice of cheques with appended cheque 'c' and bool flag
// that set to false if cheque 'c' is already presented in the slice 'lst'. // that set to false if cheque 'c' is already presented in the slice 'lst'.
func addCheque(lst []cheque, c cheque) ([]cheque, bool) { func addCheque(lst []cheque, c cheque) ([]cheque, bool) {