[#1741] neofs-adm: Use ValidUntilBlock to wait for tx persist

Signed-off-by: Evgenii Stratonikov <evgeniy@morphbits.ru>
This commit is contained in:
Evgenii Stratonikov 2022-09-14 13:11:53 +03:00 committed by fyrchik
parent 5321f8ef9c
commit 4208f7c0cf
4 changed files with 40 additions and 31 deletions

View file

@ -315,7 +315,7 @@ func (c *initializeContext) getSigner(tryGroup bool) transaction.Signer {
} }
func (c *clientContext) awaitTx(cmd *cobra.Command) error { func (c *clientContext) awaitTx(cmd *cobra.Command) error {
if len(c.Hashes) == 0 { if len(c.SentTxs) == 0 {
return nil return nil
} }
@ -325,33 +325,32 @@ func (c *clientContext) awaitTx(cmd *cobra.Command) error {
} }
} }
err := awaitTx(cmd, c.Client, c.Hashes) err := awaitTx(cmd, c.Client, c.SentTxs)
c.Hashes = c.Hashes[:0] c.SentTxs = c.SentTxs[:0]
return err return err
} }
func awaitTx(cmd *cobra.Command, c Client, hashes []util.Uint256) error { func awaitTx(cmd *cobra.Command, c Client, txs []hashVUBPair) error {
cmd.Println("Waiting for transactions to persist...") cmd.Println("Waiting for transactions to persist...")
// improve TX awaiting process:
// https://github.com/nspcc-dev/neofs-node/issues/1741
const pollInterval = time.Second const pollInterval = time.Second
const waitDuration = 30 * time.Second
tick := time.NewTicker(pollInterval) tick := time.NewTicker(pollInterval)
defer tick.Stop() defer tick.Stop()
timer := time.NewTimer(waitDuration)
defer timer.Stop()
at := trigger.Application at := trigger.Application
var retErr error var retErr error
currBlock, err := c.GetBlockCount()
if err != nil {
return fmt.Errorf("can't fetch current block height: %w", err)
}
loop: loop:
for i := range hashes { for i := range txs {
res, err := c.GetApplicationLog(hashes[i], &at) res, err := c.GetApplicationLog(txs[i].hash, &at)
if err == nil { if err == nil {
if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt { if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt {
retErr = fmt.Errorf("tx %d persisted in %s state: %s", retErr = fmt.Errorf("tx %d persisted in %s state: %s",
@ -359,10 +358,16 @@ loop:
} }
continue loop continue loop
} }
for { if txs[i].vub < currBlock {
select { return fmt.Errorf("tx was not persisted: vub=%d, height=%d", txs[i].vub, currBlock)
case <-tick.C: }
res, err := c.GetApplicationLog(hashes[i], &at) for range tick.C {
// 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 err == nil {
if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt { if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt {
retErr = fmt.Errorf("tx %d persisted in %s state: %s", retErr = fmt.Errorf("tx %d persisted in %s state: %s",
@ -370,8 +375,8 @@ loop:
} }
continue loop continue loop
} }
case <-timer.C: if txs[i].vub < currBlock {
return errors.New("timeout while waiting for transaction to persist") return fmt.Errorf("tx was not persisted: vub=%d, height=%d", txs[i].vub, currBlock)
} }
} }
} }

View file

@ -312,12 +312,12 @@ func (c *initializeContext) deployContracts() error {
return fmt.Errorf("could not create actor: %w", err) return fmt.Errorf("could not create actor: %w", err)
} }
txHash, _, err := act.SendCall(mgmtHash, deployMethodName, params...) txHash, vub, err := act.SendCall(mgmtHash, deployMethodName, params...)
if err != nil { if err != nil {
return fmt.Errorf("can't deploy alphabet #%d contract: %w", i, err) return fmt.Errorf("can't deploy alphabet #%d contract: %w", i, err)
} }
c.Hashes = append(c.Hashes, txHash) c.SentTxs = append(c.SentTxs, hashVUBPair{hash: txHash, vub: vub})
} }
for _, ctrName := range contractList { for _, ctrName := range contractList {

View file

@ -48,11 +48,16 @@ type Client interface {
SignAndPushP2PNotaryRequest(*transaction.Transaction, []byte, int64, int64, uint32, *wallet.Account) (*payload.P2PNotaryRequest, error) SignAndPushP2PNotaryRequest(*transaction.Transaction, []byte, int64, int64, uint32, *wallet.Account) (*payload.P2PNotaryRequest, error)
} }
type hashVUBPair struct {
hash util.Uint256
vub uint32
}
type clientContext struct { type clientContext struct {
Client Client // a raw neo-go client OR a local chain implementation Client Client // a raw neo-go client OR a local chain implementation
CommitteeAct *actor.Actor // committee actor with the Global witness scope CommitteeAct *actor.Actor // committee actor with the Global witness scope
ReadOnlyInvoker *invoker.Invoker // R/O contract invoker, does not contain any signer ReadOnlyInvoker *invoker.Invoker // R/O contract invoker, does not contain any signer
Hashes []util.Uint256 SentTxs []hashVUBPair
} }
func getN3Client(v *viper.Viper) (Client, error) { func getN3Client(v *viper.Viper) (Client, error) {
@ -110,7 +115,7 @@ func (c *clientContext) sendTx(tx *transaction.Transaction, cmd *cobra.Command,
return fmt.Errorf("sent and actual tx hashes mismatch:\n\tsent: %v\n\tactual: %v", tx.Hash().StringLE(), h.StringLE()) return fmt.Errorf("sent and actual tx hashes mismatch:\n\tsent: %v\n\tactual: %v", tx.Hash().StringLE(), h.StringLE())
} }
c.Hashes = append(c.Hashes, h) c.SentTxs = append(c.SentTxs, hashVUBPair{hash: h, vub: tx.ValidUntilBlock})
if await { if await {
return c.awaitTx(cmd) return c.awaitTx(cmd)

View file

@ -12,7 +12,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17" "github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -117,7 +116,7 @@ func depositNotary(cmd *cobra.Command, _ []string) error {
gas := nep17.New(act, gasHash) gas := nep17.New(act, gasHash)
txHash, _, err := gas.Transfer( txHash, vub, err := gas.Transfer(
accHash, accHash,
notaryHash, notaryHash,
big.NewInt(int64(gasAmount)), big.NewInt(int64(gasAmount)),
@ -127,5 +126,5 @@ func depositNotary(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("could not send tx: %w", err) return fmt.Errorf("could not send tx: %w", err)
} }
return awaitTx(cmd, c, []util.Uint256{txHash}) return awaitTx(cmd, c, []hashVUBPair{{hash: txHash, vub: vub}})
} }