frostfs-node/pkg/innerring/contracts.go

128 lines
3.4 KiB
Go

package innerring
import (
"errors"
"fmt"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/spf13/viper"
)
type contracts struct {
frostfs util.Uint160 // in mainnet
netmap util.Uint160 // in morph
balance util.Uint160 // in morph
container util.Uint160 // in morph
proxy util.Uint160 // in morph
processing util.Uint160 // in mainnet
frostfsID util.Uint160 // in morph
alphabet AlphabetContracts // in morph
}
func parseContracts(cfg *viper.Viper, morph nnsResolver, withoutMainNet, withoutMainNotary bool) (*contracts, error) {
var (
result = new(contracts)
err error
)
if !withoutMainNet {
result.frostfs, err = util.Uint160DecodeStringLE(cfg.GetString("contracts.frostfs"))
if err != nil {
return nil, fmt.Errorf("can't get frostfs script hash: %w", err)
}
if !withoutMainNotary {
result.processing, err = util.Uint160DecodeStringLE(cfg.GetString("contracts.processing"))
if err != nil {
return nil, fmt.Errorf("can't get processing script hash: %w", err)
}
}
}
result.proxy, err = parseContract(cfg, morph, "contracts.proxy", client.NNSProxyContractName)
if err != nil {
return nil, fmt.Errorf("can't get proxy script hash: %w", err)
}
targets := [...]struct {
cfgName string
nnsName string
dest *util.Uint160
}{
{"contracts.netmap", client.NNSNetmapContractName, &result.netmap},
{"contracts.balance", client.NNSBalanceContractName, &result.balance},
{"contracts.container", client.NNSContainerContractName, &result.container},
{"contracts.frostfsid", client.NNSFrostFSIDContractName, &result.frostfsID},
}
for _, t := range targets {
*t.dest, err = parseContract(cfg, morph, t.cfgName, t.nnsName)
if err != nil {
name := strings.TrimPrefix(t.cfgName, "contracts.")
return nil, fmt.Errorf("can't get %s script hash: %w", name, err)
}
}
result.alphabet, err = parseAlphabetContracts(cfg, morph)
if err != nil {
return nil, err
}
return result, nil
}
func parseAlphabetContracts(cfg *viper.Viper, morph nnsResolver) (AlphabetContracts, error) {
num := GlagoliticLetter(cfg.GetUint("contracts.alphabet.amount"))
alpha := NewAlphabetContracts()
if num > lastLetterNum {
return nil, fmt.Errorf("amount of alphabet contracts overflows glagolitsa %d > %d", num, lastLetterNum)
}
thresholdIsSet := num != 0
if !thresholdIsSet {
// try to read maximum alphabet contracts
// if threshold has not been set manually
num = lastLetterNum
}
for letter := az; letter < num; letter++ {
contractHash, err := parseContract(cfg, morph,
"contracts.alphabet."+letter.String(),
client.NNSAlphabetContractName(int(letter)),
)
if err != nil {
if errors.Is(err, client.ErrNNSRecordNotFound) {
break
}
return nil, fmt.Errorf("invalid alphabet %s contract: %w", letter, err)
}
alpha.set(letter, contractHash)
}
if thresholdIsSet && len(alpha) != int(num) {
return nil, fmt.Errorf("could not read all contracts: required %d, read %d", num, len(alpha))
}
return alpha, nil
}
func parseContract(cfg *viper.Viper, morph nnsResolver, cfgName, nnsName string) (res util.Uint160, err error) {
contractStr := cfg.GetString(cfgName)
if len(contractStr) == 0 {
return morph.NNSContractAddress(nnsName)
}
return util.Uint160DecodeStringLE(contractStr)
}
type nnsResolver interface {
NNSContractAddress(name string) (sh util.Uint160, err error)
}