Validate container owner namespace when putting container #819
20 changed files with 189 additions and 819 deletions
|
@ -250,9 +250,7 @@ func (s *Server) initAlphabetProcessor(cfg *viper.Viper) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (s *Server) initContainerProcessor(cfg *viper.Viper, cnrClient *container.Client,
|
||||
frostfsIDClient *frostfsid.Client,
|
||||
) error {
|
||||
func (s *Server) initContainerProcessor(cfg *viper.Viper, cnrClient *container.Client, frostfsIDClient *frostfsid.Client) error {
|
||||
// container processor
|
||||
containerProcessor, err := cont.New(&cont.Params{
|
||||
Log: s.log,
|
||||
|
@ -289,7 +287,7 @@ func (s *Server) initBalanceProcessor(cfg *viper.Viper, frostfsCli *frostfsClien
|
|||
return bindMorphProcessor(balanceProcessor, s)
|
||||
}
|
||||
|
||||
func (s *Server) initFrostFSMainnetProcessor(cfg *viper.Viper, frostfsIDClient *frostfsid.Client) error {
|
||||
func (s *Server) initFrostFSMainnetProcessor(cfg *viper.Viper) error {
|
||||
if s.withoutMainNet {
|
||||
return nil
|
||||
}
|
||||
|
@ -299,7 +297,6 @@ func (s *Server) initFrostFSMainnetProcessor(cfg *viper.Viper, frostfsIDClient *
|
|||
Metrics: s.irMetrics,
|
||||
PoolSize: cfg.GetInt("workers.frostfs"),
|
||||
FrostFSContract: s.contracts.frostfs,
|
||||
FrostFSIDClient: frostfsIDClient,
|
||||
BalanceClient: s.balanceClient,
|
||||
NetmapClient: s.netmapClient,
|
||||
MorphClient: s.morphClient,
|
||||
|
@ -403,7 +400,7 @@ func (s *Server) initClientsFromMorph() (*serverMorphClients, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
result.FrostFSIDClient, err = frostfsid.NewFromMorph(s.morphClient, s.contracts.frostfsID, fee, frostfsid.TryNotary(), frostfsid.AsAlphabet())
|
||||
result.FrostFSIDClient, err = frostfsid.NewFromMorph(s.morphClient, s.contracts.frostfsID, fee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -447,7 +444,7 @@ func (s *Server) initProcessors(cfg *viper.Viper, morphClients *serverMorphClien
|
|||
return err
|
||||
}
|
||||
|
||||
err = s.initFrostFSMainnetProcessor(cfg, morphClients.FrostFSIDClient)
|
||||
err = s.initFrostFSMainnetProcessor(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
|
@ -73,20 +72,6 @@ func (cp *Processor) verifySignature(v signatureVerificationData) error {
|
|||
|
||||
return errors.New("invalid signature calculated by container owner's key")
|
||||
}
|
||||
} else {
|
||||
var prm frostfsid.AccountKeysPrm
|
||||
prm.SetID(v.ownerContainer)
|
||||
|
||||
ownerKeys, err := cp.idClient.AccountKeys(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("receive owner keys %s: %w", v.ownerContainer, err)
|
||||
}
|
||||
|
||||
for i := range ownerKeys {
|
||||
if (*frostfsecdsa.PublicKeyRFC6979)(ownerKeys[i]).Verify(v.signedData, v.signature) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errors.New("signature is invalid or calculated with the key not bound to the container owner")
|
||||
|
|
|
@ -3,12 +3,13 @@ package container
|
|||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
frostfsidclient "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||
cntClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
||||
|
@ -40,10 +41,10 @@ func TestPutEvent(t *testing.T) {
|
|||
Log: test.NewLogger(t, true),
|
||||
PoolSize: 2,
|
||||
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||
FrostFSIDClient: &testIDClient{},
|
||||
NetworkState: nst,
|
||||
ContainerClient: &testContainerClient{},
|
||||
MorphClient: mc,
|
||||
FrostFSIDClient: &testFrostFSIDClient{},
|
||||
})
|
||||
require.NoError(t, err, "failed to create processor")
|
||||
|
||||
|
@ -95,21 +96,16 @@ func TestDeleteEvent(t *testing.T) {
|
|||
p, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
idc := &testIDClient{
|
||||
publicKeys: []*keys.PublicKey{
|
||||
p.PublicKey(),
|
||||
},
|
||||
}
|
||||
mc := &testMorphClient{}
|
||||
|
||||
proc, err := New(&Params{
|
||||
Log: test.NewLogger(t, true),
|
||||
PoolSize: 2,
|
||||
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||
FrostFSIDClient: idc,
|
||||
NetworkState: nst,
|
||||
ContainerClient: cc,
|
||||
MorphClient: mc,
|
||||
FrostFSIDClient: &testFrostFSIDClient{},
|
||||
})
|
||||
require.NoError(t, err, "failed to create processor")
|
||||
|
||||
|
@ -139,6 +135,7 @@ func TestDeleteEvent(t *testing.T) {
|
|||
ContainerIDValue: cidBin,
|
||||
SignatureValue: p.Sign(cidBin),
|
||||
NotaryRequestValue: nr,
|
||||
PublicKeyValue: p.PublicKey().Bytes(),
|
||||
}
|
||||
|
||||
var signature frostfscrypto.Signature
|
||||
|
@ -177,10 +174,10 @@ func TestSetEACLEvent(t *testing.T) {
|
|||
Log: test.NewLogger(t, true),
|
||||
PoolSize: 2,
|
||||
AlphabetState: &testAlphabetState{isAlphabet: true},
|
||||
FrostFSIDClient: &testIDClient{},
|
||||
NetworkState: nst,
|
||||
ContainerClient: cc,
|
||||
MorphClient: mc,
|
||||
FrostFSIDClient: &testFrostFSIDClient{},
|
||||
})
|
||||
require.NoError(t, err, "failed to create processor")
|
||||
|
||||
|
@ -285,14 +282,6 @@ func (c *testContainerClient) Get(cid []byte) (*containercore.Container, error)
|
|||
return nil, new(apistatus.ContainerNotFound)
|
||||
}
|
||||
|
||||
type testIDClient struct {
|
||||
publicKeys keys.PublicKeys
|
||||
}
|
||||
|
||||
func (c *testIDClient) AccountKeys(p frostfsid.AccountKeysPrm) (keys.PublicKeys, error) {
|
||||
return c.publicKeys, nil
|
||||
}
|
||||
|
||||
var _ putEvent = &testPutEvent{}
|
||||
|
||||
type testPutEvent struct {
|
||||
|
@ -332,3 +321,9 @@ func (c *testMorphClient) NotarySignAndInvokeTX(mainTx *transaction.Transaction)
|
|||
c.transactions = append(c.transactions, mainTx)
|
||||
return nil
|
||||
}
|
||||
|
||||
type testFrostFSIDClient struct{}
|
||||
|
||||
func (c *testFrostFSIDClient) GetSubject(addr util.Uint160) (*frostfsidclient.Subject, error) {
|
||||
return nil, fmt.Errorf("subject not found")
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package container
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
|
||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
@ -88,7 +90,7 @@ func (cp *Processor) checkPutContainer(ctx *putContainerContext) error {
|
|||
}
|
||||
|
||||
// check native name and zone
|
||||
err = checkNNS(ctx, cnr)
|
||||
err = cp.checkNNS(ctx, cnr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("NNS: %w", err)
|
||||
}
|
||||
|
@ -157,7 +159,7 @@ func (cp *Processor) checkDeleteContainer(e containerEvent.Delete) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkNNS(ctx *putContainerContext, cnr containerSDK.Container) error {
|
||||
func (cp *Processor) checkNNS(ctx *putContainerContext, cnr containerSDK.Container) error {
|
||||
// fetch domain info
|
||||
ctx.d = containerSDK.ReadDomain(cnr)
|
||||
|
||||
|
@ -175,6 +177,25 @@ func checkNNS(ctx *putContainerContext, cnr containerSDK.Container) error {
|
|||
}
|
||||
}
|
||||
|
||||
namespace, hasNamespace := strings.CutSuffix(ctx.d.Zone(), ".ns")
|
||||
if !hasNamespace {
|
||||
return nil
|
||||
}
|
||||
|
||||
addr, err := util.Uint160DecodeBytesBE(cnr.Owner().WalletBytes()[1 : 1+util.Uint160Size])
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get container owner address: %w", err)
|
||||
}
|
||||
|
||||
subject, err := cp.frostFSIDClient.GetSubject(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get subject from FrostfsID contract: %w", err)
|
||||
}
|
||||
|
||||
if subject.Namespace != namespace {
|
||||
return fmt.Errorf("container and owner namespaces do not match")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -4,16 +4,15 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
frostfsidclient "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
containercore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/metrics"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
containerEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/container"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"go.uber.org/zap"
|
||||
|
@ -34,20 +33,20 @@ type (
|
|||
NotarySignAndInvokeTX(mainTx *transaction.Transaction) error
|
||||
}
|
||||
|
||||
IDClient interface {
|
||||
AccountKeys(p frostfsid.AccountKeysPrm) (keys.PublicKeys, error)
|
||||
FrostFSIDClient interface {
|
||||
GetSubject(addr util.Uint160) (*frostfsidclient.Subject, error)
|
||||
}
|
||||
|
||||
// Processor of events produced by container contract in the sidechain.
|
||||
Processor struct {
|
||||
log *logger.Logger
|
||||
metrics metrics.Register
|
||||
pool *ants.Pool
|
||||
alphabetState AlphabetState
|
||||
cnrClient ContClient // notary must be enabled
|
||||
morphClient MorphClient
|
||||
idClient IDClient
|
||||
netState NetworkState
|
||||
log *logger.Logger
|
||||
metrics metrics.Register
|
||||
pool *ants.Pool
|
||||
alphabetState AlphabetState
|
||||
cnrClient ContClient // notary must be enabled
|
||||
morphClient MorphClient
|
||||
netState NetworkState
|
||||
frostFSIDClient FrostFSIDClient
|
||||
}
|
||||
|
||||
// Params of the processor constructor.
|
||||
|
@ -58,8 +57,8 @@ type (
|
|||
AlphabetState AlphabetState
|
||||
ContainerClient ContClient
|
||||
MorphClient MorphClient
|
||||
FrostFSIDClient IDClient
|
||||
NetworkState NetworkState
|
||||
FrostFSIDClient FrostFSIDClient
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -92,10 +91,10 @@ func New(p *Params) (*Processor, error) {
|
|||
return nil, errors.New("ir/container: Container client is not set")
|
||||
case p.MorphClient == nil:
|
||||
return nil, errors.New("ir/container: Morph client is not set")
|
||||
case p.FrostFSIDClient == nil:
|
||||
return nil, errors.New("ir/container: FrostFS ID client is not set")
|
||||
case p.NetworkState == nil:
|
||||
return nil, errors.New("ir/container: network state is not set")
|
||||
case p.FrostFSIDClient == nil:
|
||||
return nil, errors.New("ir/container: FrostFSID client is not set")
|
||||
}
|
||||
|
||||
p.Log.Debug(logs.ContainerContainerWorkerPool, zap.Int("size", p.PoolSize))
|
||||
|
@ -111,14 +110,14 @@ func New(p *Params) (*Processor, error) {
|
|||
}
|
||||
|
||||
return &Processor{
|
||||
log: p.Log,
|
||||
metrics: metricsRegister,
|
||||
pool: pool,
|
||||
alphabetState: p.AlphabetState,
|
||||
cnrClient: p.ContainerClient,
|
||||
idClient: p.FrostFSIDClient,
|
||||
netState: p.NetworkState,
|
||||
morphClient: p.MorphClient,
|
||||
log: p.Log,
|
||||
metrics: metricsRegister,
|
||||
pool: pool,
|
||||
alphabetState: p.AlphabetState,
|
||||
cnrClient: p.ContainerClient,
|
||||
netState: p.NetworkState,
|
||||
morphClient: p.MorphClient,
|
||||
frostFSIDClient: p.FrostFSIDClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -88,39 +88,3 @@ func (np *Processor) handleConfig(ev event.Event) {
|
|||
zap.Int("capacity", np.pool.Cap()))
|
||||
}
|
||||
}
|
||||
|
||||
func (np *Processor) handleBind(ev event.Event) {
|
||||
e := ev.(frostfsEvent.Bind)
|
||||
np.log.Info(logs.Notification,
|
||||
zap.String("type", "bind"),
|
||||
)
|
||||
|
||||
// send event to the worker pool
|
||||
|
||||
err := processors.SubmitEvent(np.pool, np.metrics, "frostfs_bind", func() bool {
|
||||
return np.processBind(e, true)
|
||||
})
|
||||
if err != nil {
|
||||
// there system can be moved into controlled degradation stage
|
||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||
zap.Int("capacity", np.pool.Cap()))
|
||||
}
|
||||
}
|
||||
|
||||
func (np *Processor) handleUnbind(ev event.Event) {
|
||||
e := ev.(frostfsEvent.Unbind)
|
||||
np.log.Info(logs.Notification,
|
||||
zap.String("type", "unbind"),
|
||||
)
|
||||
|
||||
// send event to the worker pool
|
||||
|
||||
err := processors.SubmitEvent(np.pool, np.metrics, "frostfs_unbind", func() bool {
|
||||
return np.processBind(e, false)
|
||||
})
|
||||
if err != nil {
|
||||
// there system can be moved into controlled degradation stage
|
||||
np.log.Warn(logs.FrostFSFrostfsProcessorWorkerPoolDrained,
|
||||
zap.Int("capacity", np.pool.Cap()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,9 @@ import (
|
|||
"time"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/balance"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||
frostfsEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/frostfs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -194,80 +191,11 @@ func TestHandleConfig(t *testing.T) {
|
|||
require.EqualValues(t, []nmClient.SetConfigPrm{expConfig}, nm.config, "invalid config value")
|
||||
}
|
||||
|
||||
func TestHandleUnbind(t *testing.T) {
|
||||
t.Parallel()
|
||||
es := &testEpochState{
|
||||
epochCounter: 100,
|
||||
}
|
||||
m := &testMorphClient{
|
||||
balance: 150,
|
||||
}
|
||||
id := &testIDClient{}
|
||||
proc, err := newTestProc(t, func(p *Params) {
|
||||
p.EpochState = es
|
||||
p.MorphClient = m
|
||||
p.FrostFSIDClient = id
|
||||
})
|
||||
require.NoError(t, err, "failed to create processor")
|
||||
|
||||
p, err := keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
evUnbind := frostfsEvent.Unbind{
|
||||
BindCommon: frostfsEvent.BindCommon{
|
||||
UserValue: util.Uint160{49}.BytesBE(),
|
||||
KeysValue: [][]byte{
|
||||
p.PublicKey().Bytes(),
|
||||
},
|
||||
TxHashValue: util.Uint256{100},
|
||||
},
|
||||
}
|
||||
|
||||
proc.handleUnbind(evUnbind)
|
||||
|
||||
for proc.pool.Running() > 0 {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
var userID user.ID
|
||||
userID.SetScriptHash(util.Uint160{49})
|
||||
|
||||
var expBind frostfsid.CommonBindPrm
|
||||
expBind.SetOwnerID(userID.WalletBytes())
|
||||
expBind.SetKeys(evUnbind.BindCommon.KeysValue)
|
||||
expBind.SetHash(evUnbind.BindCommon.TxHashValue)
|
||||
|
||||
var expNilSlice []frostfsid.CommonBindPrm
|
||||
|
||||
require.EqualValues(t, []frostfsid.CommonBindPrm{expBind}, id.remove, "invalid remove keys value")
|
||||
require.EqualValues(t, expNilSlice, id.add, "invalid add keys value")
|
||||
|
||||
evBind := frostfsEvent.Bind{
|
||||
BindCommon: frostfsEvent.BindCommon{
|
||||
UserValue: util.Uint160{49}.BytesBE(),
|
||||
KeysValue: [][]byte{
|
||||
p.PublicKey().Bytes(),
|
||||
},
|
||||
TxHashValue: util.Uint256{100},
|
||||
},
|
||||
}
|
||||
|
||||
proc.handleBind(evBind)
|
||||
|
||||
for proc.pool.Running() > 0 {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
require.EqualValues(t, []frostfsid.CommonBindPrm{expBind}, id.remove, "invalid remove keys value")
|
||||
require.EqualValues(t, []frostfsid.CommonBindPrm{expBind}, id.add, "invalid add keys value")
|
||||
}
|
||||
|
||||
func newTestProc(t *testing.T, nonDefault func(p *Params)) (*Processor, error) {
|
||||
p := &Params{
|
||||
Log: test.NewLogger(t, true),
|
||||
PoolSize: 1,
|
||||
FrostFSContract: util.Uint160{0},
|
||||
FrostFSIDClient: &testIDClient{},
|
||||
BalanceClient: &testBalaceClient{},
|
||||
NetmapClient: &testNetmapClient{},
|
||||
MorphClient: &testMorphClient{},
|
||||
|
@ -358,18 +286,3 @@ func (c *testMorphClient) TransferGas(receiver util.Uint160, amount fixedn.Fixed
|
|||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type testIDClient struct {
|
||||
add []frostfsid.CommonBindPrm
|
||||
remove []frostfsid.CommonBindPrm
|
||||
}
|
||||
|
||||
func (c *testIDClient) AddKeys(p frostfsid.CommonBindPrm) error {
|
||||
c.add = append(c.add, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *testIDClient) RemoveKeys(args frostfsid.CommonBindPrm) error {
|
||||
c.remove = append(c.remove, args)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
package frostfs
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type bindCommon interface {
|
||||
User() []byte
|
||||
Keys() [][]byte
|
||||
TxHash() util.Uint256
|
||||
}
|
||||
|
||||
func (np *Processor) processBind(e bindCommon, bind bool) bool {
|
||||
if !np.alphabetState.IsAlphabet() {
|
||||
np.log.Info(logs.FrostFSNonAlphabetModeIgnoreBind)
|
||||
return true
|
||||
}
|
||||
|
||||
c := &bindCommonContext{
|
||||
bindCommon: e,
|
||||
bind: bind,
|
||||
}
|
||||
|
||||
err := np.checkBindCommon(c)
|
||||
if err != nil {
|
||||
np.log.Error(logs.FrostFSInvalidManageKeyEvent,
|
||||
zap.Bool("bind", c.bind),
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return np.approveBindCommon(c) == nil
|
||||
}
|
||||
|
||||
type bindCommonContext struct {
|
||||
bindCommon
|
||||
|
||||
bind bool
|
||||
|
||||
scriptHash util.Uint160
|
||||
}
|
||||
|
||||
func (np *Processor) checkBindCommon(e *bindCommonContext) error {
|
||||
var err error
|
||||
|
||||
e.scriptHash, err = util.Uint160DecodeBytesBE(e.User())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
curve := elliptic.P256()
|
||||
|
||||
for _, key := range e.Keys() {
|
||||
_, err = keys.NewPublicKeyFromBytes(key, curve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (np *Processor) approveBindCommon(e *bindCommonContext) error {
|
||||
// calculate wallet address
|
||||
scriptHash := e.User()
|
||||
|
||||
u160, err := util.Uint160DecodeBytesBE(scriptHash)
|
||||
if err != nil {
|
||||
np.log.Error(logs.FrostFSCouldNotDecodeScriptHashFromBytes,
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
var id user.ID
|
||||
id.SetScriptHash(u160)
|
||||
|
||||
prm := frostfsid.CommonBindPrm{}
|
||||
prm.SetOwnerID(id.WalletBytes())
|
||||
prm.SetKeys(e.Keys())
|
||||
prm.SetHash(e.bindCommon.TxHash())
|
||||
|
||||
var typ string
|
||||
if e.bind {
|
||||
typ = "bind"
|
||||
err = np.frostfsIDClient.AddKeys(prm)
|
||||
} else {
|
||||
typ = "unbind"
|
||||
err = np.frostfsIDClient.RemoveKeys(prm)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
np.log.Error(fmt.Sprintf("could not approve %s", typ),
|
||||
zap.String("error", err.Error()))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -8,7 +8,6 @@ import (
|
|||
"git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring/metrics"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/balance"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/frostfsid"
|
||||
nmClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client/netmap"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
frostfsEvent "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event/frostfs"
|
||||
|
@ -51,11 +50,6 @@ type (
|
|||
TransferGas(receiver util.Uint160, amount fixedn.Fixed8) error
|
||||
}
|
||||
|
||||
IDClient interface {
|
||||
AddKeys(p frostfsid.CommonBindPrm) error
|
||||
RemoveKeys(args frostfsid.CommonBindPrm) error
|
||||
}
|
||||
|
||||
// Processor of events produced by frostfs contract in main net.
|
||||
Processor struct {
|
||||
log *logger.Logger
|
||||
|
@ -73,7 +67,6 @@ type (
|
|||
mintEmitThreshold uint64
|
||||
mintEmitValue fixedn.Fixed8
|
||||
gasBalanceThreshold int64
|
||||
frostfsIDClient IDClient
|
||||
}
|
||||
|
||||
// Params of the processor constructor.
|
||||
|
@ -82,7 +75,6 @@ type (
|
|||
Metrics metrics.Register
|
||||
PoolSize int
|
||||
FrostFSContract util.Uint160
|
||||
FrostFSIDClient IDClient
|
||||
BalanceClient BalanceClient
|
||||
NetmapClient NetmapClient
|
||||
MorphClient MorphClient
|
||||
|
@ -101,8 +93,6 @@ const (
|
|||
withdrawNotification = "Withdraw"
|
||||
chequeNotification = "Cheque"
|
||||
configNotification = "SetConfig"
|
||||
bindNotification = "Bind"
|
||||
unbindNotification = "Unbind"
|
||||
)
|
||||
|
||||
// New creates frostfs mainnet contract processor instance.
|
||||
|
@ -152,8 +142,6 @@ func New(p *Params) (*Processor, error) {
|
|||
mintEmitThreshold: p.MintEmitThreshold,
|
||||
mintEmitValue: p.MintEmitValue,
|
||||
gasBalanceThreshold: p.GasBalanceThreshold,
|
||||
|
||||
frostfsIDClient: p.FrostFSIDClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -187,16 +175,6 @@ func (np *Processor) ListenerNotificationParsers() []event.NotificationParserInf
|
|||
p.SetParser(frostfsEvent.ParseConfig)
|
||||
parsers = append(parsers, p)
|
||||
|
||||
// bind event
|
||||
p.SetType(event.TypeFromString(bindNotification))
|
||||
p.SetParser(frostfsEvent.ParseBind)
|
||||
parsers = append(parsers, p)
|
||||
|
||||
// unbind event
|
||||
p.SetType(event.TypeFromString(unbindNotification))
|
||||
p.SetParser(frostfsEvent.ParseUnbind)
|
||||
parsers = append(parsers, p)
|
||||
|
||||
return parsers
|
||||
}
|
||||
|
||||
|
@ -230,16 +208,6 @@ func (np *Processor) ListenerNotificationHandlers() []event.NotificationHandlerI
|
|||
h.SetHandler(np.handleConfig)
|
||||
handlers = append(handlers, h)
|
||||
|
||||
// bind handler
|
||||
h.SetType(event.TypeFromString(bindNotification))
|
||||
h.SetHandler(np.handleBind)
|
||||
handlers = append(handlers, h)
|
||||
|
||||
// unbind handler
|
||||
h.SetType(event.TypeFromString(unbindNotification))
|
||||
h.SetHandler(np.handleUnbind)
|
||||
handlers = append(handlers, h)
|
||||
|
||||
return handlers
|
||||
}
|
||||
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package frostfscontract
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
)
|
||||
|
||||
type commonBindArgs struct {
|
||||
scriptHash []byte // script hash of account identifier
|
||||
|
||||
keys [][]byte // list of serialized public keys
|
||||
|
||||
client.InvokePrmOptional
|
||||
}
|
||||
|
||||
// SetOptionalPrm sets optional client parameters.
|
||||
func (x *commonBindArgs) SetOptionalPrm(op client.InvokePrmOptional) {
|
||||
x.InvokePrmOptional = op
|
||||
}
|
||||
|
||||
// SetScriptHash sets script hash of the FrostFS account identifier.
|
||||
func (x *commonBindArgs) SetScriptHash(v []byte) {
|
||||
x.scriptHash = v
|
||||
}
|
||||
|
||||
// SetKeys sets a list of public keys in a binary format.
|
||||
func (x *commonBindArgs) SetKeys(v [][]byte) {
|
||||
x.keys = v
|
||||
}
|
||||
|
||||
// BindKeysPrm groups parameters of BindKeys operation.
|
||||
type BindKeysPrm struct {
|
||||
commonBindArgs
|
||||
}
|
||||
|
||||
// BindKeys binds list of public keys from FrostFS account by script hash.
|
||||
func (x *Client) BindKeys(p BindKeysPrm) error {
|
||||
prm := client.InvokePrm{}
|
||||
prm.SetMethod(bindKeysMethod)
|
||||
prm.SetArgs(p.scriptHash, p.keys)
|
||||
prm.InvokePrmOptional = p.InvokePrmOptional
|
||||
|
||||
_, err := x.client.Invoke(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not invoke method (%s): %w", bindKeysMethod, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnbindKeysPrm groups parameters of UnbindKeys operation.
|
||||
type UnbindKeysPrm struct {
|
||||
commonBindArgs
|
||||
}
|
||||
|
||||
// UnbindKeys invokes the call of key unbinding method
|
||||
// of FrostFS contract.
|
||||
func (x *Client) UnbindKeys(args UnbindKeysPrm) error {
|
||||
prm := client.InvokePrm{}
|
||||
prm.SetMethod(unbindKeysMethod)
|
||||
prm.SetArgs(args.scriptHash, args.keys)
|
||||
prm.InvokePrmOptional = args.InvokePrmOptional
|
||||
|
||||
_, err := x.client.Invoke(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not invoke method (%s): %w", unbindKeysMethod, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -21,8 +21,6 @@ type Client struct {
|
|||
}
|
||||
|
||||
const (
|
||||
bindKeysMethod = "bind"
|
||||
unbindKeysMethod = "unbind"
|
||||
alphabetUpdateMethod = "alphabetUpdate"
|
||||
chequeMethod = "cheque"
|
||||
)
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
)
|
||||
|
||||
type CommonBindPrm struct {
|
||||
ownerID []byte // FrostFS account identifier
|
||||
|
||||
keys [][]byte // list of serialized public keys
|
||||
|
||||
client.InvokePrmOptional
|
||||
}
|
||||
|
||||
func (x *CommonBindPrm) SetOptionalPrm(prm client.InvokePrmOptional) {
|
||||
x.InvokePrmOptional = prm
|
||||
}
|
||||
|
||||
// SetOwnerID sets FrostFS account identifier.
|
||||
func (x *CommonBindPrm) SetOwnerID(v []byte) {
|
||||
x.ownerID = v
|
||||
}
|
||||
|
||||
// SetKeys sets a list of public keys in a binary format.
|
||||
func (x *CommonBindPrm) SetKeys(v [][]byte) {
|
||||
x.keys = v
|
||||
}
|
||||
|
||||
// AddKeys adds a list of public keys to/from FrostFS account.
|
||||
func (x *Client) AddKeys(p CommonBindPrm) error {
|
||||
prm := client.InvokePrm{}
|
||||
|
||||
prm.SetMethod(addKeysMethod)
|
||||
prm.SetArgs(p.ownerID, p.keys)
|
||||
prm.InvokePrmOptional = p.InvokePrmOptional
|
||||
|
||||
_, err := x.client.Invoke(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not invoke method (%s): %w", addKeysMethod, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveKeys removes a list of public keys to/from FrostFS account.
|
||||
func (x *Client) RemoveKeys(args CommonBindPrm) error {
|
||||
prm := client.InvokePrm{}
|
||||
|
||||
prm.SetMethod(removeKeysMethod)
|
||||
prm.SetArgs(args.ownerID, args.keys)
|
||||
prm.InvokePrmOptional = args.InvokePrmOptional
|
||||
|
||||
_, err := x.client.Invoke(prm)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not invoke method (%s): %w", removeKeysMethod, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -20,53 +20,12 @@ type Client struct {
|
|||
client *client.StaticClient // static FrostFS ID contract client
|
||||
}
|
||||
|
||||
const (
|
||||
keyListingMethod = "key"
|
||||
addKeysMethod = "addKey"
|
||||
removeKeysMethod = "removeKey"
|
||||
)
|
||||
|
||||
// NewFromMorph wraps client to work with FrostFS ID contract.
|
||||
func NewFromMorph(cli *client.Client, contract util.Uint160, fee fixedn.Fixed8, opts ...Option) (*Client, error) {
|
||||
o := defaultOpts()
|
||||
|
||||
for i := range opts {
|
||||
opts[i](o)
|
||||
}
|
||||
|
||||
sc, err := client.NewStatic(cli, contract, fee, ([]client.StaticClientOption)(*o)...)
|
||||
func NewFromMorph(cli *client.Client, contract util.Uint160, fee fixedn.Fixed8) (*Client, error) {
|
||||
sc, err := client.NewStatic(cli, contract, fee, client.TryNotary(), client.AsAlphabet())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client of FrostFS ID contract: %w", err)
|
||||
}
|
||||
|
||||
return &Client{client: sc}, nil
|
||||
}
|
||||
|
||||
// Option allows to set an optional
|
||||
// parameter of ClientWrapper.
|
||||
type Option func(*opts)
|
||||
|
||||
type opts []client.StaticClientOption
|
||||
|
||||
func defaultOpts() *opts {
|
||||
return new(opts)
|
||||
}
|
||||
|
||||
// TryNotary returns option to enable
|
||||
// notary invocation tries.
|
||||
func TryNotary() Option {
|
||||
return func(o *opts) {
|
||||
*o = append(*o, client.TryNotary())
|
||||
}
|
||||
}
|
||||
|
||||
// AsAlphabet returns option to sign main TX
|
||||
// of notary requests with client's private
|
||||
// key.
|
||||
//
|
||||
// Considered to be used by IR nodes only.
|
||||
func AsAlphabet() Option {
|
||||
return func(o *opts) {
|
||||
*o = append(*o, client.AsAlphabet())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
)
|
||||
|
||||
// AccountKeysPrm groups parameters of AccountKeys operation.
|
||||
type AccountKeysPrm struct {
|
||||
id user.ID
|
||||
}
|
||||
|
||||
// SetID sets owner ID.
|
||||
func (a *AccountKeysPrm) SetID(id user.ID) {
|
||||
a.id = id
|
||||
}
|
||||
|
||||
// AccountKeys requests public keys of FrostFS account from FrostFS ID contract.
|
||||
func (x *Client) AccountKeys(p AccountKeysPrm) (keys.PublicKeys, error) {
|
||||
prm := client.TestInvokePrm{}
|
||||
prm.SetMethod(keyListingMethod)
|
||||
prm.SetArgs(p.id.WalletBytes())
|
||||
|
||||
items, err := x.client.TestInvoke(prm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not perform test invocation (%s): %w", keyListingMethod, err)
|
||||
} else if ln := len(items); ln != 1 {
|
||||
return nil, fmt.Errorf("unexpected stack item count (%s): %d", keyListingMethod, ln)
|
||||
}
|
||||
|
||||
items, err = client.ArrayFromStackItem(items[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("1st stack item must be an array (%s)", keyListingMethod)
|
||||
}
|
||||
|
||||
pubs := make(keys.PublicKeys, len(items))
|
||||
for i := range items {
|
||||
rawPub, err := client.BytesFromStackItem(items[i])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid stack item, expected byte array (%s)", keyListingMethod)
|
||||
}
|
||||
|
||||
pubs[i], err = keys.NewPublicKeyFromBytes(rawPub, elliptic.P256())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("received invalid key (%s): %w", keyListingMethod, err)
|
||||
}
|
||||
}
|
||||
|
||||
return pubs, nil
|
||||
}
|
117
pkg/morph/client/frostfsid/subject.go
Normal file
117
pkg/morph/client/frostfsid/subject.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
package frostfsid
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
frostfsidclient "git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||
)
|
||||
|
||||
const methodGetSubject = "getSubject"
|
||||
|
||||
func (c *Client) GetSubject(addr util.Uint160) (*frostfsidclient.Subject, error) {
|
||||
prm := client.TestInvokePrm{}
|
||||
prm.SetMethod(methodGetSubject)
|
||||
prm.SetArgs(addr)
|
||||
|
||||
res, err := c.client.TestInvoke(prm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not perform test invocation (%s): %w", methodGetSubject, err)
|
||||
}
|
||||
|
||||
subj, err := parseSubject(res)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse test invocation result (%s): %w", methodGetSubject, err)
|
||||
}
|
||||
|
||||
return subj, nil
|
||||
}
|
||||
|
||||
// parseSubject from https://git.frostfs.info/TrueCloudLab/frostfs-contract/src/commit/dd5919348da9731f24504e7bc485516c2ba5f11c/frostfsid/client/client.go#L592
|
||||
func parseSubject(structArr []stackitem.Item) (*frostfsidclient.Subject, error) {
|
||||
if len(structArr) < 5 {
|
||||
return nil, errors.New("invalid response subject struct")
|
||||
}
|
||||
|
||||
var (
|
||||
err error
|
||||
subj frostfsidclient.Subject
|
||||
)
|
||||
|
||||
subj.PrimaryKey, err = unwrap.PublicKey(makeValidRes(structArr[0]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !structArr[1].Equals(stackitem.Null{}) {
|
||||
subj.AdditionalKeys, err = unwrap.ArrayOfPublicKeys(makeValidRes(structArr[1]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !structArr[2].Equals(stackitem.Null{}) {
|
||||
subj.Namespace, err = unwrap.UTF8String(makeValidRes(structArr[2]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !structArr[3].Equals(stackitem.Null{}) {
|
||||
subj.Name, err = unwrap.UTF8String(makeValidRes(structArr[3]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
subj.KV, err = parseMap(structArr[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &subj, nil
|
||||
}
|
||||
|
||||
func makeValidRes(item stackitem.Item) (*result.Invoke, error) {
|
||||
return &result.Invoke{
|
||||
Stack: []stackitem.Item{item},
|
||||
State: vmstate.Halt.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseMap(item stackitem.Item) (map[string]string, error) {
|
||||
if item.Equals(stackitem.Null{}) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
metaMap, err := unwrap.Map(makeValidRes(item))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta, ok := metaMap.Value().([]stackitem.MapElement)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid map type")
|
||||
}
|
||||
|
||||
res := make(map[string]string, len(meta))
|
||||
for _, element := range meta {
|
||||
key, err := element.Key.TryBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
val, err := element.Value.TryBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res[string(key)] = string(val)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package frostfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
type Bind struct {
|
||||
BindCommon
|
||||
}
|
||||
|
||||
type BindCommon struct {
|
||||
UserValue []byte
|
||||
KeysValue [][]byte
|
||||
|
||||
// TxHashValue is used in notary environmental
|
||||
// for calculating unique but same for
|
||||
// all notification receivers values.
|
||||
TxHashValue util.Uint256
|
||||
}
|
||||
|
||||
// TxHash returns hash of the TX with new epoch
|
||||
// notification.
|
||||
func (b BindCommon) TxHash() util.Uint256 {
|
||||
return b.TxHashValue
|
||||
}
|
||||
|
||||
// MorphEvent implements Neo:Morph Event interface.
|
||||
func (BindCommon) MorphEvent() {}
|
||||
|
||||
func (b BindCommon) Keys() [][]byte { return b.KeysValue }
|
||||
|
||||
func (b BindCommon) User() []byte { return b.UserValue }
|
||||
|
||||
func ParseBind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||
var (
|
||||
ev Bind
|
||||
err error
|
||||
)
|
||||
|
||||
params, err := event.ParseStackArray(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
||||
}
|
||||
|
||||
err = parseBind(&ev.BindCommon, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ev.TxHashValue = e.Container
|
||||
|
||||
return ev, nil
|
||||
}
|
||||
|
||||
func parseBind(dst *BindCommon, params []stackitem.Item) error {
|
||||
if ln := len(params); ln != 2 {
|
||||
return event.WrongNumberOfParameters(2, ln)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
// parse user
|
||||
dst.UserValue, err = client.BytesFromStackItem(params[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get bind user: %w", err)
|
||||
}
|
||||
|
||||
// parse keys
|
||||
bindKeys, err := client.ArrayFromStackItem(params[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get bind keys: %w", err)
|
||||
}
|
||||
|
||||
dst.KeysValue = make([][]byte, 0, len(bindKeys))
|
||||
|
||||
for i := range bindKeys {
|
||||
rawKey, err := client.BytesFromStackItem(bindKeys[i])
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get bind public key: %w", err)
|
||||
}
|
||||
|
||||
dst.KeysValue = append(dst.KeysValue, rawKey)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package frostfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseBind(t *testing.T) {
|
||||
var (
|
||||
user = []byte{0x1, 0x2, 0x3}
|
||||
publicKeys = [][]byte{
|
||||
[]byte("key1"),
|
||||
[]byte("key2"),
|
||||
[]byte("key3"),
|
||||
}
|
||||
)
|
||||
|
||||
t.Run("wrong number of parameters", func(t *testing.T) {
|
||||
prms := []stackitem.Item{
|
||||
stackitem.NewMap(),
|
||||
}
|
||||
|
||||
_, err := ParseBind(createNotifyEventFromItems(prms))
|
||||
require.EqualError(t, err, event.WrongNumberOfParameters(2, len(prms)).Error())
|
||||
})
|
||||
|
||||
t.Run("wrong first parameter", func(t *testing.T) {
|
||||
_, err := ParseBind(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong second parameter", func(t *testing.T) {
|
||||
_, err := ParseBind(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(user),
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("correct", func(t *testing.T) {
|
||||
ev, err := ParseBind(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(user),
|
||||
stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(publicKeys[0]),
|
||||
stackitem.NewByteArray(publicKeys[1]),
|
||||
stackitem.NewByteArray(publicKeys[2]),
|
||||
}),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
|
||||
e := ev.(Bind)
|
||||
|
||||
require.Equal(t, user, e.User())
|
||||
require.Equal(t, publicKeys, e.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func createNotifyEventFromItems(items []stackitem.Item) *state.ContainedNotificationEvent {
|
||||
return &state.ContainedNotificationEvent{
|
||||
NotificationEvent: state.NotificationEvent{
|
||||
Item: stackitem.NewArray(items),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -84,3 +85,11 @@ func TestParseCheque(t *testing.T) {
|
|||
}, ev)
|
||||
})
|
||||
}
|
||||
|
||||
func createNotifyEventFromItems(items []stackitem.Item) *state.ContainedNotificationEvent {
|
||||
return &state.ContainedNotificationEvent{
|
||||
NotificationEvent: state.NotificationEvent{
|
||||
Item: stackitem.NewArray(items),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
package frostfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
)
|
||||
|
||||
type Unbind struct {
|
||||
BindCommon
|
||||
}
|
||||
|
||||
func ParseUnbind(e *state.ContainedNotificationEvent) (event.Event, error) {
|
||||
var (
|
||||
ev Unbind
|
||||
err error
|
||||
)
|
||||
|
||||
params, err := event.ParseStackArray(e)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse stack items from notify event: %w", err)
|
||||
}
|
||||
|
||||
err = parseBind(&ev.BindCommon, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ev.TxHashValue = e.Container
|
||||
|
||||
return ev, nil
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package frostfs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/event"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestParseUnbind(t *testing.T) {
|
||||
var (
|
||||
user = []byte{0x1, 0x2, 0x3}
|
||||
publicKeys = [][]byte{
|
||||
[]byte("key1"),
|
||||
[]byte("key2"),
|
||||
[]byte("key3"),
|
||||
}
|
||||
)
|
||||
|
||||
t.Run("wrong number of parameters", func(t *testing.T) {
|
||||
prms := []stackitem.Item{
|
||||
stackitem.NewMap(),
|
||||
}
|
||||
|
||||
_, err := ParseUnbind(createNotifyEventFromItems(prms))
|
||||
require.EqualError(t, err, event.WrongNumberOfParameters(2, len(prms)).Error())
|
||||
})
|
||||
|
||||
t.Run("wrong first parameter", func(t *testing.T) {
|
||||
_, err := ParseUnbind(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("wrong second parameter", func(t *testing.T) {
|
||||
_, err := ParseUnbind(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(user),
|
||||
stackitem.NewMap(),
|
||||
}))
|
||||
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("correct", func(t *testing.T) {
|
||||
ev, err := ParseUnbind(createNotifyEventFromItems([]stackitem.Item{
|
||||
stackitem.NewByteArray(user),
|
||||
stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(publicKeys[0]),
|
||||
stackitem.NewByteArray(publicKeys[1]),
|
||||
stackitem.NewByteArray(publicKeys[2]),
|
||||
}),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
|
||||
e := ev.(Unbind)
|
||||
|
||||
require.Equal(t, user, e.User())
|
||||
require.Equal(t, publicKeys, e.Keys())
|
||||
})
|
||||
}
|
Loading…
Reference in a new issue