From 088c894f44e6839b9a7ec2e9dab97353cff99d53 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 25 Oct 2021 16:19:56 +0300 Subject: [PATCH] [#733] neofs-adm: read contracts on start Fail early and reduce disk operations when reading from archive. Signed-off-by: Evgenii Stratonikov --- .../internal/modules/morph/download.go | 20 +-- .../internal/modules/morph/initialize.go | 21 +-- .../modules/morph/initialize_deploy.go | 145 ++++++++++-------- .../internal/modules/morph/initialize_nns.go | 15 +- .../modules/morph/initialize_register.go | 6 +- .../modules/morph/initialize_transfer.go | 5 +- 6 files changed, 105 insertions(+), 107 deletions(-) diff --git a/cmd/neofs-adm/internal/modules/morph/download.go b/cmd/neofs-adm/internal/modules/morph/download.go index a8e72ce2..25e04fe1 100644 --- a/cmd/neofs-adm/internal/modules/morph/download.go +++ b/cmd/neofs-adm/internal/modules/morph/download.go @@ -6,18 +6,17 @@ import ( "fmt" "io" "net/http" - "os" "strings" "github.com/google/go-github/v39/github" "github.com/spf13/cobra" ) -func downloadContractsFromGithub(cmd *cobra.Command) (string, error) { +func downloadContractsFromGithub(cmd *cobra.Command) (io.ReadCloser, error) { gcl := github.NewClient(nil) release, _, err := gcl.Repositories.GetLatestRelease(context.Background(), "nspcc-dev", "neofs-contract") 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()) @@ -30,21 +29,12 @@ func downloadContractsFromGithub(cmd *cobra.Command) (string, error) { } } 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) 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() - - 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 + return resp.Body, nil } diff --git a/cmd/neofs-adm/internal/modules/morph/initialize.go b/cmd/neofs-adm/internal/modules/morph/initialize.go index 34d178e0..dc8933b1 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize.go @@ -122,18 +122,12 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex 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) if err != nil { - return nil, fmt.Errorf("missing 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) + return nil, fmt.Errorf("invalid contracts path: %w", err) } } @@ -177,6 +171,13 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex Natives: nativeHashes, } + if needContracts { + err := initCtx.readContracts(fullContractList) + if err != nil { + return nil, err + } + } + return initCtx, nil } diff --git a/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go b/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go index 6bac0f20..a1f9a277 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go @@ -54,15 +54,24 @@ const ( defaultEigenTrustAlpha = "0.1" ) -var contractList = []string{ - auditContract, - balanceContract, - containerContract, - neofsIDContract, - netmapContract, - proxyContract, - reputationContract, -} +var ( + contractList = []string{ + auditContract, + balanceContract, + containerContract, + neofsIDContract, + netmapContract, + proxyContract, + reputationContract, + } + + fullContractList = append([]string{ + neofsContract, + processingContract, + nnsContract, + alphabetContract, + }, contractList...) +) type contractState struct { NEF *nef.File @@ -75,10 +84,7 @@ type contractState struct { const updateMethodName = "update" func (c *initializeContext) deployNNS(method string) error { - cs, err := c.readContract(nnsContract) - if err != nil { - return err - } + cs := c.getContract(nnsContract) if _, err := c.Client.GetContractStateByHash(cs.Hash); err == nil && method != updateMethodName { return nil @@ -128,17 +134,7 @@ func (c *initializeContext) deployNNS(method string) error { func (c *initializeContext) deployContracts(method string) error { mgmtHash := c.nativeHash(nativenames.Management) - for _, ctrName := range contractList { - _, err := c.readContract(ctrName) - if err != nil { - return err - } - } - - alphaCs, err := c.readContract(alphabetContract) - if err != nil { - return err - } + alphaCs := c.getContract(alphabetContract) nnsCs, err := c.Client.GetContractStateByID(1) if err != nil { @@ -245,58 +241,85 @@ func (c *initializeContext) deployContracts(method string) error { return c.awaitTx() } -func (c *initializeContext) readContract(ctrName string) (*contractState, error) { - if cs, ok := c.Contracts[ctrName]; ok { - return cs, nil - } +func (c *initializeContext) getContract(ctrName string) *contractState { + return c.Contracts[ctrName] +} - fi, err := os.Stat(c.ContractPath) - if err != nil { - return nil, fmt.Errorf("invalid contracts path: %w", err) - } - - var cs *contractState - if fi.IsDir() { - cs = new(contractState) - cs.RawNEF, err = ioutil.ReadFile(path.Join(c.ContractPath, ctrName, ctrName+"_contract.nef")) +func (c *initializeContext) readContracts(names []string) error { + var ( + fi os.FileInfo + err error + ) + if c.ContractPath != "" { + fi, err = os.Stat(c.ContractPath) 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 { - f, err := os.Open(c.ContractPath) - if err != nil { - return nil, fmt.Errorf("can't open contracts archive: %w", err) + var r io.ReadCloser + if c.ContractPath == "" { + 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 { - 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) 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.Manifest = new(manifest.Manifest) - 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 + cs.Manifest = m + return nil } func readContractsFromArchive(file io.Reader, names []string) (map[string]*contractState, error) { diff --git a/cmd/neofs-adm/internal/modules/morph/initialize_nns.go b/cmd/neofs-adm/internal/modules/morph/initialize_nns.go index 07aca041..5d4bbc06 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize_nns.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize_nns.go @@ -24,10 +24,7 @@ const defaultNameServiceSysfee = 4000_0000 const defaultRegisterSysfee = 10_0000_0000 + defaultNameServiceDomainPrice func (c *initializeContext) setNNS() error { - nnsCs, err := c.readContract(nnsContract) - if err != nil { - return err - } + nnsCs := c.getContract(nnsContract) ok, err := c.nnsRootRegistered(nnsCs.Hash) if err != nil { @@ -43,10 +40,7 @@ func (c *initializeContext) setNNS() error { } } - alphaCs, err := c.readContract(alphabetContract) - if err != nil { - return fmt.Errorf("can't read alphabet contract: %w", err) - } + alphaCs := c.getContract(alphabetContract) for i, acc := range c.Accounts { 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 { - cs, err := c.readContract(ctrName) - if err != nil { - return err - } + cs := c.getContract(ctrName) domain := ctrName + ".neofs" if err := c.nnsRegisterDomain(nnsCs.Hash, cs.Hash, domain); err != nil { diff --git a/cmd/neofs-adm/internal/modules/morph/initialize_register.go b/cmd/neofs-adm/internal/modules/morph/initialize_register.go index 7f16ab9a..ea4cc3f8 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize_register.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize_register.go @@ -71,11 +71,7 @@ func (c *initializeContext) transferNEOToAlphabetContracts() error { return err } - cs, err := c.readContract(alphabetContract) - if err != nil { - return fmt.Errorf("can't read alphabet contract: %w", err) - } - + cs := c.getContract(alphabetContract) amount := initialAlphabetNEOAmount / len(c.Wallets) bw := io.NewBufBinWriter() diff --git a/cmd/neofs-adm/internal/modules/morph/initialize_transfer.go b/cmd/neofs-adm/internal/modules/morph/initialize_transfer.go index 27e07d5c..43ac70c1 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize_transfer.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize_transfer.go @@ -132,10 +132,7 @@ func (c *initializeContext) multiSign(tx *transaction.Transaction, accType strin func (c *initializeContext) transferGASToProxy() error { gasHash := c.nativeHash(nativenames.Gas) - proxyCs, err := c.readContract(proxyContract) - if err != nil { - return err - } + proxyCs := c.getContract(proxyContract) bal, err := c.Client.NEP17BalanceOf(gasHash, proxyCs.Hash) if err != nil || bal > 0 {