2f6adb0465
RoleManagement native contract (ex designate contract) stores list of keys per role. Main net uses NeoFSAlphabet role to store keys of alphabet nodes of inner ring. Side chain uses the same role to store keys of all inner ring nodes, including alphabet. Signed-off-by: Alex Vanin <alexey@nspcc.ru>
164 lines
3.7 KiB
Go
164 lines
3.7 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ecdsa"
|
|
"time"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/client"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Option is a client configuration change function.
|
|
type Option func(*cfg)
|
|
|
|
// groups the configurations with default values.
|
|
type cfg struct {
|
|
ctx context.Context // neo-go client context
|
|
|
|
dialTimeout time.Duration // client dial timeout
|
|
|
|
logger *logger.Logger // logging component
|
|
|
|
gas util.Uint160 // native gas script-hash
|
|
|
|
waitInterval time.Duration
|
|
}
|
|
|
|
const (
|
|
defaultDialTimeout = 5 * time.Second
|
|
defaultWaitInterval = 500 * time.Millisecond
|
|
)
|
|
|
|
func defaultConfig() *cfg {
|
|
return &cfg{
|
|
ctx: context.Background(),
|
|
dialTimeout: defaultDialTimeout,
|
|
logger: zap.L(),
|
|
waitInterval: defaultWaitInterval,
|
|
}
|
|
}
|
|
|
|
// New creates, initializes and returns the Client instance.
|
|
//
|
|
// If private key is nil, crypto.ErrEmptyPrivateKey is returned.
|
|
//
|
|
// Other values are set according to provided options, or by default:
|
|
// * client context: Background;
|
|
// * dial timeout: 5s;
|
|
// * blockchain network type: netmode.PrivNet;
|
|
// * logger: zap.L().
|
|
//
|
|
// If desired option satisfies the default value, it can be omitted.
|
|
// If multiple options of the same config value are supplied,
|
|
// the option with the highest index in the arguments will be used.
|
|
func New(key *ecdsa.PrivateKey, endpoint string, opts ...Option) (*Client, error) {
|
|
if key == nil {
|
|
return nil, crypto.ErrEmptyPrivateKey
|
|
}
|
|
|
|
privKeyBytes := crypto.MarshalPrivateKey(key)
|
|
|
|
wif, err := keys.WIFEncode(privKeyBytes, keys.WIFVersion, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
account, err := wallet.NewAccountFromWIF(wif)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// build default configuration
|
|
cfg := defaultConfig()
|
|
|
|
// apply options
|
|
for _, opt := range opts {
|
|
opt(cfg)
|
|
}
|
|
|
|
cli, err := client.New(cfg.ctx, endpoint, client.Options{
|
|
DialTimeout: cfg.dialTimeout,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = cli.Init() // magic number is set there based on RPC node answer
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
gas, err := cli.GetNativeContractHash(nativenames.Gas)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
neo, err := cli.GetNativeContractHash(nativenames.Neo)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
designate, err := cli.GetNativeContractHash(nativenames.Designation)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Client{
|
|
logger: cfg.logger,
|
|
client: cli,
|
|
acc: account,
|
|
gas: gas,
|
|
neo: neo,
|
|
designate: designate,
|
|
waitInterval: cfg.waitInterval,
|
|
}, nil
|
|
}
|
|
|
|
// WithContext returns a client constructor option that
|
|
// specifies the neo-go client context.
|
|
//
|
|
// Ignores nil value.
|
|
//
|
|
// If option not provided, context.Background() is used.
|
|
func WithContext(ctx context.Context) Option {
|
|
return func(c *cfg) {
|
|
if ctx != nil {
|
|
c.ctx = ctx
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithDialTimeout returns a client constructor option
|
|
// that specifies neo-go client dial timeout duration.
|
|
//
|
|
// Ignores non-positive value.
|
|
//
|
|
// If option not provided, 5s timeout is used.
|
|
func WithDialTimeout(dur time.Duration) Option {
|
|
return func(c *cfg) {
|
|
if dur > 0 {
|
|
c.dialTimeout = dur
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithLogger returns a client constructor option
|
|
// that specifies the component for writing log messages.
|
|
//
|
|
// Ignores nil value.
|
|
//
|
|
// If option not provided, zap.L() is used.
|
|
func WithLogger(logger *logger.Logger) Option {
|
|
return func(c *cfg) {
|
|
if logger != nil {
|
|
c.logger = logger
|
|
}
|
|
}
|
|
}
|