forked from TrueCloudLab/frostfs-node
90 lines
2.4 KiB
Go
90 lines
2.4 KiB
Go
package util
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
var ErrTooManyAlphabetNodes = fmt.Errorf("too many alphabet nodes (maximum allowed is %d)", MaxAlphabetNodes)
|
|
|
|
func AwaitTx(cmd *cobra.Command, c Client, txs []HashVUBPair) error {
|
|
cmd.Println("Waiting for transactions to persist...")
|
|
|
|
at := trigger.Application
|
|
|
|
var retErr error
|
|
|
|
loop:
|
|
for i := range txs {
|
|
var it int
|
|
var pollInterval time.Duration
|
|
var pollIntervalChanged bool
|
|
for {
|
|
// We must fetch current height before application log, to avoid race condition.
|
|
currBlock, err := c.GetBlockCount()
|
|
if err != nil {
|
|
return fmt.Errorf("can't fetch current block height: %w", err)
|
|
}
|
|
res, err := c.GetApplicationLog(txs[i].Hash, &at)
|
|
if err == nil {
|
|
if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt {
|
|
retErr = fmt.Errorf("tx %d persisted in %s state: %s",
|
|
i, res.Executions[0].VMState, res.Executions[0].FaultException)
|
|
}
|
|
continue loop
|
|
}
|
|
if txs[i].Vub < currBlock {
|
|
return fmt.Errorf("tx was not persisted: Vub=%d, height=%d", txs[i].Vub, currBlock)
|
|
}
|
|
|
|
pollInterval, pollIntervalChanged = NextPollInterval(it, pollInterval)
|
|
if pollIntervalChanged && viper.GetBool(commonflags.Verbose) {
|
|
cmd.Printf("Pool interval to check transaction persistence changed: %s\n", pollInterval.String())
|
|
}
|
|
|
|
timer := time.NewTimer(pollInterval)
|
|
select {
|
|
case <-cmd.Context().Done():
|
|
return cmd.Context().Err()
|
|
case <-timer.C:
|
|
}
|
|
|
|
it++
|
|
}
|
|
}
|
|
|
|
return retErr
|
|
}
|
|
|
|
func NextPollInterval(it int, previous time.Duration) (time.Duration, bool) {
|
|
const minPollInterval = 1 * time.Second
|
|
const maxPollInterval = 16 * time.Second
|
|
const changeAfter = 5
|
|
if it == 0 {
|
|
return minPollInterval, true
|
|
}
|
|
if it%changeAfter != 0 {
|
|
return previous, false
|
|
}
|
|
nextInterval := previous * 2
|
|
if nextInterval > maxPollInterval {
|
|
return maxPollInterval, previous != maxPollInterval
|
|
}
|
|
return nextInterval, true
|
|
}
|
|
|
|
func GetWalletAccount(w *wallet.Wallet, typ string) (*wallet.Account, error) {
|
|
for i := range w.Accounts {
|
|
if w.Accounts[i].Label == typ {
|
|
return w.Accounts[i], nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("account for '%s' not found", typ)
|
|
}
|