forked from TrueCloudLab/frostfs-node
Evgenii Stratonikov
2469e0c683
It is used once, it is used only internally and it is single-statement. I see no justification in having it as a separate function. It introduces confusion, because we also have NewLocalActor(). Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
137 lines
3.4 KiB
Go
137 lines
3.4 KiB
Go
package helper
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
|
"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/neorpc/result"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
|
"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/smartcontract/trigger"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// Client represents N3 client interface capable of test-invoking scripts
|
|
// and sending signed transactions to chain.
|
|
type Client interface {
|
|
actor.RPCActor
|
|
|
|
GetNativeContracts() ([]state.Contract, error)
|
|
GetApplicationLog(util.Uint256, *trigger.Type) (*result.ApplicationLog, error)
|
|
}
|
|
|
|
type HashVUBPair struct {
|
|
Hash util.Uint256
|
|
Vub uint32
|
|
}
|
|
|
|
type ClientContext struct {
|
|
Client Client // a raw neo-go client OR a local chain implementation
|
|
CommitteeAct *actor.Actor // committee actor with the Global witness scope
|
|
ReadOnlyInvoker *invoker.Invoker // R/O contract invoker, does not contain any signer
|
|
SentTxs []HashVUBPair
|
|
}
|
|
|
|
func NewRemoteClient(v *viper.Viper) (Client, error) {
|
|
// number of opened connections
|
|
// by neo-go client per one host
|
|
const (
|
|
maxConnsPerHost = 10
|
|
requestTimeout = time.Second * 10
|
|
)
|
|
|
|
ctx := context.Background()
|
|
endpoint := v.GetString(commonflags.EndpointFlag)
|
|
if endpoint == "" {
|
|
return nil, errors.New("missing endpoint")
|
|
}
|
|
|
|
var cfg *tls.Config
|
|
if rootCAs := v.GetStringSlice("tls.trusted_ca_list"); len(rootCAs) != 0 {
|
|
certFile := v.GetString("tls.certificate")
|
|
keyFile := v.GetString("tls.key")
|
|
|
|
tlsConfig, err := rpcclient.TLSClientConfig(rootCAs, certFile, keyFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cfg = tlsConfig
|
|
}
|
|
c, err := rpcclient.New(ctx, endpoint, rpcclient.Options{
|
|
MaxConnsPerHost: maxConnsPerHost,
|
|
RequestTimeout: requestTimeout,
|
|
TLSClientConfig: cfg,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := c.Init(); err != nil {
|
|
return nil, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func DefaultClientContext(c Client, committeeAcc *wallet.Account) (*ClientContext, error) {
|
|
commAct, err := actor.New(c, []actor.SignerAccount{{
|
|
Signer: transaction.Signer{
|
|
Account: committeeAcc.Contract.ScriptHash(),
|
|
Scopes: transaction.Global,
|
|
},
|
|
Account: committeeAcc,
|
|
}})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ClientContext{
|
|
Client: c,
|
|
CommitteeAct: commAct,
|
|
ReadOnlyInvoker: invoker.New(c, nil),
|
|
}, nil
|
|
}
|
|
|
|
func (c *ClientContext) SendTx(tx *transaction.Transaction, cmd *cobra.Command, await bool) error {
|
|
h, err := c.Client.SendRawTransaction(tx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if h != tx.Hash() {
|
|
return fmt.Errorf("sent and actual tx hashes mismatch:\n\tsent: %v\n\tactual: %v", tx.Hash().StringLE(), h.StringLE())
|
|
}
|
|
|
|
c.SentTxs = append(c.SentTxs, HashVUBPair{Hash: h, Vub: tx.ValidUntilBlock})
|
|
|
|
if await {
|
|
return c.AwaitTx(cmd)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *ClientContext) AwaitTx(cmd *cobra.Command) error {
|
|
if len(c.SentTxs) == 0 {
|
|
return nil
|
|
}
|
|
|
|
if local, ok := c.Client.(*LocalClient); ok {
|
|
if err := local.putTransactions(); err != nil {
|
|
return fmt.Errorf("can't persist transactions: %w", err)
|
|
}
|
|
}
|
|
|
|
err := AwaitTx(cmd, c.Client, c.SentTxs)
|
|
c.SentTxs = c.SentTxs[:0]
|
|
|
|
return err
|
|
}
|