Skip to content

Commit

Permalink
deploy: transfer GAS in the first place if notaries are set
Browse files Browse the repository at this point in the history
It is possible to start blockchain with required roles already set. In this
case, there is no need to wait for NNS to be deployed for GAS transfers, since
notary service (requires Notary roles to be set correctly) is ready. It allows
all multi-signed operations to be applied at an earlier stage. Closes #409.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
  • Loading branch information
carpawell committed Jun 20, 2024
1 parent e78d64e commit c1bbe5c
Showing 1 changed file with 141 additions and 53 deletions.
194 changes: 141 additions & 53 deletions deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ import (
"strconv"

"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/notary"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/rolemgmt"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"github.com/nspcc-dev/neo-go/pkg/util"
Expand Down Expand Up @@ -205,11 +208,50 @@ func Deploy(ctx context.Context, prm Prm) error {

chNewBlock := make(chan struct{}, 1)

err = listenCommitteeNotaryRequests(ctx, listenCommitteeNotaryRequestsPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
localAcc: prm.LocalAccount,
committee: committee,
validatorMultiSigAcc: prm.ValidatorMultiSigAccount,
})
if err != nil {
return fmt.Errorf("start listener of committee notary requests: %w", err)
}
go autoReplenishNotaryBalance(ctx, prm.Logger, prm.Blockchain, prm.LocalAccount, chNewBlock)

monitor, err := newBlockchainMonitor(prm.Logger, prm.Blockchain, chNewBlock)
if err != nil {
return fmt.Errorf("init blockchain monitor: %w", err)
}

rolesSet, err := rolesAreSet(prm.Blockchain, committee, prm.Logger)
if err != nil {
return fmt.Errorf("roles check: %w", err)
}
transfersDone := rolesSet // currently the same
if rolesSet {
// if it is possible to transfer GAS before any network settings,
// it should be done as it speeds up expensive operations

prm.Logger.Info("making initial transfer of funds to the committee...")

err = makeInitialTransferToCommittee(ctx, makeInitialGASTransferToCommitteePrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
committee: committee,
localAcc: prm.LocalAccount,
validatorMultiSigAcc: prm.ValidatorMultiSigAccount,
tryTransfer: localAccCommitteeIndex == 0,
})
if err != nil {
return fmt.Errorf("initial transfer funds to the committee: %w", err)
}

prm.Logger.Info("initial transfer to the committee successfully done")
}

deployNNSPrm := deployNNSContractPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
Expand All @@ -235,69 +277,66 @@ func Deploy(ctx context.Context, prm Prm) error {

prm.Logger.Info("NNS contract successfully initialized on the chain", zap.Stringer("address", nnsOnChainAddress))

prm.Logger.Info("enable Notary service for the committee...")

err = enableNotary(ctx, enableNotaryPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
nnsOnChainAddress: nnsOnChainAddress,
systemEmail: prm.NNS.SystemEmail,
committee: committee,
localAcc: prm.LocalAccount,
localAccCommitteeIndex: localAccCommitteeIndex,
})
if err != nil {
return fmt.Errorf("enable Notary service for the committee: %w", err)
}

prm.Logger.Info("Notary service successfully enabled for the committee")

go autoReplenishNotaryBalance(ctx, prm.Logger, prm.Blockchain, prm.LocalAccount, chNewBlock)
if !rolesSet {
prm.Logger.Info("enable Notary service for the committee...")

err = enableNotary(ctx, enableNotaryPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
nnsOnChainAddress: nnsOnChainAddress,
systemEmail: prm.NNS.SystemEmail,
committee: committee,
localAcc: prm.LocalAccount,
localAccCommitteeIndex: localAccCommitteeIndex,
})
if err != nil {
return fmt.Errorf("enable Notary service for the committee: %w", err)
}

err = listenCommitteeNotaryRequests(ctx, listenCommitteeNotaryRequestsPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
localAcc: prm.LocalAccount,
committee: committee,
validatorMultiSigAcc: prm.ValidatorMultiSigAccount,
})
if err != nil {
return fmt.Errorf("start listener of committee notary requests: %w", err)
prm.Logger.Info("Notary service successfully enabled for the committee")
} else {
prm.Logger.Debug("notary roles are already set")
}

prm.Logger.Info("making initial transfer of funds to the committee...")
if !transfersDone {
prm.Logger.Info("making initial transfer of funds to the committee...")

err = makeInitialTransferToCommittee(ctx, makeInitialGASTransferToCommitteePrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
committee: committee,
localAcc: prm.LocalAccount,
validatorMultiSigAcc: prm.ValidatorMultiSigAccount,
tryTransfer: localAccCommitteeIndex == 0,
})
if err != nil {
return fmt.Errorf("initial transfer funds to the committee: %w", err)
}

err = makeInitialTransferToCommittee(ctx, makeInitialGASTransferToCommitteePrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
committee: committee,
localAcc: prm.LocalAccount,
validatorMultiSigAcc: prm.ValidatorMultiSigAccount,
tryTransfer: localAccCommitteeIndex == 0,
})
if err != nil {
return fmt.Errorf("initial transfer funds to the committee: %w", err)
prm.Logger.Info("initial transfer to the committee successfully done")
}

prm.Logger.Info("initial transfer to the committee successfully done")
if !rolesSet {
prm.Logger.Info("initializing NeoFS Alphabet...")

prm.Logger.Info("initializing NeoFS Alphabet...")
err = designateNeoFSAlphabet(ctx, initAlphabetPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
committee: committee,
localAcc: prm.LocalAccount,
})
if err != nil {
return fmt.Errorf("init NeoFS Alphabet: %w", err)
}

err = designateNeoFSAlphabet(ctx, initAlphabetPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
committee: committee,
localAcc: prm.LocalAccount,
})
if err != nil {
return fmt.Errorf("init NeoFS Alphabet: %w", err)
prm.Logger.Info("NeoFS Alphabet successfully initialized")
} else {
prm.Logger.Debug("alphabet roles are already set")
}

prm.Logger.Info("NeoFS Alphabet successfully initialized")

syncPrm := syncNeoFSContractPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
Expand Down Expand Up @@ -645,3 +684,52 @@ func neoFSRuntimeTransactionModifier(getBlockchainHeight func() uint32) actor.Tr
return nil
}
}

func rolesAreSet(b Blockchain, committee keys.PublicKeys, logger *zap.Logger) (bool, error) {
currHeight, err := b.GetBlockCount()
if err != nil {
return false, fmt.Errorf("current block height: %w", err)
}

roleContract := rolemgmt.NewReader(invoker.New(b, nil))

currNotaries, err := roleContract.GetDesignatedByRole(noderoles.P2PNotary, currHeight)
if err != nil {
return false, fmt.Errorf("reading notary role: %w", err)
}
sort.Sort(currNotaries)
if !keysAreEqual(currNotaries, committee) {
logger.Debug("notaries and committee mismatch",
zap.Stringers("notaries", currNotaries), zap.Stringers("committee", committee))

return false, nil
}

currAlphas, err := roleContract.GetDesignatedByRole(noderoles.NeoFSAlphabet, currHeight)
if err != nil {
return false, fmt.Errorf("reading alphabet role: %w", err)
}
sort.Sort(currAlphas)
if !keysAreEqual(currAlphas, committee) {
logger.Debug("alphabet and committee mismatch",
zap.Stringers("alphabet", currAlphas), zap.Stringers("committee", committee))

return false, nil
}

return true, nil
}

func keysAreEqual(a, b keys.PublicKeys) bool {
if len(a) != len(b) {
return false
}

for i := range a {
if !a[i].Equal(b[i]) {
return false
}
}

return true
}

0 comments on commit c1bbe5c

Please sign in to comment.