forked from TrueCloudLab/frostfs-node
[#11] Trim the old functionality
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
783ec72d56
commit
a87fdab324
235 changed files with 39 additions and 36211 deletions
0
pkg/core/container/.gitkeep
Normal file
0
pkg/core/container/.gitkeep
Normal file
|
@ -1,24 +0,0 @@
|
|||
package basic
|
||||
|
||||
const (
|
||||
// OpGetRangeHash is an index of GetRangeHash operation in basic ACL bitmask order.
|
||||
OpGetRangeHash uint8 = iota
|
||||
|
||||
// OpGetRange is an index of GetRange operation in basic ACL bitmask order.
|
||||
OpGetRange
|
||||
|
||||
// OpSearch is an index of Search operation in basic ACL bitmask order.
|
||||
OpSearch
|
||||
|
||||
// OpDelete is an index of Delete operation in basic ACL bitmask order.
|
||||
OpDelete
|
||||
|
||||
// OpPut is an index of Put operation in basic ACL bitmask order.
|
||||
OpPut
|
||||
|
||||
// OpHead is an index of Head operation in basic ACL bitmask order.
|
||||
OpHead
|
||||
|
||||
// OpGet is an index of Get operation in basic ACL bitmask order.
|
||||
OpGet
|
||||
)
|
|
@ -1,159 +0,0 @@
|
|||
package basic
|
||||
|
||||
// ACL represents a container's
|
||||
// basic permission bits.
|
||||
type ACL uint32
|
||||
|
||||
const (
|
||||
reservedBitNumber = 2 // first left bits are reserved
|
||||
|
||||
stickyBitPos = reservedBitNumber // X-bit after reserved bits
|
||||
|
||||
finalBitPos = stickyBitPos + 1 // F-bit after X-bit
|
||||
)
|
||||
|
||||
const (
|
||||
opOffset = finalBitPos + 1 // offset of operation bits
|
||||
|
||||
bitsPerOp = 4 // number of bits per operation
|
||||
|
||||
opNumber = 7 // number of operation bit sections
|
||||
)
|
||||
|
||||
const (
|
||||
bitUser uint8 = iota
|
||||
bitSystem
|
||||
bitOthers
|
||||
bitBearer
|
||||
)
|
||||
|
||||
const leftACLBitPos = opOffset + bitsPerOp*opNumber - 1
|
||||
|
||||
// returns true if n-th left bit is set (starting at 0).
|
||||
func isLeftBitSet(value ACL, n uint8) bool {
|
||||
bitMask := ACL(1 << (leftACLBitPos - n))
|
||||
return bitMask != 0 && value&bitMask == bitMask
|
||||
}
|
||||
|
||||
// sets n-th left bit (starting at 0).
|
||||
func setLeftBit(value *ACL, n uint8) {
|
||||
*value |= ACL(1 << (leftACLBitPos - n))
|
||||
}
|
||||
|
||||
// resets n-th left bit (starting at 0).
|
||||
func resetLeftBit(value *ACL, n uint8) {
|
||||
*value &= ^ACL(1 << (leftACLBitPos - n))
|
||||
}
|
||||
|
||||
// Reserved returns true if n-th reserved option is enabled in basic ACL.
|
||||
func (a ACL) Reserved(n uint8) bool {
|
||||
return n < reservedBitNumber && isLeftBitSet(a, n)
|
||||
}
|
||||
|
||||
// SetReserved enables the n-th reserved option in basic ACL.
|
||||
func (a *ACL) SetReserved(bit uint8) {
|
||||
if bit < reservedBitNumber {
|
||||
setLeftBit(a, bit)
|
||||
}
|
||||
}
|
||||
|
||||
// ResetReserved disables the n-th reserved option in basic ACL.
|
||||
func (a *ACL) ResetReserved(bit uint8) {
|
||||
if bit < reservedBitNumber {
|
||||
resetLeftBit(a, bit)
|
||||
}
|
||||
}
|
||||
|
||||
// Final returns true if final option is enabled in basic ACL.
|
||||
func (a ACL) Final() bool {
|
||||
return isLeftBitSet(a, finalBitPos)
|
||||
}
|
||||
|
||||
// SetFinal enables final option in basic ACL.
|
||||
func (a *ACL) SetFinal() {
|
||||
setLeftBit(a, finalBitPos)
|
||||
}
|
||||
|
||||
// ResetFinal disables final option in basic ACL.
|
||||
func (a *ACL) ResetFinal() {
|
||||
resetLeftBit(a, finalBitPos)
|
||||
}
|
||||
|
||||
// Sticky returns true if sticky option is enabled in basic ACL.
|
||||
func (a ACL) Sticky() bool {
|
||||
return isLeftBitSet(a, stickyBitPos)
|
||||
}
|
||||
|
||||
// SetSticky enables the sticky option in basic ACL.
|
||||
func (a *ACL) SetSticky() {
|
||||
setLeftBit(a, stickyBitPos)
|
||||
}
|
||||
|
||||
// ResetSticky disables the sticky option in basic ACL.
|
||||
func (a *ACL) ResetSticky() {
|
||||
resetLeftBit(a, stickyBitPos)
|
||||
}
|
||||
|
||||
// UserAllowed returns true if user allowed the n-th operation in basic ACL.
|
||||
func (a ACL) UserAllowed(n uint8) bool {
|
||||
return isLeftBitSet(a, opOffset+n*bitsPerOp+bitUser)
|
||||
}
|
||||
|
||||
// AllowUser allows user the n-th operation in basic ACL.
|
||||
func (a *ACL) AllowUser(n uint8) {
|
||||
setLeftBit(a, opOffset+n*bitsPerOp+bitUser)
|
||||
}
|
||||
|
||||
// ForbidUser forbids user the n-th operation in basic ACL.
|
||||
func (a *ACL) ForbidUser(n uint8) {
|
||||
resetLeftBit(a, opOffset+n*bitsPerOp+bitUser)
|
||||
}
|
||||
|
||||
// SystemAllowed returns true if System group allowed the n-th operation is set in basic ACL.
|
||||
func (a ACL) SystemAllowed(n uint8) bool {
|
||||
if n != OpDelete && n != OpGetRange {
|
||||
return true
|
||||
}
|
||||
|
||||
return isLeftBitSet(a, opOffset+n*bitsPerOp+bitSystem)
|
||||
}
|
||||
|
||||
// AllowSystem allows System group the n-th operation in basic ACL.
|
||||
func (a *ACL) AllowSystem(op uint8) {
|
||||
setLeftBit(a, opOffset+op*bitsPerOp+bitSystem)
|
||||
}
|
||||
|
||||
// ForbidSystem forbids System group the n-th operation in basic ACL.
|
||||
func (a *ACL) ForbidSystem(op uint8) {
|
||||
resetLeftBit(a, opOffset+op*bitsPerOp+bitSystem)
|
||||
}
|
||||
|
||||
// OthersAllowed returns true if Others group allowed the n-th operation is set in basic ACL.
|
||||
func (a ACL) OthersAllowed(op uint8) bool {
|
||||
return isLeftBitSet(a, opOffset+op*bitsPerOp+bitOthers)
|
||||
}
|
||||
|
||||
// AllowOthers allows Others group the n-th operation in basic ACL.
|
||||
func (a *ACL) AllowOthers(op uint8) {
|
||||
setLeftBit(a, opOffset+op*bitsPerOp+bitOthers)
|
||||
}
|
||||
|
||||
// ForbidOthers forbids Others group the n-th operation in basic ACL.
|
||||
func (a *ACL) ForbidOthers(op uint8) {
|
||||
resetLeftBit(a, opOffset+op*bitsPerOp+bitOthers)
|
||||
}
|
||||
|
||||
// BearerAllowed returns true if Bearer token usage is allowed for n-th operation in basic ACL.
|
||||
func (a ACL) BearerAllowed(op uint8) bool {
|
||||
return isLeftBitSet(a, opOffset+op*bitsPerOp+bitBearer)
|
||||
}
|
||||
|
||||
// AllowBearer allows Bearer token usage for n-th operation in basic ACL.
|
||||
func (a *ACL) AllowBearer(op uint8) {
|
||||
setLeftBit(a, opOffset+op*bitsPerOp+bitBearer)
|
||||
}
|
||||
|
||||
// ForbidBearer forbids Bearer token usage for n-th operation in basic ACL.
|
||||
func (a *ACL) ForbidBearer(op uint8) {
|
||||
resetLeftBit(a, opOffset+op*bitsPerOp+bitBearer)
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
package basic
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestACLValues(t *testing.T) {
|
||||
t.Run("private", func(t *testing.T) {
|
||||
acl := FromUint32(0x1C8C8CCC)
|
||||
|
||||
require.False(t, acl.Reserved(0))
|
||||
require.False(t, acl.Reserved(1))
|
||||
require.False(t, acl.Sticky())
|
||||
require.True(t, acl.Final())
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.SystemAllowed(OpGetRangeHash))
|
||||
require.False(t, acl.OthersAllowed(OpGetRangeHash))
|
||||
require.False(t, acl.BearerAllowed(OpGetRangeHash))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGetRange))
|
||||
require.False(t, acl.SystemAllowed(OpGetRange))
|
||||
require.False(t, acl.OthersAllowed(OpGetRange))
|
||||
require.False(t, acl.BearerAllowed(OpGetRange))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpSearch))
|
||||
require.True(t, acl.SystemAllowed(OpSearch))
|
||||
require.False(t, acl.OthersAllowed(OpSearch))
|
||||
require.False(t, acl.BearerAllowed(OpSearch))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpDelete))
|
||||
require.False(t, acl.SystemAllowed(OpDelete))
|
||||
require.False(t, acl.OthersAllowed(OpDelete))
|
||||
require.False(t, acl.BearerAllowed(OpDelete))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpPut))
|
||||
require.True(t, acl.SystemAllowed(OpPut))
|
||||
require.False(t, acl.OthersAllowed(OpPut))
|
||||
require.False(t, acl.BearerAllowed(OpPut))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpHead))
|
||||
require.True(t, acl.SystemAllowed(OpHead))
|
||||
require.False(t, acl.OthersAllowed(OpHead))
|
||||
require.False(t, acl.BearerAllowed(OpHead))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGet))
|
||||
require.True(t, acl.SystemAllowed(OpGet))
|
||||
require.False(t, acl.OthersAllowed(OpGet))
|
||||
require.False(t, acl.BearerAllowed(OpGet))
|
||||
})
|
||||
|
||||
t.Run("public with X-bit", func(t *testing.T) {
|
||||
acl := FromUint32(0x3FFFFFFF)
|
||||
|
||||
require.False(t, acl.Reserved(0))
|
||||
require.False(t, acl.Reserved(1))
|
||||
require.True(t, acl.Sticky())
|
||||
require.True(t, acl.Final())
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.SystemAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.OthersAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.BearerAllowed(OpGetRangeHash))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGetRange))
|
||||
require.True(t, acl.SystemAllowed(OpGetRange))
|
||||
require.True(t, acl.OthersAllowed(OpGetRange))
|
||||
require.True(t, acl.BearerAllowed(OpGetRange))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpSearch))
|
||||
require.True(t, acl.SystemAllowed(OpSearch))
|
||||
require.True(t, acl.OthersAllowed(OpSearch))
|
||||
require.True(t, acl.BearerAllowed(OpSearch))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpDelete))
|
||||
require.True(t, acl.SystemAllowed(OpDelete))
|
||||
require.True(t, acl.OthersAllowed(OpDelete))
|
||||
require.True(t, acl.BearerAllowed(OpDelete))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpPut))
|
||||
require.True(t, acl.SystemAllowed(OpPut))
|
||||
require.True(t, acl.OthersAllowed(OpPut))
|
||||
require.True(t, acl.BearerAllowed(OpPut))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpHead))
|
||||
require.True(t, acl.SystemAllowed(OpHead))
|
||||
require.True(t, acl.OthersAllowed(OpHead))
|
||||
require.True(t, acl.BearerAllowed(OpHead))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGet))
|
||||
require.True(t, acl.SystemAllowed(OpGet))
|
||||
require.True(t, acl.OthersAllowed(OpGet))
|
||||
require.True(t, acl.BearerAllowed(OpGet))
|
||||
})
|
||||
|
||||
t.Run("read only", func(t *testing.T) {
|
||||
acl := FromUint32(0x1FFFCCFF)
|
||||
|
||||
require.False(t, acl.Reserved(0))
|
||||
require.False(t, acl.Reserved(1))
|
||||
require.False(t, acl.Sticky())
|
||||
require.True(t, acl.Final())
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.SystemAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.OthersAllowed(OpGetRangeHash))
|
||||
require.True(t, acl.BearerAllowed(OpGetRangeHash))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGetRange))
|
||||
require.True(t, acl.SystemAllowed(OpGetRange))
|
||||
require.True(t, acl.OthersAllowed(OpGetRange))
|
||||
require.True(t, acl.BearerAllowed(OpGetRange))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpSearch))
|
||||
require.True(t, acl.SystemAllowed(OpSearch))
|
||||
require.True(t, acl.OthersAllowed(OpSearch))
|
||||
require.True(t, acl.BearerAllowed(OpSearch))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpDelete))
|
||||
require.True(t, acl.SystemAllowed(OpDelete))
|
||||
require.False(t, acl.OthersAllowed(OpDelete))
|
||||
require.False(t, acl.BearerAllowed(OpDelete))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpPut))
|
||||
require.True(t, acl.SystemAllowed(OpPut))
|
||||
require.False(t, acl.OthersAllowed(OpPut))
|
||||
require.False(t, acl.BearerAllowed(OpPut))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpHead))
|
||||
require.True(t, acl.SystemAllowed(OpHead))
|
||||
require.True(t, acl.OthersAllowed(OpHead))
|
||||
require.True(t, acl.BearerAllowed(OpHead))
|
||||
|
||||
require.True(t, acl.UserAllowed(OpGet))
|
||||
require.True(t, acl.SystemAllowed(OpGet))
|
||||
require.True(t, acl.OthersAllowed(OpGet))
|
||||
require.True(t, acl.BearerAllowed(OpGet))
|
||||
})
|
||||
}
|
||||
|
||||
func TestACLMethods(t *testing.T) {
|
||||
acl := new(ACL)
|
||||
|
||||
for i := uint8(0); i < reservedBitNumber; i++ {
|
||||
acl.SetReserved(i)
|
||||
require.True(t, acl.Reserved(i))
|
||||
acl.ResetReserved(i)
|
||||
require.False(t, acl.Reserved(i))
|
||||
}
|
||||
|
||||
acl.SetSticky()
|
||||
require.True(t, acl.Sticky())
|
||||
acl.ResetSticky()
|
||||
require.False(t, acl.Sticky())
|
||||
|
||||
acl.SetFinal()
|
||||
require.True(t, acl.Final())
|
||||
acl.ResetFinal()
|
||||
require.False(t, acl.Final())
|
||||
|
||||
for i := OpGetRangeHash; i <= OpGet; i++ {
|
||||
acl.AllowUser(i)
|
||||
require.True(t, acl.UserAllowed(i))
|
||||
acl.ForbidUser(i)
|
||||
require.False(t, acl.UserAllowed(i))
|
||||
|
||||
acl.AllowOthers(i)
|
||||
require.True(t, acl.OthersAllowed(i))
|
||||
acl.ForbidOthers(i)
|
||||
require.False(t, acl.OthersAllowed(i))
|
||||
|
||||
acl.AllowBearer(i)
|
||||
require.True(t, acl.BearerAllowed(i))
|
||||
acl.ForbidBearer(i)
|
||||
require.False(t, acl.BearerAllowed(i))
|
||||
|
||||
acl.AllowSystem(i)
|
||||
require.True(t, acl.SystemAllowed(i))
|
||||
acl.ForbidSystem(i)
|
||||
|
||||
if i == OpDelete || i == OpGetRange {
|
||||
require.False(t, acl.SystemAllowed(i))
|
||||
} else {
|
||||
require.True(t, acl.SystemAllowed(i))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
package basic
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Size is a size of ACL
|
||||
// in a binary form.
|
||||
const Size = 4
|
||||
|
||||
// FromUint32 converts builtin
|
||||
// uint32 value to ACL.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func FromUint32(v uint32) ACL {
|
||||
return ACL(v)
|
||||
}
|
||||
|
||||
// ToUint32 converts ACL value
|
||||
// to builtin uint32.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func ToUint32(v ACL) uint32 {
|
||||
return uint32(v)
|
||||
}
|
||||
|
||||
// Equal reports whether e and e2 are the same ACL.
|
||||
//
|
||||
// Function defines the relation of equality
|
||||
// between two ACL. Try to avoid comparison through
|
||||
// "==" operator for better portability.
|
||||
func Equal(a, b ACL) bool {
|
||||
return ToUint32(a) == ToUint32(b)
|
||||
}
|
||||
|
||||
// Marshal encodes ACL into a
|
||||
// binary form and returns the result.
|
||||
//
|
||||
// Result slice has Size length.
|
||||
func Marshal(a ACL) []byte {
|
||||
d := make([]byte, Size)
|
||||
|
||||
binary.BigEndian.PutUint32(d, ToUint32(a))
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals ACL from
|
||||
// a binary representation.
|
||||
//
|
||||
// If buffer size is insufficient,
|
||||
// io.ErrUnexpectedEOF is returned.
|
||||
func (a *ACL) UnmarshalBinary(data []byte) error {
|
||||
if len(data) < Size {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
*a = FromUint32(binary.BigEndian.Uint32(data))
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package basic
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
require.True(t,
|
||||
Equal(
|
||||
FromUint32(1),
|
||||
FromUint32(1),
|
||||
),
|
||||
)
|
||||
|
||||
require.False(t,
|
||||
Equal(
|
||||
FromUint32(1),
|
||||
FromUint32(2),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
a := FromUint32(1)
|
||||
a2 := new(ACL)
|
||||
|
||||
require.NoError(t,
|
||||
a2.UnmarshalBinary(
|
||||
Marshal(a),
|
||||
),
|
||||
)
|
||||
|
||||
require.True(t, Equal(a, *a2))
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
)
|
||||
|
||||
// CID represents the container identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
||||
type CID = container.ID
|
||||
|
||||
// Table represents extended ACL rule table.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/eacl/extended.Table.
|
||||
type Table = eacl.Table
|
||||
|
||||
// Storage is the interface that wraps
|
||||
// basic methods of extended ACL table storage.
|
||||
type Storage interface {
|
||||
// GetEACL reads the table from the storage by identifier.
|
||||
// It returns any error encountered.
|
||||
//
|
||||
// GetEACL must return exactly one non-nil value.
|
||||
// GetEACL must return ErrNotFound if the table is not in storage.
|
||||
//
|
||||
// Implementations must not retain or modify the table
|
||||
// (even temporarily).
|
||||
GetEACL(CID) (Table, error)
|
||||
|
||||
// PutEACL saves the table to the underlying storage.
|
||||
// It returns any error encountered that caused the saving to interrupt.
|
||||
//
|
||||
// PutEACL must return extended.ErrNilTable on nil table.
|
||||
//
|
||||
// Implementations must not retain or modify the table (even temporarily).
|
||||
//
|
||||
// Table rewriting behavior is dictated by implementation.
|
||||
PutEACL(CID, Table, []byte) error
|
||||
}
|
||||
|
||||
// ErrNotFound is the error returned when eACL table
|
||||
// was not found in storage.
|
||||
var ErrNotFound = errors.New("container not found")
|
||||
|
||||
// ErrNilStorage is the error returned by functions that
|
||||
// expect a non-nil eACL table storage implementation,
|
||||
// but received nil.
|
||||
var ErrNilStorage = errors.New("eACL storage is nil")
|
|
@ -1,48 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
||||
)
|
||||
|
||||
type testStorage struct {
|
||||
*sync.RWMutex
|
||||
|
||||
items map[container.ID]storage.Table
|
||||
}
|
||||
|
||||
func (s *testStorage) GetEACL(cid storage.CID) (storage.Table, error) {
|
||||
s.RLock()
|
||||
table, ok := s.items[cid]
|
||||
s.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return nil, storage.ErrNotFound
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
func (s *testStorage) PutEACL(cid storage.CID, table storage.Table, _ []byte) error {
|
||||
if table == nil {
|
||||
return extended.ErrNilTable
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.items[cid] = table
|
||||
s.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// New creates new eACL table storage
|
||||
// that stores table in go-builtin map.
|
||||
func New() storage.Storage {
|
||||
return &testStorage{
|
||||
RWMutex: new(sync.RWMutex),
|
||||
items: make(map[container.ID]storage.Table),
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package extended
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
)
|
||||
|
||||
// FIXME: do not duplicate constants
|
||||
|
||||
// OperationType represents the enumeration
|
||||
// of different destination types of request.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/eacl.OperationType.
|
||||
// FIXME: operation type should be defined in core lib.
|
||||
type OperationType = eacl.OperationType
|
||||
|
||||
// Group represents the enumeration
|
||||
// of different authorization groups.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/acl/extended.Group.
|
||||
// FIXME: target should be defined in core lib.
|
||||
type Group = eacl.Group
|
||||
|
||||
// HeaderType represents the enumeration
|
||||
// of different types of header.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/eacl.HeaderType.
|
||||
// FIXME: header type enum should be defined in core lib.
|
||||
type HeaderType = eacl.HeaderType
|
||||
|
||||
// CID represents the container identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
||||
type CID = container.ID
|
||||
|
||||
// Header is an interface that wraps
|
||||
// methods of string key-value header.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/eacl.Header.
|
||||
// FIXME: header should be defined in core lib.
|
||||
type Header = eacl.Header
|
||||
|
||||
// Table represents extended ACL rule table.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/eacl.ExtendedACLTable.
|
||||
// FIXME: eacl table should be defined in core package.
|
||||
// type Table = eacl.ExtendedACLTable
|
||||
|
||||
// TypedHeaderSource is the interface that wraps
|
||||
// method for selecting typed headers by type.
|
||||
type TypedHeaderSource interface {
|
||||
// HeadersOfType returns the list of key-value headers
|
||||
// of particular type.
|
||||
//
|
||||
// It returns any problem encountered through the boolean
|
||||
// false value.
|
||||
HeadersOfType(HeaderType) ([]Header, bool)
|
||||
}
|
||||
|
||||
// RequestInfo is an interface that wraps
|
||||
// request with authority methods.
|
||||
type RequestInfo interface {
|
||||
TypedHeaderSource
|
||||
|
||||
// CID returns container identifier from request context.
|
||||
CID() CID
|
||||
|
||||
// Key returns the binary representation of
|
||||
// author's public key.
|
||||
//
|
||||
// Any problem encountered can be reflected
|
||||
// through an empty slice.
|
||||
//
|
||||
// Binary key format is dictated by implementation.
|
||||
Key() []byte
|
||||
|
||||
// OperationType returns the type of request destination.
|
||||
//
|
||||
// Any problem encountered can be reflected
|
||||
// through OpTypeUnknown value. Caller should handle
|
||||
// OpTypeUnknown value according to its internal logic.
|
||||
OperationType() OperationType
|
||||
|
||||
// Group returns the authority group type.
|
||||
//
|
||||
// Any problem encountered can be reflected
|
||||
// through GroupUnknown value. Caller should handle
|
||||
// TargetUnknown value according to its internal logic.
|
||||
Group() Group
|
||||
}
|
||||
|
||||
// ErrNilTable is the error returned by functions that
|
||||
// expect a non-nil eACL table, but received nil.
|
||||
var ErrNilTable = errors.New("eACL table is nil")
|
|
@ -1,82 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/nspcc-dev/netmap"
|
||||
)
|
||||
|
||||
// BasicACL represents the basic
|
||||
// ACL rules.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/basic.ACL.
|
||||
type BasicACL = basic.ACL
|
||||
|
||||
// PlacementRule represents placement
|
||||
// rules of the container.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/netmap.PlacementRule.
|
||||
// FIXME: container placement rules should be defined in core lib.
|
||||
type PlacementRule = netmap.PlacementRule
|
||||
|
||||
// Container represents NeoFS container.
|
||||
type Container struct {
|
||||
basicACL BasicACL // basic ACL mask
|
||||
|
||||
ownerID OwnerID // the identifier of container's owner
|
||||
|
||||
salt []byte // unique container bytes
|
||||
|
||||
placementRule PlacementRule // placement rules
|
||||
}
|
||||
|
||||
// ErrNilContainer is the error returned by functions that
|
||||
// expect a non-nil container pointer, but received nil.
|
||||
var ErrNilContainer = errors.New("container is nil")
|
||||
|
||||
// OwnerID returns an ID of the container's owner.
|
||||
func (c *Container) OwnerID() OwnerID {
|
||||
return c.ownerID
|
||||
}
|
||||
|
||||
// SetOwnerID sets the ID of the container's owner.
|
||||
func (c *Container) SetOwnerID(v OwnerID) {
|
||||
c.ownerID = v
|
||||
}
|
||||
|
||||
// Salt returns the container salt.
|
||||
//
|
||||
// Slice is returned by reference without copying.
|
||||
func (c *Container) Salt() []byte {
|
||||
return c.salt
|
||||
}
|
||||
|
||||
// SetSalt sets the container salt.
|
||||
//
|
||||
// Slice is assigned by reference without copying.
|
||||
func (c *Container) SetSalt(v []byte) {
|
||||
c.salt = v
|
||||
}
|
||||
|
||||
// BasicACL returns the mask of basic container permissions.
|
||||
func (c *Container) BasicACL() BasicACL {
|
||||
return c.basicACL
|
||||
}
|
||||
|
||||
// SetBasicACL sets the mask of basic container permissions.
|
||||
func (c *Container) SetBasicACL(v BasicACL) {
|
||||
c.basicACL = v
|
||||
}
|
||||
|
||||
// PlacementRule returns placement rule of the container.
|
||||
func (c *Container) PlacementRule() PlacementRule {
|
||||
return c.placementRule
|
||||
}
|
||||
|
||||
// SetPlacementRule sets placement rule of the container.
|
||||
func (c *Container) SetPlacementRule(v PlacementRule) {
|
||||
c.placementRule = v
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestContainerMethods(t *testing.T) {
|
||||
c := new(Container)
|
||||
|
||||
acl := basic.FromUint32(1)
|
||||
c.SetBasicACL(acl)
|
||||
require.True(t, basic.Equal(acl, c.BasicACL()))
|
||||
|
||||
ownerID := OwnerID{1, 2, 3}
|
||||
c.SetOwnerID(ownerID)
|
||||
require.Equal(t, ownerID, c.OwnerID())
|
||||
|
||||
salt := []byte{4, 5, 6}
|
||||
c.SetSalt(salt)
|
||||
require.Equal(t, salt, c.Salt())
|
||||
|
||||
rule := PlacementRule{
|
||||
ReplFactor: 1,
|
||||
}
|
||||
c.SetPlacementRule(rule)
|
||||
require.Equal(t, rule, c.PlacementRule())
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
)
|
||||
|
||||
// ID represents the
|
||||
// container identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/refs.CID.
|
||||
// FIXME: container id should be defined in core package.
|
||||
type ID = refs.CID
|
||||
|
||||
// OwnerID represents the
|
||||
// container owner identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/refs.OwnerID.
|
||||
// FIXME: owner ID should be defined in core lib.
|
||||
type OwnerID = refs.OwnerID
|
||||
|
||||
// OwnerIDSize is a size of OwnerID
|
||||
// in a binary form.
|
||||
const OwnerIDSize = refs.OwnerIDSize
|
||||
|
||||
// CalculateID calculates container identifier
|
||||
// as SHA256 checksum of the binary form.
|
||||
//
|
||||
// If container is nil, ErrNilContainer is returned.
|
||||
func CalculateID(cnr *Container) (*ID, error) {
|
||||
if cnr == nil {
|
||||
return nil, ErrNilContainer
|
||||
}
|
||||
|
||||
data, err := cnr.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := new(ID)
|
||||
sh := sha256.Sum256(data)
|
||||
|
||||
copy(res[:], sh[:])
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCalculateID(t *testing.T) {
|
||||
_, err := CalculateID(nil)
|
||||
require.True(t, errors.Is(err, ErrNilContainer))
|
||||
|
||||
cnr := new(Container)
|
||||
cnr.SetBasicACL(basic.FromUint32(1))
|
||||
cnr.SetOwnerID(OwnerID{1, 2, 3})
|
||||
cnr.SetSalt([]byte{4, 5, 6})
|
||||
|
||||
id1, err := CalculateID(cnr)
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := cnr.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
|
||||
sh := sha256.Sum256(data)
|
||||
|
||||
require.Equal(t, id1.Bytes(), sh[:])
|
||||
|
||||
// change the container
|
||||
cnr.SetSalt(append(cnr.Salt(), 1))
|
||||
|
||||
id2, err := CalculateID(cnr)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotEqual(t, id1, id2)
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
)
|
||||
|
||||
const (
|
||||
saltLenSize = 2
|
||||
|
||||
fixedSize = 0 +
|
||||
basic.Size +
|
||||
OwnerIDSize +
|
||||
saltLenSize
|
||||
)
|
||||
|
||||
// MarshalBinary encodes the container into a binary form
|
||||
// and returns the result.
|
||||
func (c *Container) MarshalBinary() ([]byte, error) {
|
||||
data := make([]byte, binaryContainerSize(c))
|
||||
|
||||
off := copy(data, basic.Marshal(c.basicACL))
|
||||
|
||||
off += copy(data[off:], c.ownerID.Bytes())
|
||||
|
||||
binary.BigEndian.PutUint16(data[off:], uint16(len(c.salt)))
|
||||
off += saltLenSize
|
||||
|
||||
off += copy(data[off:], c.salt)
|
||||
|
||||
if _, err := c.placementRule.MarshalTo(data[off:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals container from a binary
|
||||
// representation.
|
||||
//
|
||||
// If buffer size is insufficient, io.ErrUnexpectedEOF is returned.
|
||||
func (c *Container) UnmarshalBinary(data []byte) error {
|
||||
if len(data) < binaryContainerSize(c) {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
if err := c.basicACL.UnmarshalBinary(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
off := basic.Size
|
||||
|
||||
off += copy(c.ownerID[:], data[off:])
|
||||
|
||||
saltLen := binary.BigEndian.Uint16(data[off:])
|
||||
off += saltLenSize
|
||||
|
||||
c.salt = make([]byte, saltLen)
|
||||
off += copy(c.salt, data[off:])
|
||||
|
||||
if err := c.placementRule.Unmarshal(data[off:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// returns the length of the container in binary form.
|
||||
func binaryContainerSize(cnr *Container) int {
|
||||
return fixedSize +
|
||||
len(cnr.salt) +
|
||||
cnr.placementRule.Size()
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestContainerMarshal(t *testing.T) {
|
||||
srcCnr := new(Container)
|
||||
srcCnr.SetBasicACL(basic.FromUint32(1))
|
||||
srcCnr.SetOwnerID(OwnerID{1, 2, 3})
|
||||
srcCnr.SetSalt([]byte{4, 5, 6})
|
||||
srcCnr.SetPlacementRule(PlacementRule{
|
||||
ReplFactor: 3,
|
||||
})
|
||||
|
||||
data, err := srcCnr.MarshalBinary()
|
||||
require.NoError(t, err)
|
||||
|
||||
dstCnr := new(Container)
|
||||
require.NoError(t, dstCnr.UnmarshalBinary(data))
|
||||
|
||||
require.Equal(t, srcCnr, dstCnr)
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
)
|
||||
|
||||
// Container represents the NeoFS container.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.Container.
|
||||
type Container = container.Container
|
||||
|
||||
// OwnerID represents the container
|
||||
// owner identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
||||
type OwnerID = container.OwnerID
|
||||
|
||||
// CID represents the container identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
||||
type CID = container.ID
|
||||
|
||||
// Storage is an interface that wraps
|
||||
// basic container storage methods.
|
||||
type Storage interface {
|
||||
// Put saves pointed container to the underlying storage.
|
||||
// It returns calculated container identifier and any error
|
||||
// encountered that caused the saving to interrupt.
|
||||
//
|
||||
// Put must return container.ErrNilContainer on nil-pointer.
|
||||
//
|
||||
// Implementations must not modify the container through the pointer (even temporarily).
|
||||
// Implementations must not retain the container pointer.
|
||||
//
|
||||
// Container rewriting behavior is dictated by implementation.
|
||||
Put(*Container) (*CID, error)
|
||||
|
||||
// Get reads the container from the storage by identifier.
|
||||
// It returns the pointer to requested container and any error encountered.
|
||||
//
|
||||
// Get must return exactly one non-nil value.
|
||||
// Get must return ErrNotFound if the container is not in storage.
|
||||
//
|
||||
// Implementations must not retain the container pointer and modify
|
||||
// the container through it.
|
||||
Get(CID) (*Container, error)
|
||||
|
||||
// Delete removes the container from the storage.
|
||||
// It returns any error encountered that caused the deletion to interrupt.
|
||||
//
|
||||
// Delete must return nil if container was successfully deleted.
|
||||
//
|
||||
// Behavior when deleting a nonexistent container is dictated by implementation.
|
||||
Delete(CID) error
|
||||
|
||||
// List returns a list of container identifiers belonging to the specified owner.
|
||||
// It returns any error encountered that caused the listing to interrupt.
|
||||
//
|
||||
// List must return the identifiers of all stored containers if owner pointer is nil.
|
||||
// List must return the empty list and no error in the absence of containers in storage.
|
||||
//
|
||||
// Result slice can be either empty slice or nil, so empty list should be checked
|
||||
// by comparing with zero length (not nil).
|
||||
//
|
||||
// Callers should carefully handle the incomplete list in case of interrupt error.
|
||||
List(*OwnerID) ([]CID, error)
|
||||
}
|
||||
|
||||
// ErrNotFound is the error returned when container was not found in storage.
|
||||
var ErrNotFound = errors.New("container not found")
|
||||
|
||||
// ErrNilStorage is the error returned by functions that
|
||||
// expect a non-nil container storage implementation, but received nil.
|
||||
var ErrNilStorage = errors.New("container storage is nil")
|
|
@ -1,127 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testStorage struct {
|
||||
*sync.RWMutex
|
||||
|
||||
items map[container.ID]*container.Container
|
||||
}
|
||||
|
||||
func (s *testStorage) Put(cnr *storage.Container) (*storage.CID, error) {
|
||||
if cnr == nil {
|
||||
return nil, container.ErrNilContainer
|
||||
}
|
||||
|
||||
cid, err := container.CalculateID(cnr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
s.items[*cid] = cnr
|
||||
s.Unlock()
|
||||
|
||||
return cid, nil
|
||||
}
|
||||
|
||||
func (s *testStorage) Get(cid storage.CID) (*storage.Container, error) {
|
||||
s.RLock()
|
||||
cnr, ok := s.items[cid]
|
||||
s.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return nil, storage.ErrNotFound
|
||||
}
|
||||
|
||||
return cnr, nil
|
||||
}
|
||||
|
||||
func (s *testStorage) Delete(cid storage.CID) error {
|
||||
s.Lock()
|
||||
delete(s.items, cid)
|
||||
s.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *testStorage) List(ownerID *storage.OwnerID) ([]storage.CID, error) {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
res := make([]storage.CID, 0)
|
||||
|
||||
for cid, cnr := range s.items {
|
||||
if ownerID == nil || ownerID.Equal(cnr.OwnerID()) {
|
||||
res = append(res, cid)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// New creates new container storage
|
||||
// that stores containers in go-builtin map.
|
||||
func New() storage.Storage {
|
||||
return &testStorage{
|
||||
RWMutex: new(sync.RWMutex),
|
||||
items: make(map[container.ID]*container.Container),
|
||||
}
|
||||
}
|
||||
|
||||
// Storage conducts testing of container
|
||||
// storage for interface specification.
|
||||
//
|
||||
// Storage must be empty.
|
||||
func Storage(t *testing.T, s storage.Storage) {
|
||||
list, err := s.List(nil)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list)
|
||||
|
||||
cnr1 := new(container.Container)
|
||||
cnr1.SetOwnerID(container.OwnerID{1, 2, 3})
|
||||
|
||||
id1, err := s.Put(cnr1)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := s.Get(*id1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, cnr1, res)
|
||||
|
||||
cnr2 := new(container.Container)
|
||||
owner1 := cnr1.OwnerID()
|
||||
owner1[0]++
|
||||
cnr2.SetOwnerID(owner1)
|
||||
|
||||
id2, err := s.Put(cnr2)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err = s.Get(*id2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, cnr2, res)
|
||||
|
||||
list, err = s.List(nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 2)
|
||||
require.Contains(t, list, *id1)
|
||||
require.Contains(t, list, *id2)
|
||||
|
||||
owner1 = cnr1.OwnerID()
|
||||
list, err = s.List(&owner1)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 1)
|
||||
require.Equal(t, *id1, list[0])
|
||||
|
||||
owner2 := cnr2.OwnerID()
|
||||
list, err = s.List(&owner2)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, 1)
|
||||
require.Equal(t, *id2, list[0])
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewStorage(t *testing.T) {
|
||||
s := New()
|
||||
|
||||
Storage(t, s)
|
||||
}
|
0
pkg/core/netmap/.gitkeep
Normal file
0
pkg/core/netmap/.gitkeep
Normal file
|
@ -1,37 +0,0 @@
|
|||
package epoch
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Size is a size of Epoch
|
||||
// in a binary form.
|
||||
const Size = 8
|
||||
|
||||
// Marshal encodes Epoch into a
|
||||
// binary form and returns the result.
|
||||
//
|
||||
// Result slice has Size length.
|
||||
func Marshal(e Epoch) []byte {
|
||||
d := make([]byte, Size)
|
||||
|
||||
binary.BigEndian.PutUint64(d, ToUint64(e))
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
// UnmarshalBinary unmarshals Epoch from
|
||||
// a binary representation.
|
||||
//
|
||||
// If buffer size is insufficient,
|
||||
// io.ErrUnexpectedEOF is returned.
|
||||
func (e *Epoch) UnmarshalBinary(data []byte) error {
|
||||
if len(data) < Size {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
*e = FromUint64(binary.BigEndian.Uint64(data))
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package epoch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEpochMarshal(t *testing.T) {
|
||||
e := FromUint64(1)
|
||||
e2 := new(Epoch)
|
||||
|
||||
require.NoError(t,
|
||||
e2.UnmarshalBinary(
|
||||
Marshal(e),
|
||||
),
|
||||
)
|
||||
|
||||
require.True(t, EQ(e, *e2))
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package epoch
|
||||
|
||||
// Sum returns the result of
|
||||
// summing up two Epoch.
|
||||
//
|
||||
// Function defines a binary
|
||||
// operation of summing two Epoch.
|
||||
// Try to avoid using operator
|
||||
// "+" for better portability.
|
||||
func Sum(a, b Epoch) Epoch {
|
||||
return FromUint64(ToUint64(a) + ToUint64(b))
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package epoch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEpochMath(t *testing.T) {
|
||||
items := []struct {
|
||||
mathFn func(Epoch, Epoch) Epoch
|
||||
|
||||
a, b, c uint64
|
||||
}{
|
||||
{
|
||||
mathFn: Sum, a: 1, b: 2, c: 3},
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
require.Equal(t,
|
||||
item.mathFn(
|
||||
FromUint64(item.a),
|
||||
FromUint64(item.b),
|
||||
),
|
||||
FromUint64(item.c),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package epoch
|
||||
|
||||
// EQ reports whether e and e2 are the same Epoch.
|
||||
//
|
||||
// Function defines the relation of equality
|
||||
// between two Epoch. Try to avoid comparison through
|
||||
// "==" operator for better portability.
|
||||
func EQ(e1, e2 Epoch) bool {
|
||||
return ToUint64(e1) == ToUint64(e2)
|
||||
}
|
||||
|
||||
// NE reports whether e1 and e2 are the different Epoch.
|
||||
//
|
||||
// Method defines the relation of inequality
|
||||
// between two Epoch. Try to avoid comparison through
|
||||
// "!=" operator for better portability.
|
||||
func NE(e1, e2 Epoch) bool {
|
||||
return ToUint64(e1) != ToUint64(e2)
|
||||
}
|
||||
|
||||
// LT reports whether e1 is less Epoch than e2.
|
||||
//
|
||||
// Method defines the "less than" relation
|
||||
// between two Epoch. Try to avoid comparison through
|
||||
// "<" operator for better portability.
|
||||
func LT(e1, e2 Epoch) bool {
|
||||
return ToUint64(e1) < ToUint64(e2)
|
||||
}
|
||||
|
||||
// GT reports whether e1 is greater Epoch than e2.
|
||||
//
|
||||
// Method defines the "greater than" relation
|
||||
// between two Epoch. Try to avoid comparison through
|
||||
// ">" operator for better portability.
|
||||
func GT(e1, e2 Epoch) bool {
|
||||
return ToUint64(e1) > ToUint64(e2)
|
||||
}
|
||||
|
||||
// LE reports whether e1 is less or equal Epoch than e2.
|
||||
//
|
||||
// Method defines the "less or equal" relation
|
||||
// between two Epoch. Try to avoid comparison through
|
||||
// "<=" operator for better portability.
|
||||
func LE(e1, e2 Epoch) bool {
|
||||
return ToUint64(e1) <= ToUint64(e2)
|
||||
}
|
||||
|
||||
// GE reports whether e1 is greater or equal Epoch than e2.
|
||||
//
|
||||
// Method defines the "greater or equal" relation
|
||||
// between two Epoch. Try to avoid comparison through
|
||||
// ">=" operator for better portability.
|
||||
func GE(e1, e2 Epoch) bool {
|
||||
return ToUint64(e1) >= ToUint64(e2)
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package epoch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEpochRelations(t *testing.T) {
|
||||
items := []struct {
|
||||
relFn func(Epoch, Epoch) bool
|
||||
|
||||
base, ok, fail uint64
|
||||
}{
|
||||
{relFn: EQ, base: 1, ok: 1, fail: 2},
|
||||
{relFn: NE, base: 1, ok: 2, fail: 1},
|
||||
{relFn: LT, base: 1, ok: 2, fail: 0},
|
||||
{relFn: GT, base: 1, ok: 0, fail: 2},
|
||||
{relFn: LE, base: 1, ok: 1, fail: 0},
|
||||
{relFn: LE, base: 1, ok: 2, fail: 0},
|
||||
{relFn: GE, base: 1, ok: 0, fail: 2},
|
||||
{relFn: GE, base: 1, ok: 1, fail: 2},
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
require.True(t,
|
||||
item.relFn(
|
||||
FromUint64(item.base),
|
||||
FromUint64(item.ok),
|
||||
),
|
||||
)
|
||||
|
||||
require.False(t,
|
||||
item.relFn(
|
||||
FromUint64(item.base),
|
||||
FromUint64(item.fail),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package epoch
|
||||
|
||||
// Epoch represents the
|
||||
// number of NeoFS epoch.
|
||||
type Epoch uint64
|
||||
|
||||
// FromUint64 converts builtin
|
||||
// uint64 value to Epoch.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func FromUint64(e uint64) Epoch {
|
||||
return Epoch(e)
|
||||
}
|
||||
|
||||
// ToUint64 converts Epoch value
|
||||
// to builtin uint64.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func ToUint64(e Epoch) uint64 {
|
||||
return uint64(e)
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
package netmap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/node"
|
||||
"github.com/nspcc-dev/netmap"
|
||||
)
|
||||
|
||||
// Info represent node information.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/netmap/node.Info.
|
||||
type Info = node.Info
|
||||
|
||||
// Bucket represents NeoFS network map as a graph.
|
||||
//
|
||||
// If is a type alias of
|
||||
// github.com/nspcc-dev/netmap.Bucket.
|
||||
type Bucket = netmap.Bucket
|
||||
|
||||
// NetMap represents NeoFS network map
|
||||
// with concurrent access support.
|
||||
type NetMap struct {
|
||||
mtx *sync.RWMutex
|
||||
|
||||
root *Bucket
|
||||
|
||||
items []Info
|
||||
}
|
||||
|
||||
// New creates and initializes a new NetMap.
|
||||
//
|
||||
// Using the NetMap that has been created with new(NetMap)
|
||||
// expression (or just declaring a NetMap variable) is unsafe
|
||||
// and can lead to panic.
|
||||
func New() *NetMap {
|
||||
return &NetMap{
|
||||
mtx: new(sync.RWMutex),
|
||||
root: new(Bucket),
|
||||
}
|
||||
}
|
||||
|
||||
// Root returns the root bucket of the network map.
|
||||
//
|
||||
// Changing the result is unsafe and
|
||||
// affects the network map.
|
||||
func (n NetMap) Root() *Bucket {
|
||||
n.mtx.RLock()
|
||||
defer n.mtx.RUnlock()
|
||||
|
||||
return n.root
|
||||
}
|
||||
|
||||
// SetRoot sets the root bucket of the network map.
|
||||
//
|
||||
// Subsequent changing the source bucket
|
||||
// is unsafe and affects the network map.
|
||||
func (n *NetMap) SetRoot(v *Bucket) {
|
||||
n.mtx.Lock()
|
||||
n.root = v
|
||||
n.mtx.Unlock()
|
||||
}
|
||||
|
||||
// Nodes returns node list of the network map.
|
||||
//
|
||||
// Changing the result is unsafe and
|
||||
// affects the network map.
|
||||
func (n NetMap) Nodes() []Info {
|
||||
n.mtx.RLock()
|
||||
defer n.mtx.RUnlock()
|
||||
|
||||
return n.items
|
||||
}
|
||||
|
||||
// SetNodes sets node list of the network map.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is unsafe and affects the network map.
|
||||
func (n *NetMap) SetNodes(v []Info) {
|
||||
n.mtx.Lock()
|
||||
n.items = v
|
||||
n.mtx.Unlock()
|
||||
}
|
||||
|
||||
// AddNode adds node information to the network map
|
||||
//
|
||||
// If node with provided information is already presented
|
||||
// in network map, nothing happens,
|
||||
func (n *NetMap) AddNode(nodeInfo Info) error {
|
||||
n.mtx.Lock()
|
||||
defer n.mtx.Unlock()
|
||||
|
||||
num := -1
|
||||
|
||||
// looking for existed node info item
|
||||
for i := range n.items {
|
||||
if bytes.Equal(
|
||||
n.items[i].PublicKey(),
|
||||
nodeInfo.PublicKey(),
|
||||
) {
|
||||
num = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// add node if it does not exist
|
||||
if num < 0 {
|
||||
n.items = append(n.items, nodeInfo)
|
||||
num = len(n.items) - 1
|
||||
}
|
||||
|
||||
return n.root.AddStrawNode(netmap.Node{
|
||||
N: uint32(num),
|
||||
C: n.items[num].Capacity(),
|
||||
P: n.items[num].Price(),
|
||||
}, nodeInfo.Options()...)
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package netmap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNetMap_Nodes(t *testing.T) {
|
||||
nm := New()
|
||||
|
||||
info1 := Info{}
|
||||
info1.SetPublicKey([]byte{1, 2, 3})
|
||||
|
||||
info2 := Info{}
|
||||
info2.SetPublicKey([]byte{4, 5, 6})
|
||||
|
||||
nodes := []Info{
|
||||
info1,
|
||||
info2,
|
||||
}
|
||||
|
||||
nm.SetNodes(nodes)
|
||||
|
||||
require.Equal(t, nodes, nm.Nodes())
|
||||
}
|
||||
|
||||
func TestNetMap_Root(t *testing.T) {
|
||||
nm := New()
|
||||
|
||||
bucket := &Bucket{
|
||||
Key: "key",
|
||||
Value: "value",
|
||||
}
|
||||
|
||||
nm.SetRoot(bucket)
|
||||
|
||||
require.Equal(t, bucket, nm.Root())
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Info represents the information
|
||||
// about NeoFS storage node.
|
||||
type Info struct {
|
||||
address string // net address
|
||||
|
||||
key []byte // public key
|
||||
|
||||
opts []string // options
|
||||
|
||||
status Status // status bits
|
||||
}
|
||||
|
||||
// ErrNilInfo is returned by functions that expect
|
||||
// a non-nil Info pointer, but received nil.
|
||||
var ErrNilInfo = errors.New("node info is nil")
|
||||
|
||||
// Address returns node network address.
|
||||
//
|
||||
// Address format is dictated by
|
||||
// application architecture.
|
||||
func (i Info) Address() string {
|
||||
return i.address
|
||||
}
|
||||
|
||||
// SetAddress sets node network address.
|
||||
func (i *Info) SetAddress(v string) {
|
||||
i.address = v
|
||||
}
|
||||
|
||||
// Status returns the node status.
|
||||
func (i Info) Status() Status {
|
||||
return i.status
|
||||
}
|
||||
|
||||
// SetStatus sets the node status.
|
||||
func (i *Info) SetStatus(v Status) {
|
||||
i.status = v
|
||||
}
|
||||
|
||||
// PublicKey returns node public key in
|
||||
// a binary format.
|
||||
//
|
||||
// Changing the result is unsafe and
|
||||
// affects the node info. In order to
|
||||
// prevent state mutations, use
|
||||
// CopyPublicKey.
|
||||
//
|
||||
// Key format is dictated by
|
||||
// application architecture.
|
||||
func (i Info) PublicKey() []byte {
|
||||
return i.key
|
||||
}
|
||||
|
||||
// CopyPublicKey returns the copy of
|
||||
// node public key.
|
||||
//
|
||||
// Changing the result is safe and
|
||||
// does not affect the node info.
|
||||
func CopyPublicKey(i Info) []byte {
|
||||
res := make([]byte, len(i.key))
|
||||
|
||||
copy(res, i.key)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// SetPublicKey sets node public key
|
||||
// in a binary format.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is unsafe and affects node info.
|
||||
// In order to prevent state mutations,
|
||||
// use SetPublicKeyCopy.
|
||||
func (i *Info) SetPublicKey(v []byte) {
|
||||
i.key = v
|
||||
}
|
||||
|
||||
// SetPublicKeyCopy copies public key and
|
||||
// sets the copy as node public key.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is safe and does not affect node info.
|
||||
//
|
||||
// Returns ErrNilInfo on nil node info.
|
||||
func SetPublicKeyCopy(i *Info, key []byte) error {
|
||||
if i == nil {
|
||||
return ErrNilInfo
|
||||
}
|
||||
|
||||
i.key = make([]byte, len(key))
|
||||
|
||||
copy(i.key, key)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns node option list.
|
||||
//
|
||||
// Changing the result is unsafe and
|
||||
// affects the node info. In order to
|
||||
// prevent state mutations, use
|
||||
// CopyOptions.
|
||||
//
|
||||
// Option format is dictated by
|
||||
// application architecture.
|
||||
func (i Info) Options() []string {
|
||||
return i.opts
|
||||
}
|
||||
|
||||
// CopyOptions returns the copy of
|
||||
// node options list.
|
||||
//
|
||||
// Changing the result is safe and
|
||||
// does not affect the node info.
|
||||
func CopyOptions(i Info) []string {
|
||||
res := make([]string, len(i.opts))
|
||||
|
||||
copy(res, i.opts)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// SetOptions sets node option list.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is unsafe and affects node info.
|
||||
// In order to prevent state mutations,
|
||||
// use SetOptionsCopy.
|
||||
func (i *Info) SetOptions(v []string) {
|
||||
i.opts = v
|
||||
}
|
||||
|
||||
// SetOptionsCopy copies option list and sets
|
||||
// the copy as node options list.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is safe and does not affect node info.
|
||||
//
|
||||
// SetOptionsCopy does nothing if Info is nil.
|
||||
func SetOptionsCopy(i *Info, opts []string) {
|
||||
if i == nil {
|
||||
return
|
||||
}
|
||||
|
||||
i.opts = make([]string, len(opts))
|
||||
|
||||
copy(i.opts, opts)
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInfo_Address(t *testing.T) {
|
||||
i := new(Info)
|
||||
|
||||
addr := "address"
|
||||
i.SetAddress(addr)
|
||||
|
||||
require.Equal(t, addr, i.Address())
|
||||
}
|
||||
|
||||
func TestInfo_Status(t *testing.T) {
|
||||
i := new(Info)
|
||||
|
||||
st := StatusFromUint64(1)
|
||||
i.SetStatus(st)
|
||||
|
||||
require.Equal(t, st, i.Status())
|
||||
}
|
||||
|
||||
func TestInfo_PublicKey(t *testing.T) {
|
||||
i := new(Info)
|
||||
|
||||
key := []byte{1, 2, 3}
|
||||
i.SetPublicKey(key)
|
||||
|
||||
require.Equal(t, key, i.PublicKey())
|
||||
}
|
||||
|
||||
func TestCopyPublicKey(t *testing.T) {
|
||||
i := Info{}
|
||||
|
||||
// set initial node key
|
||||
initKey := []byte{1, 2, 3}
|
||||
i.SetPublicKey(initKey)
|
||||
|
||||
// get node key copy
|
||||
keyCopy := CopyPublicKey(i)
|
||||
|
||||
// change the copy
|
||||
keyCopy[0]++
|
||||
|
||||
// check that node key has not changed
|
||||
require.Equal(t, initKey, i.PublicKey())
|
||||
}
|
||||
|
||||
func TestSetPublicKeyCopy(t *testing.T) {
|
||||
require.EqualError(t,
|
||||
SetPublicKeyCopy(nil, nil),
|
||||
ErrNilInfo.Error(),
|
||||
)
|
||||
|
||||
i := new(Info)
|
||||
|
||||
// create source key
|
||||
srcKey := []byte{1, 2, 3}
|
||||
|
||||
// copy and set node key
|
||||
require.NoError(t, SetPublicKeyCopy(i, srcKey))
|
||||
|
||||
// get node key
|
||||
nodeKey := i.PublicKey()
|
||||
|
||||
// change the source key
|
||||
srcKey[0]++
|
||||
|
||||
// check that node key has not changed
|
||||
require.Equal(t, nodeKey, i.PublicKey())
|
||||
}
|
||||
|
||||
func TestInfo_Options(t *testing.T) {
|
||||
i := new(Info)
|
||||
|
||||
opts := []string{
|
||||
"opt1",
|
||||
"opt2",
|
||||
}
|
||||
i.SetOptions(opts)
|
||||
|
||||
require.Equal(t, opts, i.Options())
|
||||
}
|
||||
|
||||
func TestCopyOptions(t *testing.T) {
|
||||
i := Info{}
|
||||
|
||||
// set initial node options
|
||||
initOpts := []string{
|
||||
"opt1",
|
||||
"opt2",
|
||||
}
|
||||
i.SetOptions(initOpts)
|
||||
|
||||
// get node options copy
|
||||
optsCopy := CopyOptions(i)
|
||||
|
||||
// change the copy
|
||||
optsCopy[0] = "some other opt"
|
||||
|
||||
// check that node options have not changed
|
||||
require.Equal(t, initOpts, i.Options())
|
||||
}
|
||||
|
||||
func TestSetOptionsCopy(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
SetOptionsCopy(nil, nil)
|
||||
})
|
||||
|
||||
i := new(Info)
|
||||
|
||||
// create source options
|
||||
srcOpts := []string{
|
||||
"opt1",
|
||||
"opt2",
|
||||
}
|
||||
|
||||
// copy and set node options
|
||||
SetOptionsCopy(i, srcOpts)
|
||||
|
||||
// get node options
|
||||
nodeOpts := i.Options()
|
||||
|
||||
// change the source options
|
||||
srcOpts[0] = "some other opt"
|
||||
|
||||
// check that node options have not changed
|
||||
require.Equal(t, nodeOpts, i.Options())
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/object"
|
||||
)
|
||||
|
||||
const optionPrice = "/Price:"
|
||||
|
||||
const optionCapacity = "/Capacity:"
|
||||
|
||||
// Price parses node options and returns the price in 1e-8*GAS/Megabyte per month.
|
||||
//
|
||||
// User sets the price in GAS/Terabyte per month.
|
||||
func (i Info) Price() uint64 {
|
||||
for j := range i.opts {
|
||||
if strings.HasPrefix(i.opts[j], optionPrice) {
|
||||
n, err := strconv.ParseFloat(i.opts[j][len(optionPrice):], 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return uint64(n*1e8) / uint64(object.UnitsMB) // UnitsMB == megabytes in 1 terabyte
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Capacity parses node options and returns the capacity .
|
||||
func (i Info) Capacity() uint64 {
|
||||
for j := range i.opts {
|
||||
if strings.HasPrefix(i.opts[j], optionCapacity) {
|
||||
n, err := strconv.ParseUint(i.opts[j][len(optionCapacity):], 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/object"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInfo_Price(t *testing.T) {
|
||||
var info Info
|
||||
|
||||
// too small value
|
||||
info.opts = []string{"/Price:0.01048575"}
|
||||
require.Equal(t, uint64(0), info.Price())
|
||||
|
||||
// min value
|
||||
info.opts = []string{"/Price:0.01048576"}
|
||||
require.Equal(t, uint64(1), info.Price())
|
||||
|
||||
// big value
|
||||
info.opts = []string{"/Price:1000000000.666"}
|
||||
require.Equal(t, uint64(1000000000.666*1e8/object.UnitsMB), info.Price())
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package node
|
||||
|
||||
// Status represents a node
|
||||
// status bits.
|
||||
type Status uint64
|
||||
|
||||
const leftBitPos = 64
|
||||
|
||||
const (
|
||||
bitFullStorage = 1
|
||||
)
|
||||
|
||||
// returns true if n-th left bit is set (starting at 0).
|
||||
func isLeftBitSet(value Status, n uint8) bool {
|
||||
bitMask := Status(1 << (leftBitPos - n))
|
||||
return bitMask != 0 && value&bitMask == bitMask
|
||||
}
|
||||
|
||||
// sets n-th left bit (starting at 0).
|
||||
func setLeftBit(value *Status, n uint8) {
|
||||
*value |= Status(1 << (leftBitPos - n))
|
||||
}
|
||||
|
||||
// resets n-th left bit (starting at 0).
|
||||
func resetLeftBit(value *Status, n uint8) {
|
||||
*value &= ^Status(1 << (leftBitPos - n))
|
||||
}
|
||||
|
||||
// Full returns true if node is in Full status.
|
||||
//
|
||||
// Full status marks node has enough space
|
||||
// for storing users objects.
|
||||
func (n Status) Full() bool {
|
||||
return isLeftBitSet(n, bitFullStorage)
|
||||
}
|
||||
|
||||
// SetFull sets Full status of node.
|
||||
func (n *Status) SetFull() {
|
||||
setLeftBit(n, bitFullStorage)
|
||||
}
|
||||
|
||||
// ResetFull resets Full status of node.
|
||||
func (n *Status) ResetFull() {
|
||||
resetLeftBit(n, bitFullStorage)
|
||||
}
|
||||
|
||||
// StatusFromUint64 converts builtin
|
||||
// uint64 value to Status.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func StatusFromUint64(v uint64) Status {
|
||||
return Status(v)
|
||||
}
|
||||
|
||||
// StatusToUint64 converts Status value
|
||||
// to builtin uint64.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func StatusToUint64(s Status) uint64 {
|
||||
return uint64(s)
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestStatus_Full(t *testing.T) {
|
||||
st := new(Status)
|
||||
|
||||
st.SetFull()
|
||||
require.True(t, st.Full())
|
||||
|
||||
st.ResetFull()
|
||||
require.False(t, st.Full())
|
||||
}
|
0
pkg/core/object/.gitkeep
Normal file
0
pkg/core/object/.gitkeep
Normal file
|
@ -1,94 +0,0 @@
|
|||
package object
|
||||
|
||||
// ExtendedHeaderType represents the enumeration
|
||||
// of extended header types of the NeoFS object.
|
||||
type ExtendedHeaderType uint32
|
||||
|
||||
// ExtendedHeader represents the extended
|
||||
// header of NeoFS object.
|
||||
type ExtendedHeader struct {
|
||||
typ ExtendedHeaderType
|
||||
|
||||
val interface{}
|
||||
}
|
||||
|
||||
// Type returns the extended header type.
|
||||
func (h ExtendedHeader) Type() ExtendedHeaderType {
|
||||
return h.typ
|
||||
}
|
||||
|
||||
// SetType sets the extended header type.
|
||||
func (h *ExtendedHeader) SetType(v ExtendedHeaderType) {
|
||||
h.typ = v
|
||||
}
|
||||
|
||||
// Value returns the extended header value.
|
||||
//
|
||||
// In the case of a reference type, the value is
|
||||
// returned by reference, so value mutations affect
|
||||
// header state. Therefore, callers must first copy
|
||||
// the value before changing manipulations.
|
||||
func (h ExtendedHeader) Value() interface{} {
|
||||
return h.val
|
||||
}
|
||||
|
||||
// SetValue sets the extended header value.
|
||||
//
|
||||
// Caller must take into account that each type of
|
||||
// header usually has a limited set of expected
|
||||
// value types.
|
||||
//
|
||||
// In the case of a reference type, the value is set
|
||||
// by reference, so source value mutations affect
|
||||
// header state. Therefore, callers must first copy
|
||||
// the source value before changing manipulations.
|
||||
func (h *ExtendedHeader) SetValue(v interface{}) {
|
||||
h.val = v
|
||||
}
|
||||
|
||||
// TypeFromUint32 converts builtin
|
||||
// uint32 value to Epoch.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func TypeFromUint32(v uint32) ExtendedHeaderType {
|
||||
return ExtendedHeaderType(v)
|
||||
}
|
||||
|
||||
// TypeToUint32 converts Epoch value
|
||||
// to builtin uint32.
|
||||
//
|
||||
// Try to avoid direct cast for
|
||||
// better portability.
|
||||
func TypeToUint32(v ExtendedHeaderType) uint32 {
|
||||
return uint32(v)
|
||||
}
|
||||
|
||||
// TypesEQ reports whether t1 and t2 are the same ExtendedHeaderType.
|
||||
//
|
||||
// Function defines the relation of equality
|
||||
// between two ExtendedHeaderType. Try to avoid comparison through
|
||||
// "==" operator for better portability.
|
||||
func TypesEQ(t1, t2 ExtendedHeaderType) bool {
|
||||
return TypeToUint32(t1) == TypeToUint32(t2)
|
||||
}
|
||||
|
||||
// TypesLT reports whether t1 ExtendedHeaderType
|
||||
// is less than t2.
|
||||
//
|
||||
// Function defines the "less than" relation
|
||||
// between two ExtendedHeaderType. Try to avoid
|
||||
// comparison through "<" operator for better portability.
|
||||
func TypesLT(t1, t2 ExtendedHeaderType) bool {
|
||||
return TypeToUint32(t1) < TypeToUint32(t2)
|
||||
}
|
||||
|
||||
// TypesGT reports whether t1 ExtendedHeaderType
|
||||
// is greater than t2.
|
||||
//
|
||||
// Function defines the "greater than" relation
|
||||
// between two ExtendedHeaderType. Try to avoid
|
||||
// comparison through ">" operator for better portability.
|
||||
func TypesGT(t1, t2 ExtendedHeaderType) bool {
|
||||
return TypeToUint32(t1) > TypeToUint32(t2)
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestExtendedHeader_Type(t *testing.T) {
|
||||
h := new(ExtendedHeader)
|
||||
|
||||
ht := TypeFromUint32(3)
|
||||
h.SetType(ht)
|
||||
|
||||
require.True(t, TypesEQ(ht, h.Type()))
|
||||
}
|
||||
|
||||
func TestExtendedHeader_Value(t *testing.T) {
|
||||
h := new(ExtendedHeader)
|
||||
|
||||
val := 100
|
||||
h.SetValue(val)
|
||||
|
||||
require.Equal(t, val, h.Value())
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Header represents NeoFS object header.
|
||||
type Header struct {
|
||||
// SystemHeader is an obligatory part of any object header.
|
||||
// It is used to set the identity and basic parameters of
|
||||
// the object.
|
||||
//
|
||||
// Header must inherit all the methods of SystemHeader,
|
||||
// so the SystemHeader is embedded in Header.
|
||||
SystemHeader
|
||||
|
||||
extendedHeaders []ExtendedHeader // extended headers
|
||||
}
|
||||
|
||||
// ErrNilHeader is returned by functions that expect
|
||||
// a non-nil Header pointer, but received nil.
|
||||
var ErrNilHeader = errors.New("object header is nil")
|
||||
|
||||
// ExtendedHeaders returns the extended headers of header.
|
||||
//
|
||||
// Changing the result is unsafe and affects the header.
|
||||
// In order to prevent state mutations, use CopyExtendedHeaders.
|
||||
func (h *Header) ExtendedHeaders() []ExtendedHeader {
|
||||
return h.extendedHeaders
|
||||
}
|
||||
|
||||
// CopyExtendedHeaders returns the copy of extended headers.
|
||||
//
|
||||
// Changing the result is safe and does not affect the header.
|
||||
//
|
||||
// Returns nil if header is nil.
|
||||
func CopyExtendedHeaders(h *Header) []ExtendedHeader {
|
||||
if h == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]ExtendedHeader, len(h.extendedHeaders))
|
||||
|
||||
copy(res, h.extendedHeaders)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// SetExtendedHeaders sets the extended headers of the header.
|
||||
//
|
||||
// Subsequent changing the source slice is unsafe and affects
|
||||
// the header. In order to prevent state mutations, use
|
||||
// SetExtendedHeadersCopy.
|
||||
func (h *Header) SetExtendedHeaders(v []ExtendedHeader) {
|
||||
h.extendedHeaders = v
|
||||
}
|
||||
|
||||
// SetExtendedHeadersCopy copies extended headers and sets the copy
|
||||
// as the object extended headers.
|
||||
//
|
||||
// Subsequent changing the source slice is safe and does not affect
|
||||
// the header.
|
||||
//
|
||||
// SetExtendedHeadersCopy does nothing if Header is nil.
|
||||
func SetExtendedHeadersCopy(h *Header, hs []ExtendedHeader) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
|
||||
h.extendedHeaders = make([]ExtendedHeader, len(hs))
|
||||
|
||||
copy(h.extendedHeaders, hs)
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testHeaders(num uint32) []ExtendedHeader {
|
||||
res := make([]ExtendedHeader, num)
|
||||
|
||||
for i := uint32(0); i < num; i++ {
|
||||
res[i].SetType(TypeFromUint32(i))
|
||||
res[i].SetValue(i)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func TestObject_ExtendedHeaders(t *testing.T) {
|
||||
h := new(Header)
|
||||
|
||||
hs := testHeaders(2)
|
||||
|
||||
h.SetExtendedHeaders(hs)
|
||||
|
||||
require.Equal(t, hs, h.ExtendedHeaders())
|
||||
}
|
||||
|
||||
func TestCopyExtendedHeaders(t *testing.T) {
|
||||
require.Nil(t, CopyExtendedHeaders(nil))
|
||||
|
||||
h := new(Header)
|
||||
|
||||
// set initial headers
|
||||
initHs := testHeaders(2)
|
||||
h.SetExtendedHeaders(initHs)
|
||||
|
||||
// get extended headers copy
|
||||
hsCopy := CopyExtendedHeaders(h)
|
||||
|
||||
// change the copy
|
||||
hsCopy[0] = hsCopy[1]
|
||||
|
||||
// check that extended headers have not changed
|
||||
require.Equal(t, initHs, h.ExtendedHeaders())
|
||||
}
|
||||
|
||||
func TestSetExtendedHeadersCopy(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
SetExtendedHeadersCopy(nil, nil)
|
||||
})
|
||||
|
||||
h := new(Header)
|
||||
|
||||
// create source headers
|
||||
srcHs := testHeaders(2)
|
||||
|
||||
// copy and set headers
|
||||
SetExtendedHeadersCopy(h, srcHs)
|
||||
|
||||
// get extended headers
|
||||
objHs := h.ExtendedHeaders()
|
||||
|
||||
// change the source headers
|
||||
srcHs[0] = srcHs[1]
|
||||
|
||||
// check that headeres have not changed
|
||||
require.Equal(t, objHs, h.ExtendedHeaders())
|
||||
}
|
||||
|
||||
func TestHeaderRelations(t *testing.T) {
|
||||
items := []struct {
|
||||
relFn func(ExtendedHeaderType, ExtendedHeaderType) bool
|
||||
|
||||
base, ok, fail uint32
|
||||
}{
|
||||
{relFn: TypesEQ, base: 1, ok: 1, fail: 2},
|
||||
{relFn: TypesLT, base: 1, ok: 2, fail: 0},
|
||||
{relFn: TypesGT, base: 1, ok: 0, fail: 2},
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
require.True(t,
|
||||
item.relFn(
|
||||
TypeFromUint32(item.base),
|
||||
TypeFromUint32(item.ok),
|
||||
),
|
||||
)
|
||||
|
||||
require.False(t,
|
||||
item.relFn(
|
||||
TypeFromUint32(item.base),
|
||||
TypeFromUint32(item.fail),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package headers
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
)
|
||||
|
||||
// Header represents object extended header.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.ExtendedHeader.
|
||||
type Header = object.ExtendedHeader
|
||||
|
||||
// Type represents extended header type.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.ExtendedHeaderType.
|
||||
type Type = object.ExtendedHeaderType
|
||||
|
||||
const (
|
||||
// this is the only place where this cast is appropriate,
|
||||
// use object.TypeFromUint32 instead.
|
||||
lowerUndefined = Type(iota) // lower unsupported Type value
|
||||
|
||||
// TypeLink is the type of object reference header.
|
||||
TypeLink
|
||||
|
||||
// TypeUser is the of user key-value string header.
|
||||
TypeUser
|
||||
|
||||
// TypeTransform is the type of transformation mark header.
|
||||
TypeTransform
|
||||
|
||||
// TypeTombstone is the type of tombstone mark header.
|
||||
TypeTombstone
|
||||
|
||||
// TypeSessionToken is the type of session token header.
|
||||
TypeSessionToken
|
||||
|
||||
// TypeHomomorphicHash is the type of homomorphic hash header.
|
||||
TypeHomomorphicHash
|
||||
|
||||
// TypePayloadChecksum is the type of payload checksum header.
|
||||
TypePayloadChecksum
|
||||
|
||||
// TypeIntegrity is the type of integrity header.
|
||||
TypeIntegrity
|
||||
|
||||
// TypeStorageGroup is the type of storage group header.
|
||||
TypeStorageGroup
|
||||
|
||||
// TypePublicKey is the type of public key header.
|
||||
TypePublicKey
|
||||
|
||||
upperUndefined // upper unsupported Type value
|
||||
)
|
||||
|
||||
// SupportedType returns true if Type is
|
||||
// the known type of extended header. Each
|
||||
// supported type has named constant.
|
||||
func SupportedType(t Type) bool {
|
||||
return object.TypesGT(t, lowerUndefined) &&
|
||||
object.TypesLT(t, upperUndefined)
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package headers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSupportedType(t *testing.T) {
|
||||
for _, typ := range []Type{
|
||||
TypeLink,
|
||||
TypeUser,
|
||||
TypeTransform,
|
||||
TypeTombstone,
|
||||
TypeSessionToken,
|
||||
TypeHomomorphicHash,
|
||||
TypePayloadChecksum,
|
||||
TypeIntegrity,
|
||||
TypeStorageGroup,
|
||||
TypePublicKey,
|
||||
} {
|
||||
require.True(t, SupportedType(typ))
|
||||
}
|
||||
|
||||
for _, typ := range []Type{
|
||||
lowerUndefined,
|
||||
upperUndefined,
|
||||
object.TypeFromUint32(object.TypeToUint32(lowerUndefined) - 1),
|
||||
object.TypeFromUint32(object.TypeToUint32(upperUndefined) + 1),
|
||||
} {
|
||||
require.False(t, SupportedType(typ))
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package headers
|
||||
|
||||
// UserHeader is a value of object extended header
|
||||
// that carries user string key-value pairs.
|
||||
//
|
||||
// All user headers must be type of TypeUser.
|
||||
// All user header must have UserHeader pointer value.
|
||||
type UserHeader struct {
|
||||
key, val string
|
||||
}
|
||||
|
||||
// NewUserHeader creates, initialized and returns
|
||||
// the user extended header.
|
||||
func NewUserHeader(key, val string) *Header {
|
||||
res := new(Header)
|
||||
|
||||
res.SetType(TypeUser)
|
||||
|
||||
res.SetValue(&UserHeader{
|
||||
key: key,
|
||||
val: val,
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Key returns the user header key.
|
||||
func (u UserHeader) Key() string {
|
||||
return u.key
|
||||
}
|
||||
|
||||
// SetKey sets the user header key.
|
||||
func (u *UserHeader) SetKey(key string) {
|
||||
u.key = key
|
||||
}
|
||||
|
||||
// Value returns the user header value.
|
||||
func (u UserHeader) Value() string {
|
||||
return u.val
|
||||
}
|
||||
|
||||
// SetValue sets the user header value.
|
||||
func (u *UserHeader) SetValue(val string) {
|
||||
u.val = val
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package headers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUserHeader_Key(t *testing.T) {
|
||||
h := new(UserHeader)
|
||||
|
||||
key := "random key"
|
||||
h.SetKey(key)
|
||||
|
||||
require.Equal(t, key, h.Key())
|
||||
}
|
||||
|
||||
func TestUserHeader_Value(t *testing.T) {
|
||||
h := new(UserHeader)
|
||||
|
||||
val := "random value"
|
||||
h.SetValue(val)
|
||||
|
||||
require.Equal(t, val, h.Value())
|
||||
}
|
||||
|
||||
func TestNewUserHeader(t *testing.T) {
|
||||
key := "user key"
|
||||
val := "user val"
|
||||
|
||||
h := NewUserHeader(key, val)
|
||||
|
||||
require.True(t,
|
||||
object.TypesEQ(
|
||||
TypeUser,
|
||||
h.Type(),
|
||||
),
|
||||
)
|
||||
|
||||
uh := h.Value().(*UserHeader)
|
||||
|
||||
require.Equal(t, key, uh.Key())
|
||||
require.Equal(t, val, uh.Value())
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
)
|
||||
|
||||
// ID represents the object identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/refs.ObjectID.
|
||||
// FIXME: object ID should be defined in core package.
|
||||
type ID = refs.ObjectID
|
||||
|
||||
// Address represents NeoFS Object address.
|
||||
// Acts as a reference to the object.
|
||||
type Address struct {
|
||||
cid CID
|
||||
|
||||
id ID
|
||||
}
|
||||
|
||||
// CID return the identifier of the container
|
||||
// that the object belongs to.
|
||||
func (a Address) CID() CID {
|
||||
return a.cid
|
||||
}
|
||||
|
||||
// SetCID sets the identifier of the container
|
||||
// that the object belongs to.
|
||||
func (a *Address) SetCID(v CID) {
|
||||
a.cid = v
|
||||
}
|
||||
|
||||
// ID returns the unique identifier of the
|
||||
// object in container.
|
||||
func (a Address) ID() ID {
|
||||
return a.id
|
||||
}
|
||||
|
||||
// SetID sets the unique identifier of the
|
||||
// object in container.
|
||||
func (a *Address) SetID(v ID) {
|
||||
a.id = v
|
||||
}
|
||||
|
||||
// AddressFromObject returns an address based
|
||||
// on the object's header.
|
||||
//
|
||||
// Returns nil on nil object.
|
||||
func AddressFromObject(o *Object) *Address {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
a := new(Address)
|
||||
|
||||
a.SetCID(o.CID())
|
||||
a.SetID(o.ID())
|
||||
|
||||
return a
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAddress_CID(t *testing.T) {
|
||||
a := new(Address)
|
||||
|
||||
cid := CID{1, 2, 3}
|
||||
a.SetCID(cid)
|
||||
|
||||
require.Equal(t, cid, a.CID())
|
||||
}
|
||||
|
||||
func TestAddress_ID(t *testing.T) {
|
||||
a := new(Address)
|
||||
|
||||
id := ID{1, 2, 3}
|
||||
a.SetID(id)
|
||||
|
||||
require.Equal(t, id, a.ID())
|
||||
}
|
||||
|
||||
func TestAddressFromObject(t *testing.T) {
|
||||
require.Nil(t, AddressFromObject(nil))
|
||||
|
||||
o := new(Object)
|
||||
|
||||
cid := CID{4, 5, 6}
|
||||
o.SetCID(cid)
|
||||
|
||||
id := ID{1, 2, 3}
|
||||
o.SetID(id)
|
||||
|
||||
a := AddressFromObject(o)
|
||||
|
||||
require.Equal(t, cid, a.CID())
|
||||
require.Equal(t, id, a.ID())
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Object represents NeoFS Object.
|
||||
type Object struct {
|
||||
// Header is an obligatory part of any object.
|
||||
// It is used to carry any additional information
|
||||
// besides payload.
|
||||
//
|
||||
// Object must inherit all the methods of Header,
|
||||
// so the Header is embedded in Object.
|
||||
Header
|
||||
|
||||
payload []byte // payload bytes
|
||||
}
|
||||
|
||||
// ErrNilObject is returned by functions that expect
|
||||
// a non-nil Object pointer, but received nil.
|
||||
var ErrNilObject = errors.New("object is nil")
|
||||
|
||||
// Payload returns payload bytes of the object.
|
||||
//
|
||||
// Changing the result is unsafe and affects
|
||||
// the object. In order to prevent state
|
||||
// mutations, use CopyPayload.
|
||||
func (o *Object) Payload() []byte {
|
||||
return o.payload
|
||||
}
|
||||
|
||||
// CopyPayload returns the copy of
|
||||
// object payload.
|
||||
//
|
||||
// Changing the result is safe and
|
||||
// does not affect the object.
|
||||
//
|
||||
// CopyPayload returns nil if object is nil.
|
||||
func CopyPayload(o *Object) []byte {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := make([]byte, len(o.payload))
|
||||
copy(res, o.payload)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// SetPayload sets objecyt payload bytes.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is unsafe and affects the object.
|
||||
// In order to prevent state mutations,
|
||||
// use SetPayloadCopy.
|
||||
func (o *Object) SetPayload(v []byte) {
|
||||
o.payload = v
|
||||
}
|
||||
|
||||
// SetPayloadCopy copies slice bytes and sets
|
||||
// the copy as object payload.
|
||||
//
|
||||
// Subsequent changing the source slice
|
||||
// is safe and does not affect the object.
|
||||
//
|
||||
// SetPayloadCopy does nothing if object is nil.
|
||||
func SetPayloadCopy(o *Object, payload []byte) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
o.payload = make([]byte, len(payload))
|
||||
|
||||
copy(o.payload, payload)
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestObject_Payload(t *testing.T) {
|
||||
o := new(Object)
|
||||
|
||||
payload := []byte{1, 2, 3}
|
||||
o.SetPayload(payload)
|
||||
|
||||
require.Equal(t, payload, o.Payload())
|
||||
}
|
||||
|
||||
func TestCopyPayload(t *testing.T) {
|
||||
require.Nil(t, CopyPayload(nil))
|
||||
|
||||
o := new(Object)
|
||||
|
||||
// set initial node key
|
||||
initPayload := []byte{1, 2, 3}
|
||||
o.SetPayload(initPayload)
|
||||
|
||||
// get payload copy
|
||||
pCopy := CopyPayload(o)
|
||||
|
||||
// change the copy
|
||||
pCopy[0]++
|
||||
|
||||
// check that payload has not changed
|
||||
require.Equal(t, initPayload, o.Payload())
|
||||
}
|
||||
|
||||
func TestSetPayloadCopy(t *testing.T) {
|
||||
require.NotPanics(t, func() {
|
||||
SetExtendedHeadersCopy(nil, nil)
|
||||
})
|
||||
|
||||
o := new(Object)
|
||||
|
||||
// create source payload
|
||||
srcPayload := []byte{1, 2, 3}
|
||||
|
||||
// copy and set payload
|
||||
SetPayloadCopy(o, srcPayload)
|
||||
|
||||
// get payload
|
||||
objPayload := o.Payload()
|
||||
|
||||
// change the source payload
|
||||
srcPayload[0]++
|
||||
|
||||
// check that payload has not changed
|
||||
require.Equal(t, objPayload, o.Payload())
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
)
|
||||
|
||||
// Object represents the NeoFS Object.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.Object.
|
||||
type Object = object.Object
|
||||
|
||||
// Address represents the address of
|
||||
// NeoFS Object.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/object.Address.
|
||||
type Address = object.Address
|
||||
|
||||
// Storage is an interface that wraps
|
||||
// basic object storage methods.
|
||||
type Storage interface {
|
||||
// Put saves pointed object to the underlying storage.
|
||||
// It returns object address for reference and any error
|
||||
// encountered that caused the saving to interrupt.
|
||||
//
|
||||
// Put must return object.ErrNilObject on nil-pointer.
|
||||
//
|
||||
// Implementations must not modify the object through the pointer (even temporarily).
|
||||
// Implementations must not retain the object pointer.
|
||||
//
|
||||
// Object rewriting behavior is dictated by implementation.
|
||||
Put(*Object) (*Address, error)
|
||||
|
||||
// Get reads the object from the storage by address.
|
||||
// It returns the pointer to requested object and any error encountered.
|
||||
//
|
||||
// Get must return exactly one non-nil value.
|
||||
// Get must return ErrNotFound if the object is not in storage.
|
||||
//
|
||||
// Implementations must not retain the object pointer and modify
|
||||
// the object through it.
|
||||
Get(Address) (*Object, error)
|
||||
|
||||
// Delete removes the object from the storage.
|
||||
// It returns any error encountered that caused the deletion to interrupt.
|
||||
//
|
||||
// Delete must return nil if object was successfully deleted.
|
||||
//
|
||||
// Behavior when deleting a nonexistent object is dictated by implementation.
|
||||
Delete(Address) error
|
||||
}
|
||||
|
||||
// ErrNotFound is the error returned when object was not found in storage.
|
||||
var ErrNotFound = errors.New("object not found")
|
||||
|
||||
// ErrNilStorage is the error returned by functions that
|
||||
// expect a non-nil object storage implementation, but received nil.
|
||||
var ErrNilStorage = errors.New("object storage is nil")
|
|
@ -1,88 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object/storage"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testStorage struct {
|
||||
*sync.RWMutex
|
||||
|
||||
items map[storage.Address]*storage.Object
|
||||
}
|
||||
|
||||
func (s *testStorage) Put(o *storage.Object) (*storage.Address, error) {
|
||||
if o == nil {
|
||||
return nil, object.ErrNilObject
|
||||
}
|
||||
|
||||
a := object.AddressFromObject(o)
|
||||
|
||||
s.Lock()
|
||||
s.items[*a] = o
|
||||
s.Unlock()
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (s *testStorage) Get(a storage.Address) (*storage.Object, error) {
|
||||
s.RLock()
|
||||
o, ok := s.items[a]
|
||||
s.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return nil, storage.ErrNotFound
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func (s *testStorage) Delete(a storage.Address) error {
|
||||
s.Lock()
|
||||
delete(s.items, a)
|
||||
s.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// New creates new container storage
|
||||
// that stores containers in go-builtin map.
|
||||
func New() storage.Storage {
|
||||
return &testStorage{
|
||||
RWMutex: new(sync.RWMutex),
|
||||
items: make(map[storage.Address]*storage.Object),
|
||||
}
|
||||
}
|
||||
|
||||
// Storage conducts testing of object
|
||||
// storage for interface specification.
|
||||
//
|
||||
// Storage must be empty.
|
||||
func Storage(t *testing.T, s storage.Storage) {
|
||||
_, err := s.Put(nil)
|
||||
require.True(t, errors.Is(err, object.ErrNilObject))
|
||||
|
||||
a := new(object.Address)
|
||||
_, err = s.Get(*a)
|
||||
require.True(t, errors.Is(err, storage.ErrNotFound))
|
||||
|
||||
o := new(object.Object)
|
||||
o.SetID(object.ID{1, 2, 3})
|
||||
|
||||
a, err = s.Put(o)
|
||||
require.NoError(t, err)
|
||||
|
||||
o2, err := s.Get(*a)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, o, o2)
|
||||
|
||||
require.NoError(t, s.Delete(*a))
|
||||
_, err = s.Get(*a)
|
||||
require.True(t, errors.Is(err, storage.ErrNotFound))
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewStorage(t *testing.T) {
|
||||
s := New()
|
||||
|
||||
Storage(t, s)
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch"
|
||||
)
|
||||
|
||||
// CID represents the container identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
||||
type CID = container.ID
|
||||
|
||||
// OwnerID represents the container
|
||||
// owner identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
||||
type OwnerID = container.OwnerID
|
||||
|
||||
// Epoch represents the NeoFS epoch number.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch.Epoch.
|
||||
type Epoch = epoch.Epoch
|
||||
|
||||
// SystemHeader represents the
|
||||
// system header of NeoFS Object.
|
||||
type SystemHeader struct {
|
||||
version uint64 // object version
|
||||
|
||||
payloadLen uint64 // length of the payload bytes
|
||||
|
||||
id ID // object ID
|
||||
|
||||
cid CID // container ID
|
||||
|
||||
ownerID OwnerID // object owner ID
|
||||
|
||||
creatEpoch Epoch // creation epoch number
|
||||
}
|
||||
|
||||
// Version returns the object version number.
|
||||
func (s *SystemHeader) Version() uint64 {
|
||||
return s.version
|
||||
}
|
||||
|
||||
// SetVersion sets the object version number.
|
||||
func (s *SystemHeader) SetVersion(v uint64) {
|
||||
s.version = v
|
||||
}
|
||||
|
||||
// PayloadLength returns the length of the
|
||||
// object payload bytes.
|
||||
func (s *SystemHeader) PayloadLength() uint64 {
|
||||
return s.payloadLen
|
||||
}
|
||||
|
||||
// SetPayloadLength sets the length of the object
|
||||
// payload bytes.
|
||||
func (s *SystemHeader) SetPayloadLength(v uint64) {
|
||||
s.payloadLen = v
|
||||
}
|
||||
|
||||
// ID returns the object identifier.
|
||||
func (s *SystemHeader) ID() ID {
|
||||
return s.id
|
||||
}
|
||||
|
||||
// SetID sets the object identifier.
|
||||
func (s *SystemHeader) SetID(v ID) {
|
||||
s.id = v
|
||||
}
|
||||
|
||||
// CID returns the container identifier
|
||||
// to which the object belongs.
|
||||
func (s *SystemHeader) CID() CID {
|
||||
return s.cid
|
||||
}
|
||||
|
||||
// SetCID sets the container identifier
|
||||
// to which the object belongs.
|
||||
func (s *SystemHeader) SetCID(v CID) {
|
||||
s.cid = v
|
||||
}
|
||||
|
||||
// OwnerID returns the object owner identifier.
|
||||
func (s *SystemHeader) OwnerID() OwnerID {
|
||||
return s.ownerID
|
||||
}
|
||||
|
||||
// SetOwnerID sets the object owner identifier.
|
||||
func (s *SystemHeader) SetOwnerID(v OwnerID) {
|
||||
s.ownerID = v
|
||||
}
|
||||
|
||||
// CreationEpoch returns the epoch number
|
||||
// in which the object was created.
|
||||
func (s *SystemHeader) CreationEpoch() Epoch {
|
||||
return s.creatEpoch
|
||||
}
|
||||
|
||||
// SetCreationEpoch sets the epoch number
|
||||
// in which the object was created.
|
||||
func (s *SystemHeader) SetCreationEpoch(v Epoch) {
|
||||
s.creatEpoch = v
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSystemHeader_Version(t *testing.T) {
|
||||
h := new(SystemHeader)
|
||||
|
||||
v := uint64(7)
|
||||
h.SetVersion(v)
|
||||
|
||||
require.Equal(t, v, h.Version())
|
||||
}
|
||||
|
||||
func TestSystemHeader_PayloadLength(t *testing.T) {
|
||||
h := new(SystemHeader)
|
||||
|
||||
ln := uint64(3)
|
||||
h.SetPayloadLength(ln)
|
||||
|
||||
require.Equal(t, ln, h.PayloadLength())
|
||||
}
|
||||
|
||||
func TestSystemHeader_ID(t *testing.T) {
|
||||
h := new(SystemHeader)
|
||||
|
||||
id := ID{1, 2, 3}
|
||||
h.SetID(id)
|
||||
|
||||
require.Equal(t, id, h.ID())
|
||||
}
|
||||
|
||||
func TestSystemHeader_CID(t *testing.T) {
|
||||
h := new(SystemHeader)
|
||||
|
||||
cid := CID{1, 2, 3}
|
||||
h.SetCID(cid)
|
||||
|
||||
require.Equal(t, cid, h.CID())
|
||||
}
|
||||
|
||||
func TestSystemHeader_OwnerID(t *testing.T) {
|
||||
h := new(SystemHeader)
|
||||
|
||||
ownerID := OwnerID{1, 2, 3}
|
||||
h.SetOwnerID(ownerID)
|
||||
|
||||
require.Equal(t, ownerID, h.OwnerID())
|
||||
}
|
||||
|
||||
func TestSystemHeader_CreationEpoch(t *testing.T) {
|
||||
h := new(SystemHeader)
|
||||
|
||||
ep := epoch.FromUint64(1)
|
||||
h.SetCreationEpoch(ep)
|
||||
|
||||
require.True(t, epoch.EQ(ep, h.CreationEpoch()))
|
||||
}
|
|
@ -1,35 +1,11 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/balance"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// OwnerID represents the container owner identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
||||
type OwnerID = container.OwnerID
|
||||
// FIXME: correct the definition.
|
||||
type OwnerID struct{}
|
||||
|
||||
// BalanceOf receives the amount of funds in the client's account
|
||||
// through the Balance contract call, and returns it.
|
||||
func (w *Wrapper) BalanceOf(ownerID OwnerID) (int64, error) {
|
||||
// convert Neo wallet address to Uint160
|
||||
u160, err := address.StringToUint160(ownerID.String())
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not convert wallet address to Uint160")
|
||||
}
|
||||
|
||||
// prepare invocation arguments
|
||||
args := balance.GetBalanceOfArgs{}
|
||||
args.SetWallet(u160.BytesBE())
|
||||
|
||||
values, err := w.client.BalanceOf(args)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "could not invoke smart contract")
|
||||
}
|
||||
|
||||
return values.Amount(), nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
@ -1,24 +1,12 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// OwnerID represents the container owner identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/storage.OwnerID.
|
||||
type OwnerID = storage.OwnerID
|
||||
// FIXME: correct the definition.
|
||||
type OwnerID struct{}
|
||||
|
||||
// Container represents the NeoFS Container structure.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/storage.Container.
|
||||
type Container = storage.Container
|
||||
// FIXME: correct the definition.
|
||||
type Container struct{}
|
||||
|
||||
// Put saves passed container structure in NeoFS system
|
||||
// through Container contract call.
|
||||
|
@ -26,33 +14,7 @@ type Container = storage.Container
|
|||
// Returns calculated container identifier and any error
|
||||
// encountered that caused the saving to interrupt.
|
||||
func (w *Wrapper) Put(cnr *Container) (*CID, error) {
|
||||
// calculate container identifier
|
||||
//
|
||||
// Note: cid is used as return value only, but the calculation is performed
|
||||
// primarily in order to catch potential error before contract client call.
|
||||
cid, err := container.CalculateID(cnr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not calculate container identifier")
|
||||
}
|
||||
|
||||
// marshal the container
|
||||
cnrBytes, err := cnr.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not marshal the container")
|
||||
}
|
||||
|
||||
// prepare invocation arguments
|
||||
args := contract.PutArgs{}
|
||||
args.SetOwnerID(cnr.OwnerID().Bytes())
|
||||
args.SetContainer(cnrBytes)
|
||||
args.SetSignature(nil) // TODO: set signature from request when will appear.
|
||||
|
||||
// invoke smart contract call
|
||||
if err := w.client.Put(args); err != nil {
|
||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
||||
}
|
||||
|
||||
return cid, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// Get reads the container from NeoFS system by identifier
|
||||
|
@ -61,29 +23,7 @@ func (w *Wrapper) Put(cnr *Container) (*CID, error) {
|
|||
// If an empty slice is returned for the requested identifier,
|
||||
// storage.ErrNotFound error is returned.
|
||||
func (w *Wrapper) Get(cid CID) (*Container, error) {
|
||||
// prepare invocation arguments
|
||||
args := contract.GetArgs{}
|
||||
args.SetCID(cid.Bytes())
|
||||
|
||||
// invoke smart contract call
|
||||
values, err := w.client.Get(args)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
||||
}
|
||||
|
||||
cnrBytes := values.Container()
|
||||
if len(cnrBytes) == 0 {
|
||||
return nil, storage.ErrNotFound
|
||||
}
|
||||
|
||||
cnr := new(Container)
|
||||
|
||||
// unmarshal the container
|
||||
if err := cnr.UnmarshalBinary(cnrBytes); err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal container")
|
||||
}
|
||||
|
||||
return cnr, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// Delete removes the container from NeoFS system
|
||||
|
@ -92,19 +32,7 @@ func (w *Wrapper) Get(cid CID) (*Container, error) {
|
|||
// Returns any error encountered that caused
|
||||
// the removal to interrupt.
|
||||
func (w *Wrapper) Delete(cid CID) error {
|
||||
// prepare invocation arguments
|
||||
args := contract.DeleteArgs{}
|
||||
args.SetCID(cid.Bytes())
|
||||
args.SetOwnerID(nil) // TODO: add owner ID when will appear.
|
||||
args.SetSignature(nil) // TODO: add CID signature when will appear.
|
||||
|
||||
// invoke smart contract call
|
||||
//
|
||||
// Note: errors.Wrap return nil on nil error arg.
|
||||
return errors.Wrap(
|
||||
w.client.Delete(args),
|
||||
"could not invoke smart contract",
|
||||
)
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// List returns a list of container identifiers belonging
|
||||
|
@ -114,35 +42,5 @@ func (w *Wrapper) Delete(cid CID) error {
|
|||
// Returns the identifiers of all NeoFS containers if pointer
|
||||
// to owner identifier is nil.
|
||||
func (w *Wrapper) List(ownerID *OwnerID) ([]CID, error) {
|
||||
// prepare invocation arguments
|
||||
args := contract.ListArgs{}
|
||||
|
||||
// Note: by default owner identifier slice is nil,
|
||||
// so client won't attach invocation arguments.
|
||||
// This behavior matches the nil argument of current method.
|
||||
// If argument is not nil, we must specify owner identifier.
|
||||
if ownerID != nil {
|
||||
args.SetOwnerID(ownerID.Bytes())
|
||||
}
|
||||
|
||||
// invoke smart contract call
|
||||
values, err := w.client.List(args)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
||||
}
|
||||
|
||||
binCIDList := values.CIDList()
|
||||
cidList := make([]CID, 0, len(binCIDList))
|
||||
|
||||
// unmarshal all container identifiers
|
||||
for i := range binCIDList {
|
||||
cid, err := refs.CIDFromBytes(binCIDList[i])
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not decode container ID #%d", i)
|
||||
}
|
||||
|
||||
cidList = append(cidList, cid)
|
||||
}
|
||||
|
||||
return cidList, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
@ -1,33 +1,13 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Table represents extended ACL rule table.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage.Table.
|
||||
type Table = storage.Table
|
||||
// FIXME: correct the definition.
|
||||
type Table struct{}
|
||||
|
||||
// GetEACL reads the extended ACL table from NeoFS system
|
||||
// through Container contract call.
|
||||
func (w *Wrapper) GetEACL(cid CID) (Table, error) {
|
||||
// prepare invocation arguments
|
||||
args := contract.EACLArgs{}
|
||||
args.SetCID(cid.Bytes())
|
||||
|
||||
// invoke smart contract call
|
||||
values, err := w.client.EACL(args)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
||||
}
|
||||
|
||||
// unmarshal and return eACL table
|
||||
return eacl.UnmarshalTable(values.EACL())
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// PutEACL saves the extended ACL table in NeoFS system
|
||||
|
@ -35,17 +15,5 @@ func (w *Wrapper) GetEACL(cid CID) (Table, error) {
|
|||
//
|
||||
// Returns any error encountered that caused the saving to interrupt.
|
||||
func (w *Wrapper) PutEACL(cid CID, table Table, sig []byte) error {
|
||||
// prepare invocation arguments
|
||||
args := contract.SetEACLArgs{}
|
||||
args.SetEACL(eacl.MarshalTable(table))
|
||||
args.SetCID(cid.Bytes())
|
||||
args.SetSignature(sig)
|
||||
|
||||
// invoke smart contract call
|
||||
//
|
||||
// Note: errors.Wrap return nil on nil error arg.
|
||||
return errors.Wrap(
|
||||
w.client.SetEACL(args),
|
||||
"could not invoke smart contract",
|
||||
)
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/container"
|
||||
)
|
||||
|
||||
|
@ -12,10 +11,8 @@ import (
|
|||
type Client = container.Client
|
||||
|
||||
// CID represents the container identifier.
|
||||
//
|
||||
// CID is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container/storage.CID.
|
||||
type CID = storage.CID
|
||||
// FIXME: correct the definition.
|
||||
type CID struct{}
|
||||
|
||||
// Wrapper is a wrapper over container contract
|
||||
// client which implements container storage and
|
||||
|
|
|
@ -1,37 +1,10 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
// NodeInfo groups information about NeoFS storage node.
|
||||
type NodeInfo struct{}
|
||||
|
||||
// AddPeer registers peer in NeoFS network through
|
||||
// Netmap contract call.
|
||||
func (w *Wrapper) AddPeer(nodeInfo netmap.Info) error {
|
||||
// prepare invocation arguments
|
||||
args := contract.AddPeerArgs{}
|
||||
|
||||
info := contract.PeerInfo{}
|
||||
info.SetPublicKey(nodeInfo.PublicKey())
|
||||
info.SetAddress([]byte(nodeInfo.Address()))
|
||||
|
||||
opts := nodeInfo.Options()
|
||||
binOpts := make([][]byte, 0, len(opts))
|
||||
|
||||
for i := range opts {
|
||||
binOpts = append(binOpts, []byte(opts[i]))
|
||||
}
|
||||
|
||||
info.SetOptions(binOpts)
|
||||
|
||||
args.SetInfo(info)
|
||||
|
||||
// invoke smart contract call
|
||||
//
|
||||
// Note: errors.Wrap returns nil on nil error arg.
|
||||
return errors.Wrap(
|
||||
w.client.AddPeer(args),
|
||||
"could not invoke smart contract",
|
||||
)
|
||||
func (w *Wrapper) AddPeer(nodeInfo NodeInfo) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
@ -1,60 +1,12 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// NetMap represents the NeoFS network map.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/NetMap.
|
||||
type NetMap = netmap.NetMap
|
||||
|
||||
// Info represents node information.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/netmap.Info.
|
||||
type Info = netmap.Info
|
||||
// FIXME: correct the definition.
|
||||
type NetMap struct{}
|
||||
|
||||
// GetNetMap receives information list about storage nodes
|
||||
// through the Netmap contract call, composes network map
|
||||
// from them and returns it.
|
||||
func (w *Wrapper) GetNetMap() (*NetMap, error) {
|
||||
// prepare invocation arguments
|
||||
args := contract.GetNetMapArgs{}
|
||||
|
||||
// invoke smart contract call
|
||||
values, err := w.client.NetMap(args)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not invoke smart contract")
|
||||
}
|
||||
|
||||
// parse response and fill the network map
|
||||
nm := netmap.New()
|
||||
|
||||
peerList := values.Peers()
|
||||
|
||||
for i := range peerList {
|
||||
info := Info{}
|
||||
|
||||
info.SetPublicKey(peerList[i].PublicKey())
|
||||
info.SetAddress(string(peerList[i].Address()))
|
||||
|
||||
binOpts := peerList[i].Options()
|
||||
opts := make([]string, 0, len(binOpts))
|
||||
|
||||
for j := range binOpts {
|
||||
opts = append(opts, string(binOpts[j]))
|
||||
}
|
||||
|
||||
info.SetOptions(opts)
|
||||
|
||||
if err := nm.AddNode(info); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not add node #%d to network map", i)
|
||||
}
|
||||
}
|
||||
|
||||
return nm, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
|
@ -1,23 +1,11 @@
|
|||
package wrapper
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap/epoch"
|
||||
contract "github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
// Epoch represents the NeoFS epoch.
|
||||
// FIXME: correct the definition.
|
||||
type Epoch struct{}
|
||||
|
||||
// NewEpoch updates NeoFS epoch number through
|
||||
// Netmap contract call.
|
||||
func (w *Wrapper) NewEpoch(e epoch.Epoch) error {
|
||||
// prepare invocation arguments
|
||||
args := contract.NewEpochArgs{}
|
||||
args.SetEpochNumber(int64(epoch.ToUint64(e)))
|
||||
|
||||
// invoke smart contract call
|
||||
//
|
||||
// Note: errors.Wrap returns nil on nil error arg.
|
||||
return errors.Wrap(
|
||||
w.client.NewEpoch(args),
|
||||
"could not invoke smart contract",
|
||||
)
|
||||
func (w *Wrapper) NewEpoch(e Epoch) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
|
0
pkg/network/bootstrap/.gitkeep
Normal file
0
pkg/network/bootstrap/.gitkeep
Normal file
|
@ -1,60 +0,0 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper"
|
||||
)
|
||||
|
||||
// ContractClient represents the Netmap
|
||||
// contract client.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/morph/client/netmap/wrapper.Wrapper.
|
||||
type ContractClient = *wrapper.Wrapper
|
||||
|
||||
// NodeInfo represents the
|
||||
// information about storage node.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/netmap.Info.
|
||||
type NodeInfo = netmap.Info
|
||||
|
||||
// Registerer represents the tool that
|
||||
// registers storage node in NeoFS system.
|
||||
//
|
||||
// Working Registerer must be created via constructor New.
|
||||
// Using the Registerer that has been created with new(Registerer)
|
||||
// expression (or just declaring a Registerer variable) is unsafe
|
||||
// and can lead to panic.
|
||||
type Registerer struct {
|
||||
client ContractClient
|
||||
|
||||
info NodeInfo
|
||||
}
|
||||
|
||||
// New creates, initializes and returns the Registerer instance.
|
||||
//
|
||||
// If passed contract client is nil, wrapper.ErrNilWrapper is returned.
|
||||
func New(client ContractClient, info NodeInfo) (*Registerer, error) {
|
||||
if client == nil {
|
||||
return nil, wrapper.ErrNilWrapper
|
||||
}
|
||||
|
||||
return &Registerer{
|
||||
client: client,
|
||||
info: info,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Bootstrap registers storage node in NeoFS system
|
||||
// through Netmap contract client.
|
||||
//
|
||||
// If contract client returns error, panic arises without retry.
|
||||
func (r *Registerer) Bootstrap(context.Context) {
|
||||
// register peer in NeoFS network
|
||||
if err := r.client.AddPeer(r.info); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
0
pkg/network/peers/.gitkeep
Normal file
0
pkg/network/peers/.gitkeep
Normal file
|
@ -1,45 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
)
|
||||
|
||||
const stateLabel = "state"
|
||||
|
||||
var grpcConnections = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Help: "gRPC connections",
|
||||
Name: "grpc_connections",
|
||||
Namespace: "neofs",
|
||||
},
|
||||
[]string{stateLabel},
|
||||
)
|
||||
|
||||
var conStates = []connectivity.State{
|
||||
connectivity.Idle,
|
||||
connectivity.Connecting,
|
||||
connectivity.Ready,
|
||||
connectivity.TransientFailure,
|
||||
connectivity.Shutdown,
|
||||
}
|
||||
|
||||
func updateMetrics(items map[connectivity.State]float64) {
|
||||
for _, state := range conStates {
|
||||
grpcConnections.With(prometheus.Labels{
|
||||
stateLabel: state.String(),
|
||||
}).Set(items[state])
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
prometheus.MustRegister(
|
||||
grpcConnections,
|
||||
)
|
||||
|
||||
for _, state := range conStates {
|
||||
grpcConnections.With(prometheus.Labels{
|
||||
stateLabel: state.String(),
|
||||
}).Set(0)
|
||||
}
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr-net"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type (
|
||||
// Interface is an interface of network connections controller.
|
||||
Interface interface {
|
||||
Job(context.Context)
|
||||
GRPCConnector
|
||||
}
|
||||
|
||||
// GRPCConnector is an interface of gRPC virtual connector.
|
||||
GRPCConnector interface {
|
||||
GRPCConnection(ctx context.Context, maddr multiaddr.Multiaddr) (*grpc.ClientConn, error)
|
||||
}
|
||||
|
||||
// Params groups the parameters of Interface.
|
||||
Params struct {
|
||||
Logger *zap.Logger
|
||||
ConnectionTTL time.Duration
|
||||
ConnectionIDLE time.Duration
|
||||
MetricsTimeout time.Duration
|
||||
KeepAliveTTL time.Duration
|
||||
KeepAlivePingTTL time.Duration
|
||||
}
|
||||
|
||||
connItem struct {
|
||||
sync.RWMutex
|
||||
conn *grpc.ClientConn
|
||||
used time.Time
|
||||
}
|
||||
|
||||
iface struct {
|
||||
log *zap.Logger
|
||||
tick time.Duration
|
||||
idle time.Duration
|
||||
|
||||
keepAlive time.Duration
|
||||
pingTTL time.Duration
|
||||
|
||||
metricsTimeout time.Duration
|
||||
|
||||
grpc struct {
|
||||
// globalMutex used by garbage collector and other high
|
||||
globalMutex *sync.RWMutex
|
||||
// bookMutex resolves concurrent access to the new connection
|
||||
bookMutex *sync.RWMutex
|
||||
// connBook contains connection info
|
||||
// it's mutex resolves concurrent access to existed connection
|
||||
connBook map[string]*connItem
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
defaultCloseTimer = 30 * time.Second
|
||||
defaultConIdleTTL = 30 * time.Second
|
||||
defaultKeepAliveTTL = 5 * time.Second
|
||||
defaultMetricsTimeout = 5 * time.Second
|
||||
defaultKeepAlivePingTTL = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
var errNilMultiaddr = errors.New("empty multi-address")
|
||||
|
||||
func (s *iface) removeGRPCConnection(addr string) error {
|
||||
if gCon, ok := s.grpc.connBook[addr]; ok && gCon.conn != nil {
|
||||
if err := gCon.conn.Close(); err != nil {
|
||||
state, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
s.log.Debug("error state",
|
||||
zap.String("address", addr),
|
||||
zap.Any("code", state.Code()),
|
||||
zap.String("state", state.Message()),
|
||||
zap.Any("details", state.Details()))
|
||||
}
|
||||
}
|
||||
|
||||
delete(s.grpc.connBook, addr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isGRPCClosed(con *grpc.ClientConn) bool {
|
||||
switch con.GetState() {
|
||||
case connectivity.Idle, connectivity.Connecting, connectivity.Ready:
|
||||
return false
|
||||
default:
|
||||
// connectivity.TransientFailure, connectivity.Shutdown
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func convertAddress(maddr multiaddr.Multiaddr) (string, error) {
|
||||
if maddr == nil {
|
||||
return "", errNilMultiaddr
|
||||
}
|
||||
|
||||
addr, err := manet.ToNetAddr(maddr)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "could not convert address `%s`", maddr)
|
||||
}
|
||||
|
||||
return addr.String(), nil
|
||||
}
|
||||
|
||||
// GRPCConnection creates gRPC connection over peers connection.
|
||||
func (s *iface) GRPCConnection(ctx context.Context, maddr multiaddr.Multiaddr) (*grpc.ClientConn, error) {
|
||||
addr, err := convertAddress(maddr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not convert `%v`", maddr)
|
||||
}
|
||||
|
||||
// Get global mutex on read.
|
||||
// All high level function e.g. peers garbage collector
|
||||
// or shutdown must use globalMutex.Lock instead
|
||||
s.grpc.globalMutex.RLock()
|
||||
|
||||
// Get connection item from connection book or create a new one.
|
||||
// Concurrent map access resolved by bookMutex.
|
||||
s.grpc.bookMutex.Lock()
|
||||
|
||||
item, ok := s.grpc.connBook[addr]
|
||||
if !ok {
|
||||
item = new(connItem)
|
||||
s.grpc.connBook[addr] = item
|
||||
}
|
||||
|
||||
s.grpc.bookMutex.Unlock()
|
||||
|
||||
// Now lock connection item.
|
||||
// This denies concurrent access to the same address,
|
||||
// but allows concurrent access to a different addresses.
|
||||
item.Lock()
|
||||
|
||||
if item.conn != nil && !isGRPCClosed(item.conn) {
|
||||
item.used = time.Now()
|
||||
|
||||
item.Unlock()
|
||||
s.grpc.globalMutex.RUnlock()
|
||||
|
||||
return item.conn, nil
|
||||
}
|
||||
|
||||
// Если вышеописанные строки переместить внутрь WithDialer,
|
||||
// мы получим сломанный коннекшн, но ошибка не будет возвращена,
|
||||
// поэтому мы сначала проверяем коннекшн и лишь потом возвращаем
|
||||
// *gRPC.ClientConn
|
||||
//
|
||||
// Это будет работать с `grpc.WithBlock()`, см. ниже
|
||||
conn, err := grpc.DialContext(ctx, maddr.String(),
|
||||
grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||
Time: s.pingTTL,
|
||||
Timeout: s.keepAlive,
|
||||
PermitWithoutStream: true,
|
||||
}),
|
||||
// TODO: we must provide grpc.WithInsecure() or set credentials
|
||||
grpc.WithInsecure(),
|
||||
grpc.WithBlock(),
|
||||
grpc.WithContextDialer(func(ctx context.Context, _ string) (net.Conn, error) {
|
||||
return network.Dial(ctx, maddr)
|
||||
}),
|
||||
)
|
||||
if err == nil {
|
||||
item.conn = conn
|
||||
item.used = time.Now()
|
||||
}
|
||||
|
||||
item.Unlock()
|
||||
s.grpc.globalMutex.RUnlock()
|
||||
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// New create iface instance and check arguments.
|
||||
func New(p Params) (Interface, error) {
|
||||
if p.ConnectionTTL <= 0 {
|
||||
p.ConnectionTTL = defaultCloseTimer
|
||||
}
|
||||
|
||||
if p.ConnectionIDLE <= 0 {
|
||||
p.ConnectionIDLE = defaultConIdleTTL
|
||||
}
|
||||
|
||||
if p.KeepAliveTTL <= 0 {
|
||||
p.KeepAliveTTL = defaultKeepAliveTTL
|
||||
}
|
||||
|
||||
if p.KeepAlivePingTTL <= 0 {
|
||||
p.KeepAlivePingTTL = defaultKeepAlivePingTTL
|
||||
}
|
||||
|
||||
if p.MetricsTimeout <= 0 {
|
||||
p.MetricsTimeout = defaultMetricsTimeout
|
||||
}
|
||||
|
||||
return &iface{
|
||||
tick: p.ConnectionTTL,
|
||||
idle: p.ConnectionIDLE,
|
||||
|
||||
keepAlive: p.KeepAliveTTL,
|
||||
pingTTL: p.KeepAlivePingTTL,
|
||||
|
||||
metricsTimeout: p.MetricsTimeout,
|
||||
|
||||
log: p.Logger,
|
||||
grpc: struct {
|
||||
globalMutex *sync.RWMutex
|
||||
bookMutex *sync.RWMutex
|
||||
connBook map[string]*connItem
|
||||
}{
|
||||
globalMutex: new(sync.RWMutex),
|
||||
bookMutex: new(sync.RWMutex),
|
||||
connBook: make(map[string]*connItem),
|
||||
},
|
||||
}, nil
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type (
|
||||
fakeAddress struct {
|
||||
json.Marshaler
|
||||
json.Unmarshaler
|
||||
encoding.TextMarshaler
|
||||
encoding.TextUnmarshaler
|
||||
encoding.BinaryMarshaler
|
||||
encoding.BinaryUnmarshaler
|
||||
}
|
||||
|
||||
// service is used to implement GreaterServer.
|
||||
service struct{}
|
||||
)
|
||||
|
||||
// Hello is simple handler
|
||||
func (*service) Hello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) {
|
||||
return &HelloResponse{
|
||||
Message: "Hello " + req.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ multiaddr.Multiaddr = (*fakeAddress)(nil)
|
||||
|
||||
func (fakeAddress) Equal(multiaddr.Multiaddr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (fakeAddress) Bytes() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fakeAddress) String() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (fakeAddress) Protocols() []multiaddr.Protocol {
|
||||
return []multiaddr.Protocol{{Name: "fake"}}
|
||||
}
|
||||
|
||||
func (fakeAddress) Encapsulate(multiaddr.Multiaddr) multiaddr.Multiaddr {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (fakeAddress) Decapsulate(multiaddr.Multiaddr) multiaddr.Multiaddr {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (fakeAddress) ValueForProtocol(code int) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
const testCount = 10
|
||||
|
||||
func newTestAddress(t *testing.T) multiaddr.Multiaddr {
|
||||
lis, err := net.Listen("tcp", "0.0.0.0:0") // nolint:gosec
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, lis.Close())
|
||||
|
||||
l, ok := lis.(*net.TCPListener)
|
||||
require.True(t, ok)
|
||||
|
||||
_, port, err := net.SplitHostPort(l.Addr().String())
|
||||
require.NoError(t, err)
|
||||
|
||||
items := []string{
|
||||
"ip4",
|
||||
"127.0.0.1",
|
||||
"tcp",
|
||||
port,
|
||||
}
|
||||
|
||||
maddr, err := multiaddr.NewMultiaddr("/" + strings.Join(items, "/"))
|
||||
require.NoError(t, err)
|
||||
|
||||
return maddr
|
||||
}
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
t.Run("gRPC connection test", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
s Interface
|
||||
h = &service{}
|
||||
g = grpc.NewServer()
|
||||
a1 = newTestAddress(t)
|
||||
_ = h
|
||||
done = make(chan struct{})
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s, err = New(Params{})
|
||||
require.NoError(t, err)
|
||||
|
||||
RegisterGreeterServer(g, h) // register service
|
||||
|
||||
l, err := network.Listen(a1)
|
||||
require.NoError(t, err)
|
||||
|
||||
defer l.Close() // nolint:golint
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
close(done)
|
||||
|
||||
_ = g.Serve(l)
|
||||
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
<-done // wait for server is start listening connections:
|
||||
|
||||
// Fail connection
|
||||
con, err := s.GRPCConnection(ctx, &fakeAddress{})
|
||||
require.Nil(t, con)
|
||||
require.Error(t, err)
|
||||
|
||||
con, err = s.GRPCConnection(ctx, a1)
|
||||
require.NoError(t, err)
|
||||
|
||||
cli := NewGreeterClient(con)
|
||||
resp, err := cli.Hello(ctx, &HelloRequest{
|
||||
Name: "Interface test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, "Hello Interface test", resp.Message)
|
||||
|
||||
g.GracefulStop()
|
||||
|
||||
wg.Wait()
|
||||
})
|
||||
|
||||
t.Run("test grpc connections", func(t *testing.T) {
|
||||
var (
|
||||
ifaces = make([]Interface, 0, testCount)
|
||||
addresses = make([]multiaddr.Multiaddr, 0, testCount)
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
for i := 0; i < testCount; i++ {
|
||||
addresses = append(addresses, newTestAddress(t))
|
||||
|
||||
s, err := New(Params{})
|
||||
require.NoError(t, err)
|
||||
|
||||
lis, err := network.Listen(addresses[i])
|
||||
require.NoError(t, err)
|
||||
|
||||
svc := &service{}
|
||||
srv := grpc.NewServer()
|
||||
|
||||
RegisterGreeterServer(srv, svc)
|
||||
|
||||
ifaces = append(ifaces, s)
|
||||
|
||||
go func() {
|
||||
require.NoError(t, srv.Serve(lis))
|
||||
}()
|
||||
}
|
||||
|
||||
const reqName = "test"
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
for i := 0; i < testCount; i++ {
|
||||
for j := 0; j < testCount; j++ {
|
||||
wg.Add(1)
|
||||
go func(i, j int) {
|
||||
defer wg.Done()
|
||||
|
||||
con, err := ifaces[i].GRPCConnection(ctx, addresses[j])
|
||||
require.NoError(t, err)
|
||||
|
||||
cli := NewGreeterClient(con)
|
||||
|
||||
resp, err := cli.Hello(ctx, &HelloRequest{Name: reqName})
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Hello "+reqName, resp.Message)
|
||||
|
||||
require.NoError(t, con.Close())
|
||||
}(i, j)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
})
|
||||
}
|
601
pkg/network/peers/peers_test.pb.go
generated
601
pkg/network/peers/peers_test.pb.go
generated
|
@ -1,601 +0,0 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: pkg/network/peers/peers_test.proto
|
||||
|
||||
package peers
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// Request message example
|
||||
type HelloRequest struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *HelloRequest) Reset() { *m = HelloRequest{} }
|
||||
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*HelloRequest) ProtoMessage() {}
|
||||
func (*HelloRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_34a082b16b4e437d, []int{0}
|
||||
}
|
||||
func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *HelloRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HelloRequest.Merge(m, src)
|
||||
}
|
||||
func (m *HelloRequest) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *HelloRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HelloRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *HelloRequest) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type HelloResponse struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *HelloResponse) Reset() { *m = HelloResponse{} }
|
||||
func (m *HelloResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*HelloResponse) ProtoMessage() {}
|
||||
func (*HelloResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_34a082b16b4e437d, []int{1}
|
||||
}
|
||||
func (m *HelloResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *HelloResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_HelloResponse.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *HelloResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HelloResponse.Merge(m, src)
|
||||
}
|
||||
func (m *HelloResponse) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *HelloResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HelloResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HelloResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *HelloResponse) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*HelloRequest)(nil), "peers.HelloRequest")
|
||||
proto.RegisterType((*HelloResponse)(nil), "peers.HelloResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("pkg/network/peers/peers_test.proto", fileDescriptor_34a082b16b4e437d) }
|
||||
|
||||
var fileDescriptor_34a082b16b4e437d = []byte{
|
||||
// 210 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2a, 0xc8, 0x4e, 0xd7,
|
||||
0xcf, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, 0xca, 0xd6, 0x2f, 0x48, 0x4d, 0x2d, 0x2a, 0x86, 0x90, 0xf1,
|
||||
0x25, 0xa9, 0xc5, 0x25, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0xac, 0x60, 0x11, 0x25, 0x25,
|
||||
0x2e, 0x1e, 0x8f, 0xd4, 0x9c, 0x9c, 0xfc, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x21,
|
||||
0x2e, 0x96, 0xbc, 0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0x49,
|
||||
0x93, 0x8b, 0x17, 0xaa, 0xa6, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0x48, 0x82, 0x8b, 0x3d, 0x37,
|
||||
0xb5, 0xb8, 0x38, 0x31, 0x1d, 0xa6, 0x0e, 0xc6, 0x35, 0xb2, 0xe5, 0x62, 0x77, 0x2f, 0x4a, 0x4d,
|
||||
0x2d, 0x49, 0x2d, 0x12, 0x32, 0xe2, 0x62, 0x05, 0xeb, 0x12, 0x12, 0xd6, 0x03, 0x5b, 0xa5, 0x87,
|
||||
0x6c, 0x8f, 0x94, 0x08, 0xaa, 0x20, 0xc4, 0x60, 0x27, 0xe7, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c,
|
||||
0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xc3, 0xf4, 0xcc, 0x92,
|
||||
0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xbc, 0xe2, 0x82, 0xe4, 0x64, 0xdd, 0x94, 0xd4,
|
||||
0x32, 0xfd, 0xbc, 0xd4, 0xfc, 0xb4, 0x62, 0xdd, 0xbc, 0xfc, 0x94, 0x54, 0x7d, 0x0c, 0xaf, 0x26,
|
||||
0xb1, 0x81, 0x3d, 0x68, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x70, 0xa7, 0x10, 0xcc, 0x06, 0x01,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// GreeterClient is the client API for Greeter service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type GreeterClient interface {
|
||||
Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error)
|
||||
}
|
||||
|
||||
type greeterClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewGreeterClient(cc *grpc.ClientConn) GreeterClient {
|
||||
return &greeterClient{cc}
|
||||
}
|
||||
|
||||
func (c *greeterClient) Hello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) {
|
||||
out := new(HelloResponse)
|
||||
err := c.cc.Invoke(ctx, "/peers.Greeter/Hello", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// GreeterServer is the server API for Greeter service.
|
||||
type GreeterServer interface {
|
||||
Hello(context.Context, *HelloRequest) (*HelloResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedGreeterServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedGreeterServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedGreeterServer) Hello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented")
|
||||
}
|
||||
|
||||
func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
|
||||
s.RegisterService(&_Greeter_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Greeter_Hello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GreeterServer).Hello(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/peers.Greeter/Hello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GreeterServer).Hello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Greeter_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "peers.Greeter",
|
||||
HandlerType: (*GreeterServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Hello",
|
||||
Handler: _Greeter_Hello_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "pkg/network/peers/peers_test.proto",
|
||||
}
|
||||
|
||||
func (m *HelloRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *HelloRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *HelloRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Name) > 0 {
|
||||
i -= len(m.Name)
|
||||
copy(dAtA[i:], m.Name)
|
||||
i = encodeVarintPeersTest(dAtA, i, uint64(len(m.Name)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *HelloResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *HelloResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *HelloResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.Message) > 0 {
|
||||
i -= len(m.Message)
|
||||
copy(dAtA[i:], m.Message)
|
||||
i = encodeVarintPeersTest(dAtA, i, uint64(len(m.Message)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintPeersTest(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovPeersTest(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *HelloRequest) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Name)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovPeersTest(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *HelloResponse) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Message)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovPeersTest(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovPeersTest(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozPeersTest(x uint64) (n int) {
|
||||
return sovPeersTest(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *HelloRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: HelloRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: HelloRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipPeersTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *HelloResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: HelloResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: HelloResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Message = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipPeersTest(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthPeersTest
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipPeersTest(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowPeersTest
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthPeersTest
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupPeersTest
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthPeersTest
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthPeersTest = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowPeersTest = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupPeersTest = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
|
@ -1,18 +0,0 @@
|
|||
syntax = "proto3";
|
||||
option go_package = "github.com/nspcc-dev/neofs-node/pkg/network/peers";
|
||||
|
||||
package peers;
|
||||
|
||||
// The Greater service definition.
|
||||
service Greeter {
|
||||
rpc Hello(HelloRequest) returns (HelloResponse);
|
||||
}
|
||||
|
||||
// Request message example
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message HelloResponse {
|
||||
string message = 1;
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
netmap "github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
// Store is an interface to storage of all p2p connections
|
||||
Store interface {
|
||||
SelfIDReceiver
|
||||
PublicKeyStore
|
||||
AddressIDReceiver
|
||||
AddPeer(multiaddr.Multiaddr, *ecdsa.PublicKey, *ecdsa.PrivateKey) (ID, error)
|
||||
DeletePeer(ID)
|
||||
PeerNetAddressStore
|
||||
GetPrivateKey(ID) (*ecdsa.PrivateKey, error)
|
||||
Update(*netmap.NetMap) error
|
||||
Sign([]byte) ([]byte, error)
|
||||
Verify(id ID, data, sign []byte) error
|
||||
Check(min int) error
|
||||
}
|
||||
|
||||
// PublicKeyStore is an interface of the storage of peer's public keys.
|
||||
PublicKeyStore interface {
|
||||
GetPublicKey(ID) (*ecdsa.PublicKey, error)
|
||||
}
|
||||
|
||||
// SelfIDReceiver is an interface of local peer ID value with read access.
|
||||
SelfIDReceiver interface {
|
||||
SelfID() ID
|
||||
}
|
||||
|
||||
// AddressIDReceiver is an interface of Multiaddr to ID converter.
|
||||
AddressIDReceiver interface {
|
||||
AddressID(multiaddr.Multiaddr) (ID, error)
|
||||
}
|
||||
|
||||
// PeerNetAddressStore is an interface of ID to Multiaddr converter.
|
||||
PeerNetAddressStore interface {
|
||||
GetAddr(ID) (multiaddr.Multiaddr, error)
|
||||
}
|
||||
|
||||
// StoreParams for creating new Store.
|
||||
StoreParams struct {
|
||||
Addr multiaddr.Multiaddr
|
||||
Key *ecdsa.PrivateKey
|
||||
Storage Storage
|
||||
StoreCap int
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
store struct {
|
||||
self ID
|
||||
addr multiaddr.Multiaddr
|
||||
storage Storage
|
||||
log *zap.Logger
|
||||
key *ecdsa.PrivateKey
|
||||
}
|
||||
)
|
||||
|
||||
const defaultMinimalSignaturesCount = 3
|
||||
|
||||
var errPeerNotFound = errors.New("peer not found")
|
||||
|
||||
func (p *store) AddressID(addr multiaddr.Multiaddr) (ID, error) {
|
||||
if p.addr.Equal(addr) {
|
||||
return p.self, nil
|
||||
}
|
||||
|
||||
res := p.storage.Filter(maddrFilter(addr))
|
||||
if len(res) == 0 {
|
||||
return "", errPeerNotFound
|
||||
}
|
||||
|
||||
return res[0], nil
|
||||
}
|
||||
|
||||
func maddrFilter(addr multiaddr.Multiaddr) PeerFilter {
|
||||
return func(p Peer) bool { return addr.Equal(p.Address()) }
|
||||
}
|
||||
|
||||
// SelfID return ID of current Node.
|
||||
func (p *store) SelfID() ID {
|
||||
return p.self
|
||||
}
|
||||
|
||||
// AddPeer to store..
|
||||
// Try to get PeerID from PublicKey, or return error
|
||||
// Store Address and PublicKey for that PeerID.
|
||||
func (p *store) AddPeer(addr multiaddr.Multiaddr, pub *ecdsa.PublicKey, key *ecdsa.PrivateKey) (ID, error) {
|
||||
item := NewPeer(addr, pub, key)
|
||||
if err := p.storage.Set(item.ID(), item); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return item.ID(), nil
|
||||
}
|
||||
|
||||
// DeletePeer from store.
|
||||
func (p *store) DeletePeer(id ID) {
|
||||
if err := p.storage.Rem(id); err != nil {
|
||||
p.log.Error("could not delete peer",
|
||||
zap.Stringer("id", id),
|
||||
zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Update update Store by new network map.
|
||||
func (p *store) Update(nm *netmap.NetMap) error {
|
||||
if err := p.storage.Update(nm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we must provide our PrivateKey, after updating
|
||||
if peer, err := p.storage.Get(p.self); err != nil {
|
||||
peer = NewPeer(p.addr, &p.key.PublicKey, p.key)
|
||||
return p.storage.Set(p.self, peer)
|
||||
} else if err := peer.SetPrivateKey(p.key); err != nil {
|
||||
return errors.Wrapf(err, "could not update private key (%s)", p.self.String())
|
||||
} else if err := p.storage.Set(p.self, peer); err != nil {
|
||||
return errors.Wrapf(err, "could not save peer(%s)", p.self.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAddr by PeerID.
|
||||
func (p *store) GetAddr(id ID) (multiaddr.Multiaddr, error) {
|
||||
n, err := p.storage.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return n.Address(), nil
|
||||
}
|
||||
|
||||
// GetPublicKey by PeerID.
|
||||
func (p *store) GetPublicKey(id ID) (*ecdsa.PublicKey, error) {
|
||||
n, err := p.storage.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return n.PublicKey(), nil
|
||||
}
|
||||
|
||||
// GetPrivateKey by PeerID.
|
||||
func (p *store) GetPrivateKey(id ID) (*ecdsa.PrivateKey, error) {
|
||||
n, err := p.storage.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return n.PrivateKey()
|
||||
}
|
||||
|
||||
// Sign signs a data using the private key. If the data is longer than
|
||||
// the bit-length of the private key's curve order, the hash will be
|
||||
// truncated to that length. It returns the signature as slice bytes.
|
||||
// The security of the private key depends on the entropy of rand.
|
||||
func (p *store) Sign(data []byte) ([]byte, error) {
|
||||
return crypto.Sign(p.key, data)
|
||||
}
|
||||
|
||||
// Verify verifies the signature in r, s of hash using the public key, pub. Its
|
||||
// return value records whether the signature is valid.
|
||||
// If store doesn't contains public key for ID,
|
||||
// returns error about that
|
||||
// TODO we must provide same method, but for IR list, to check,
|
||||
// that we have valid signatures of needed IR members
|
||||
func (p *store) Verify(id ID, data, sign []byte) error {
|
||||
if pub, err := p.GetPublicKey(id); err != nil {
|
||||
return errors.Wrap(err, "could not get PublicKey")
|
||||
} else if err := crypto.Verify(pub, data, sign); err != nil {
|
||||
return errors.Wrapf(err, "could not verify signature: sign(`%x`) & data(`%x`)", sign, data)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Neighbours peers that which are distributed by hrw(id).
|
||||
func (p *store) Neighbours(seed int64, count int) ([]ID, error) {
|
||||
return p.storage.List(p.self, seed, count)
|
||||
}
|
||||
|
||||
// Check validate signatures count
|
||||
// TODO replace with settings or something else.
|
||||
// We can fetch min-count from settings, or
|
||||
// use another method for validate this..
|
||||
func (p *store) Check(min int) error {
|
||||
if min <= defaultMinimalSignaturesCount {
|
||||
return errors.Errorf("invalid count of valid signatures: minimum %d, actual %d",
|
||||
defaultMinimalSignaturesCount,
|
||||
min,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewStore creates new store by params.
|
||||
func NewStore(p StoreParams) (Store, error) {
|
||||
var storage Storage
|
||||
|
||||
if p.Key == nil || p.Key.Curve != elliptic.P256() {
|
||||
return nil, crypto.ErrEmptyPrivateKey
|
||||
}
|
||||
|
||||
if p.Addr == nil {
|
||||
return nil, errNilMultiaddr
|
||||
}
|
||||
|
||||
if storage = p.Storage; storage == nil {
|
||||
storage = NewSimpleStorage(p.StoreCap, p.Logger)
|
||||
}
|
||||
|
||||
id := IDFromPublicKey(&p.Key.PublicKey)
|
||||
peer := NewPeer(p.Addr, &p.Key.PublicKey, p.Key)
|
||||
|
||||
if err := storage.Set(id, peer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &store{
|
||||
self: id,
|
||||
storage: storage,
|
||||
key: p.Key,
|
||||
addr: p.Addr,
|
||||
log: p.Logger,
|
||||
}, nil
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
loggertest "github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type testSign struct {
|
||||
ID ID
|
||||
Sign []byte
|
||||
}
|
||||
|
||||
const debug = false
|
||||
|
||||
func createNetworkMap(t *testing.T) *netmap.NetMap {
|
||||
var (
|
||||
Region = []string{"America", "Europe", "Asia"}
|
||||
Country = map[string][]string{
|
||||
"America": {"USA", "Canada", "Brazil"},
|
||||
"Europe": {"France", "Germany", "Sweden"},
|
||||
"Asia": {"Russia", "China", "Korea", "Japan"},
|
||||
}
|
||||
City = map[string][]string{
|
||||
"USA": {"Washington", "New-York", "Seattle", "Chicago", "Detroit"},
|
||||
"Canada": {"Toronto", "Ottawa", "Quebec", "Winnipeg"},
|
||||
"Brazil": {"Rio-de-Janeiro", "San-Paulo", "Salvador"},
|
||||
"France": {"Paris", "Lion", "Nice", "Marseille"},
|
||||
"Germany": {"Berlin", "Munich", "Dortmund", "Hamburg", "Cologne"},
|
||||
"Sweden": {"Stockholm", "Malmo", "Uppsala"},
|
||||
"Russia": {"Moscow", "Saint-Petersburg", "Ekaterinburg", "Novosibirsk"},
|
||||
"China": {"Beijing", "Shanghai", "Shenzhen", "Guangzhou"},
|
||||
"Korea": {"Seoul", "Busan"},
|
||||
"Japan": {"Tokyo", "Kyoto", "Yokohama", "Osaka"},
|
||||
}
|
||||
nm = netmap.New()
|
||||
port int64 = 4000
|
||||
i = 0
|
||||
)
|
||||
for _, r := range Region {
|
||||
for _, co := range Country[r] {
|
||||
for _, ci := range City[co] {
|
||||
addr := "/ip4/127.0.0.1/tcp/" + strconv.FormatInt(port, 10)
|
||||
port++
|
||||
option := "/Region:" + r + "/Country:" + co + "/City:" + ci
|
||||
pk := crypto.MarshalPublicKey(&test.DecodeKey(i).PublicKey)
|
||||
i++
|
||||
|
||||
info := netmap.Info{}
|
||||
info.SetAddress(addr)
|
||||
info.SetPublicKey(pk)
|
||||
info.SetOptions([]string{option})
|
||||
|
||||
require.NoError(t, nm.AddNode(info))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nm
|
||||
}
|
||||
|
||||
func testMultiAddress(t *testing.T) multiaddr.Multiaddr {
|
||||
addr, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
|
||||
require.NoError(t, err)
|
||||
return addr
|
||||
}
|
||||
|
||||
func TestPeerstore(t *testing.T) {
|
||||
var (
|
||||
l = loggertest.NewLogger(false)
|
||||
key = test.DecodeKey(1)
|
||||
)
|
||||
|
||||
t.Run("it should creates new store", func(t *testing.T) {
|
||||
ps, err := NewStore(StoreParams{
|
||||
Key: key,
|
||||
Logger: l,
|
||||
Addr: testMultiAddress(t),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ps)
|
||||
|
||||
maddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/4000")
|
||||
require.NoError(t, err)
|
||||
|
||||
expect := crypto.MarshalPublicKey(&key.PublicKey)
|
||||
|
||||
id, err := ps.AddPeer(maddr, &key.PublicKey, key)
|
||||
require.NoError(t, err)
|
||||
|
||||
pub, err := ps.GetPublicKey(id)
|
||||
require.NoError(t, err)
|
||||
|
||||
actual := crypto.MarshalPublicKey(pub)
|
||||
require.Equal(t, expect, actual)
|
||||
|
||||
addr1, err := ps.GetAddr(id)
|
||||
require.NoError(t, err)
|
||||
require.True(t, maddr.Equal(addr1))
|
||||
|
||||
ps.DeletePeer(id)
|
||||
addr1, err = ps.GetAddr(id)
|
||||
require.Nil(t, addr1)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("it should creates new store based on netmap", func(t *testing.T) {
|
||||
var nm = createNetworkMap(t)
|
||||
|
||||
ps, err := NewStore(StoreParams{
|
||||
Key: key,
|
||||
Logger: l,
|
||||
Addr: testMultiAddress(t),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ps)
|
||||
|
||||
err = ps.Update(nm)
|
||||
require.NoError(t, err)
|
||||
|
||||
expect := nm.Nodes()[0].PublicKey()
|
||||
|
||||
id := IDFromBinary(expect)
|
||||
|
||||
addr, err := ps.GetAddr(id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, nm.Nodes()[0].Address(), addr.String())
|
||||
|
||||
pub, err := ps.GetPublicKey(id)
|
||||
require.NoError(t, err)
|
||||
|
||||
actual := crypto.MarshalPublicKey(pub)
|
||||
require.Equal(t, expect, actual)
|
||||
})
|
||||
|
||||
t.Run("multiple store's", func(t *testing.T) {
|
||||
var (
|
||||
count = 10
|
||||
items = make([]Store, 0, count)
|
||||
|
||||
data = []byte("Hello world")
|
||||
peers = make([]Peer, 0, count)
|
||||
signs = make([]*testSign, 0, count)
|
||||
)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
key := test.DecodeKey(i)
|
||||
addr, err := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/0")
|
||||
require.NoError(t, err)
|
||||
|
||||
peers = append(peers, NewLocalPeer(addr, key))
|
||||
}
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
key, err := peers[i].PrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
store, err := NewStore(StoreParams{
|
||||
Addr: peers[i].Address(),
|
||||
Key: key,
|
||||
Logger: zap.L(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
items = append(items, store)
|
||||
|
||||
hash, err := store.Sign(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
sign := &testSign{
|
||||
ID: peers[i].ID(),
|
||||
Sign: hash,
|
||||
}
|
||||
signs = append(signs, sign)
|
||||
l.Info("add peer",
|
||||
zap.Stringer("id", peers[i].ID()))
|
||||
}
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
signature, err := items[i].Sign(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
// check the newly generated signature
|
||||
err = items[i].Verify(peers[i].ID(), data, signature)
|
||||
require.NoError(t, err)
|
||||
|
||||
for j := 0; j < count; j++ {
|
||||
// check previously generated signature
|
||||
addr, pub := peers[j].Address(), peers[j].PublicKey()
|
||||
key, err := peers[j].PrivateKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = items[i].AddPeer(addr, pub, key)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = items[i].Verify(signs[j].ID, data, signs[j].Sign)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Get self address", func(t *testing.T) {
|
||||
addr := testMultiAddress(t)
|
||||
|
||||
ps, err := NewStore(StoreParams{
|
||||
Key: key,
|
||||
Logger: l,
|
||||
Addr: addr,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ps)
|
||||
|
||||
selfAddr, err := ps.GetAddr(ps.SelfID())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, selfAddr, addr)
|
||||
})
|
||||
|
||||
t.Run("Get ID for multi address", func(t *testing.T) {
|
||||
addr := testMultiAddress(t)
|
||||
|
||||
ps, err := NewStore(StoreParams{
|
||||
Key: key,
|
||||
Logger: l,
|
||||
Addr: addr,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, ps)
|
||||
|
||||
maddr, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/4000")
|
||||
require.NoError(t, err)
|
||||
|
||||
id, err := ps.AddPeer(maddr, &key.PublicKey, key)
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := ps.AddressID(maddr)
|
||||
require.NoError(t, err)
|
||||
require.True(t, id.Equal(res))
|
||||
|
||||
maddr2, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/4001")
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err = ps.AddressID(maddr2)
|
||||
require.EqualError(t, err, errPeerNotFound.Error())
|
||||
})
|
||||
}
|
|
@ -1,297 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/sha256"
|
||||
"sync"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"github.com/nspcc-dev/hrw"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spaolacci/murmur3"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
// Peer is value, that stores in Store storage
|
||||
Peer interface {
|
||||
ID() ID
|
||||
Address() multiaddr.Multiaddr
|
||||
PublicKey() *ecdsa.PublicKey
|
||||
PrivateKey() (*ecdsa.PrivateKey, error)
|
||||
SetPrivateKey(*ecdsa.PrivateKey) error
|
||||
|
||||
// TODO implement marshal/unmarshal binary.
|
||||
// Not sure that this method need for now,
|
||||
// that's why let's leave it on future
|
||||
// encoding.BinaryMarshaler
|
||||
// encoding.BinaryUnmarshaler
|
||||
}
|
||||
|
||||
peer struct {
|
||||
id ID
|
||||
pub *ecdsa.PublicKey
|
||||
key *ecdsa.PrivateKey
|
||||
addr multiaddr.Multiaddr
|
||||
}
|
||||
|
||||
// ID is a type of peer identification
|
||||
ID string
|
||||
|
||||
storage struct {
|
||||
log *zap.Logger
|
||||
|
||||
mu *sync.RWMutex
|
||||
items map[ID]Peer
|
||||
}
|
||||
|
||||
// PeerFilter is a Peer filtering function.
|
||||
PeerFilter func(Peer) bool
|
||||
|
||||
// Storage is storage interface for Store
|
||||
Storage interface {
|
||||
Get(ID) (Peer, error)
|
||||
Set(ID, Peer) error
|
||||
Has(ID) bool
|
||||
Rem(ID) error
|
||||
List(ID, int64, int) ([]ID, error)
|
||||
Filter(PeerFilter) []ID
|
||||
Update(*netmap.NetMap) error
|
||||
}
|
||||
)
|
||||
|
||||
const defaultStoreCapacity = 100
|
||||
|
||||
var (
|
||||
errUnknownPeer = errors.New("unknown peer")
|
||||
errBadPublicKey = errors.New("bad public key")
|
||||
)
|
||||
|
||||
var errNilNetMap = errors.New("netmap is nil")
|
||||
|
||||
// Hash method used in HRW-library.
|
||||
func (i ID) Hash() uint64 {
|
||||
return murmur3.Sum64(i.Bytes())
|
||||
}
|
||||
|
||||
// NewLocalPeer creates new peer instance.
|
||||
func NewLocalPeer(addr multiaddr.Multiaddr, key *ecdsa.PrivateKey) Peer {
|
||||
pub := &key.PublicKey
|
||||
|
||||
return &peer{
|
||||
id: IDFromPublicKey(pub),
|
||||
pub: pub,
|
||||
key: key,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPeer creates new peer instance.
|
||||
func NewPeer(addr multiaddr.Multiaddr, pub *ecdsa.PublicKey, key *ecdsa.PrivateKey) Peer {
|
||||
return &peer{
|
||||
id: IDFromPublicKey(pub),
|
||||
pub: pub,
|
||||
key: key,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *peer) SetPrivateKey(key *ecdsa.PrivateKey) error {
|
||||
if key == nil || key.Curve != elliptic.P256() {
|
||||
return crypto.ErrEmptyPrivateKey
|
||||
}
|
||||
|
||||
p.key = key
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ID of peer.
|
||||
func (p peer) ID() ID {
|
||||
return p.id
|
||||
}
|
||||
|
||||
// Address of peer.
|
||||
func (p peer) Address() multiaddr.Multiaddr {
|
||||
return p.addr
|
||||
}
|
||||
|
||||
// PublicKey returns copy of peer public key.
|
||||
func (p peer) PublicKey() *ecdsa.PublicKey {
|
||||
return p.pub
|
||||
}
|
||||
|
||||
func (p peer) PrivateKey() (*ecdsa.PrivateKey, error) {
|
||||
if p.key == nil {
|
||||
return nil, crypto.ErrEmptyPrivateKey
|
||||
}
|
||||
|
||||
return p.key, nil
|
||||
}
|
||||
|
||||
// String returns string representation of PeerID.
|
||||
func (i ID) String() string {
|
||||
return string(i)
|
||||
}
|
||||
|
||||
// -- -- //
|
||||
|
||||
// Bytes returns bytes representation of PeerID.
|
||||
func (i ID) Bytes() []byte {
|
||||
return []byte(i)
|
||||
}
|
||||
|
||||
// Equal checks that both id's are identical.
|
||||
func (i ID) Equal(id ID) bool {
|
||||
return i == id
|
||||
}
|
||||
|
||||
// IDFromPublicKey returns peer ID for host with given public key.
|
||||
func IDFromPublicKey(pk *ecdsa.PublicKey) ID {
|
||||
if pk == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return IDFromBinary(crypto.MarshalPublicKey(pk))
|
||||
}
|
||||
|
||||
// IDFromBinary returns peer ID for host with given slice of byte.
|
||||
func IDFromBinary(b []byte) ID {
|
||||
bytes := sha256.Sum256(b)
|
||||
hash, _ := multihash.Encode(bytes[:], multihash.IDENTITY)
|
||||
ident := multihash.Multihash(hash)
|
||||
|
||||
return ID(ident.B58String())
|
||||
}
|
||||
|
||||
// NewSimpleStorage is implementation over map.
|
||||
func NewSimpleStorage(capacity int, l *zap.Logger) Storage {
|
||||
if capacity <= 0 {
|
||||
capacity = defaultStoreCapacity
|
||||
}
|
||||
|
||||
return &storage{
|
||||
log: l,
|
||||
mu: new(sync.RWMutex),
|
||||
items: make(map[ID]Peer, capacity),
|
||||
}
|
||||
}
|
||||
|
||||
// List peers that which are distributed by hrw(seed).
|
||||
func (s *storage) List(id ID, seed int64, count int) ([]ID, error) {
|
||||
s.mu.RLock()
|
||||
items := make([]ID, 0, len(s.items))
|
||||
|
||||
for key := range s.items {
|
||||
// ignore ourselves
|
||||
if id.Equal(key) {
|
||||
continue
|
||||
}
|
||||
|
||||
items = append(items, key)
|
||||
}
|
||||
s.mu.RUnlock()
|
||||
|
||||
// distribute keys by hrw(seed)
|
||||
hrw.SortSliceByValue(items,
|
||||
uint64(seed))
|
||||
|
||||
return items[:count], nil
|
||||
}
|
||||
|
||||
// Get peer by ID.
|
||||
func (s *storage) Get(id ID) (Peer, error) {
|
||||
s.mu.RLock()
|
||||
p, ok := s.items[id]
|
||||
s.mu.RUnlock()
|
||||
|
||||
if ok {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
return nil, errors.Wrapf(errUnknownPeer, "peer(%s)", id)
|
||||
}
|
||||
|
||||
// Set peer by id.
|
||||
func (s *storage) Set(id ID, p Peer) error {
|
||||
s.mu.Lock()
|
||||
s.items[id] = p
|
||||
s.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Has checks peer exists by id.
|
||||
func (s *storage) Has(id ID) bool {
|
||||
s.mu.RLock()
|
||||
_, ok := s.items[id]
|
||||
s.mu.RUnlock()
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
// Rem peer by id.
|
||||
func (s *storage) Rem(id ID) error {
|
||||
s.mu.Lock()
|
||||
delete(s.items, id)
|
||||
s.mu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update storage by network map.
|
||||
func (s *storage) Update(nm *netmap.NetMap) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
list := nm.Nodes()
|
||||
if len(list) == 0 {
|
||||
return errNilNetMap
|
||||
}
|
||||
|
||||
items := make(map[ID]Peer, len(s.items))
|
||||
|
||||
for i := range list {
|
||||
addr, err := multiaddr.NewMultiaddr(list[i].Address())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "address=`%s`", list[i].Address())
|
||||
}
|
||||
|
||||
pubKey := list[i].PublicKey()
|
||||
pk := crypto.UnmarshalPublicKey(pubKey)
|
||||
if pk == nil && pubKey != nil {
|
||||
return errors.Wrapf(errBadPublicKey, "pubkey=`%x`", pubKey)
|
||||
}
|
||||
|
||||
id := IDFromPublicKey(pk)
|
||||
if pv, ok := s.items[id]; ok {
|
||||
if pv.Address() != nil && pv.Address().Equal(addr) {
|
||||
items[id] = pv
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
items[id] = NewPeer(addr, pk, nil)
|
||||
}
|
||||
|
||||
s.items = items
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *storage) Filter(filter PeerFilter) (res []ID) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
for id, peer := range s.items {
|
||||
if filter(peer) {
|
||||
res = append(res, id)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package peers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
)
|
||||
|
||||
func (s *iface) Job(ctx context.Context) {
|
||||
var (
|
||||
tick = time.NewTimer(s.tick)
|
||||
metrics = time.NewTimer(s.metricsTimeout)
|
||||
)
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
break loop
|
||||
case <-metrics.C:
|
||||
var items = make(map[connectivity.State]float64)
|
||||
s.grpc.globalMutex.Lock()
|
||||
for _, item := range s.grpc.connBook {
|
||||
if item.conn != nil {
|
||||
items[item.conn.GetState()]++
|
||||
}
|
||||
}
|
||||
s.grpc.globalMutex.Unlock()
|
||||
|
||||
updateMetrics(items)
|
||||
|
||||
metrics.Reset(s.metricsTimeout)
|
||||
case <-tick.C:
|
||||
var count int
|
||||
|
||||
s.grpc.globalMutex.Lock()
|
||||
for addr, item := range s.grpc.connBook {
|
||||
if item.conn == nil || isGRPCClosed(item.conn) || time.Since(item.used) > s.idle {
|
||||
if err := s.removeGRPCConnection(addr); err != nil {
|
||||
s.log.Error("could not close connection",
|
||||
zap.String("address", addr),
|
||||
zap.String("target", item.conn.Target()),
|
||||
zap.Stringer("idle", time.Since(item.used)),
|
||||
zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
count++
|
||||
} else {
|
||||
s.log.Debug("ignore connection",
|
||||
zap.String("address", addr),
|
||||
zap.Stringer("idle", time.Since(item.used)))
|
||||
}
|
||||
}
|
||||
s.grpc.globalMutex.Unlock()
|
||||
|
||||
s.log.Debug("cleanup connections done",
|
||||
zap.Int("closed", count))
|
||||
|
||||
tick.Reset(s.tick)
|
||||
}
|
||||
}
|
||||
|
||||
tick.Stop()
|
||||
}
|
0
pkg/network/transport/accounting/grpc/.gitkeep
Normal file
0
pkg/network/transport/accounting/grpc/.gitkeep
Normal file
|
@ -1,94 +0,0 @@
|
|||
package accounting
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/accounting"
|
||||
"github.com/nspcc-dev/neofs-api-go/decimal"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/morph/client/balance/wrapper"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc"
|
||||
libgrpc "github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
type (
|
||||
// Service is an interface of the server of Accounting service.
|
||||
Service interface {
|
||||
grpc.Service
|
||||
accounting.AccountingServer
|
||||
}
|
||||
|
||||
// ContractClient represents the client of Balance contract.
|
||||
//
|
||||
// It is a type alias of the pointer to
|
||||
// github.com/nspcc-dev/neofs-node/pkg/morph/client/balance/wrapper.Wrapper.
|
||||
ContractClient = *wrapper.Wrapper
|
||||
|
||||
// Params groups the parameters of Accounting service server's constructor.
|
||||
Params struct {
|
||||
ContractClient ContractClient
|
||||
}
|
||||
|
||||
accService struct {
|
||||
contractClient ContractClient
|
||||
}
|
||||
)
|
||||
|
||||
var requestVerifyFunc = libgrpc.VerifyRequestWithSignatures
|
||||
|
||||
// New is an Accounting service server's constructor.
|
||||
//
|
||||
// If Balance contract client is nil,
|
||||
// wrapper.ErrNilWrapper is returned.
|
||||
func New(p Params) (Service, error) {
|
||||
if p.ContractClient == nil {
|
||||
return nil, wrapper.ErrNilWrapper
|
||||
}
|
||||
|
||||
return &accService{
|
||||
contractClient: p.ContractClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (accService) Name() string { return "AccountingService" }
|
||||
|
||||
func (s accService) Register(g *grpc.Server) { accounting.RegisterAccountingServer(g, s) }
|
||||
|
||||
func (s accService) Balance(ctx context.Context, req *accounting.BalanceRequest) (*accounting.BalanceResponse, error) {
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// get the amount of funds in client's account
|
||||
fundsAmount, err := s.contractClient.BalanceOf(req.GetOwnerID())
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, err.Error())
|
||||
}
|
||||
|
||||
// get decimals precision of currency transactions
|
||||
|
||||
// TODO: Reconsider the approach of getting decimals.
|
||||
//
|
||||
// Decimals value does not seem to be frequently changing.
|
||||
// In this case service can work in static decimals mode and
|
||||
// the value can be received once to facilitate call flow.
|
||||
//
|
||||
// In a true dynamic value installation it is advisable to get
|
||||
// a balance with decimals through a single call. Variations:
|
||||
// - add decimal value stack parameter of balanceOf method;
|
||||
// - create a new method entitled smth like balanceWithDecimals.
|
||||
decimals, err := s.contractClient.Decimals()
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Aborted, err.Error())
|
||||
}
|
||||
|
||||
res := new(accounting.BalanceResponse)
|
||||
res.Balance = decimal.NewWithPrecision(
|
||||
fundsAmount,
|
||||
decimals,
|
||||
)
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
package accounting
|
||||
|
||||
// TODO: write unit tests
|
0
pkg/network/transport/container/grpc/.gitkeep
Normal file
0
pkg/network/transport/container/grpc/.gitkeep
Normal file
|
@ -1,70 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s cnrService) SetExtendedACL(ctx context.Context, req *container.SetExtendedACLRequest) (*container.SetExtendedACLResponse, error) {
|
||||
// check healthiness
|
||||
if err := s.healthy.Healthy(); err != nil {
|
||||
return nil, status.Error(codes.Unavailable, err.Error())
|
||||
}
|
||||
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// unmarshal eACL table
|
||||
table, err := eacl.UnmarshalTable(req.GetEACL())
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.InvalidArgument,
|
||||
errors.Wrap(err, "could not decode eACL table").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// store eACL table
|
||||
if err := s.aclStore.PutEACL(req.GetID(), table, req.GetSignature()); err != nil {
|
||||
return nil, status.Error(
|
||||
codes.Aborted,
|
||||
errors.Wrap(err, "could not save eACL in storage").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
return new(container.SetExtendedACLResponse), nil
|
||||
}
|
||||
|
||||
func (s cnrService) GetExtendedACL(ctx context.Context, req *container.GetExtendedACLRequest) (*container.GetExtendedACLResponse, error) {
|
||||
// check healthiness
|
||||
if err := s.healthy.Healthy(); err != nil {
|
||||
return nil, status.Error(codes.Unavailable, err.Error())
|
||||
}
|
||||
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// receive binary eACL
|
||||
table, err := s.aclStore.GetEACL(req.GetID())
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.NotFound,
|
||||
errors.Wrap(err, "could not get eACL from storage").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// fill the response
|
||||
res := new(container.GetExtendedACLResponse)
|
||||
res.SetEACL(eacl.MarshalTable(table))
|
||||
res.SetSignature(nil) // TODO: set signature when will appear.
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/acl"
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Entity for mocking interfaces.
|
||||
// Implementation of any interface intercepts arguments via f (if not nil).
|
||||
// If err is not nil, it returns as it is. Otherwise, casted to needed type res returns w/o error.
|
||||
type testEACLEntity struct {
|
||||
// Set of interfaces which entity must implement, but some methods from those does not call.
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
|
||||
var requestSignFunc = service.SignRequestData
|
||||
|
||||
func (s *testEACLEntity) GetEACL(cid CID) (Table, error) {
|
||||
if s.f != nil {
|
||||
s.f(cid)
|
||||
}
|
||||
|
||||
if s.err != nil {
|
||||
return nil, s.err
|
||||
}
|
||||
|
||||
return s.res.(Table), nil
|
||||
}
|
||||
|
||||
func (s *testEACLEntity) PutEACL(cid CID, table Table, sig []byte) error {
|
||||
if s.f != nil {
|
||||
s.f(cid, table, sig)
|
||||
}
|
||||
|
||||
return s.err
|
||||
}
|
||||
|
||||
func TestCnrService_SetExtendedACL(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("unhealthy", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: &testCommonEntity{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.SetExtendedACL(ctx, new(container.SetExtendedACLRequest))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid request structure", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
}
|
||||
|
||||
// create unsigned request
|
||||
req := new(container.SetExtendedACLRequest)
|
||||
require.Error(t, requestVerifyFunc(req))
|
||||
|
||||
_, err := s.SetExtendedACL(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.InvalidArgument, st.Code())
|
||||
})
|
||||
|
||||
t.Run("EACL storage failure", func(t *testing.T) {
|
||||
record := new(acl.EACLRecord)
|
||||
record.SetAction(acl.EACLRecord_Allow)
|
||||
|
||||
table := eacl.WrapTable(nil)
|
||||
table.SetRecords([]eacl.Record{eacl.WrapRecord(record)})
|
||||
|
||||
req := new(container.SetExtendedACLRequest)
|
||||
req.SetID(CID{1, 2, 3})
|
||||
req.SetEACL(eacl.MarshalTable(table))
|
||||
req.SetSignature([]byte{4, 5, 6})
|
||||
|
||||
require.NoError(t, requestSignFunc(test.DecodeKey(0), req))
|
||||
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
aclStore: &testEACLEntity{
|
||||
f: func(items ...interface{}) {
|
||||
require.Equal(t, req.GetID(), items[0])
|
||||
require.Equal(t, req.GetSignature(), items[2])
|
||||
},
|
||||
err: errors.New("storage error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.SetExtendedACL(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.Aborted, st.Code())
|
||||
})
|
||||
|
||||
t.Run("correct result", func(t *testing.T) {
|
||||
req := new(container.SetExtendedACLRequest)
|
||||
|
||||
require.NoError(t, requestSignFunc(test.DecodeKey(0), req))
|
||||
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
aclStore: new(testEACLEntity),
|
||||
}
|
||||
|
||||
res, err := s.SetExtendedACL(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, res)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCnrService_GetExtendedACL(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("unhealthy", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: &testCommonEntity{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.GetExtendedACL(ctx, new(container.GetExtendedACLRequest))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid request structure", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
}
|
||||
|
||||
// create unsigned request
|
||||
req := new(container.GetExtendedACLRequest)
|
||||
require.Error(t, requestVerifyFunc(req))
|
||||
|
||||
_, err := s.GetExtendedACL(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.InvalidArgument, st.Code())
|
||||
})
|
||||
|
||||
t.Run("EACL storage failure", func(t *testing.T) {
|
||||
req := new(container.GetExtendedACLRequest)
|
||||
req.SetID(CID{1, 2, 3})
|
||||
|
||||
require.NoError(t, requestSignFunc(test.DecodeKey(0), req))
|
||||
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
aclStore: &testEACLEntity{
|
||||
f: func(items ...interface{}) {
|
||||
require.Equal(t, req.GetID(), items[0])
|
||||
},
|
||||
err: errors.New("storage error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.GetExtendedACL(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.NotFound, st.Code())
|
||||
})
|
||||
|
||||
t.Run("correct result", func(t *testing.T) {
|
||||
req := new(container.GetExtendedACLRequest)
|
||||
req.SetID(CID{1, 2, 3})
|
||||
|
||||
require.NoError(t, requestSignFunc(test.DecodeKey(0), req))
|
||||
|
||||
table := eacl.WrapTable(nil)
|
||||
|
||||
record := new(acl.EACLRecord)
|
||||
record.SetAction(acl.EACLRecord_Allow)
|
||||
|
||||
table.SetRecords([]eacl.Record{eacl.WrapRecord(record)})
|
||||
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
aclStore: &testEACLEntity{
|
||||
res: table,
|
||||
},
|
||||
}
|
||||
|
||||
res, err := s.GetExtendedACL(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, eacl.MarshalTable(table), res.GetEACL())
|
||||
require.Empty(t, res.GetSignature())
|
||||
})
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
)
|
||||
|
||||
// CID represents the container identifier.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.ID.
|
||||
type CID = container.ID
|
||||
|
||||
// OwnerID represents the container owner identifier..
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.OwnerID.
|
||||
type OwnerID = container.OwnerID
|
||||
|
||||
// Container represents the NeoFS Container structure.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-node/pkg/core/container.Container.
|
||||
type Container = container.Container
|
||||
|
||||
// Table represents the eACL table.
|
||||
//
|
||||
// It is a type alias of
|
||||
// github.com/nspcc-dev/neofs-api-go/acl/extended.ExtendedACLTable.
|
||||
type Table = eacl.Table
|
|
@ -1,19 +0,0 @@
|
|||
package container
|
||||
|
||||
// Entity for mocking interfaces.
|
||||
// Implementation of any interface intercepts arguments via f (if not nil).
|
||||
// If err is not nil, it returns as it is. Otherwise, casted to needed type res returns w/o error.
|
||||
type testCommonEntity struct {
|
||||
// Set of interfaces which entity must implement, but some methods from those does not call.
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
|
||||
func (s testCommonEntity) Healthy() error {
|
||||
return s.err
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s cnrService) Delete(ctx context.Context, req *container.DeleteRequest) (*container.DeleteResponse, error) {
|
||||
// check healthiness
|
||||
if err := s.healthy.Healthy(); err != nil {
|
||||
return nil, errors.Wrap(err, "try again later")
|
||||
}
|
||||
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// remove container from storage
|
||||
if err := s.cnrStore.Delete(req.GetCID()); err != nil {
|
||||
return nil, status.Error(
|
||||
codes.Aborted,
|
||||
errors.Wrap(err, "could not remove container from storage").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
return new(container.DeleteResponse), nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Entity for mocking interfaces.
|
||||
// Implementation of any interface intercepts arguments via f (if not nil).
|
||||
// If err is not nil, it returns as it is. Otherwise, casted to needed type res returns w/o error.
|
||||
type testDeleteEntity struct {
|
||||
// Set of interfaces which entity must implement, but some methods from those does not call.
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
|
||||
func TestCnrService_Delete(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("unhealthy", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: &testCommonEntity{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.Delete(ctx, new(container.DeleteRequest))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid request structure", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
}
|
||||
|
||||
// create unsigned request
|
||||
req := new(container.DeleteRequest)
|
||||
require.Error(t, requestVerifyFunc(req))
|
||||
|
||||
_, err := s.Delete(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.InvalidArgument, st.Code())
|
||||
})
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s cnrService) Get(ctx context.Context, req *container.GetRequest) (*container.GetResponse, error) {
|
||||
// check healthiness
|
||||
if err := s.healthy.Healthy(); err != nil {
|
||||
return nil, status.Error(codes.Unavailable, err.Error())
|
||||
}
|
||||
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// get container from storage
|
||||
cnr, err := s.cnrStore.Get(req.GetCID())
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.NotFound,
|
||||
errors.Wrap(err, "could not get container from storage").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// fill the response
|
||||
res := new(container.GetResponse)
|
||||
|
||||
// FIXME: salt should be []byte in the message
|
||||
salt, err := uuid.FromBytes(cnr.Salt())
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.Aborted,
|
||||
errors.Wrap(err, "could not decode salt").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// FIXME: message field should be the same type or []byte.
|
||||
res.Container = new(container.Container)
|
||||
res.Container.Salt = refs.UUID(salt)
|
||||
res.Container = new(container.Container)
|
||||
res.Container.OwnerID = cnr.OwnerID()
|
||||
res.Container.Rules = cnr.PlacementRule()
|
||||
res.Container.BasicACL = basic.ToUint32(cnr.BasicACL())
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Entity for mocking interfaces.
|
||||
// Implementation of any interface intercepts arguments via f (if not nil).
|
||||
// If err is not nil, it returns as it is. Otherwise, casted to needed type res returns w/o error.
|
||||
type testGetEntity struct {
|
||||
// Set of interfaces which entity must implement, but some methods from those does not call.
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
|
||||
func TestCnrService_Get(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("unhealthy", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: &testCommonEntity{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.Get(ctx, new(container.GetRequest))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid request structure", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
}
|
||||
|
||||
// create unsigned request
|
||||
req := new(container.GetRequest)
|
||||
require.Error(t, requestVerifyFunc(req))
|
||||
|
||||
_, err := s.Get(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.InvalidArgument, st.Code())
|
||||
})
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s cnrService) List(ctx context.Context, req *container.ListRequest) (*container.ListResponse, error) {
|
||||
// check healthiness
|
||||
if err := s.healthy.Healthy(); err != nil {
|
||||
return nil, errors.Wrap(err, "try again later")
|
||||
}
|
||||
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// list container identifiers from storage
|
||||
ownerID := req.GetOwnerID()
|
||||
cidList, err := s.cnrStore.List(&ownerID)
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.NotFound,
|
||||
errors.Wrap(err, "could not list the containers in storage").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// fill the response
|
||||
res := new(container.ListResponse)
|
||||
res.CID = cidList
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Entity for mocking interfaces.
|
||||
// Implementation of any interface intercepts arguments via f (if not nil).
|
||||
// If err is not nil, it returns as it is. Otherwise, casted to needed type res returns w/o error.
|
||||
type testListEntity struct {
|
||||
// Set of interfaces which entity must implement, but some methods from those does not call.
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
|
||||
func TestCnrService_List(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("unhealthy", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: &testCommonEntity{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.List(ctx, new(container.ListRequest))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid request structure", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
}
|
||||
|
||||
// create unsigned request
|
||||
req := new(container.ListRequest)
|
||||
require.Error(t, requestVerifyFunc(req))
|
||||
|
||||
_, err := s.List(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.InvalidArgument, st.Code())
|
||||
})
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// TODO verify MessageID.
|
||||
func (s cnrService) Put(ctx context.Context, req *container.PutRequest) (*container.PutResponse, error) {
|
||||
// check healthiness
|
||||
if err := s.healthy.Healthy(); err != nil {
|
||||
return nil, errors.Wrap(err, "try again later")
|
||||
}
|
||||
|
||||
// verify request structure
|
||||
if err := requestVerifyFunc(req); err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
// create container structure
|
||||
// FIXME: message field should be the same type or []byte.
|
||||
cnr := new(Container)
|
||||
cnr.SetOwnerID(req.GetOwnerID())
|
||||
cnr.SetPlacementRule(req.GetRules())
|
||||
cnr.SetBasicACL(basic.FromUint32(req.GetBasicACL()))
|
||||
|
||||
uid, err := refs.NewUUID()
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.Aborted,
|
||||
errors.Wrap(err, "could not generate the salt").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
cnr.SetSalt(uid.Bytes())
|
||||
|
||||
// save container in storage
|
||||
cid, err := s.cnrStore.Put(cnr)
|
||||
if err != nil {
|
||||
return nil, status.Error(
|
||||
codes.Aborted,
|
||||
errors.Wrap(err, "could not save the container instorage").Error(),
|
||||
)
|
||||
}
|
||||
|
||||
// fill the response
|
||||
res := new(container.PutResponse)
|
||||
res.CID = *cid
|
||||
|
||||
return res, nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// Entity for mocking interfaces.
|
||||
// Implementation of any interface intercepts arguments via f (if not nil).
|
||||
// If err is not nil, it returns as it is. Otherwise, casted to needed type res returns w/o error.
|
||||
type testPutEntity struct {
|
||||
// Set of interfaces which entity must implement, but some methods from those does not call.
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
|
||||
func TestCnrService_Put(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("unhealthy", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: &testCommonEntity{
|
||||
err: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
_, err := s.Put(ctx, new(container.PutRequest))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid request structure", func(t *testing.T) {
|
||||
s := cnrService{
|
||||
healthy: new(testCommonEntity),
|
||||
}
|
||||
|
||||
// create unsigned request
|
||||
req := new(container.PutRequest)
|
||||
require.Error(t, requestVerifyFunc(req))
|
||||
|
||||
_, err := s.Put(ctx, req)
|
||||
require.Error(t, err)
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, codes.InvalidArgument, st.Code())
|
||||
})
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
eacl "github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc"
|
||||
libgrpc "github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
// Service is an interface of the server of Container service.
|
||||
Service interface {
|
||||
grpc.Service
|
||||
container.ServiceServer
|
||||
}
|
||||
|
||||
// HealthChecker is an interface of node healthiness checking tool.
|
||||
HealthChecker interface {
|
||||
Healthy() error
|
||||
}
|
||||
|
||||
// Params groups the parameters of Container service server's constructor.
|
||||
Params struct {
|
||||
Logger *zap.Logger
|
||||
|
||||
Healthy HealthChecker
|
||||
|
||||
Store storage.Storage
|
||||
|
||||
ExtendedACLStore eacl.Storage
|
||||
}
|
||||
|
||||
cnrService struct {
|
||||
log *zap.Logger
|
||||
|
||||
healthy HealthChecker
|
||||
|
||||
cnrStore storage.Storage
|
||||
|
||||
aclStore eacl.Storage
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyLogger = errors.New("empty log component")
|
||||
errEmptyHealthChecker = errors.New("empty healthy component")
|
||||
)
|
||||
|
||||
var requestVerifyFunc = libgrpc.VerifyRequestWithSignatures
|
||||
|
||||
// New is an Container service server's constructor.
|
||||
func New(p Params) (Service, error) {
|
||||
switch {
|
||||
case p.Logger == nil:
|
||||
return nil, errEmptyLogger
|
||||
case p.Store == nil:
|
||||
return nil, storage.ErrNilStorage
|
||||
case p.Healthy == nil:
|
||||
return nil, errEmptyHealthChecker
|
||||
case p.ExtendedACLStore == nil:
|
||||
return nil, eacl.ErrNilStorage
|
||||
}
|
||||
|
||||
return &cnrService{
|
||||
log: p.Logger,
|
||||
healthy: p.Healthy,
|
||||
cnrStore: p.Store,
|
||||
aclStore: p.ExtendedACLStore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cnrService) Name() string { return "ContainerService" }
|
||||
|
||||
func (s cnrService) Register(g *grpc.Server) { container.RegisterServiceServer(g, s) }
|
0
pkg/network/transport/grpc/.gitkeep
Normal file
0
pkg/network/transport/grpc/.gitkeep
Normal file
|
@ -1,13 +0,0 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type Server = grpc.Server
|
||||
|
||||
// Service interface
|
||||
type Service interface {
|
||||
Name() string
|
||||
Register(*Server)
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
)
|
||||
|
||||
// ErrMissingKeySignPairs is returned by functions that expect
|
||||
// a non-empty SignKeyPair slice, but received empty.
|
||||
var ErrMissingKeySignPairs = errors.New("missing key-signature pairs")
|
||||
|
||||
// VerifyRequestWithSignatures checks if request has signatures and all of them are valid.
|
||||
//
|
||||
// Returns ErrMissingKeySignPairs if request does not have signatures.
|
||||
// Otherwise, behaves like service.VerifyRequestData.
|
||||
func VerifyRequestWithSignatures(req service.RequestVerifyData) error {
|
||||
if len(req.GetSignKeyPairs()) == 0 {
|
||||
return ErrMissingKeySignPairs
|
||||
}
|
||||
|
||||
return service.VerifyRequestData(req)
|
||||
}
|
0
pkg/network/transport/metrics/grpc/.gitkeep
Normal file
0
pkg/network/transport/metrics/grpc/.gitkeep
Normal file
|
@ -1,60 +0,0 @@
|
|||
package metrics
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/metrics"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
// Service is an interface of the server of Metrics service.
|
||||
Service interface {
|
||||
MetricsServer
|
||||
grpc.Service
|
||||
}
|
||||
|
||||
// Params groups the parameters of Metrics service server's constructor.
|
||||
Params struct {
|
||||
Logger *zap.Logger
|
||||
Collector metrics.Collector
|
||||
}
|
||||
|
||||
serviceMetrics struct {
|
||||
log *zap.Logger
|
||||
col metrics.Collector
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
errEmptyLogger = errors.New("empty logger")
|
||||
errEmptyCollector = errors.New("empty metrics collector")
|
||||
)
|
||||
|
||||
// New is a Metrics service server's constructor.
|
||||
func New(p Params) (Service, error) {
|
||||
switch {
|
||||
case p.Logger == nil:
|
||||
return nil, errEmptyLogger
|
||||
case p.Collector == nil:
|
||||
return nil, errEmptyCollector
|
||||
}
|
||||
|
||||
return &serviceMetrics{
|
||||
log: p.Logger,
|
||||
col: p.Collector,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *serviceMetrics) ResetSpaceCounter(_ context.Context, _ *ResetSpaceRequest) (*ResetSpaceResponse, error) {
|
||||
s.col.UpdateSpaceUsage()
|
||||
return &ResetSpaceResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *serviceMetrics) Name() string { return "metrics" }
|
||||
|
||||
func (s *serviceMetrics) Register(srv *grpc.Server) {
|
||||
RegisterMetricsServer(srv, s)
|
||||
}
|
499
pkg/network/transport/metrics/grpc/service.pb.go
generated
499
pkg/network/transport/metrics/grpc/service.pb.go
generated
|
@ -1,499 +0,0 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: pkg/network/transport/metrics/grpc/service.proto
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type ResetSpaceRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ResetSpaceRequest) Reset() { *m = ResetSpaceRequest{} }
|
||||
func (m *ResetSpaceRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResetSpaceRequest) ProtoMessage() {}
|
||||
func (*ResetSpaceRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_cdef708412a96383, []int{0}
|
||||
}
|
||||
func (m *ResetSpaceRequest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ResetSpaceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ResetSpaceRequest.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *ResetSpaceRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ResetSpaceRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ResetSpaceRequest) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ResetSpaceRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ResetSpaceRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ResetSpaceRequest proto.InternalMessageInfo
|
||||
|
||||
type ResetSpaceResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ResetSpaceResponse) Reset() { *m = ResetSpaceResponse{} }
|
||||
func (m *ResetSpaceResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ResetSpaceResponse) ProtoMessage() {}
|
||||
func (*ResetSpaceResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_cdef708412a96383, []int{1}
|
||||
}
|
||||
func (m *ResetSpaceResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ResetSpaceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ResetSpaceResponse.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *ResetSpaceResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ResetSpaceResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ResetSpaceResponse) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ResetSpaceResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ResetSpaceResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ResetSpaceResponse proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ResetSpaceRequest)(nil), "metrics.ResetSpaceRequest")
|
||||
proto.RegisterType((*ResetSpaceResponse)(nil), "metrics.ResetSpaceResponse")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("pkg/network/transport/metrics/grpc/service.proto", fileDescriptor_cdef708412a96383)
|
||||
}
|
||||
|
||||
var fileDescriptor_cdef708412a96383 = []byte{
|
||||
// 207 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x8f, 0xb1, 0x4a, 0xc4, 0x40,
|
||||
0x10, 0x86, 0x4d, 0xe3, 0xc1, 0x76, 0xae, 0x56, 0x27, 0x6c, 0x71, 0xfd, 0xed, 0x88, 0xbe, 0xc1,
|
||||
0xd9, 0x6a, 0x73, 0x0a, 0x82, 0x5d, 0xb2, 0x19, 0x63, 0x08, 0xd9, 0x59, 0x67, 0x26, 0xf1, 0x55,
|
||||
0x7c, 0x24, 0x4b, 0x1f, 0x41, 0xe2, 0x8b, 0x08, 0x49, 0x8a, 0xc0, 0xa5, 0x9d, 0x9f, 0xef, 0x1b,
|
||||
0x3e, 0x73, 0x93, 0x9a, 0x0a, 0x22, 0xea, 0x27, 0x71, 0x03, 0xca, 0x79, 0x94, 0x44, 0xac, 0xd0,
|
||||
0xa2, 0x72, 0x1d, 0x04, 0x2a, 0x4e, 0x01, 0x04, 0xb9, 0xaf, 0x03, 0xfa, 0xc4, 0xa4, 0x64, 0x37,
|
||||
0xf3, 0xb6, 0xbb, 0x34, 0x17, 0x47, 0x14, 0xd4, 0xa7, 0x94, 0x07, 0x3c, 0xe2, 0x47, 0x87, 0xa2,
|
||||
0xbb, 0x2b, 0x63, 0x97, 0x47, 0x49, 0x14, 0x05, 0x6f, 0x5f, 0xcc, 0xe6, 0x71, 0xa2, 0xec, 0xc3,
|
||||
0x92, 0xba, 0xa7, 0x2e, 0x2a, 0xb2, 0xdd, 0xfa, 0x59, 0xea, 0x4f, 0x8c, 0xdb, 0xeb, 0xd5, 0x6d,
|
||||
0x12, 0x1f, 0x9e, 0xbf, 0x07, 0x97, 0xfd, 0x0c, 0x2e, 0xfb, 0x1d, 0x5c, 0xf6, 0xf5, 0xe7, 0xce,
|
||||
0x5e, 0x0f, 0x55, 0xad, 0xef, 0x5d, 0xe1, 0x03, 0xb5, 0x10, 0x25, 0x85, 0xb0, 0x2f, 0xb1, 0x87,
|
||||
0x88, 0xf4, 0x26, 0xfb, 0x48, 0x25, 0xc2, 0x7a, 0xf0, 0x18, 0x3a, 0x3f, 0x2a, 0xce, 0xc7, 0xd2,
|
||||
0xbb, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x26, 0xa6, 0xbe, 0x1d, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// MetricsClient is the client API for Metrics service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type MetricsClient interface {
|
||||
ResetSpaceCounter(ctx context.Context, in *ResetSpaceRequest, opts ...grpc.CallOption) (*ResetSpaceResponse, error)
|
||||
}
|
||||
|
||||
type metricsClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewMetricsClient(cc *grpc.ClientConn) MetricsClient {
|
||||
return &metricsClient{cc}
|
||||
}
|
||||
|
||||
func (c *metricsClient) ResetSpaceCounter(ctx context.Context, in *ResetSpaceRequest, opts ...grpc.CallOption) (*ResetSpaceResponse, error) {
|
||||
out := new(ResetSpaceResponse)
|
||||
err := c.cc.Invoke(ctx, "/metrics.Metrics/ResetSpaceCounter", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// MetricsServer is the server API for Metrics service.
|
||||
type MetricsServer interface {
|
||||
ResetSpaceCounter(context.Context, *ResetSpaceRequest) (*ResetSpaceResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedMetricsServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedMetricsServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedMetricsServer) ResetSpaceCounter(ctx context.Context, req *ResetSpaceRequest) (*ResetSpaceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ResetSpaceCounter not implemented")
|
||||
}
|
||||
|
||||
func RegisterMetricsServer(s *grpc.Server, srv MetricsServer) {
|
||||
s.RegisterService(&_Metrics_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Metrics_ResetSpaceCounter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ResetSpaceRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MetricsServer).ResetSpaceCounter(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/metrics.Metrics/ResetSpaceCounter",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MetricsServer).ResetSpaceCounter(ctx, req.(*ResetSpaceRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Metrics_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "metrics.Metrics",
|
||||
HandlerType: (*MetricsServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "ResetSpaceCounter",
|
||||
Handler: _Metrics_ResetSpaceCounter_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "pkg/network/transport/metrics/grpc/service.proto",
|
||||
}
|
||||
|
||||
func (m *ResetSpaceRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ResetSpaceRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *ResetSpaceRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *ResetSpaceResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ResetSpaceResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *ResetSpaceResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintService(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovService(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *ResetSpaceRequest) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ResetSpaceResponse) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovService(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozService(x uint64) (n int) {
|
||||
return sovService(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *ResetSpaceRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowService
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ResetSpaceRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ResetSpaceRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipService(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthService
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthService
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ResetSpaceResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowService
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ResetSpaceResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ResetSpaceResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipService(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthService
|
||||
}
|
||||
if (iNdEx + skippy) < 0 {
|
||||
return ErrInvalidLengthService
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipService(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowService
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowService
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowService
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthService
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupService
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthService
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthService = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowService = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupService = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
syntax = "proto3";
|
||||
package metrics;
|
||||
option go_package = "github.com/nspcc-dev/neofs-node/pkg/network/transport/grpc/metrics";
|
||||
|
||||
service Metrics {
|
||||
rpc ResetSpaceCounter(ResetSpaceRequest) returns (ResetSpaceResponse);
|
||||
}
|
||||
|
||||
message ResetSpaceRequest {}
|
||||
message ResetSpaceResponse {}
|
0
pkg/network/transport/object/grpc/.gitkeep
Normal file
0
pkg/network/transport/object/grpc/.gitkeep
Normal file
|
@ -1,742 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-api-go/object"
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended"
|
||||
eaclstorage "github.com/nspcc-dev/neofs-node/pkg/core/container/acl/extended/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/localstore"
|
||||
eaclcheck "github.com/nspcc-dev/neofs-node/pkg/network/transport/object/grpc/eacl"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transport"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
// RequestTargeter is an interface of request's ACL group calculator.
|
||||
RequestTargeter interface {
|
||||
Target(context.Context, serviceRequest) requestTarget
|
||||
}
|
||||
|
||||
// aclPreProcessor is an implementation of requestPreProcessor interface.
|
||||
aclPreProcessor struct {
|
||||
log *zap.Logger
|
||||
|
||||
aclInfoReceiver aclInfoReceiver
|
||||
|
||||
reqActionCalc requestActionCalculator
|
||||
|
||||
localStore localstore.Localstore
|
||||
|
||||
extACLSource eaclstorage.Storage
|
||||
|
||||
bearerVerifier bearerTokenVerifier
|
||||
}
|
||||
|
||||
// duplicates NetmapClient method, used for testing.
|
||||
irKeysReceiver interface {
|
||||
InnerRingKeys() ([][]byte, error)
|
||||
}
|
||||
|
||||
containerNodesLister interface {
|
||||
ContainerNodes(ctx context.Context, cid CID) ([]multiaddr.Multiaddr, error)
|
||||
ContainerNodesInfo(ctx context.Context, cid CID, prev int) ([]netmap.Info, error)
|
||||
}
|
||||
|
||||
targetFinder struct {
|
||||
log *zap.Logger
|
||||
|
||||
irKeysRecv irKeysReceiver
|
||||
cnrLister containerNodesLister
|
||||
cnrStorage storage.Storage
|
||||
}
|
||||
)
|
||||
|
||||
type objectHeadersSource interface {
|
||||
getHeaders() (*Object, bool)
|
||||
}
|
||||
|
||||
type requestActionCalculator interface {
|
||||
calculateRequestAction(context.Context, requestActionParams) eacl.Action
|
||||
}
|
||||
|
||||
type aclInfoReceiver struct {
|
||||
cnrStorage storage.Storage
|
||||
|
||||
targetFinder RequestTargeter
|
||||
}
|
||||
|
||||
type aclInfo struct {
|
||||
rule container.BasicACL
|
||||
|
||||
checkExtended bool
|
||||
|
||||
checkBearer bool
|
||||
|
||||
targetInfo requestTarget
|
||||
}
|
||||
|
||||
type reqActionCalc struct {
|
||||
storage eaclstorage.Storage
|
||||
|
||||
log *zap.Logger
|
||||
}
|
||||
|
||||
type serviceRequestInfo struct {
|
||||
group eacl.Group
|
||||
|
||||
req serviceRequest
|
||||
|
||||
objHdrSrc objectHeadersSource
|
||||
}
|
||||
|
||||
type requestObjHdrSrc struct {
|
||||
req serviceRequest
|
||||
|
||||
ls localstore.Localstore
|
||||
}
|
||||
|
||||
type eaclFromBearer struct {
|
||||
eaclstorage.Storage
|
||||
|
||||
bearer service.BearerToken
|
||||
}
|
||||
|
||||
type requestTarget struct {
|
||||
group eacl.Group
|
||||
|
||||
ir bool
|
||||
}
|
||||
|
||||
var _ requestPreProcessor = (*aclPreProcessor)(nil)
|
||||
|
||||
var errMissingSignatures = errors.New("empty signature list")
|
||||
|
||||
func (p *aclPreProcessor) preProcess(ctx context.Context, req serviceRequest) error {
|
||||
if req == nil {
|
||||
panic(pmEmptyServiceRequest)
|
||||
}
|
||||
|
||||
// fetch ACL info
|
||||
aclInfo, err := p.aclInfoReceiver.getACLInfo(ctx, req)
|
||||
if err != nil {
|
||||
p.log.Warn("can't get acl of the container", zap.Stringer("cid", req.CID()))
|
||||
return errAccessDenied
|
||||
}
|
||||
|
||||
// check basic ACL permissions
|
||||
var checkFn func(uint8) bool
|
||||
|
||||
switch aclInfo.targetInfo.group {
|
||||
case eacl.GroupUser:
|
||||
checkFn = aclInfo.rule.UserAllowed
|
||||
case eacl.GroupSystem:
|
||||
checkFn = aclInfo.rule.SystemAllowed
|
||||
case eacl.GroupOthers:
|
||||
checkFn = aclInfo.rule.OthersAllowed
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown request group (aclPreProcessor): %d", aclInfo.targetInfo.group))
|
||||
}
|
||||
|
||||
if requestType := req.Type(); !checkFn(requestACLSection(requestType)) ||
|
||||
aclInfo.targetInfo.ir && !allowedInnerRingRequest(requestType) {
|
||||
return errAccessDenied
|
||||
}
|
||||
|
||||
if aclInfo.targetInfo.group != eacl.GroupSystem &&
|
||||
aclInfo.rule.Sticky() &&
|
||||
!checkObjectRequestOwnerMatch(req) {
|
||||
return errAccessDenied
|
||||
}
|
||||
|
||||
if !aclInfo.checkBearer && !aclInfo.checkExtended {
|
||||
return nil
|
||||
}
|
||||
|
||||
actionParams := requestActionParams{
|
||||
eaclSrc: p.extACLSource,
|
||||
request: req,
|
||||
objHdrSrc: &requestObjHdrSrc{
|
||||
req: req,
|
||||
ls: p.localStore,
|
||||
},
|
||||
group: aclInfo.targetInfo.group,
|
||||
}
|
||||
|
||||
if aclInfo.checkBearer {
|
||||
bearer := req.GetBearerToken()
|
||||
|
||||
if err := p.bearerVerifier.verifyBearerToken(ctx, req.CID(), bearer); err != nil {
|
||||
p.log.Warn("bearer token verification failure",
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return errAccessDenied
|
||||
}
|
||||
|
||||
actionParams.eaclSrc = eaclFromBearer{
|
||||
bearer: bearer,
|
||||
}
|
||||
}
|
||||
|
||||
if p.reqActionCalc.calculateRequestAction(ctx, actionParams) != eacl.ActionAllow {
|
||||
return errAccessDenied
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *targetFinder) Target(ctx context.Context, req serviceRequest) requestTarget {
|
||||
res := requestTarget{
|
||||
group: eacl.GroupUnknown,
|
||||
}
|
||||
|
||||
ownerID, ownerKey, err := requestOwner(req)
|
||||
if err != nil {
|
||||
t.log.Warn("could not get request owner",
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return res
|
||||
} else if ownerKey == nil {
|
||||
t.log.Warn("signature with nil public key detected")
|
||||
return res
|
||||
}
|
||||
|
||||
// if request from container owner then return GroupUser
|
||||
isOwner, err := isContainerOwner(t.cnrStorage, req.CID(), ownerID)
|
||||
if err != nil {
|
||||
t.log.Warn("can't check container owner", zap.String("err", err.Error()))
|
||||
return res
|
||||
} else if isOwner {
|
||||
res.group = eacl.GroupUser
|
||||
return res
|
||||
}
|
||||
|
||||
ownerKeyBytes := crypto.MarshalPublicKey(ownerKey)
|
||||
|
||||
// if request from inner ring then return GroupSystem
|
||||
irKeyList, err := t.irKeysRecv.InnerRingKeys()
|
||||
if err != nil {
|
||||
t.log.Warn("could not verify the key belongs to the IR node", zap.String("err", err.Error()))
|
||||
return res
|
||||
}
|
||||
|
||||
for i := range irKeyList {
|
||||
if bytes.Equal(irKeyList[i], ownerKeyBytes) {
|
||||
res.group = eacl.GroupSystem
|
||||
res.ir = true
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
// if request from current container node then return GroupSystem
|
||||
cnr, err := t.cnrLister.ContainerNodesInfo(ctx, req.CID(), 0)
|
||||
if err != nil {
|
||||
t.log.Warn("can't get current container list", zap.String("err", err.Error()))
|
||||
return res
|
||||
}
|
||||
|
||||
for i := range cnr {
|
||||
if bytes.Equal(cnr[i].PublicKey(), ownerKeyBytes) {
|
||||
res.group = eacl.GroupSystem
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
// if request from previous container node then return GroupSystem
|
||||
cnr, err = t.cnrLister.ContainerNodesInfo(ctx, req.CID(), 1)
|
||||
if err != nil {
|
||||
t.log.Warn("can't get previous container list", zap.String("err", err.Error()))
|
||||
return res
|
||||
}
|
||||
|
||||
for i := range cnr {
|
||||
if bytes.Equal(cnr[i].PublicKey(), ownerKeyBytes) {
|
||||
res.group = eacl.GroupSystem
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
res.group = eacl.GroupOthers
|
||||
|
||||
// if none of the above return GroupOthers
|
||||
return res
|
||||
}
|
||||
|
||||
func checkObjectRequestOwnerMatch(req serviceRequest) bool {
|
||||
rt := req.Type()
|
||||
|
||||
// ignore all request types except Put and Delete
|
||||
if rt != object.RequestPut && rt != object.RequestDelete {
|
||||
return true
|
||||
}
|
||||
|
||||
// get request owner
|
||||
reqOwner, _, err := requestOwner(req)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var payloadOwner OwnerID
|
||||
|
||||
// get owner from request payload
|
||||
if rt == object.RequestPut {
|
||||
obj := req.(transport.PutInfo).GetHead()
|
||||
if obj == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
payloadOwner = obj.GetSystemHeader().OwnerID
|
||||
} else {
|
||||
payloadOwner = req.(*object.DeleteRequest).OwnerID
|
||||
}
|
||||
|
||||
return reqOwner.Equal(payloadOwner)
|
||||
}
|
||||
|
||||
// FIXME: this solution only works with healthy key-to-owner conversion.
|
||||
func requestOwner(req serviceRequest) (OwnerID, *ecdsa.PublicKey, error) {
|
||||
// if session token exists => return its owner
|
||||
if token := req.GetSessionToken(); token != nil {
|
||||
return token.GetOwnerID(), crypto.UnmarshalPublicKey(token.GetOwnerKey()), nil
|
||||
}
|
||||
|
||||
signKeys := req.GetSignKeyPairs()
|
||||
if len(signKeys) == 0 {
|
||||
return OwnerID{}, nil, errMissingSignatures
|
||||
}
|
||||
|
||||
firstKey := signKeys[0].GetPublicKey()
|
||||
if firstKey == nil {
|
||||
return OwnerID{}, nil, crypto.ErrEmptyPublicKey
|
||||
}
|
||||
|
||||
owner, err := refs.NewOwnerID(firstKey)
|
||||
|
||||
return owner, firstKey, err
|
||||
}
|
||||
|
||||
// HeadersOfType returns request or object headers.
|
||||
func (s serviceRequestInfo) HeadersOfType(typ eacl.HeaderType) ([]eacl.Header, bool) {
|
||||
switch typ {
|
||||
default:
|
||||
return nil, true
|
||||
case eacl.HdrTypeRequest:
|
||||
return TypedHeaderSourceFromExtendedHeaders(s.req).HeadersOfType(typ)
|
||||
case eacl.HdrTypeObjSys, eacl.HdrTypeObjUsr:
|
||||
obj, ok := s.objHdrSrc.getHeaders()
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return TypedHeaderSourceFromObject(obj).HeadersOfType(typ)
|
||||
}
|
||||
}
|
||||
|
||||
// Key returns a binary representation of sender public key.
|
||||
func (s serviceRequestInfo) Key() []byte {
|
||||
_, key, err := requestOwner(s.req)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return crypto.MarshalPublicKey(key)
|
||||
}
|
||||
|
||||
// TypeOf returns true of object request type corresponds to passed OperationType.
|
||||
func (s serviceRequestInfo) OperationType() eacl.OperationType {
|
||||
switch t := s.req.Type(); t {
|
||||
case object.RequestGet:
|
||||
return eacl.OpTypeGet
|
||||
case object.RequestPut:
|
||||
return eacl.OpTypePut
|
||||
case object.RequestHead:
|
||||
return eacl.OpTypeHead
|
||||
case object.RequestSearch:
|
||||
return eacl.OpTypeSearch
|
||||
case object.RequestDelete:
|
||||
return eacl.OpTypeDelete
|
||||
case object.RequestRange:
|
||||
return eacl.OpTypeRange
|
||||
case object.RequestRangeHash:
|
||||
return eacl.OpTypeRangeHash
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown request type (serviceRequestInfo): %d", t))
|
||||
}
|
||||
}
|
||||
|
||||
// Group returns the access group of the request.
|
||||
func (s serviceRequestInfo) Group() eacl.Group {
|
||||
return s.group
|
||||
}
|
||||
|
||||
// CID returns the container identifier of request.
|
||||
func (s serviceRequestInfo) CID() CID {
|
||||
return s.req.CID()
|
||||
}
|
||||
|
||||
func (s requestObjHdrSrc) getHeaders() (*Object, bool) {
|
||||
switch s.req.Type() {
|
||||
case object.RequestSearch:
|
||||
// object header filters is not supported in Search request now
|
||||
return nil, true
|
||||
case object.RequestPut:
|
||||
// for Put we get object headers from request
|
||||
return s.req.(transport.PutInfo).GetHead(), true
|
||||
default:
|
||||
tReq := &transportRequest{
|
||||
serviceRequest: s.req,
|
||||
}
|
||||
|
||||
// for other requests we get object headers from local storage
|
||||
m, err := s.ls.Meta(tReq.GetAddress())
|
||||
if err == nil {
|
||||
return m.GetObject(), true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
type requestActionParams struct {
|
||||
eaclSrc eaclstorage.Storage
|
||||
|
||||
request serviceRequest
|
||||
|
||||
objHdrSrc objectHeadersSource
|
||||
|
||||
group eacl.Group
|
||||
}
|
||||
|
||||
func (s reqActionCalc) calculateRequestAction(ctx context.Context, p requestActionParams) eacl.Action {
|
||||
// build eACL validator
|
||||
validator, err := eaclcheck.NewValidator(p.eaclSrc, s.log)
|
||||
if err != nil {
|
||||
s.log.Warn("could not build eacl acl validator",
|
||||
zap.String("error", err.Error()),
|
||||
)
|
||||
|
||||
return eacl.ActionUnknown
|
||||
}
|
||||
|
||||
// create RequestInfo instance
|
||||
reqInfo := &serviceRequestInfo{
|
||||
group: p.group,
|
||||
req: p.request,
|
||||
objHdrSrc: p.objHdrSrc,
|
||||
}
|
||||
|
||||
// calculate ACL action
|
||||
return validator.CalculateAction(reqInfo)
|
||||
}
|
||||
|
||||
func (s aclInfoReceiver) getACLInfo(ctx context.Context, req serviceRequest) (*aclInfo, error) {
|
||||
cnr, err := s.cnrStorage.Get(req.CID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rule := cnr.BasicACL()
|
||||
|
||||
isBearer := rule.BearerAllowed(requestACLSection(req.Type()))
|
||||
|
||||
// fetch group from the request
|
||||
t := s.targetFinder.Target(ctx, req)
|
||||
|
||||
return &aclInfo{
|
||||
rule: rule,
|
||||
|
||||
checkExtended: !rule.Final(),
|
||||
|
||||
targetInfo: t,
|
||||
|
||||
checkBearer: t.group != eacl.GroupSystem && isBearer && req.GetBearerToken() != nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s eaclFromBearer) GetEACL(cid CID) (eaclstorage.Table, error) {
|
||||
return eacl.UnmarshalTable(s.bearer.GetACLRules())
|
||||
}
|
||||
|
||||
// returns true if request of type argument is allowed for IR needs (audit).
|
||||
func allowedInnerRingRequest(t object.RequestType) (res bool) {
|
||||
switch t {
|
||||
case
|
||||
object.RequestSearch,
|
||||
object.RequestHead,
|
||||
object.RequestRangeHash:
|
||||
res = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// returns the index number of request section bits.
|
||||
func requestACLSection(t object.RequestType) uint8 {
|
||||
switch t {
|
||||
case object.RequestRangeHash:
|
||||
return 0
|
||||
case object.RequestRange:
|
||||
return 1
|
||||
case object.RequestSearch:
|
||||
return 2
|
||||
case object.RequestDelete:
|
||||
return 3
|
||||
case object.RequestPut:
|
||||
return 4
|
||||
case object.RequestHead:
|
||||
return 5
|
||||
case object.RequestGet:
|
||||
return 6
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown request type (requestACLSection): %d", t))
|
||||
}
|
||||
}
|
||||
|
||||
type objectHeaderSource struct {
|
||||
obj *Object
|
||||
}
|
||||
|
||||
type typedHeader struct {
|
||||
n string
|
||||
v string
|
||||
t eacl.HeaderType
|
||||
}
|
||||
|
||||
type extendedHeadersWrapper struct {
|
||||
hdrSrc service.ExtendedHeadersSource
|
||||
}
|
||||
|
||||
type typedExtendedHeader struct {
|
||||
hdr service.ExtendedHeader
|
||||
}
|
||||
|
||||
func newTypedObjSysHdr(name, value string) eacl.TypedHeader {
|
||||
return &typedHeader{
|
||||
n: name,
|
||||
v: value,
|
||||
t: eacl.HdrTypeObjSys,
|
||||
}
|
||||
}
|
||||
|
||||
// Name is a name field getter.
|
||||
func (s typedHeader) Name() string {
|
||||
return s.n
|
||||
}
|
||||
|
||||
// Value is a value field getter.
|
||||
func (s typedHeader) Value() string {
|
||||
return s.v
|
||||
}
|
||||
|
||||
// HeaderType is a type field getter.
|
||||
func (s typedHeader) HeaderType() eacl.HeaderType {
|
||||
return s.t
|
||||
}
|
||||
|
||||
// TypedHeaderSourceFromObject wraps passed object and returns TypedHeaderSource interface.
|
||||
func TypedHeaderSourceFromObject(obj *object.Object) extended.TypedHeaderSource {
|
||||
return &objectHeaderSource{
|
||||
obj: obj,
|
||||
}
|
||||
}
|
||||
|
||||
// HeaderOfType gathers object headers of passed type and returns Header list.
|
||||
//
|
||||
// If value of some header can not be calculated (e.g. nil eacl header), it does not appear in list.
|
||||
//
|
||||
// Always returns true.
|
||||
func (s objectHeaderSource) HeadersOfType(typ eacl.HeaderType) ([]eacl.Header, bool) {
|
||||
if s.obj == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
var res []eacl.Header
|
||||
|
||||
switch typ {
|
||||
case eacl.HdrTypeObjUsr:
|
||||
objHeaders := s.obj.GetHeaders()
|
||||
|
||||
res = make([]eacl.Header, 0, len(objHeaders)) // 7 system header fields
|
||||
|
||||
for i := range objHeaders {
|
||||
if h := newTypedObjectExtendedHeader(objHeaders[i]); h != nil {
|
||||
res = append(res, h)
|
||||
}
|
||||
}
|
||||
case eacl.HdrTypeObjSys:
|
||||
res = make([]eacl.Header, 0, 7)
|
||||
|
||||
sysHdr := s.obj.GetSystemHeader()
|
||||
|
||||
created := sysHdr.GetCreatedAt()
|
||||
|
||||
res = append(res,
|
||||
// ID
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNameID,
|
||||
sysHdr.ID.String(),
|
||||
),
|
||||
|
||||
// CID
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNameCID,
|
||||
sysHdr.CID.String(),
|
||||
),
|
||||
|
||||
// OwnerID
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNameOwnerID,
|
||||
sysHdr.OwnerID.String(),
|
||||
),
|
||||
|
||||
// Version
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNameVersion,
|
||||
strconv.FormatUint(sysHdr.GetVersion(), 10),
|
||||
),
|
||||
|
||||
// PayloadLength
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNamePayloadLength,
|
||||
strconv.FormatUint(sysHdr.GetPayloadLength(), 10),
|
||||
),
|
||||
|
||||
// CreatedAt.UnitTime
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNameCreatedUnix,
|
||||
strconv.FormatUint(uint64(created.GetUnixTime()), 10),
|
||||
),
|
||||
|
||||
// CreatedAt.Epoch
|
||||
newTypedObjSysHdr(
|
||||
eacl.HdrObjSysNameCreatedEpoch,
|
||||
strconv.FormatUint(created.GetEpoch(), 10),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
func newTypedObjectExtendedHeader(h object.Header) eacl.TypedHeader {
|
||||
val := h.GetValue()
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res := new(typedHeader)
|
||||
res.t = eacl.HdrTypeObjSys
|
||||
|
||||
switch hdr := val.(type) {
|
||||
case *object.Header_UserHeader:
|
||||
if hdr.UserHeader == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
res.t = eacl.HdrTypeObjUsr
|
||||
res.n = hdr.UserHeader.GetKey()
|
||||
res.v = hdr.UserHeader.GetValue()
|
||||
case *object.Header_Link:
|
||||
if hdr.Link == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch hdr.Link.GetType() {
|
||||
case object.Link_Previous:
|
||||
res.n = eacl.HdrObjSysLinkPrev
|
||||
case object.Link_Next:
|
||||
res.n = eacl.HdrObjSysLinkNext
|
||||
case object.Link_Child:
|
||||
res.n = eacl.HdrObjSysLinkChild
|
||||
case object.Link_Parent:
|
||||
res.n = eacl.HdrObjSysLinkPar
|
||||
case object.Link_StorageGroup:
|
||||
res.n = eacl.HdrObjSysLinkSG
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
res.v = hdr.Link.ID.String()
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// TypedHeaderSourceFromExtendedHeaders wraps passed ExtendedHeadersSource and returns TypedHeaderSource interface.
|
||||
func TypedHeaderSourceFromExtendedHeaders(hdrSrc service.ExtendedHeadersSource) extended.TypedHeaderSource {
|
||||
return &extendedHeadersWrapper{
|
||||
hdrSrc: hdrSrc,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the result of Key method.
|
||||
func (s typedExtendedHeader) Name() string {
|
||||
return s.hdr.Key()
|
||||
}
|
||||
|
||||
// Value returns the result of Value method.
|
||||
func (s typedExtendedHeader) Value() string {
|
||||
return s.hdr.Value()
|
||||
}
|
||||
|
||||
// HeaderType always returns HdrTypeRequest.
|
||||
func (s typedExtendedHeader) HeaderType() eacl.HeaderType {
|
||||
return eacl.HdrTypeRequest
|
||||
}
|
||||
|
||||
// TypedHeaders gathers eacl request headers and returns TypedHeader list.
|
||||
//
|
||||
// Nil headers are ignored.
|
||||
//
|
||||
// Always returns true.
|
||||
func (s extendedHeadersWrapper) HeadersOfType(typ eacl.HeaderType) ([]eacl.Header, bool) {
|
||||
if s.hdrSrc == nil {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
var res []eacl.Header
|
||||
|
||||
if typ == eacl.HdrTypeRequest {
|
||||
hs := s.hdrSrc.ExtendedHeaders()
|
||||
|
||||
res = make([]eacl.Header, 0, len(hs))
|
||||
|
||||
for i := range hs {
|
||||
if hs[i] == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
res = append(res, &typedExtendedHeader{
|
||||
hdr: hs[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return res, true
|
||||
}
|
||||
|
||||
func isContainerOwner(storage storage.Storage, cid CID, ownerID OwnerID) (bool, error) {
|
||||
cnr, err := storage.Get(cid)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return cnr.OwnerID().Equal(ownerID), nil
|
||||
}
|
|
@ -1,575 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
eacl "github.com/nspcc-dev/neofs-api-go/acl/extended"
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/nspcc-dev/neofs-api-go/object"
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
libcnr "github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/acl/basic"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
testlogger "github.com/nspcc-dev/neofs-node/pkg/util/logger/test"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type (
|
||||
testACLEntity struct {
|
||||
// Set of interfaces which testCommonEntity must implement, but some methods from those does not call.
|
||||
serviceRequest
|
||||
RequestTargeter
|
||||
eacl.Table
|
||||
storage.Storage
|
||||
containerNodesLister
|
||||
|
||||
// Argument interceptor. Used for ascertain of correct parameter passage between components.
|
||||
f func(...interface{})
|
||||
// Mocked result of any interface.
|
||||
res interface{}
|
||||
// Mocked error of any interface.
|
||||
err error
|
||||
}
|
||||
)
|
||||
|
||||
type testBasicChecker struct {
|
||||
actionErr error
|
||||
action bool
|
||||
|
||||
sticky bool
|
||||
|
||||
extended bool
|
||||
|
||||
bearer bool
|
||||
}
|
||||
|
||||
func (t *testACLEntity) Get(cid storage.CID) (*storage.Container, error) {
|
||||
if t.err != nil {
|
||||
return nil, t.err
|
||||
}
|
||||
|
||||
return t.res.(*storage.Container), nil
|
||||
}
|
||||
|
||||
func (t *testACLEntity) calculateRequestAction(context.Context, requestActionParams) eacl.Action {
|
||||
return t.res.(eacl.Action)
|
||||
}
|
||||
|
||||
func (t *testACLEntity) GetBasicACL(context.Context, CID) (libcnr.BasicACL, error) {
|
||||
if t.err != nil {
|
||||
return 0, t.err
|
||||
}
|
||||
|
||||
return t.res.(libcnr.BasicACL), nil
|
||||
}
|
||||
|
||||
func (t *testACLEntity) Target(context.Context, serviceRequest) requestTarget {
|
||||
return t.res.(requestTarget)
|
||||
}
|
||||
|
||||
func (t *testACLEntity) CID() CID { return CID{} }
|
||||
|
||||
func (t *testACLEntity) Type() object.RequestType { return t.res.(object.RequestType) }
|
||||
|
||||
func (t *testACLEntity) GetBearerToken() service.BearerToken { return nil }
|
||||
|
||||
func (t *testACLEntity) GetOwner() (*ecdsa.PublicKey, error) {
|
||||
if t.err != nil {
|
||||
return nil, t.err
|
||||
}
|
||||
|
||||
return t.res.(*ecdsa.PublicKey), nil
|
||||
}
|
||||
|
||||
func (t testACLEntity) InnerRingKeys() ([][]byte, error) {
|
||||
if t.err != nil {
|
||||
return nil, t.err
|
||||
}
|
||||
|
||||
return t.res.([][]byte), nil
|
||||
}
|
||||
|
||||
func (t *testACLEntity) ContainerNodesInfo(ctx context.Context, cid CID, prev int) ([]netmap.Info, error) {
|
||||
if t.err != nil {
|
||||
return nil, t.err
|
||||
}
|
||||
|
||||
return t.res.([][]netmap.Info)[prev], nil
|
||||
}
|
||||
|
||||
func (t testACLEntity) GetSignKeyPairs() []service.SignKeyPair {
|
||||
if t.res == nil {
|
||||
return nil
|
||||
}
|
||||
return t.res.([]service.SignKeyPair)
|
||||
}
|
||||
|
||||
func TestPreprocessor(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
t.Run("empty request", func(t *testing.T) {
|
||||
require.PanicsWithValue(t, pmEmptyServiceRequest, func() {
|
||||
_ = new(aclPreProcessor).preProcess(ctx, nil)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("everything is okay", func(t *testing.T) {
|
||||
var rule basic.ACL
|
||||
rule.SetFinal()
|
||||
rule.AllowOthers(requestACLSection(object.RequestGet))
|
||||
|
||||
cnr := new(storage.Container)
|
||||
cnr.SetBasicACL(rule)
|
||||
|
||||
reqTarget := requestTarget{
|
||||
group: eacl.GroupOthers,
|
||||
}
|
||||
|
||||
preprocessor := aclPreProcessor{
|
||||
log: testlogger.NewLogger(false),
|
||||
aclInfoReceiver: aclInfoReceiver{
|
||||
cnrStorage: &testACLEntity{
|
||||
res: cnr,
|
||||
},
|
||||
targetFinder: &testACLEntity{res: reqTarget},
|
||||
},
|
||||
}
|
||||
require.NoError(t, preprocessor.preProcess(ctx, &testACLEntity{res: object.RequestGet}))
|
||||
|
||||
reqTarget.group = eacl.GroupSystem
|
||||
preprocessor.aclInfoReceiver.targetFinder = &testACLEntity{res: reqTarget}
|
||||
require.NoError(t, preprocessor.preProcess(ctx, &testACLEntity{res: object.RequestGet}))
|
||||
|
||||
reqTarget.group = eacl.GroupUser
|
||||
preprocessor.aclInfoReceiver.targetFinder = &testACLEntity{res: reqTarget}
|
||||
require.Error(t, preprocessor.preProcess(ctx, &testACLEntity{res: object.RequestGet}))
|
||||
})
|
||||
|
||||
t.Run("can't fetch container", func(t *testing.T) {
|
||||
preprocessor := aclPreProcessor{
|
||||
log: testlogger.NewLogger(false),
|
||||
aclInfoReceiver: aclInfoReceiver{
|
||||
cnrStorage: &testACLEntity{err: container.ErrNotFound},
|
||||
targetFinder: &testACLEntity{res: requestTarget{
|
||||
group: eacl.GroupOthers,
|
||||
}},
|
||||
},
|
||||
}
|
||||
require.Error(t, preprocessor.preProcess(ctx, &testACLEntity{res: object.RequestGet}))
|
||||
|
||||
})
|
||||
|
||||
t.Run("sticky bit", func(t *testing.T) {
|
||||
var rule basic.ACL
|
||||
rule.SetSticky()
|
||||
rule.SetFinal()
|
||||
for i := uint8(0); i < 7; i++ {
|
||||
rule.AllowUser(i)
|
||||
}
|
||||
|
||||
cnr := new(storage.Container)
|
||||
cnr.SetBasicACL(rule)
|
||||
|
||||
s := &aclPreProcessor{
|
||||
log: testlogger.NewLogger(false),
|
||||
aclInfoReceiver: aclInfoReceiver{
|
||||
cnrStorage: &testACLEntity{
|
||||
res: cnr,
|
||||
},
|
||||
targetFinder: &testACLEntity{
|
||||
res: requestTarget{
|
||||
group: eacl.GroupUser,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ownerKey := &test.DecodeKey(0).PublicKey
|
||||
|
||||
ownerID, err := refs.NewOwnerID(ownerKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
okItems := []func() []serviceRequest{
|
||||
// Read requests
|
||||
func() []serviceRequest {
|
||||
return []serviceRequest{
|
||||
new(object.GetRequest),
|
||||
new(object.HeadRequest),
|
||||
new(object.SearchRequest),
|
||||
new(GetRangeRequest),
|
||||
new(object.GetRangeHashRequest),
|
||||
}
|
||||
},
|
||||
// PutRequest / DeleteRequest (w/o token)
|
||||
func() []serviceRequest {
|
||||
req := object.MakePutRequestHeader(&Object{
|
||||
SystemHeader: SystemHeader{
|
||||
OwnerID: ownerID,
|
||||
},
|
||||
})
|
||||
req.AddSignKey(nil, ownerKey)
|
||||
putReq := &putRequest{
|
||||
PutRequest: req,
|
||||
}
|
||||
|
||||
delReq := new(object.DeleteRequest)
|
||||
delReq.OwnerID = ownerID
|
||||
delReq.AddSignKey(nil, ownerKey)
|
||||
|
||||
return []serviceRequest{putReq, delReq}
|
||||
},
|
||||
// PutRequest / DeleteRequest (w/ token)
|
||||
func() []serviceRequest {
|
||||
token := new(service.Token)
|
||||
token.SetOwnerID(ownerID)
|
||||
token.SetOwnerKey(crypto.MarshalPublicKey(ownerKey))
|
||||
|
||||
req := object.MakePutRequestHeader(&Object{
|
||||
SystemHeader: SystemHeader{
|
||||
OwnerID: ownerID,
|
||||
},
|
||||
})
|
||||
req.SetToken(token)
|
||||
putReq := &putRequest{
|
||||
PutRequest: req,
|
||||
}
|
||||
|
||||
delReq := new(object.DeleteRequest)
|
||||
delReq.OwnerID = ownerID
|
||||
delReq.SetToken(token)
|
||||
|
||||
return []serviceRequest{putReq, delReq}
|
||||
},
|
||||
}
|
||||
|
||||
failItems := []func() []serviceRequest{
|
||||
// PutRequest / DeleteRequest (w/o token and wrong owner)
|
||||
func() []serviceRequest {
|
||||
otherOwner := ownerID
|
||||
otherOwner[0]++
|
||||
|
||||
req := object.MakePutRequestHeader(&Object{
|
||||
SystemHeader: SystemHeader{
|
||||
OwnerID: otherOwner,
|
||||
},
|
||||
})
|
||||
req.AddSignKey(nil, ownerKey)
|
||||
putReq := &putRequest{
|
||||
PutRequest: req,
|
||||
}
|
||||
|
||||
delReq := new(object.DeleteRequest)
|
||||
delReq.OwnerID = otherOwner
|
||||
delReq.AddSignKey(nil, ownerKey)
|
||||
|
||||
return []serviceRequest{putReq, delReq}
|
||||
},
|
||||
// PutRequest / DeleteRequest (w/ token w/ wrong owner)
|
||||
func() []serviceRequest {
|
||||
otherOwner := ownerID
|
||||
otherOwner[0]++
|
||||
|
||||
token := new(service.Token)
|
||||
token.SetOwnerID(ownerID)
|
||||
token.SetOwnerKey(crypto.MarshalPublicKey(ownerKey))
|
||||
|
||||
req := object.MakePutRequestHeader(&Object{
|
||||
SystemHeader: SystemHeader{
|
||||
OwnerID: otherOwner,
|
||||
},
|
||||
})
|
||||
req.SetToken(token)
|
||||
putReq := &putRequest{
|
||||
PutRequest: req,
|
||||
}
|
||||
|
||||
delReq := new(object.DeleteRequest)
|
||||
delReq.OwnerID = otherOwner
|
||||
delReq.SetToken(token)
|
||||
|
||||
return []serviceRequest{putReq, delReq}
|
||||
},
|
||||
}
|
||||
|
||||
for _, ok := range okItems {
|
||||
for _, req := range ok() {
|
||||
require.NoError(t, s.preProcess(ctx, req))
|
||||
}
|
||||
}
|
||||
|
||||
for _, fail := range failItems {
|
||||
for _, req := range fail() {
|
||||
require.Error(t, s.preProcess(ctx, req))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("eacl ACL", func(t *testing.T) {
|
||||
target := requestTarget{
|
||||
group: eacl.GroupOthers,
|
||||
}
|
||||
|
||||
req := &testACLEntity{
|
||||
res: object.RequestGet,
|
||||
}
|
||||
|
||||
actCalc := new(testACLEntity)
|
||||
|
||||
var rule basic.ACL
|
||||
rule.AllowOthers(requestACLSection(object.RequestGet))
|
||||
|
||||
cnr := new(storage.Container)
|
||||
cnr.SetBasicACL(rule)
|
||||
|
||||
s := &aclPreProcessor{
|
||||
log: testlogger.NewLogger(false),
|
||||
aclInfoReceiver: aclInfoReceiver{
|
||||
cnrStorage: &testACLEntity{
|
||||
res: cnr,
|
||||
},
|
||||
targetFinder: &testACLEntity{
|
||||
res: target,
|
||||
},
|
||||
},
|
||||
|
||||
reqActionCalc: actCalc,
|
||||
}
|
||||
|
||||
// force to return non-ActionAllow
|
||||
actCalc.res = eacl.ActionAllow + 1
|
||||
require.EqualError(t, s.preProcess(ctx, req), errAccessDenied.Error())
|
||||
|
||||
// force to return ActionAllow
|
||||
actCalc.res = eacl.ActionAllow
|
||||
require.NoError(t, s.preProcess(ctx, req))
|
||||
})
|
||||
|
||||
t.Run("inner ring group", func(t *testing.T) {
|
||||
reqTarget := requestTarget{
|
||||
group: eacl.GroupSystem,
|
||||
ir: true,
|
||||
}
|
||||
|
||||
cnr := new(storage.Container)
|
||||
cnr.SetBasicACL(basic.FromUint32(^uint32(0)))
|
||||
|
||||
preprocessor := aclPreProcessor{
|
||||
log: testlogger.NewLogger(false),
|
||||
aclInfoReceiver: aclInfoReceiver{
|
||||
cnrStorage: &testACLEntity{res: cnr},
|
||||
targetFinder: &testACLEntity{res: reqTarget},
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range []object.RequestType{
|
||||
object.RequestSearch,
|
||||
object.RequestHead,
|
||||
object.RequestRangeHash,
|
||||
} {
|
||||
require.NoError(t,
|
||||
preprocessor.preProcess(ctx, &testACLEntity{
|
||||
res: rt,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
for _, rt := range []object.RequestType{
|
||||
object.RequestRange,
|
||||
object.RequestPut,
|
||||
object.RequestDelete,
|
||||
object.RequestGet,
|
||||
} {
|
||||
require.EqualError(t,
|
||||
preprocessor.preProcess(ctx, &testACLEntity{
|
||||
res: rt,
|
||||
}),
|
||||
errAccessDenied.Error(),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestTargetFinder(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
irKey := test.DecodeKey(2)
|
||||
containerKey := test.DecodeKey(3)
|
||||
prevContainerKey := test.DecodeKey(4)
|
||||
|
||||
var infoList1 []netmap.Info
|
||||
info := netmap.Info{}
|
||||
info.SetPublicKey(crypto.MarshalPublicKey(&containerKey.PublicKey))
|
||||
infoList1 = append(infoList1, info)
|
||||
|
||||
var infoList2 []netmap.Info
|
||||
info.SetPublicKey(crypto.MarshalPublicKey(&prevContainerKey.PublicKey))
|
||||
infoList2 = append(infoList2, info)
|
||||
|
||||
finder := &targetFinder{
|
||||
log: testlogger.NewLogger(false),
|
||||
irKeysRecv: &testACLEntity{
|
||||
res: [][]byte{crypto.MarshalPublicKey(&irKey.PublicKey)},
|
||||
},
|
||||
cnrLister: &testACLEntity{res: [][]netmap.Info{
|
||||
infoList1,
|
||||
infoList2,
|
||||
}},
|
||||
}
|
||||
|
||||
t.Run("trusted node", func(t *testing.T) {
|
||||
|
||||
pk := &test.DecodeKey(0).PublicKey
|
||||
|
||||
ownerKey := &test.DecodeKey(1).PublicKey
|
||||
owner, err := refs.NewOwnerID(ownerKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
token := new(service.Token)
|
||||
token.SetSessionKey(crypto.MarshalPublicKey(pk))
|
||||
token.SetOwnerKey(crypto.MarshalPublicKey(ownerKey))
|
||||
token.SetOwnerID(owner)
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.ContainerID = CID{1, 2, 3}
|
||||
req.SetToken(token)
|
||||
req.AddSignKey(nil, pk)
|
||||
|
||||
cnr := new(storage.Container)
|
||||
cnr.SetOwnerID(owner)
|
||||
|
||||
finder.cnrStorage = &testACLEntity{
|
||||
res: cnr,
|
||||
}
|
||||
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupUser,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("container owner", func(t *testing.T) {
|
||||
key := &test.DecodeKey(0).PublicKey
|
||||
owner, err := refs.NewOwnerID(key)
|
||||
require.NoError(t, err)
|
||||
|
||||
cnr := new(storage.Container)
|
||||
cnr.SetOwnerID(owner)
|
||||
|
||||
finder.cnrStorage = &testACLEntity{res: cnr}
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.AddSignKey(nil, key)
|
||||
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupUser,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("system owner", func(t *testing.T) {
|
||||
finder.cnrStorage = &testACLEntity{res: new(storage.Container)}
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &irKey.PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupSystem,
|
||||
ir: true,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
|
||||
req = new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &containerKey.PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupSystem,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
|
||||
req = new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &prevContainerKey.PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupSystem,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("other owner", func(t *testing.T) {
|
||||
finder.cnrStorage = &testACLEntity{res: new(storage.Container)}
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &test.DecodeKey(0).PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupOthers,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("can't fetch request owner", func(t *testing.T) {
|
||||
req := new(object.SearchRequest)
|
||||
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupUnknown,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("can't fetch container", func(t *testing.T) {
|
||||
finder.cnrStorage = &testACLEntity{err: container.ErrNotFound}
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &test.DecodeKey(0).PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupUnknown,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("can't fetch ir list", func(t *testing.T) {
|
||||
finder.cnrStorage = &testACLEntity{res: new(storage.Container)}
|
||||
finder.irKeysRecv = &testACLEntity{err: errors.New("blockchain is busy")}
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &test.DecodeKey(0).PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupUnknown,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("can't fetch container list", func(t *testing.T) {
|
||||
finder.cnrStorage = &testACLEntity{res: new(storage.Container)}
|
||||
finder.cnrLister = &testACLEntity{err: container.ErrNotFound}
|
||||
|
||||
req := new(object.SearchRequest)
|
||||
req.AddSignKey(nil, &test.DecodeKey(0).PublicKey)
|
||||
require.Equal(t,
|
||||
requestTarget{
|
||||
group: eacl.GroupUnknown,
|
||||
},
|
||||
finder.Target(ctx, req),
|
||||
)
|
||||
})
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/service"
|
||||
crypto "github.com/nspcc-dev/neofs-crypto"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container/storage"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type bearerTokenVerifier interface {
|
||||
verifyBearerToken(context.Context, CID, service.BearerToken) error
|
||||
}
|
||||
|
||||
type complexBearerVerifier struct {
|
||||
items []bearerTokenVerifier
|
||||
}
|
||||
|
||||
type bearerActualityVerifier struct {
|
||||
epochRecv EpochReceiver
|
||||
}
|
||||
|
||||
type bearerOwnershipVerifier struct {
|
||||
cnrStorage storage.Storage
|
||||
}
|
||||
|
||||
type bearerSignatureVerifier struct{}
|
||||
|
||||
var errWrongBearerOwner = errors.New("bearer author is not a container owner")
|
||||
|
||||
func (s complexBearerVerifier) verifyBearerToken(ctx context.Context, cid CID, token service.BearerToken) error {
|
||||
for i := range s.items {
|
||||
if err := s.items[i].verifyBearerToken(ctx, cid, token); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s bearerActualityVerifier) verifyBearerToken(_ context.Context, _ CID, token service.BearerToken) error {
|
||||
local := s.epochRecv.Epoch()
|
||||
validUntil := token.ExpirationEpoch()
|
||||
|
||||
if local > validUntil {
|
||||
return errors.Errorf("bearer token is expired (local %d, valid until %d)",
|
||||
local,
|
||||
validUntil,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s bearerOwnershipVerifier) verifyBearerToken(ctx context.Context, cid CID, token service.BearerToken) error {
|
||||
isOwner, err := isContainerOwner(s.cnrStorage, cid, token.GetOwnerID())
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !isOwner {
|
||||
return errWrongBearerOwner
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s bearerSignatureVerifier) verifyBearerToken(_ context.Context, _ CID, token service.BearerToken) error {
|
||||
return service.VerifySignatureWithKey(
|
||||
crypto.UnmarshalPublicKey(token.GetOwnerKey()),
|
||||
service.NewVerifiedBearerToken(token),
|
||||
)
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package object
|
||||
|
||||
func (s *objectService) RelativeAvailableCap() float64 {
|
||||
diff := float64(s.ls.Size()) / float64(s.storageCap)
|
||||
if 1-diff < 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return 1 - diff
|
||||
}
|
||||
|
||||
func (s *objectService) AbsoluteAvailableCap() uint64 {
|
||||
localSize := uint64(s.ls.Size())
|
||||
if localSize > s.storageCap {
|
||||
return 0
|
||||
}
|
||||
|
||||
return s.storageCap - localSize
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue