Skip to content

Commit

Permalink
sidechain/deploy: Transfer GAS to the Proxy contract when deployed
Browse files Browse the repository at this point in the history
Proxy contact pays for main transactions sent using Notary service, so
it needs a lot of GAS to do so.

Transfer 90% of GAS from the committee multi-sig account to the Proxy
contract if it has no GAS. Later replenishments are done by NeoFS
GAS emission cycles.

Signed-off-by: Leonard Lyubich <[email protected]>
  • Loading branch information
cthulhu-rider committed Aug 22, 2023
1 parent 7ba3094 commit 9b3d17c
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
17 changes: 17 additions & 0 deletions pkg/morph/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,23 @@ func Deploy(ctx context.Context, prm Prm) error {
syncPrm.isProxy = false
syncPrm.proxyContract = proxyContractAddress

prm.Logger.Info("replenishing the the Proxy contract's balance...")

err = transferGASToProxy(ctx, transferGASToProxyPrm{
logger: prm.Logger,
blockchain: prm.Blockchain,
monitor: monitor,
proxyContract: proxyContractAddress,
committee: committee,
localAcc: prm.LocalAccount,
tryTransfer: localAccLeads,
})
if err != nil {
return fmt.Errorf("replenish balance of the Proxy contract: %w", err)
}

prm.Logger.Info("Proxy balance successfully replenished")

// NNS (update)
//
// Special contract which is always deployed first, but its update depends on
Expand Down
106 changes: 106 additions & 0 deletions pkg/morph/deploy/funds.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/notary"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"go.uber.org/zap"
)
Expand All @@ -24,6 +25,9 @@ const (
// to pay fees for transfer transaction(s). The value is big enough for
// transfer, and not very big to leave no tail on the account.
validatorLowerGASThreshold = 10
// share of GAS on the committee multi-sig account to be transferred to the
// Proxy contract (in %)
initialProxyGASPercent = 90
)

// groups parameters of makeInitialGASTransferToCommittee.
Expand Down Expand Up @@ -230,3 +234,105 @@ upperLoop:
transferTxMonitor.trackPendingTransactionsAsync(ctx, vub, mainTxID, fallbackTxID)
}
}

// groups parameters of transferGASToProxy.
type transferGASToProxyPrm struct {
logger *zap.Logger

blockchain Blockchain

// based on blockchain
monitor *blockchainMonitor

proxyContract util.Uint160

committee keys.PublicKeys

localAcc *wallet.Account

tryTransfer bool
}

// transfers 90% of GAS from committee multi-sig account to the Proxy contract.
// No-op if Proxy contract already has GAS.
func transferGASToProxy(ctx context.Context, prm transferGASToProxyPrm) error {
var committeeMultiSigAccAddress util.Uint160

committeeActor, err := newCommitteeNotaryActorWithCustomCommitteeSigner(prm.blockchain, prm.localAcc, prm.committee, func(s *transaction.Signer) {
committeeMultiSigAccAddress = s.Account
s.Scopes = transaction.CalledByEntry
})
if err != nil {
return fmt.Errorf("create Notary service client sending transactions to be signed by the committee: %w", err)
}

// wrap the parent context into the context of the current function so that
// transaction wait routines do not leak
ctx, cancel := context.WithCancel(ctx)
defer cancel()

gasContract := gas.New(committeeActor)
transferTxMonitor := newTransactionGroupMonitor(committeeActor)

for ; ; prm.monitor.waitForNextBlock(ctx) {
select {
case <-ctx.Done():
return fmt.Errorf("wait for distribution of initial funds: %w", ctx.Err())
default:
}

proxyBalance, err := gasContract.BalanceOf(prm.proxyContract)
if err != nil {
prm.logger.Error("failed to get GAS balance of the Proxy contract, will try again later",
zap.Error(err))
continue
}

if proxyBalance.Sign() > 0 {
prm.logger.Info("Proxy contract already has GAS, skip transfer")
return nil
}

if !prm.tryTransfer {
prm.logger.Info("GAS balance of the Proxy contract is empty but attempts to transfer are disabled, will wait for a leader")
continue
}

committeeBalance, err := gasContract.BalanceOf(committeeMultiSigAccAddress)
if err != nil {
prm.logger.Error("failed to get GAS balance of the committee multi-sig account, will try again later",
zap.Error(err))
continue
}

amount := new(big.Int).Mul(committeeBalance, big.NewInt(initialProxyGASPercent))
amount.Div(amount, big.NewInt(100))
if amount.Sign() <= 0 {
prm.logger.Info("nothing to transfer from the committee multi-sig account, skip")
return nil
}

if transferTxMonitor.isPending() {
prm.logger.Info("previously sent transaction transferring funds from committee multi-sig account to the Proxy contract is still pending, will wait for the outcome")
continue
}

prm.logger.Info("sending new Notary request transferring funds from committee multi-sig account to the Proxy contract...")

mainTxID, fallbackTxID, vub, err := committeeActor.Notarize(
gasContract.TransferTransaction(committeeMultiSigAccAddress, prm.proxyContract, amount, nil))
if err != nil {
if isErrNotEnoughGAS(err) {
prm.logger.Info("insufficient Notary balance to transfer funds from committee multi-sig account to the Proxy contract, will try again later")
} else {
prm.logger.Error("failed to send Notary request transferring funds from committee multi-sig account to the Proxy contract, will try again later", zap.Error(err))
}
continue
}

prm.logger.Info("Notary request transferring funds from committee multi-sig account to the Proxy contract has been successfully sent, will wait for the outcome",
zap.Stringer("main tx", mainTxID), zap.Stringer("fallback tx", fallbackTxID), zap.Uint32("vub", vub))

transferTxMonitor.trackPendingTransactionsAsync(ctx, vub, mainTxID, fallbackTxID)
}
}

0 comments on commit 9b3d17c

Please sign in to comment.