forked from TrueCloudLab/frostfs-node
[#733] neofs-adm: read contracts on start
Fail early and reduce disk operations when reading from archive. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
0b6350d463
commit
088c894f44
6 changed files with 105 additions and 107 deletions
|
@ -6,18 +6,17 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/go-github/v39/github"
|
"github.com/google/go-github/v39/github"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func downloadContractsFromGithub(cmd *cobra.Command) (string, error) {
|
func downloadContractsFromGithub(cmd *cobra.Command) (io.ReadCloser, error) {
|
||||||
gcl := github.NewClient(nil)
|
gcl := github.NewClient(nil)
|
||||||
release, _, err := gcl.Repositories.GetLatestRelease(context.Background(), "nspcc-dev", "neofs-contract")
|
release, _, err := gcl.Repositories.GetLatestRelease(context.Background(), "nspcc-dev", "neofs-contract")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("can't fetch release info: %w", err)
|
return nil, fmt.Errorf("can't fetch release info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Printf("Found %s (%s), downloading...\n", release.GetTagName(), release.GetName())
|
cmd.Printf("Found %s (%s), downloading...\n", release.GetTagName(), release.GetName())
|
||||||
|
@ -30,21 +29,12 @@ func downloadContractsFromGithub(cmd *cobra.Command) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if url == "" {
|
if url == "" {
|
||||||
return "", errors.New("can't find contracts archive in release assets")
|
return nil, errors.New("can't find contracts archive in release assets")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("can't fetch contracts archive: %w", err)
|
return nil, fmt.Errorf("can't fetch contracts archive: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
return resp.Body, nil
|
||||||
|
|
||||||
f, err := os.CreateTemp("", "neofs-contract-*.tar.gz")
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("can't allocate temporary file: %w", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(f, resp.Body)
|
|
||||||
return f.Name(), err
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,18 +122,12 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex
|
||||||
return nil, fmt.Errorf("max object size must be positive")
|
return nil, fmt.Errorf("max object size must be positive")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cmd.Name() == "update-contracts" || cmd.Name() == "init" {
|
|
||||||
|
needContracts := cmd.Name() == "update-contracts" || cmd.Name() == "init"
|
||||||
|
if needContracts {
|
||||||
ctrPath, err = cmd.Flags().GetString(contractsInitFlag)
|
ctrPath, err = cmd.Flags().GetString(contractsInitFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("missing contracts path: %w", err)
|
return nil, fmt.Errorf("invalid contracts path: %w", err)
|
||||||
}
|
|
||||||
if ctrPath == "" {
|
|
||||||
cmd.Println("Contracts flag is missing, latest release will be fetched from Github.")
|
|
||||||
ctrPath, err = downloadContractsFromGithub(cmd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cmd.Printf("Saved to %s\n", ctrPath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +171,13 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex
|
||||||
Natives: nativeHashes,
|
Natives: nativeHashes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if needContracts {
|
||||||
|
err := initCtx.readContracts(fullContractList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return initCtx, nil
|
return initCtx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,15 +54,24 @@ const (
|
||||||
defaultEigenTrustAlpha = "0.1"
|
defaultEigenTrustAlpha = "0.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
var contractList = []string{
|
var (
|
||||||
auditContract,
|
contractList = []string{
|
||||||
balanceContract,
|
auditContract,
|
||||||
containerContract,
|
balanceContract,
|
||||||
neofsIDContract,
|
containerContract,
|
||||||
netmapContract,
|
neofsIDContract,
|
||||||
proxyContract,
|
netmapContract,
|
||||||
reputationContract,
|
proxyContract,
|
||||||
}
|
reputationContract,
|
||||||
|
}
|
||||||
|
|
||||||
|
fullContractList = append([]string{
|
||||||
|
neofsContract,
|
||||||
|
processingContract,
|
||||||
|
nnsContract,
|
||||||
|
alphabetContract,
|
||||||
|
}, contractList...)
|
||||||
|
)
|
||||||
|
|
||||||
type contractState struct {
|
type contractState struct {
|
||||||
NEF *nef.File
|
NEF *nef.File
|
||||||
|
@ -75,10 +84,7 @@ type contractState struct {
|
||||||
const updateMethodName = "update"
|
const updateMethodName = "update"
|
||||||
|
|
||||||
func (c *initializeContext) deployNNS(method string) error {
|
func (c *initializeContext) deployNNS(method string) error {
|
||||||
cs, err := c.readContract(nnsContract)
|
cs := c.getContract(nnsContract)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := c.Client.GetContractStateByHash(cs.Hash); err == nil && method != updateMethodName {
|
if _, err := c.Client.GetContractStateByHash(cs.Hash); err == nil && method != updateMethodName {
|
||||||
return nil
|
return nil
|
||||||
|
@ -128,17 +134,7 @@ func (c *initializeContext) deployNNS(method string) error {
|
||||||
|
|
||||||
func (c *initializeContext) deployContracts(method string) error {
|
func (c *initializeContext) deployContracts(method string) error {
|
||||||
mgmtHash := c.nativeHash(nativenames.Management)
|
mgmtHash := c.nativeHash(nativenames.Management)
|
||||||
for _, ctrName := range contractList {
|
alphaCs := c.getContract(alphabetContract)
|
||||||
_, err := c.readContract(ctrName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alphaCs, err := c.readContract(alphabetContract)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
nnsCs, err := c.Client.GetContractStateByID(1)
|
nnsCs, err := c.Client.GetContractStateByID(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -245,58 +241,85 @@ func (c *initializeContext) deployContracts(method string) error {
|
||||||
return c.awaitTx()
|
return c.awaitTx()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *initializeContext) readContract(ctrName string) (*contractState, error) {
|
func (c *initializeContext) getContract(ctrName string) *contractState {
|
||||||
if cs, ok := c.Contracts[ctrName]; ok {
|
return c.Contracts[ctrName]
|
||||||
return cs, nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(c.ContractPath)
|
func (c *initializeContext) readContracts(names []string) error {
|
||||||
if err != nil {
|
var (
|
||||||
return nil, fmt.Errorf("invalid contracts path: %w", err)
|
fi os.FileInfo
|
||||||
}
|
err error
|
||||||
|
)
|
||||||
var cs *contractState
|
if c.ContractPath != "" {
|
||||||
if fi.IsDir() {
|
fi, err = os.Stat(c.ContractPath)
|
||||||
cs = new(contractState)
|
|
||||||
cs.RawNEF, err = ioutil.ReadFile(path.Join(c.ContractPath, ctrName, ctrName+"_contract.nef"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't read NEF file for %s contract: %w", ctrName, err)
|
return fmt.Errorf("invalid contracts path: %w", err)
|
||||||
}
|
}
|
||||||
cs.RawManifest, err = ioutil.ReadFile(path.Join(c.ContractPath, ctrName, "config.json"))
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("can't read manifest file for %s contract: %w", ctrName, err)
|
if c.ContractPath != "" && fi.IsDir() {
|
||||||
|
for _, ctrName := range names {
|
||||||
|
cs := new(contractState)
|
||||||
|
cs.RawNEF, err = ioutil.ReadFile(path.Join(c.ContractPath, ctrName, ctrName+"_contract.nef"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't read NEF file for %s contract: %w", ctrName, err)
|
||||||
|
}
|
||||||
|
cs.RawManifest, err = ioutil.ReadFile(path.Join(c.ContractPath, ctrName, "config.json"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't read manifest file for %s contract: %w", ctrName, err)
|
||||||
|
}
|
||||||
|
c.Contracts[ctrName] = cs
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
f, err := os.Open(c.ContractPath)
|
var r io.ReadCloser
|
||||||
if err != nil {
|
if c.ContractPath == "" {
|
||||||
return nil, fmt.Errorf("can't open contracts archive: %w", err)
|
c.Command.Println("Contracts flag is missing, latest release will be fetched from Github.")
|
||||||
|
r, err = downloadContractsFromGithub(c.Command)
|
||||||
|
} else {
|
||||||
|
r, err = os.Open(c.ContractPath)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't open contracts archive: %w", err)
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
m, err := readContractsFromArchive(f, []string{ctrName})
|
m, err := readContractsFromArchive(r, names)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
|
}
|
||||||
|
for _, name := range names {
|
||||||
|
c.Contracts[name] = m[name]
|
||||||
}
|
}
|
||||||
cs = m[ctrName]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ctrName := range names {
|
||||||
|
cs := c.Contracts[ctrName]
|
||||||
|
if err := cs.parse(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctrName != alphabetContract {
|
||||||
|
cs.Hash = state.CreateContractHash(c.CommitteeAcc.Contract.ScriptHash(),
|
||||||
|
cs.NEF.Checksum, cs.Manifest.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *contractState) parse() error {
|
||||||
nf, err := nef.FileFromBytes(cs.RawNEF)
|
nf, err := nef.FileFromBytes(cs.RawNEF)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can't parse NEF file: %w", err)
|
return fmt.Errorf("can't parse NEF file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m := new(manifest.Manifest)
|
||||||
|
if err := json.Unmarshal(cs.RawManifest, m); err != nil {
|
||||||
|
return fmt.Errorf("can't parse manifest file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
cs.NEF = &nf
|
cs.NEF = &nf
|
||||||
|
cs.Manifest = m
|
||||||
cs.Manifest = new(manifest.Manifest)
|
return nil
|
||||||
if err := json.Unmarshal(cs.RawManifest, cs.Manifest); err != nil {
|
|
||||||
return nil, fmt.Errorf("can't parse manifest file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctrName != alphabetContract {
|
|
||||||
cs.Hash = state.CreateContractHash(c.CommitteeAcc.Contract.ScriptHash(),
|
|
||||||
cs.NEF.Checksum, cs.Manifest.Name)
|
|
||||||
}
|
|
||||||
c.Contracts[ctrName] = cs
|
|
||||||
return cs, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readContractsFromArchive(file io.Reader, names []string) (map[string]*contractState, error) {
|
func readContractsFromArchive(file io.Reader, names []string) (map[string]*contractState, error) {
|
||||||
|
|
|
@ -24,10 +24,7 @@ const defaultNameServiceSysfee = 4000_0000
|
||||||
const defaultRegisterSysfee = 10_0000_0000 + defaultNameServiceDomainPrice
|
const defaultRegisterSysfee = 10_0000_0000 + defaultNameServiceDomainPrice
|
||||||
|
|
||||||
func (c *initializeContext) setNNS() error {
|
func (c *initializeContext) setNNS() error {
|
||||||
nnsCs, err := c.readContract(nnsContract)
|
nnsCs := c.getContract(nnsContract)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ok, err := c.nnsRootRegistered(nnsCs.Hash)
|
ok, err := c.nnsRootRegistered(nnsCs.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -43,10 +40,7 @@ func (c *initializeContext) setNNS() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
alphaCs, err := c.readContract(alphabetContract)
|
alphaCs := c.getContract(alphabetContract)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("can't read alphabet contract: %w", err)
|
|
||||||
}
|
|
||||||
for i, acc := range c.Accounts {
|
for i, acc := range c.Accounts {
|
||||||
alphaCs.Hash = state.CreateContractHash(acc.Contract.ScriptHash(), alphaCs.NEF.Checksum, alphaCs.Manifest.Name)
|
alphaCs.Hash = state.CreateContractHash(acc.Contract.ScriptHash(), alphaCs.NEF.Checksum, alphaCs.Manifest.Name)
|
||||||
|
|
||||||
|
@ -58,10 +52,7 @@ func (c *initializeContext) setNNS() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ctrName := range contractList {
|
for _, ctrName := range contractList {
|
||||||
cs, err := c.readContract(ctrName)
|
cs := c.getContract(ctrName)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
domain := ctrName + ".neofs"
|
domain := ctrName + ".neofs"
|
||||||
if err := c.nnsRegisterDomain(nnsCs.Hash, cs.Hash, domain); err != nil {
|
if err := c.nnsRegisterDomain(nnsCs.Hash, cs.Hash, domain); err != nil {
|
||||||
|
|
|
@ -71,11 +71,7 @@ func (c *initializeContext) transferNEOToAlphabetContracts() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cs, err := c.readContract(alphabetContract)
|
cs := c.getContract(alphabetContract)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("can't read alphabet contract: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
amount := initialAlphabetNEOAmount / len(c.Wallets)
|
amount := initialAlphabetNEOAmount / len(c.Wallets)
|
||||||
|
|
||||||
bw := io.NewBufBinWriter()
|
bw := io.NewBufBinWriter()
|
||||||
|
|
|
@ -132,10 +132,7 @@ func (c *initializeContext) multiSign(tx *transaction.Transaction, accType strin
|
||||||
|
|
||||||
func (c *initializeContext) transferGASToProxy() error {
|
func (c *initializeContext) transferGASToProxy() error {
|
||||||
gasHash := c.nativeHash(nativenames.Gas)
|
gasHash := c.nativeHash(nativenames.Gas)
|
||||||
proxyCs, err := c.readContract(proxyContract)
|
proxyCs := c.getContract(proxyContract)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
bal, err := c.Client.NEP17BalanceOf(gasHash, proxyCs.Hash)
|
bal, err := c.Client.NEP17BalanceOf(gasHash, proxyCs.Hash)
|
||||||
if err != nil || bal > 0 {
|
if err != nil || bal > 0 {
|
||||||
|
|
Loading…
Reference in a new issue