forked from TrueCloudLab/frostfs-node
[#1741] neofs-adm: Use `ValidUntilBlock` to wait for tx persist
Signed-off-by: Evgenii Stratonikov <evgeniy@morphbits.ru>support/v0.34
parent
5321f8ef9c
commit
4208f7c0cf
|
@ -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,19 +358,25 @@ 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 {
|
||||||
if err == nil {
|
// We must fetch current height before application log, to avoid race condition.
|
||||||
if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt {
|
currBlock, err = c.GetBlockCount()
|
||||||
retErr = fmt.Errorf("tx %d persisted in %s state: %s",
|
if err != nil {
|
||||||
i, res.Executions[0].VMState, res.Executions[0].FaultException)
|
return fmt.Errorf("can't fetch current block height: %w", err)
|
||||||
}
|
}
|
||||||
continue loop
|
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)
|
||||||
}
|
}
|
||||||
case <-timer.C:
|
continue loop
|
||||||
return errors.New("timeout while waiting for transaction to persist")
|
}
|
||||||
|
if txs[i].vub < currBlock {
|
||||||
|
return fmt.Errorf("tx was not persisted: vub=%d, height=%d", txs[i].vub, currBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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}})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue