Merge branch 'release/1.3.0'

This commit is contained in:
Leonard Lyubich 2020-07-23 17:59:24 +03:00
commit 64c941ae06
24 changed files with 1291 additions and 1085 deletions

View file

@ -1,6 +1,14 @@
# Changelog
This is the changelog for NeoFS-API-Go
## [1.3.0] - 2020-07-23
### Changed
- Format of ```refs.OwnerID``` based on NEO3.
- Binary format of extended ACL table.
- ```acl``` package structure.
## [1.2.0] - 2020-07-08
### Added
@ -375,3 +383,4 @@ Initial public release
[1.0.0]: https://github.com/nspcc-dev/neofs-api-go/compare/v0.7.6...v1.0.0
[1.1.0]: https://github.com/nspcc-dev/neofs-api-go/compare/v1.0.0...v1.1.0
[1.2.0]: https://github.com/nspcc-dev/neofs-api-go/compare/v1.1.0...v1.2.0
[1.3.0]: https://github.com/nspcc-dev/neofs-api-go/compare/v1.2.0...v1.3.0

View file

@ -21,6 +21,9 @@ can be used for integration with NeoFS.
[neofs-api-go v1.2.0]: https://github.com/nspcc-dev/neofs-api-go/releases/tag/v1.2.0
* [neofs-api-go v1.2.0] supports [neofs-api v1.2.0]
[neofs-api-go v1.3.0]: https://github.com/nspcc-dev/neofs-api-go/releases/tag/v1.3.0
* [neofs-api-go v1.3.0] supports [neofs-api v1.2.0]
## Description
Repository contains 13 packages that implement NeoFS core structures. These

126
acl/extended/enum.go Normal file
View file

@ -0,0 +1,126 @@
package eacl
const (
// MatchUnknown is a MatchType value used to mark value as undefined.
// Most of the tools consider MatchUnknown as incalculable.
// Using MatchUnknown in HeaderFilter is unsafe.
MatchUnknown MatchType = iota
// StringEqual is a MatchType of string equality.
StringEqual
// StringNotEqual is a MatchType of string inequality.
StringNotEqual
)
const (
// ActionUnknown is Action used to mark value as undefined.
// Most of the tools consider ActionUnknown as incalculable.
// Using ActionUnknown in Record is unsafe.
ActionUnknown Action = iota
// ActionAllow is Action used to mark an applicability of ACL rule.
ActionAllow
// ActionDeny is Action used to mark an inapplicability of ACL rule.
ActionDeny
)
const (
// GroupUnknown is a Group value used to mark value as undefined.
// Most of the tools consider GroupUnknown as incalculable.
// Using GroupUnknown in Target is unsafe.
GroupUnknown Group = iota
// GroupUser is a Group value for User access group.
GroupUser
// GroupSystem is a Group value for System access group.
GroupSystem
// GroupOthers is a Group value for Others access group.
GroupOthers
)
const (
// HdrTypeUnknown is a HeaderType value used to mark value as undefined.
// Most of the tools consider HdrTypeUnknown as incalculable.
// Using HdrTypeUnknown in HeaderFilter is unsafe.
HdrTypeUnknown HeaderType = iota
// HdrTypeRequest is a HeaderType for request header.
HdrTypeRequest
// HdrTypeObjSys is a HeaderType for system headers of object.
HdrTypeObjSys
// HdrTypeObjUsr is a HeaderType for user headers of object.
HdrTypeObjUsr
)
const (
// OpTypeUnknown is a OperationType value used to mark value as undefined.
// Most of the tools consider OpTypeUnknown as incalculable.
// Using OpTypeUnknown in Record is unsafe.
OpTypeUnknown OperationType = iota
// OpTypeGet is an OperationType for object.Get RPC
OpTypeGet
// OpTypePut is an OperationType for object.Put RPC
OpTypePut
// OpTypeHead is an OperationType for object.Head RPC
OpTypeHead
// OpTypeSearch is an OperationType for object.Search RPC
OpTypeSearch
// OpTypeDelete is an OperationType for object.Delete RPC
OpTypeDelete
// OpTypeRange is an OperationType for object.GetRange RPC
OpTypeRange
// OpTypeRangeHash is an OperationType for object.GetRangeHash RPC
OpTypeRangeHash
)
const (
// HdrObjSysNameID is a name of ID field in system header of object.
HdrObjSysNameID = "ID"
// HdrObjSysNameCID is a name of CID field in system header of object.
HdrObjSysNameCID = "CID"
// HdrObjSysNameOwnerID is a name of OwnerID field in system header of object.
HdrObjSysNameOwnerID = "OWNER_ID"
// HdrObjSysNameVersion is a name of Version field in system header of object.
HdrObjSysNameVersion = "VERSION"
// HdrObjSysNamePayloadLength is a name of PayloadLength field in system header of object.
HdrObjSysNamePayloadLength = "PAYLOAD_LENGTH"
// HdrObjSysNameCreatedUnix is a name of CreatedAt.UnitTime field in system header of object.
HdrObjSysNameCreatedUnix = "CREATED_UNIX"
// HdrObjSysNameCreatedEpoch is a name of CreatedAt.Epoch field in system header of object.
HdrObjSysNameCreatedEpoch = "CREATED_EPOCH"
// HdrObjSysLinkPrev is a name of previous link header in extended headers of object.
HdrObjSysLinkPrev = "LINK_PREV"
// HdrObjSysLinkNext is a name of next link header in extended headers of object.
HdrObjSysLinkNext = "LINK_NEXT"
// HdrObjSysLinkChild is a name of child link header in extended headers of object.
HdrObjSysLinkChild = "LINK_CHILD"
// HdrObjSysLinkPar is a name of parent link header in extended headers of object.
HdrObjSysLinkPar = "LINK_PAR"
// HdrObjSysLinkSG is a name of storage group link header in extended headers of object.
HdrObjSysLinkSG = "LINK_SG"
)

333
acl/extended/marshal.go Normal file
View file

@ -0,0 +1,333 @@
package eacl
import (
"encoding/binary"
"github.com/pkg/errors"
)
const (
sliceLenSize = 2 // uint16 for len()
actionSize = 4 // uint32
opTypeSize = 4 // uint32
hdrTypeSize = 4 // uint32
matchTypeSize = 4 // uint32
targetSize = 4 // uint32
)
// MarshalTable encodes Table into a
// binary form and returns the result.
//
// If table is nil, empty slice is returned.
func MarshalTable(table Table) []byte {
if table == nil {
return make([]byte, 0)
}
// allocate buffer
buf := make([]byte, tableBinSize(table))
records := table.Records()
// write record number
binary.BigEndian.PutUint16(buf, uint16(len(records)))
off := sliceLenSize
// write all records
for _, record := range records {
// write action
binary.BigEndian.PutUint32(buf[off:], uint32(record.Action()))
off += actionSize
// write operation type
binary.BigEndian.PutUint32(buf[off:], uint32(record.OperationType()))
off += actionSize
filters := record.HeaderFilters()
// write filter number
binary.BigEndian.PutUint16(buf[off:], uint16(len(filters)))
off += sliceLenSize
// write all filters
for _, filter := range filters {
// write header type
binary.BigEndian.PutUint32(buf[off:], uint32(filter.HeaderType()))
off += hdrTypeSize
// write match type
binary.BigEndian.PutUint32(buf[off:], uint32(filter.MatchType()))
off += matchTypeSize
// write header name size
name := []byte(filter.Name())
binary.BigEndian.PutUint16(buf[off:], uint16(len(name)))
off += sliceLenSize
// write header name bytes
off += copy(buf[off:], name)
// write header value size
val := []byte(filter.Value())
binary.BigEndian.PutUint16(buf[off:], uint16(len(val)))
off += sliceLenSize
// write header value bytes
off += copy(buf[off:], val)
}
targets := record.TargetList()
// write target number
binary.BigEndian.PutUint16(buf[off:], uint16(len(targets)))
off += sliceLenSize
// write all targets
for _, target := range targets {
// write target group
binary.BigEndian.PutUint32(buf[off:], uint32(target.Group()))
off += targetSize
keys := target.KeyList()
// write key number
binary.BigEndian.PutUint16(buf[off:], uint16(len(keys)))
off += sliceLenSize
// write keys
for i := range keys {
// write key size
binary.BigEndian.PutUint16(buf[off:], uint16(len(keys[i])))
off += sliceLenSize
// write key bytes
off += copy(buf[off:], keys[i])
}
}
}
return buf
}
// returns the size of Table in a binary format.
func tableBinSize(table Table) (sz int) {
sz = sliceLenSize // number of records
records := table.Records()
ln := len(records)
sz += ln * actionSize // action type of each record
sz += ln * opTypeSize // operation type of each record
for _, record := range records {
sz += sliceLenSize // number of filters
filters := record.HeaderFilters()
ln := len(filters)
sz += ln * hdrTypeSize // header type of each filter
sz += ln * matchTypeSize // match type of each filter
for _, filter := range filters {
sz += sliceLenSize // header name size
sz += len(filter.Name()) // header name bytes
sz += sliceLenSize // header value size
sz += len(filter.Value()) // header value bytes
}
sz += sliceLenSize // number of targets
targets := record.TargetList()
ln = len(targets)
sz += ln * targetSize // target group of each target
for _, target := range targets {
sz += sliceLenSize // number of keys
for _, key := range target.KeyList() {
sz += sliceLenSize // key size
sz += len(key) // key bytes
}
}
}
return
}
// UnmarshalTable unmarshals Table from
// a binary representation.
//
// If data is empty, table w/o records is returned.
func UnmarshalTable(data []byte) (Table, error) {
table := WrapTable(nil)
if len(data) == 0 {
return table, nil
}
// decode record number
if len(data) < sliceLenSize {
return nil, errors.New("could not decode record number")
}
recordNum := binary.BigEndian.Uint16(data)
records := make([]Record, 0, recordNum)
off := sliceLenSize
// decode all records one by one
for i := uint16(0); i < recordNum; i++ {
record := WrapRecord(nil)
// decode action
if len(data[off:]) < actionSize {
return nil, errors.Errorf("could not decode action of record #%d", i)
}
record.SetAction(Action(binary.BigEndian.Uint32(data[off:])))
off += actionSize
// decode operation type
if len(data[off:]) < opTypeSize {
return nil, errors.Errorf("could not decode operation type of record #%d", i)
}
record.SetOperationType(OperationType(binary.BigEndian.Uint32(data[off:])))
off += opTypeSize
// decode filter number
if len(data[off:]) < sliceLenSize {
return nil, errors.Errorf("could not decode filter number of record #%d", i)
}
filterNum := binary.BigEndian.Uint16(data[off:])
off += sliceLenSize
filters := make([]HeaderFilter, 0, filterNum)
// decode filters one by one
for j := uint16(0); j < filterNum; j++ {
filter := WrapFilterInfo(nil)
// decode header type
if len(data[off:]) < hdrTypeSize {
return nil, errors.Errorf("could not decode header type of filter #%d of record #%d", j, i)
}
filter.SetHeaderType(HeaderType(binary.BigEndian.Uint32(data[off:])) )
off += hdrTypeSize
// decode match type
if len(data[off:]) < matchTypeSize {
return nil, errors.Errorf("could not decode match type of filter #%d of record #%d", j, i)
}
filter.SetMatchType(MatchType(binary.BigEndian.Uint32(data[off:])) )
off += matchTypeSize
// decode header name size
if len(data[off:]) < sliceLenSize {
return nil, errors.Errorf("could not decode header name size of filter #%d of record #%d", j, i)
}
hdrNameSize := int(binary.BigEndian.Uint16(data[off:]))
off += sliceLenSize
// decode header name
if len(data[off:]) < hdrNameSize {
return nil, errors.Errorf("could not decode header name of filter #%d of record #%d", j, i)
}
filter.SetName(string(data[off : off+hdrNameSize]))
off += hdrNameSize
// decode header value size
if len(data[off:]) < sliceLenSize {
return nil, errors.Errorf("could not decode header value size of filter #%d of record #%d", j, i)
}
hdrValSize := int(binary.BigEndian.Uint16(data[off:]))
off += sliceLenSize
// decode header value
if len(data[off:]) < hdrValSize {
return nil, errors.Errorf("could not decode header value of filter #%d of record #%d", j, i)
}
filter.SetValue(string(data[off : off+hdrValSize]))
off += hdrValSize
filters = append(filters, filter)
}
record.SetHeaderFilters(filters)
// decode target number
if len(data[off:]) < sliceLenSize {
return nil, errors.Errorf("could not decode target number of record #%d", i)
}
targetNum := int(binary.BigEndian.Uint16(data[off:]))
off += sliceLenSize
targets := make([]Target, 0, targetNum)
// decode targets one by one
for j := 0; j < targetNum; j++ {
target := WrapTarget(nil)
// decode target group
if len(data[off:]) < targetSize {
return nil, errors.Errorf("could not decode target group of target #%d of record #%d", j, i)
}
target.SetGroup( Group(binary.BigEndian.Uint32(data[off:])), )
off += targetSize
// decode key number
if len(data[off:]) < sliceLenSize {
return nil, errors.Errorf("could not decode key number of target #%d of record #%d", j, i)
}
keyNum := int(binary.BigEndian.Uint16(data[off:]))
off += sliceLenSize
keys := make([][]byte, 0, keyNum)
for k := 0; k < keyNum; k++ {
// decode key size
if len(data[off:]) < sliceLenSize {
return nil, errors.Errorf("could not decode size of key #%d target #%d of record #%d", k, j, i)
}
keySz := int(binary.BigEndian.Uint16(data[off:]))
off += sliceLenSize
// decode key
if len(data[off:]) < keySz {
return nil, errors.Errorf("could not decode key #%d target #%d of record #%d", k, j, i)
}
key := make([]byte, keySz)
off += copy(key, data[off:off+keySz])
keys = append(keys, key)
}
target.SetKeyList(keys)
targets = append(targets, target)
}
record.SetTargetList(targets)
records = append(records, record)
}
table.SetRecords(records)
return table, nil
}

View file

@ -1,4 +1,4 @@
package acl
package eacl
// OperationType is an enumeration of operation types for extended ACL.
type OperationType uint32
@ -9,8 +9,11 @@ type HeaderType uint32
// MatchType is an enumeration of match types for extended ACL.
type MatchType uint32
// ExtendedACLAction is an enumeration of extended ACL actions.
type ExtendedACLAction uint32
// Action is an enumeration of extended ACL actions.
type Action uint32
// Group is an enumeration of access groups.
type Group uint32
// Header is an interface of string key-value pair,
type Header interface {
@ -37,17 +40,17 @@ type HeaderFilter interface {
TypedHeader
}
// ExtendedACLTarget is an interface of grouped information about extended ACL rule target.
type ExtendedACLTarget interface {
// Target is an interface of grouped information about extended ACL rule target.
type Target interface {
// Must return ACL target type.
Target() Target
Group() Group
// Must return public key list of ACL targets.
KeyList() [][]byte
}
// ExtendedACLRecord is an interface of record of extended ACL rule table.
type ExtendedACLRecord interface {
// Record is an interface of record of extended ACL rule table.
type Record interface {
// Must return operation type of extended ACL rule.
OperationType() OperationType
@ -55,39 +58,16 @@ type ExtendedACLRecord interface {
HeaderFilters() []HeaderFilter
// Must return target list of extended ACL rule.
TargetList() []ExtendedACLTarget
TargetList() []Target
// Must return action of extended ACL rule.
Action() ExtendedACLAction
Action() Action
}
// ExtendedACLTable is an interface of extended ACL table.
type ExtendedACLTable interface {
// Table is an interface of extended ACL table.
type Table interface {
// Must return list of extended ACL rules.
Records() []ExtendedACLRecord
Records() []Record
}
const (
_ OperationType = iota
// OpTypeGet is an OperationType for object.Get RPC
OpTypeGet
// OpTypePut is an OperationType for object.Put RPC
OpTypePut
// OpTypeHead is an OperationType for object.Head RPC
OpTypeHead
// OpTypeSearch is an OperationType for object.Search RPC
OpTypeSearch
// OpTypeDelete is an OperationType for object.Delete RPC
OpTypeDelete
// OpTypeRange is an OperationType for object.GetRange RPC
OpTypeRange
// OpTypeRangeHash is an OperationType for object.GetRangeHash RPC
OpTypeRangeHash
)

528
acl/extended/wrappers.go Normal file
View file

@ -0,0 +1,528 @@
package eacl
import (
"github.com/nspcc-dev/neofs-api-go/acl"
)
// FilterWrapper is a wrapper over acl.EACLRecord_FilterInfo pointer.
type FilterWrapper struct {
filter *acl.EACLRecord_FilterInfo
}
// TargetWrapper is a wrapper over acl.EACLRecord_TargetInfo pointer.
type TargetWrapper struct {
target *acl.EACLRecord_TargetInfo
}
// RecordWrapper is a wrapper over acl.EACLRecord pointer.
type RecordWrapper struct {
record *acl.EACLRecord
}
// TableWrapper is a wrapper over acl.EACLTable pointer.
type TableWrapper struct {
table *acl.EACLTable
}
// WrapFilterInfo wraps EACLRecord_FilterInfo pointer.
//
// If argument is nil, new EACLRecord_FilterInfo is initialized.
func WrapFilterInfo(v *acl.EACLRecord_FilterInfo) FilterWrapper {
if v == nil {
v = new(acl.EACLRecord_FilterInfo)
}
return FilterWrapper{
filter: v,
}
}
// WrapTarget wraps EACLRecord_TargetInfo pointer.
//
// If argument is nil, new EACLRecord_TargetInfo is initialized.
func WrapTarget(v *acl.EACLRecord_TargetInfo) TargetWrapper {
if v == nil {
v = new(acl.EACLRecord_TargetInfo)
}
return TargetWrapper{
target: v,
}
}
// WrapRecord wraps EACLRecord pointer.
//
// If argument is nil, new EACLRecord is initialized.
func WrapRecord(v *acl.EACLRecord) RecordWrapper {
if v == nil {
v = new(acl.EACLRecord)
}
return RecordWrapper{
record: v,
}
}
// WrapTable wraps EACLTable pointer.
//
// If argument is nil, new EACLTable is initialized.
func WrapTable(v *acl.EACLTable) TableWrapper {
if v == nil {
v = new(acl.EACLTable)
}
return TableWrapper{
table: v,
}
}
// MatchType returns the match type of the filter.
//
// If filter is not initialized, 0 returns.
//
// Returns 0 if MatchType is not one of:
// - EACLRecord_FilterInfo_StringEqual;
// - EACLRecord_FilterInfo_StringNotEqual.
func (s FilterWrapper) MatchType() (res MatchType) {
if s.filter != nil {
switch s.filter.GetMatchType() {
case acl.EACLRecord_FilterInfo_StringEqual:
res = StringEqual
case acl.EACLRecord_FilterInfo_StringNotEqual:
res = StringNotEqual
}
}
return
}
// SetMatchType sets the match type of the filter.
//
// If filter is not initialized, nothing changes.
//
// MatchType is set to EACLRecord_FilterInfo_MatchUnknown if argument is not one of:
// - StringEqual;
// - StringNotEqual.
func (s FilterWrapper) SetMatchType(v MatchType) {
if s.filter != nil {
switch v {
case StringEqual:
s.filter.SetMatchType(acl.EACLRecord_FilterInfo_StringEqual)
case StringNotEqual:
s.filter.SetMatchType(acl.EACLRecord_FilterInfo_StringNotEqual)
default:
s.filter.SetMatchType(acl.EACLRecord_FilterInfo_MatchUnknown)
}
}
}
// Name returns the name of filtering header.
//
// If filter is not initialized, empty string returns.
func (s FilterWrapper) Name() string {
if s.filter == nil {
return ""
}
return s.filter.GetHeaderName()
}
// SetName sets the name of the filtering header.
//
// If filter is not initialized, nothing changes.
func (s FilterWrapper) SetName(v string) {
if s.filter != nil {
s.filter.SetHeaderName(v)
}
}
// Value returns the value of filtering header.
//
// If filter is not initialized, empty string returns.
func (s FilterWrapper) Value() string {
if s.filter == nil {
return ""
}
return s.filter.GetHeaderVal()
}
// SetValue sets the value of filtering header.
//
// If filter is not initialized, nothing changes.
func (s FilterWrapper) SetValue(v string) {
if s.filter != nil {
s.filter.SetHeaderVal(v)
}
}
// HeaderType returns the header type of the filter.
//
// If filter is not initialized, HdrTypeUnknown returns.
//
// Returns HdrTypeUnknown if Header is not one of:
// - EACLRecord_FilterInfo_Request;
// - EACLRecord_FilterInfo_ObjectSystem;
// - EACLRecord_FilterInfo_ObjectUser.
func (s FilterWrapper) HeaderType() (res HeaderType) {
res = HdrTypeUnknown
if s.filter != nil {
switch s.filter.GetHeader() {
case acl.EACLRecord_FilterInfo_Request:
res = HdrTypeRequest
case acl.EACLRecord_FilterInfo_ObjectSystem:
res = HdrTypeObjSys
case acl.EACLRecord_FilterInfo_ObjectUser:
res = HdrTypeObjUsr
}
}
return
}
// SetHeaderType sets the header type of the filter.
//
// If filter is not initialized, nothing changes.
//
// Header is set to EACLRecord_FilterInfo_HeaderUnknown if argument is not one of:
// - HdrTypeRequest;
// - HdrTypeObjSys;
// - HdrTypeObjUsr.
func (s FilterWrapper) SetHeaderType(t HeaderType) {
if s.filter != nil {
switch t {
case HdrTypeRequest:
s.filter.SetHeader(acl.EACLRecord_FilterInfo_Request)
case HdrTypeObjSys:
s.filter.SetHeader(acl.EACLRecord_FilterInfo_ObjectSystem)
case HdrTypeObjUsr:
s.filter.SetHeader(acl.EACLRecord_FilterInfo_ObjectUser)
default:
s.filter.SetHeader(acl.EACLRecord_FilterInfo_HeaderUnknown)
}
}
}
// Group returns the access group of the target.
//
// If target is not initialized, GroupUnknown returns.
//
// Returns GroupUnknown if Target is not one of:
// - Target_User;
// - GroupSystem;
// - GroupOthers.
func (s TargetWrapper) Group() (res Group) {
res = GroupUnknown
if s.target != nil {
switch s.target.GetTarget() {
case acl.Target_User:
res = GroupUser
case acl.Target_System:
res = GroupSystem
case acl.Target_Others:
res = GroupOthers
}
}
return
}
// SetGroup sets the access group of the target.
//
// If target is not initialized, nothing changes.
//
// Target is set to Target_Unknown if argument is not one of:
// - GroupUser;
// - GroupSystem;
// - GroupOthers.
func (s TargetWrapper) SetGroup(g Group) {
if s.target != nil {
switch g {
case GroupUser:
s.target.SetTarget(acl.Target_User)
case GroupSystem:
s.target.SetTarget(acl.Target_System)
case GroupOthers:
s.target.SetTarget(acl.Target_Others)
default:
s.target.SetTarget(acl.Target_Unknown)
}
}
}
// KeyList returns the key list of the target.
//
// If target is not initialized, nil returns.
func (s TargetWrapper) KeyList() [][]byte {
if s.target == nil {
return nil
}
return s.target.GetKeyList()
}
// SetKeyList sets the key list of the target.
//
// If target is not initialized, nothing changes.
func (s TargetWrapper) SetKeyList(v [][]byte) {
if s.target != nil {
s.target.SetKeyList(v)
}
}
// OperationType returns the operation type of the record.
//
// If record is not initialized, OpTypeUnknown returns.
//
// Returns OpTypeUnknown if Operation is not one of:
// - EACLRecord_HEAD;
// - EACLRecord_PUT;
// - EACLRecord_SEARCH;
// - EACLRecord_GET;
// - EACLRecord_GETRANGE;
// - EACLRecord_GETRANGEHASH;
// - EACLRecord_DELETE.
func (s RecordWrapper) OperationType() (res OperationType) {
res = OpTypeUnknown
if s.record != nil {
switch s.record.GetOperation() {
case acl.EACLRecord_HEAD:
res = OpTypeHead
case acl.EACLRecord_PUT:
res = OpTypePut
case acl.EACLRecord_SEARCH:
res = OpTypeSearch
case acl.EACLRecord_GET:
res = OpTypeGet
case acl.EACLRecord_GETRANGE:
res = OpTypeRange
case acl.EACLRecord_GETRANGEHASH:
res = OpTypeRangeHash
case acl.EACLRecord_DELETE:
res = OpTypeDelete
}
}
return
}
// SetOperationType sets the operation type of the record.
//
// If record is not initialized, nothing changes.
//
// Operation is set to EACLRecord_OPERATION_UNKNOWN if argument is not one of:
// - OpTypeHead;
// - OpTypePut;
// - OpTypeSearch;
// - OpTypeGet;
// - OpTypeRange;
// - OpTypeRangeHash;
// - OpTypeDelete.
func (s RecordWrapper) SetOperationType(v OperationType) {
if s.record != nil {
switch v {
case OpTypeHead:
s.record.SetOperation(acl.EACLRecord_HEAD)
case OpTypePut:
s.record.SetOperation(acl.EACLRecord_PUT)
case OpTypeSearch:
s.record.SetOperation(acl.EACLRecord_SEARCH)
case OpTypeGet:
s.record.SetOperation(acl.EACLRecord_GET)
case OpTypeRange:
s.record.SetOperation(acl.EACLRecord_GETRANGE)
case OpTypeRangeHash:
s.record.SetOperation(acl.EACLRecord_GETRANGEHASH)
case OpTypeDelete:
s.record.SetOperation(acl.EACLRecord_DELETE)
default:
s.record.SetOperation(acl.EACLRecord_OPERATION_UNKNOWN)
}
}
}
// Action returns the action of the record.
//
// If record is not initialized, ActionUnknown returns.
//
// Returns ActionUnknown if Action is not one of:
// - EACLRecord_Deny;
// - EACLRecord_Allow.
func (s RecordWrapper) Action() (res Action) {
res = ActionUnknown
if s.record != nil {
switch s.record.GetAction() {
case acl.EACLRecord_Deny:
res = ActionDeny
case acl.EACLRecord_Allow:
res = ActionAllow
}
}
return
}
// SetAction sets the action of the record.
//
// If record is not initialized, nothing changes.
//
// Action is set to EACLRecord_ActionUnknown if argument is not one of:
// - ActionDeny;
// - ActionAllow.
func (s RecordWrapper) SetAction(v Action) {
if s.record != nil {
switch v {
case ActionDeny:
s.record.SetAction(acl.EACLRecord_Deny)
case ActionAllow:
s.record.SetAction(acl.EACLRecord_Allow)
default:
s.record.SetAction(acl.EACLRecord_ActionUnknown)
}
}
}
// HeaderFilters returns the header filter list of the record.
//
// If record is not initialized, nil returns.
func (s RecordWrapper) HeaderFilters() []HeaderFilter {
if s.record == nil {
return nil
}
filters := s.record.GetFilters()
res := make([]HeaderFilter, 0, len(filters))
for i := range filters {
res = append(res, WrapFilterInfo(filters[i]))
}
return res
}
// SetHeaderFilters sets the header filter list of the record.
//
// Ignores nil elements of argument.
// If record is not initialized, nothing changes.
func (s RecordWrapper) SetHeaderFilters(v []HeaderFilter) {
if s.record == nil {
return
}
filters := make([]*acl.EACLRecord_FilterInfo, 0, len(v))
for i := range v {
if v[i] == nil {
continue
}
w := WrapFilterInfo(nil)
w.SetMatchType(v[i].MatchType())
w.SetHeaderType(v[i].HeaderType())
w.SetName(v[i].Name())
w.SetValue(v[i].Value())
filters = append(filters, w.filter)
}
s.record.SetFilters(filters)
}
// TargetList returns the target list of the record.
//
// If record is not initialized, nil returns.
func (s RecordWrapper) TargetList() []Target {
if s.record == nil {
return nil
}
targets := s.record.GetTargets()
res := make([]Target, 0, len(targets))
for i := range targets {
res = append(res, WrapTarget(targets[i]))
}
return res
}
// SetTargetList sets the target list of the record.
//
// Ignores nil elements of argument.
// If record is not initialized, nothing changes.
func (s RecordWrapper) SetTargetList(v []Target) {
if s.record == nil {
return
}
targets := make([]*acl.EACLRecord_TargetInfo, 0, len(v))
for i := range v {
if v[i] == nil {
continue
}
w := WrapTarget(nil)
w.SetGroup(v[i].Group())
w.SetKeyList(v[i].KeyList())
targets = append(targets, w.target)
}
s.record.SetTargets(targets)
}
// Records returns the record list of the table.
//
// If table is not initialized, nil returns.
func (s TableWrapper) Records() []Record {
if s.table == nil {
return nil
}
records := s.table.GetRecords()
res := make([]Record, 0, len(records))
for i := range records {
res = append(res, WrapRecord(records[i]))
}
return res
}
// SetRecords sets the record list of the table.
//
// Ignores nil elements of argument.
// If table is not initialized, nothing changes.
func (s TableWrapper) SetRecords(v []Record) {
if s.table == nil {
return
}
records := make([]*acl.EACLRecord, 0, len(v))
for i := range v {
if v[i] == nil {
continue
}
w := WrapRecord(nil)
w.SetOperationType(v[i].OperationType())
w.SetAction(v[i].Action())
w.SetHeaderFilters(v[i].HeaderFilters())
w.SetTargetList(v[i].TargetList())
records = append(records, w.record)
}
s.table.SetRecords(records)
}

View file

@ -1,4 +1,4 @@
package acl
package eacl
import (
"testing"
@ -27,11 +27,11 @@ func TestEACLFilterWrapper(t *testing.T) {
}
func TestEACLTargetWrapper(t *testing.T) {
s := WrapEACLTarget(nil)
s := WrapTarget(nil)
target := Target(10)
s.SetTarget(target)
require.Equal(t, target, s.Target())
group := Group(3)
s.SetGroup(group)
require.Equal(t, group, s.Group())
keys := [][]byte{
{1, 2, 3},
@ -42,7 +42,7 @@ func TestEACLTargetWrapper(t *testing.T) {
}
func TestEACLRecordWrapper(t *testing.T) {
s := WrapEACLRecord(nil)
s := WrapRecord(nil)
action := ActionAllow
s.SetAction(action)
@ -67,46 +67,43 @@ func TestEACLRecordWrapper(t *testing.T) {
require.Equal(t, f1Name, filters[0].Name())
require.Equal(t, f2Name, filters[1].Name())
target1 := Target(1)
t1 := WrapEACLTarget(nil)
t1.SetTarget(target1)
group1 := Group(1)
t1 := WrapTarget(nil)
t1.SetGroup(group1)
target2 := Target(2)
t2 := WrapEACLTarget(nil)
t2.SetTarget(target2)
group2 := Group(2)
t2 := WrapTarget(nil)
t2.SetGroup(group2)
s.SetTargetList([]ExtendedACLTarget{t1, t2})
s.SetTargetList([]Target{t1, t2})
targets := s.TargetList()
require.Len(t, targets, 2)
require.Equal(t, target1, targets[0].Target())
require.Equal(t, target2, targets[1].Target())
require.Equal(t, group1, targets[0].Group())
require.Equal(t, group2, targets[1].Group())
}
func TestEACLTableWrapper(t *testing.T) {
s := WrapEACLTable(nil)
s := WrapTable(nil)
action1 := ExtendedACLAction(1)
r1 := WrapEACLRecord(nil)
action1 := Action(1)
r1 := WrapRecord(nil)
r1.SetAction(action1)
action2 := ExtendedACLAction(2)
r2 := WrapEACLRecord(nil)
action2 := Action(2)
r2 := WrapRecord(nil)
r2.SetAction(action2)
s.SetRecords([]ExtendedACLRecord{r1, r2})
s.SetRecords([]Record{r1, r2})
records := s.Records()
require.Len(t, records, 2)
require.Equal(t, action1, records[0].Action())
require.Equal(t, action2, records[1].Action())
data, err := s.MarshalBinary()
s2, err := UnmarshalTable(MarshalTable(s))
require.NoError(t, err)
s2 := WrapEACLTable(nil)
require.NoError(t, s2.UnmarshalBinary(data))
records1 := s.Records()
records2 := s2.Records()
require.Len(t, records1, len(records2))
@ -120,7 +117,7 @@ func TestEACLTableWrapper(t *testing.T) {
require.Len(t, targets1, len(targets2))
for j := range targets1 {
require.Equal(t, targets1[j].Target(), targets2[j].Target())
require.Equal(t, targets1[j].Group(), targets2[j].Group())
require.Equal(t, targets1[j].KeyList(), targets2[j].KeyList())
}

View file

@ -1,78 +1,5 @@
package acl
const (
_ MatchType = iota
// StringEqual is a MatchType of string equality.
StringEqual
// StringNotEqual is a MatchType of string inequality.
StringNotEqual
)
const (
// ActionUndefined is ExtendedACLAction used to mark value as undefined.
// Most of the tools consider ActionUndefined as incalculable.
// Using ActionUndefined in ExtendedACLRecord is unsafe.
ActionUndefined ExtendedACLAction = iota
// ActionAllow is ExtendedACLAction used to mark an applicability of ACL rule.
ActionAllow
// ActionDeny is ExtendedACLAction used to mark an inapplicability of ACL rule.
ActionDeny
)
const (
_ HeaderType = iota
// HdrTypeRequest is a HeaderType for request header.
HdrTypeRequest
// HdrTypeObjSys is a HeaderType for system headers of object.
HdrTypeObjSys
// HdrTypeObjUsr is a HeaderType for user headers of object.
HdrTypeObjUsr
)
const (
// HdrObjSysNameID is a name of ID field in system header of object.
HdrObjSysNameID = "ID"
// HdrObjSysNameCID is a name of CID field in system header of object.
HdrObjSysNameCID = "CID"
// HdrObjSysNameOwnerID is a name of OwnerID field in system header of object.
HdrObjSysNameOwnerID = "OWNER_ID"
// HdrObjSysNameVersion is a name of Version field in system header of object.
HdrObjSysNameVersion = "VERSION"
// HdrObjSysNamePayloadLength is a name of PayloadLength field in system header of object.
HdrObjSysNamePayloadLength = "PAYLOAD_LENGTH"
// HdrObjSysNameCreatedUnix is a name of CreatedAt.UnitTime field in system header of object.
HdrObjSysNameCreatedUnix = "CREATED_UNIX"
// HdrObjSysNameCreatedEpoch is a name of CreatedAt.Epoch field in system header of object.
HdrObjSysNameCreatedEpoch = "CREATED_EPOCH"
// HdrObjSysLinkPrev is a name of previous link header in extended headers of object.
HdrObjSysLinkPrev = "LINK_PREV"
// HdrObjSysLinkNext is a name of next link header in extended headers of object.
HdrObjSysLinkNext = "LINK_NEXT"
// HdrObjSysLinkChild is a name of child link header in extended headers of object.
HdrObjSysLinkChild = "LINK_CHILD"
// HdrObjSysLinkPar is a name of parent link header in extended headers of object.
HdrObjSysLinkPar = "LINK_PAR"
// HdrObjSysLinkSG is a name of storage group link header in extended headers of object.
HdrObjSysLinkSG = "LINK_SG"
)
// SetMatchType is MatchType field setter.
func (m *EACLRecord_FilterInfo) SetMatchType(v EACLRecord_FilterInfo_MatchType) {

View file

@ -1,498 +0,0 @@
package acl
// EACLFilterWrapper is a wrapper over EACLRecord_FilterInfo pointer.
type EACLFilterWrapper struct {
filter *EACLRecord_FilterInfo
}
// EACLTargetWrapper is a wrapper over EACLRecord_TargetInfo pointer.
type EACLTargetWrapper struct {
target *EACLRecord_TargetInfo
}
// EACLRecordWrapper is a wrapper over EACLRecord pointer.
type EACLRecordWrapper struct {
record *EACLRecord
}
// EACLTableWrapper is a wrapper over EACLTable pointer.
type EACLTableWrapper struct {
table *EACLTable
}
// WrapFilterInfo wraps EACLRecord_FilterInfo pointer.
//
// If argument is nil, new EACLRecord_FilterInfo is initialized.
func WrapFilterInfo(v *EACLRecord_FilterInfo) EACLFilterWrapper {
if v == nil {
v = new(EACLRecord_FilterInfo)
}
return EACLFilterWrapper{
filter: v,
}
}
// WrapEACLTarget wraps EACLRecord_TargetInfo pointer.
//
// If argument is nil, new EACLRecord_TargetInfo is initialized.
func WrapEACLTarget(v *EACLRecord_TargetInfo) EACLTargetWrapper {
if v == nil {
v = new(EACLRecord_TargetInfo)
}
return EACLTargetWrapper{
target: v,
}
}
// WrapEACLRecord wraps EACLRecord pointer.
//
// If argument is nil, new EACLRecord is initialized.
func WrapEACLRecord(v *EACLRecord) EACLRecordWrapper {
if v == nil {
v = new(EACLRecord)
}
return EACLRecordWrapper{
record: v,
}
}
// WrapEACLTable wraps EACLTable pointer.
//
// If argument is nil, new EACLTable is initialized.
func WrapEACLTable(v *EACLTable) EACLTableWrapper {
if v == nil {
v = new(EACLTable)
}
return EACLTableWrapper{
table: v,
}
}
// MatchType returns casted result of MatchType field getter.
//
// If filter is not initialized, 0 returns.
//
// Returns 0 if MatchType is not one of:
// - EACLRecord_FilterInfo_StringEqual;
// - EACLRecord_FilterInfo_StringNotEqual.
func (s EACLFilterWrapper) MatchType() (res MatchType) {
if s.filter != nil {
switch s.filter.GetMatchType() {
case EACLRecord_FilterInfo_StringEqual:
res = StringEqual
case EACLRecord_FilterInfo_StringNotEqual:
res = StringNotEqual
}
}
return
}
// SetMatchType passes casted argument to MatchType field setter.
//
// If filter is not initialized, nothing changes.
//
// MatchType is set to EACLRecord_FilterInfo_MatchUnknown if argument is not one of:
// - StringEqual;
// - StringNotEqual.
func (s EACLFilterWrapper) SetMatchType(v MatchType) {
if s.filter != nil {
switch v {
case StringEqual:
s.filter.SetMatchType(EACLRecord_FilterInfo_StringEqual)
case StringNotEqual:
s.filter.SetMatchType(EACLRecord_FilterInfo_StringNotEqual)
default:
s.filter.SetMatchType(EACLRecord_FilterInfo_MatchUnknown)
}
}
}
// Name returns the result of HeaderName field getter.
//
// If filter is not initialized, empty string returns.
func (s EACLFilterWrapper) Name() string {
if s.filter == nil {
return ""
}
return s.filter.GetHeaderName()
}
// SetName passes argument to HeaderName field setter.
//
// If filter is not initialized, nothing changes.
func (s EACLFilterWrapper) SetName(v string) {
if s.filter != nil {
s.filter.SetHeaderName(v)
}
}
// Value returns the result of HeaderVal field getter.
//
// If filter is not initialized, empty string returns.
func (s EACLFilterWrapper) Value() string {
if s.filter == nil {
return ""
}
return s.filter.GetHeaderVal()
}
// SetValue passes argument to HeaderVal field setter.
//
// If filter is not initialized, nothing changes.
func (s EACLFilterWrapper) SetValue(v string) {
if s.filter != nil {
s.filter.SetHeaderVal(v)
}
}
// HeaderType returns the result of Header field getter.
//
// If filter is not initialized, 0 returns.
//
// Returns 0 if Header is not one of:
// - EACLRecord_FilterInfo_Request;
// - EACLRecord_FilterInfo_ObjectSystem;
// - EACLRecord_FilterInfo_ObjectUser.
func (s EACLFilterWrapper) HeaderType() (res HeaderType) {
if s.filter != nil {
switch s.filter.GetHeader() {
case EACLRecord_FilterInfo_Request:
res = HdrTypeRequest
case EACLRecord_FilterInfo_ObjectSystem:
res = HdrTypeObjSys
case EACLRecord_FilterInfo_ObjectUser:
res = HdrTypeObjUsr
}
}
return
}
// SetHeaderType passes casted argument to Header field setter.
//
// If filter is not initialized, nothing changes.
//
// Header is set to EACLRecord_FilterInfo_HeaderUnknown if argument is not one of:
// - HdrTypeRequest;
// - HdrTypeObjSys;
// - HdrTypeObjUsr.
func (s EACLFilterWrapper) SetHeaderType(t HeaderType) {
if s.filter != nil {
switch t {
case HdrTypeRequest:
s.filter.SetHeader(EACLRecord_FilterInfo_Request)
case HdrTypeObjSys:
s.filter.SetHeader(EACLRecord_FilterInfo_ObjectSystem)
case HdrTypeObjUsr:
s.filter.SetHeader(EACLRecord_FilterInfo_ObjectUser)
default:
s.filter.SetHeader(EACLRecord_FilterInfo_HeaderUnknown)
}
}
}
// Target returns the result of Target field getter.
//
// If target is not initialized, Target_Unknown returns.
func (s EACLTargetWrapper) Target() Target {
if s.target == nil {
return Target_Unknown
}
return s.target.GetTarget()
}
// SetTarget passes argument to Target field setter.
//
// If target is not initialized, nothing changes.
func (s EACLTargetWrapper) SetTarget(v Target) {
if s.target != nil {
s.target.SetTarget(v)
}
}
// KeyList returns the result of KeyList field getter.
//
// If target is not initialized, nil returns.
func (s EACLTargetWrapper) KeyList() [][]byte {
if s.target == nil {
return nil
}
return s.target.GetKeyList()
}
// SetKeyList passes argument to KeyList field setter.
//
// If target is not initialized, nothing changes.
func (s EACLTargetWrapper) SetKeyList(v [][]byte) {
if s.target != nil {
s.target.SetKeyList(v)
}
}
// OperationType returns casted result of Operation field getter.
//
// If record is not initialized, 0 returns.
//
// Returns 0 if Operation is not one of:
// - EACLRecord_HEAD;
// - EACLRecord_PUT;
// - EACLRecord_SEARCH;
// - EACLRecord_GET;
// - EACLRecord_GETRANGE;
// - EACLRecord_GETRANGEHASH;
// - EACLRecord_DELETE.
func (s EACLRecordWrapper) OperationType() (res OperationType) {
if s.record != nil {
switch s.record.GetOperation() {
case EACLRecord_HEAD:
res = OpTypeHead
case EACLRecord_PUT:
res = OpTypePut
case EACLRecord_SEARCH:
res = OpTypeSearch
case EACLRecord_GET:
res = OpTypeGet
case EACLRecord_GETRANGE:
res = OpTypeRange
case EACLRecord_GETRANGEHASH:
res = OpTypeRangeHash
case EACLRecord_DELETE:
res = OpTypeDelete
}
}
return
}
// SetOperationType passes casted argument to Operation field setter.
//
// If record is not initialized, nothing changes.
//
// Operation is set to EACLRecord_OPERATION_UNKNOWN if argument is not one of:
// - OpTypeHead;
// - OpTypePut;
// - OpTypeSearch;
// - OpTypeGet;
// - OpTypeRange;
// - OpTypeRangeHash;
// - OpTypeDelete.
func (s EACLRecordWrapper) SetOperationType(v OperationType) {
if s.record != nil {
switch v {
case OpTypeHead:
s.record.SetOperation(EACLRecord_HEAD)
case OpTypePut:
s.record.SetOperation(EACLRecord_PUT)
case OpTypeSearch:
s.record.SetOperation(EACLRecord_SEARCH)
case OpTypeGet:
s.record.SetOperation(EACLRecord_GET)
case OpTypeRange:
s.record.SetOperation(EACLRecord_GETRANGE)
case OpTypeRangeHash:
s.record.SetOperation(EACLRecord_GETRANGEHASH)
case OpTypeDelete:
s.record.SetOperation(EACLRecord_DELETE)
default:
s.record.SetOperation(EACLRecord_OPERATION_UNKNOWN)
}
}
}
// Action returns casted result of Action field getter.
//
// If record is not initialized, 0 returns.
//
// Returns 0 if Action is not one of:
// - EACLRecord_Deny;
// - EACLRecord_Allow.
func (s EACLRecordWrapper) Action() (res ExtendedACLAction) {
if s.record != nil {
switch s.record.GetAction() {
case EACLRecord_Deny:
res = ActionDeny
case EACLRecord_Allow:
res = ActionAllow
}
}
return
}
// SetAction passes casted argument to Action field setter.
//
// If record is not initialized, nothing changes.
//
// Action is set to EACLRecord_ActionUnknown if argument is not one of:
// - ActionDeny;
// - ActionAllow.
func (s EACLRecordWrapper) SetAction(v ExtendedACLAction) {
if s.record != nil {
switch v {
case ActionDeny:
s.record.SetAction(EACLRecord_Deny)
case ActionAllow:
s.record.SetAction(EACLRecord_Allow)
default:
s.record.SetAction(EACLRecord_ActionUnknown)
}
}
}
// HeaderFilters wraps all elements from Filters field getter result and returns HeaderFilter list.
//
// If record is not initialized, nil returns.
func (s EACLRecordWrapper) HeaderFilters() []HeaderFilter {
if s.record == nil {
return nil
}
filters := s.record.GetFilters()
res := make([]HeaderFilter, 0, len(filters))
for i := range filters {
res = append(res, WrapFilterInfo(filters[i]))
}
return res
}
// SetHeaderFilters converts HeaderFilter list to EACLRecord_FilterInfo list and passes it to Filters field setter.
//
// Ignores nil elements of argument.
// If record is not initialized, nothing changes.
func (s EACLRecordWrapper) SetHeaderFilters(v []HeaderFilter) {
if s.record == nil {
return
}
filters := make([]*EACLRecord_FilterInfo, 0, len(v))
for i := range v {
if v[i] == nil {
continue
}
w := WrapFilterInfo(nil)
w.SetMatchType(v[i].MatchType())
w.SetHeaderType(v[i].HeaderType())
w.SetName(v[i].Name())
w.SetValue(v[i].Value())
filters = append(filters, w.filter)
}
s.record.SetFilters(filters)
}
// TargetList wraps all elements from Targets field getter result and returns ExtendedACLTarget list.
//
// If record is not initialized, nil returns.
func (s EACLRecordWrapper) TargetList() []ExtendedACLTarget {
if s.record == nil {
return nil
}
targets := s.record.GetTargets()
res := make([]ExtendedACLTarget, 0, len(targets))
for i := range targets {
res = append(res, WrapEACLTarget(targets[i]))
}
return res
}
// SetTargetList converts ExtendedACLTarget list to EACLRecord_TargetInfo list and passes it to Targets field setter.
//
// Ignores nil elements of argument.
// If record is not initialized, nothing changes.
func (s EACLRecordWrapper) SetTargetList(v []ExtendedACLTarget) {
if s.record == nil {
return
}
targets := make([]*EACLRecord_TargetInfo, 0, len(v))
for i := range v {
if v[i] == nil {
continue
}
w := WrapEACLTarget(nil)
w.SetTarget(v[i].Target())
w.SetKeyList(v[i].KeyList())
targets = append(targets, w.target)
}
s.record.SetTargets(targets)
}
// Records wraps all elements from Records field getter result and returns ExtendedACLRecord list.
//
// If table is not initialized, nil returns.
func (s EACLTableWrapper) Records() []ExtendedACLRecord {
if s.table == nil {
return nil
}
records := s.table.GetRecords()
res := make([]ExtendedACLRecord, 0, len(records))
for i := range records {
res = append(res, WrapEACLRecord(records[i]))
}
return res
}
// SetRecords converts ExtendedACLRecord list to EACLRecord list and passes it to Records field setter.
//
// Ignores nil elements of argument.
// If table is not initialized, nothing changes.
func (s EACLTableWrapper) SetRecords(v []ExtendedACLRecord) {
if s.table == nil {
return
}
records := make([]*EACLRecord, 0, len(v))
for i := range v {
if v[i] == nil {
continue
}
w := WrapEACLRecord(nil)
w.SetOperationType(v[i].OperationType())
w.SetAction(v[i].Action())
w.SetHeaderFilters(v[i].HeaderFilters())
w.SetTargetList(v[i].TargetList())
records = append(records, w.record)
}
s.table.SetRecords(records)
}
// MarshalBinary returns the result of Marshal method.
func (s EACLTableWrapper) MarshalBinary() ([]byte, error) {
return s.table.Marshal()
}
// UnmarshalBinary passes argument to Unmarshal method and returns its result.
func (s EACLTableWrapper) UnmarshalBinary(data []byte) error {
return s.table.Unmarshal(data)
}

View file

@ -1,16 +1,9 @@
package chain
import (
"bytes"
"crypto/ecdsa"
"crypto/sha256"
"encoding/hex"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-api-go/internal"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/pkg/errors"
"golang.org/x/crypto/ripemd160"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)
// WalletAddress implements NEO address.
@ -18,168 +11,20 @@ type WalletAddress [AddressLength]byte
const (
// AddressLength contains size of address,
// 0x17 byte (address version) + 20 bytes of ScriptHash + 4 bytes of checksum.
// 1 byte of address version + 20 bytes of ScriptHash + 4 bytes of checksum.
AddressLength = 25
// ScriptHashLength contains size of ScriptHash.
ScriptHashLength = 20
// ErrEmptyAddress is raised when empty Address is passed.
ErrEmptyAddress = internal.Error("empty address")
// ErrAddressLength is raised when passed address has wrong size.
ErrAddressLength = internal.Error("wrong address length")
)
func checksum(sign []byte) []byte {
hash := sha256.Sum256(sign)
hash = sha256.Sum256(hash[:])
return hash[:4]
}
// FetchPublicKeys tries to parse public keys from verification script.
func FetchPublicKeys(vs []byte) []*ecdsa.PublicKey {
var (
count int
offset int
ln = len(vs)
result []*ecdsa.PublicKey
)
switch {
case ln < 1: // wrong data size
return nil
case vs[ln-1] == 0xac: // last byte is CHECKSIG
count = 1
case vs[ln-1] == 0xae: // last byte is CHECKMULTISIG
// 2nd byte from the end indicates about PK's count
count = int(vs[ln-2] - 0x50)
// ignores CHECKMULTISIG
offset = 1
default: // unknown type
return nil
}
result = make([]*ecdsa.PublicKey, 0, count)
for i := 0; i < count; i++ {
// ignores PUSHBYTE33 and tries to parse
from, to := offset+1, offset+1+crypto.PublicKeyCompressedSize
// when passed VerificationScript has wrong size
if len(vs) < to {
return nil
}
key := crypto.UnmarshalPublicKey(vs[from:to])
// when wrong public key is passed
if key == nil {
return nil
}
result = append(result, key)
offset += 1 + crypto.PublicKeyCompressedSize
}
return result
}
// VerificationScript returns VerificationScript composed from public keys.
func VerificationScript(pubs ...*ecdsa.PublicKey) []byte {
var (
pre []byte
suf []byte
body []byte
offset int
lnPK = len(pubs)
ln = crypto.PublicKeyCompressedSize*lnPK + lnPK // 33 * count + count * 1 (PUSHBYTES33)
)
if len(pubs) > 1 {
pre = []byte{0x51} // one address
suf = []byte{byte(0x50 + lnPK), 0xae} // count of PK's + CHECKMULTISIG
} else {
suf = []byte{0xac} // CHECKSIG
}
ln += len(pre) + len(suf)
body = make([]byte, ln)
offset += copy(body, pre)
for i := range pubs {
body[offset] = 0x21
offset++
offset += copy(body[offset:], crypto.MarshalPublicKey(pubs[i]))
}
copy(body[offset:], suf)
return body
}
// KeysToAddress return NEO address composed from public keys.
func KeysToAddress(pubs ...*ecdsa.PublicKey) string {
if len(pubs) == 0 {
// KeyToAddress returns NEO address composed from public key.
func KeyToAddress(key *ecdsa.PublicKey) string {
if key == nil {
return ""
}
return Address(VerificationScript(pubs...))
}
// Address returns NEO address based on passed VerificationScript.
func Address(verificationScript []byte) string {
sign := [AddressLength]byte{0x17}
hash := sha256.Sum256(verificationScript)
ripe := ripemd160.New()
ripe.Write(hash[:])
copy(sign[1:], ripe.Sum(nil))
copy(sign[21:], checksum(sign[:21]))
return base58.Encode(sign[:])
}
// ReversedScriptHashToAddress parses script hash and returns valid NEO address.
func ReversedScriptHashToAddress(sc string) (addr string, err error) {
var data []byte
if data, err = DecodeScriptHash(sc); err != nil {
return
}
sign := [AddressLength]byte{0x17}
copy(sign[1:], data)
copy(sign[1+ScriptHashLength:], checksum(sign[:1+ScriptHashLength]))
return base58.Encode(sign[:]), nil
}
// IsAddress checks that passed NEO Address is valid.
func IsAddress(s string) error {
if s == "" {
return ErrEmptyAddress
} else if addr, err := base58.Decode(s); err != nil {
return errors.Wrap(err, "base58 decode")
} else if ln := len(addr); ln != AddressLength {
return errors.Wrapf(ErrAddressLength, "length %d != %d", AddressLength, ln)
} else if sum := checksum(addr[:21]); !bytes.Equal(addr[21:], sum) {
return errors.Errorf("wrong checksum %0x != %0x",
addr[21:], sum)
neoPublicKey := keys.PublicKey{
X: key.X,
Y: key.Y,
}
return nil
}
// ReverseBytes returns reversed []byte of given.
func ReverseBytes(data []byte) []byte {
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
return data
}
// DecodeScriptHash parses script hash into slice of bytes.
func DecodeScriptHash(s string) ([]byte, error) {
if s == "" {
return nil, ErrEmptyAddress
} else if addr, err := hex.DecodeString(s); err != nil {
return nil, errors.Wrap(err, "hex decode")
} else if ln := len(addr); ln != ScriptHashLength {
return nil, errors.Wrapf(ErrAddressLength, "length %d != %d", ScriptHashLength, ln)
} else {
return addr, nil
}
return neoPublicKey.Address()
}

View file

@ -1,292 +1,41 @@
package chain
import (
"crypto/ecdsa"
"encoding/hex"
"testing"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-crypto/test"
"github.com/stretchr/testify/require"
)
func TestAddress(t *testing.T) {
var (
multiSigVerificationScript = "512103c02a93134f98d9c78ec54b1b1f97fc64cd81360f53a293f41e4ad54aac3c57172103fea219d4ccfd7641cebbb2439740bb4bd7c4730c1abd6ca1dc44386533816df952ae"
multiSigAddress = "ANbvKqa2SfgTUkq43NRUhCiyxPrpUPn7S3"
normalVerificationScript = "2102a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61ac"
normalAddress = "AcraNnCuPKnUYtPYyrACRCVJhLpvskbfhu"
)
t.Run("check multi-sig address", func(t *testing.T) {
data, err := hex.DecodeString(multiSigVerificationScript)
require.NoError(t, err)
require.Equal(t, multiSigAddress, Address(data))
})
t.Run("check normal address", func(t *testing.T) {
data, err := hex.DecodeString(normalVerificationScript)
require.NoError(t, err)
require.Equal(t, normalAddress, Address(data))
})
type addressTestCase struct {
name string
publicKey string
wallet string
}
func TestVerificationScript(t *testing.T) {
t.Run("check normal", func(t *testing.T) {
pkString := "02a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61"
pkBytes, err := hex.DecodeString(pkString)
require.NoError(t, err)
pk := crypto.UnmarshalPublicKey(pkBytes)
expect, err := hex.DecodeString(
"21" + pkString + // PUSHBYTES33
"ac", // CHECKSIG
)
require.Equal(t, expect, VerificationScript(pk))
})
t.Run("check multisig", func(t *testing.T) {
pk1String := "03c02a93134f98d9c78ec54b1b1f97fc64cd81360f53a293f41e4ad54aac3c5717"
pk2String := "03fea219d4ccfd7641cebbb2439740bb4bd7c4730c1abd6ca1dc44386533816df9"
pk1Bytes, err := hex.DecodeString(pk1String)
require.NoError(t, err)
pk1 := crypto.UnmarshalPublicKey(pk1Bytes)
pk2Bytes, err := hex.DecodeString(pk2String)
require.NoError(t, err)
pk2 := crypto.UnmarshalPublicKey(pk2Bytes)
expect, err := hex.DecodeString(
"51" + // one address
"21" + pk1String + // PUSHBYTES33
"21" + pk2String + // PUSHBYTES33
"52" + // 2 PublicKeys
"ae", // CHECKMULTISIG
)
require.Equal(t, expect, VerificationScript(pk1, pk2))
})
}
func TestKeysToAddress(t *testing.T) {
t.Run("check normal", func(t *testing.T) {
pkString := "02a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61"
pkBytes, err := hex.DecodeString(pkString)
require.NoError(t, err)
pk := crypto.UnmarshalPublicKey(pkBytes)
expect := "AcraNnCuPKnUYtPYyrACRCVJhLpvskbfhu"
actual := KeysToAddress(pk)
require.Equal(t, expect, actual)
require.NoError(t, IsAddress(actual))
})
t.Run("check multisig", func(t *testing.T) {
pk1String := "03c02a93134f98d9c78ec54b1b1f97fc64cd81360f53a293f41e4ad54aac3c5717"
pk2String := "03fea219d4ccfd7641cebbb2439740bb4bd7c4730c1abd6ca1dc44386533816df9"
pk1Bytes, err := hex.DecodeString(pk1String)
require.NoError(t, err)
pk1 := crypto.UnmarshalPublicKey(pk1Bytes)
pk2Bytes, err := hex.DecodeString(pk2String)
require.NoError(t, err)
pk2 := crypto.UnmarshalPublicKey(pk2Bytes)
expect := "ANbvKqa2SfgTUkq43NRUhCiyxPrpUPn7S3"
actual := KeysToAddress(pk1, pk2)
require.Equal(t, expect, actual)
require.NoError(t, IsAddress(actual))
})
}
func TestFetchPublicKeys(t *testing.T) {
var (
multiSigVerificationScript = "512103c02a93134f98d9c78ec54b1b1f97fc64cd81360f53a293f41e4ad54aac3c57172103fea219d4ccfd7641cebbb2439740bb4bd7c4730c1abd6ca1dc44386533816df952ae"
normalVerificationScript = "2102a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61ac"
pk1String = "03c02a93134f98d9c78ec54b1b1f97fc64cd81360f53a293f41e4ad54aac3c5717"
pk2String = "03fea219d4ccfd7641cebbb2439740bb4bd7c4730c1abd6ca1dc44386533816df9"
pk3String = "02a33413277a319cc6fd4c54a2feb9032eba668ec587f307e319dc48733087fa61"
)
t.Run("shouls not fail", func(t *testing.T) {
wrongVS, err := hex.DecodeString(multiSigVerificationScript)
require.NoError(t, err)
wrongVS[len(wrongVS)-1] = 0x1
wrongPK, err := hex.DecodeString(multiSigVerificationScript)
require.NoError(t, err)
wrongPK[2] = 0x1
var testCases = []struct {
name string
value []byte
}{
{name: "empty VerificationScript"},
{
name: "wrong size VerificationScript",
value: []byte{0x1},
},
{
name: "wrong VerificationScript type",
value: wrongVS,
},
{
name: "wrong public key in VerificationScript",
value: wrongPK,
},
}
for i := range testCases {
tt := testCases[i]
t.Run(tt.name, func(t *testing.T) {
var keys []*ecdsa.PublicKey
require.NotPanics(t, func() {
keys = FetchPublicKeys(tt.value)
})
require.Nil(t, keys)
})
}
})
t.Run("check multi-sig address", func(t *testing.T) {
data, err := hex.DecodeString(multiSigVerificationScript)
require.NoError(t, err)
pk1Bytes, err := hex.DecodeString(pk1String)
require.NoError(t, err)
pk2Bytes, err := hex.DecodeString(pk2String)
require.NoError(t, err)
pk1 := crypto.UnmarshalPublicKey(pk1Bytes)
pk2 := crypto.UnmarshalPublicKey(pk2Bytes)
keys := FetchPublicKeys(data)
require.Len(t, keys, 2)
require.Equal(t, keys[0], pk1)
require.Equal(t, keys[1], pk2)
})
t.Run("check normal address", func(t *testing.T) {
data, err := hex.DecodeString(normalVerificationScript)
require.NoError(t, err)
pkBytes, err := hex.DecodeString(pk3String)
require.NoError(t, err)
pk := crypto.UnmarshalPublicKey(pkBytes)
keys := FetchPublicKeys(data)
require.Len(t, keys, 1)
require.Equal(t, keys[0], pk)
})
t.Run("generate 10 keys VerificationScript and try parse it", func(t *testing.T) {
var (
count = 10
expect = make([]*ecdsa.PublicKey, 0, count)
)
for i := 0; i < count; i++ {
key := test.DecodeKey(i)
expect = append(expect, &key.PublicKey)
}
vs := VerificationScript(expect...)
actual := FetchPublicKeys(vs)
require.Equal(t, expect, actual)
})
}
func TestReversedScriptHashToAddress(t *testing.T) {
var testCases = []struct {
name string
value string
expect string
}{
func TestKeyToAddress(t *testing.T) {
tests := []addressTestCase{
{
name: "first",
expect: "APfiG5imQgn8dzTTfaDfqHnxo3QDUkF69A",
value: "5696acd07f0927fd5f01946828638c9e2c90c5dc",
"nil key",
"",
"",
},
{
name: "second",
expect: "AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y",
value: "23ba2703c53263e8d6e522dc32203339dcd8eee9",
"correct key",
"031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a",
"NgzuJWWGVEwFGsRrgzj8knswEYRJrTe7sm",
},
}
for i := range testCases {
tt := testCases[i]
t.Run(tt.name, func(t *testing.T) {
actual, err := ReversedScriptHashToAddress(tt.value)
for i := range tests {
t.Run(tests[i].name, func(t *testing.T) {
data, err := hex.DecodeString(tests[i].publicKey)
require.NoError(t, err)
require.Equal(t, tt.expect, actual)
require.NoError(t, IsAddress(actual))
})
}
}
func TestReverseBytes(t *testing.T) {
var testCases = []struct {
name string
value []byte
expect []byte
}{
{name: "empty"},
{
name: "single byte",
expect: []byte{0x1},
value: []byte{0x1},
},
{
name: "two bytes",
expect: []byte{0x2, 0x1},
value: []byte{0x1, 0x2},
},
{
name: "three bytes",
expect: []byte{0x3, 0x2, 0x1},
value: []byte{0x1, 0x2, 0x3},
},
{
name: "five bytes",
expect: []byte{0x5, 0x4, 0x3, 0x2, 0x1},
value: []byte{0x1, 0x2, 0x3, 0x4, 0x5},
},
{
name: "eight bytes",
expect: []byte{0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1},
value: []byte{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
},
}
for i := range testCases {
tt := testCases[i]
t.Run(tt.name, func(t *testing.T) {
actual := ReverseBytes(tt.value)
require.Equal(t, tt.expect, actual)
key := crypto.UnmarshalPublicKey(data)
require.Equal(t, tests[i].wallet, KeyToAddress(key))
})
}
}

View file

@ -3,6 +3,7 @@ package container
import (
"bytes"
"github.com/gogo/protobuf/proto"
"github.com/google/uuid"
"github.com/nspcc-dev/neofs-api-go/internal"
"github.com/nspcc-dev/neofs-api-go/refs"
@ -63,6 +64,13 @@ func (m *Container) ID() (CID, error) {
return refs.CIDForBytes(data), nil
}
// Merge used by proto.Clone
func (m *Container) Merge(src proto.Message) {
if tmp, ok := src.(*Container); ok {
*m = *tmp
}
}
// Empty checks that container is empty.
func (m *Container) Empty() bool {
return m.Capacity == 0 || bytes.Equal(m.Salt.Bytes(), emptySalt) || bytes.Equal(m.OwnerID.Bytes(), emptyOwner)

1
go.mod
View file

@ -7,6 +7,7 @@ require (
github.com/golang/protobuf v1.4.2
github.com/google/uuid v1.1.1
github.com/mr-tron/base58 v1.1.3
github.com/nspcc-dev/neo-go v0.90.0
github.com/nspcc-dev/neofs-crypto v0.3.0
github.com/nspcc-dev/netmap v1.7.0
github.com/nspcc-dev/tzhash v1.4.0

83
go.sum
View file

@ -14,14 +14,23 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CityOfZion/neo-go v0.62.1-pre.0.20191114145240-e740fbe708f8/go.mod h1:MJCkWUBhi9pn/CrYO1Q3P687y2KeahrOPS9BD9LDGb0=
github.com/CityOfZion/neo-go v0.70.1-pre.0.20191209120015-fccb0085941e/go.mod h1:0enZl0az8xA6PVkwzEOwPWVJGqlt/GO4hA4kmQ5Xzig=
github.com/CityOfZion/neo-go v0.70.1-pre.0.20191212173117-32ac01130d4c/go.mod h1:JtlHfeqLywZLswKIKFnAp+yzezY4Dji9qlfQKB2OD/I=
github.com/CityOfZion/neo-go v0.71.1-pre.0.20200129171427-f773ec69fb84/go.mod h1:FLI526IrRWHmcsO+mHsCbj64pJZhwQFTLJZu+A4PGOA=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/awalterschulze/gographviz v0.0.0-20181013152038-b2885df04310 h1:t+qxRrRtwNiUYA+Xh2jSXhoG2grnMCMKX4Fg6lx9X1U=
@ -35,28 +44,40 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=
github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:rZfgFAXFS/z/lEd6LJmf9HVZ1LkgYiHx5pHhV5DR16M=
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@ -65,7 +86,9 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-redis/redis v6.10.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@ -91,6 +114,9 @@ github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -134,8 +160,11 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
@ -148,19 +177,27 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
@ -176,20 +213,36 @@ github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW
github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw=
github.com/nspcc-dev/dbft v0.0.0-20191209120240-0d6b7568d9ae/go.mod h1:3FjXOoHmA51EGfb5GS/HOv7VdmngNRTssSeQ729dvGY=
github.com/nspcc-dev/dbft v0.0.0-20200117124306-478e5cfbf03a/go.mod h1:/YFK+XOxxg0Bfm6P92lY5eDSLYfp06XOdL8KAVgXjVk=
github.com/nspcc-dev/dbft v0.0.0-20200219114139-199d286ed6c1/go.mod h1:O0qtn62prQSqizzoagHmuuKoz8QMkU3SzBoKdEvm3aQ=
github.com/nspcc-dev/dbft v0.0.0-20200711144034-c526ccc6f570/go.mod h1:1FYQXSbb6/9HQIkoF8XO7W/S8N7AZRkBsgwbcXRvk0E=
github.com/nspcc-dev/hrw v1.0.8 h1:vwRuJXZXgkMvf473vFzeWGCfY1WBVeSHAEHvR4u3/Cg=
github.com/nspcc-dev/hrw v1.0.8/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU=
github.com/nspcc-dev/neo-go v0.73.1-pre.0.20200303142215-f5a1b928ce09/go.mod h1:pPYwPZ2ks+uMnlRLUyXOpLieaDQSEaf4NM3zHVbRjmg=
github.com/nspcc-dev/neo-go v0.90.0 h1:ABNDrJuF9C1XuLQu0q9DKSVMlg9eQn/g6rX8Jbr31bo=
github.com/nspcc-dev/neo-go v0.90.0/go.mod h1:pPFdnApJwUSRAnpdiPBZl7I7jv0doDg5naecpSPK4+Q=
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
github.com/nspcc-dev/neofs-crypto v0.2.3/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
github.com/nspcc-dev/neofs-crypto v0.3.0 h1:zlr3pgoxuzrmGCxc5W8dGVfA9Rro8diFvVnBg0L4ifM=
github.com/nspcc-dev/neofs-crypto v0.3.0/go.mod h1:8w16GEJbH6791ktVqHN9YRNH3s9BEEKYxGhlFnp0cDw=
github.com/nspcc-dev/netmap v1.7.0 h1:ak64xn/gPdgYw4tsqSSF7kAGQGbEpeuJEF3XwBX4L9Y=
github.com/nspcc-dev/netmap v1.7.0/go.mod h1:mhV3UOg9ljQmu0teQShD6+JYX09XY5gu2I4hIByCH9M=
github.com/nspcc-dev/rfc6979 v0.1.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
github.com/nspcc-dev/rfc6979 v0.2.0 h1:3e1WNxrN60/6N0DW7+UYisLeZJyfqZTNOjeV/toYvOE=
github.com/nspcc-dev/rfc6979 v0.2.0/go.mod h1:exhIh1PdpDC5vQmyEsGvc4YDM/lyQp/452QxGq/UEso=
github.com/nspcc-dev/tzhash v1.4.0 h1:RVIR+mxOBHl58CE99+DXtE31ylD5PEkZSoWqoj4fVjg=
github.com/nspcc-dev/tzhash v1.4.0/go.mod h1:Z8gp/VZbyWgPhaMp/KTmeoW5UTynp/N60g0jTtSzBws=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -201,6 +254,7 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@ -212,16 +266,19 @@ github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@ -238,10 +295,12 @@ github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -254,9 +313,17 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@ -264,9 +331,11 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -289,6 +358,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -317,11 +387,15 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -330,8 +404,14 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
@ -342,6 +422,7 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180318012157-96caea41033d/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -408,9 +489,11 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=

View file

@ -3,6 +3,7 @@ package hash
import (
"bytes"
"github.com/gogo/protobuf/proto"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-api-go/internal"
"github.com/nspcc-dev/tzhash/tz"
@ -78,6 +79,13 @@ func (h Hash) Validate(hashes []Hash) bool {
return err == nil && ok
}
// Merge used by proto.Clone
func (h *Hash) Merge(src proto.Message) {
if tmp, ok := src.(*Hash); ok {
*h = *tmp
}
}
// Sum returns Tillich-Zémor checksum of data.
func Sum(data []byte) Hash { return tz.Sum(data) }

View file

@ -13,4 +13,7 @@ type Custom interface {
MarshalTo(data []byte) (int, error)
Unmarshal(data []byte) error
proto.Message
// Should contains for proto.Clone
proto.Merger
}

View file

@ -163,6 +163,13 @@ func (m *Object) SetHeader(h *Header) {
m.AddHeader(h)
}
// Merge used by proto.Clone
func (m *Object) Merge(src proto.Message) {
if tmp, ok := src.(*Object); ok {
tmp.CopyTo(m)
}
}
func (m Header) typeOf(t isHeader_Value) (ok bool) {
switch t.(type) {
case *Header_Link:
@ -233,8 +240,15 @@ func (m *Object) Copy() (obj *Object) {
// This function creates copies on every available data slice.
func (m *Object) CopyTo(o *Object) {
o.SystemHeader = m.SystemHeader
o.Headers = make([]Header, len(m.Headers))
o.Payload = make([]byte, len(m.Payload))
if m.Headers != nil {
o.Headers = make([]Header, len(m.Headers))
}
if m.Payload != nil {
o.Payload = make([]byte, len(m.Payload))
copy(o.Payload, m.Payload)
}
for i := range m.Headers {
switch v := m.Headers[i].Value.(type) {
@ -246,23 +260,23 @@ func (m *Object) CopyTo(o *Object) {
},
}
case *Header_HomoHash:
hash := proto.Clone(&v.HomoHash).(*Hash)
o.Headers[i] = Header{
Value: &Header_HomoHash{
HomoHash: v.HomoHash,
HomoHash: *hash,
},
}
case *Header_Token:
token := *v.Token
o.Headers[i] = Header{
Value: &Header_Token{
Token: v.Token,
Token: &token,
},
}
default:
o.Headers[i] = *proto.Clone(&m.Headers[i]).(*Header)
}
}
copy(o.Payload, m.Payload)
}
// Address returns object's address.

View file

@ -4,6 +4,7 @@ import (
"bytes"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/nspcc-dev/neofs-api-go/refs"
"github.com/nspcc-dev/neofs-api-go/service"
"github.com/nspcc-dev/neofs-api-go/storagegroup"
@ -17,7 +18,7 @@ Object:
SystemHeader:
- ID=7e0b9c6c-aabc-4985-949e-2680e577b48b
- CID=11111111111111111111111111111111
- OwnerID=ALYeYC41emF6MrmUMc4a8obEPdgFhq9ran
- OwnerID=NQHKh7fKGieCPrPuiEkY58ucRFwWMyU1Mc
- Version=1
- PayloadLength=1
- CreatedAt={UnixTime=1 Epoch=1}
@ -33,7 +34,7 @@ Object:
- Type=Tombstone
Value=MARKED
- Type=Token
Value={ID=7e0b9c6c-aabc-4985-949e-2680e577b48b OwnerID=ALYeYC41emF6MrmUMc4a8obEPdgFhq9ran Verb=Search Address=11111111111111111111111111111111/7e0b9c6c-aabc-4985-949e-2680e577b48b Created=1 ValidUntil=2 SessionKey=010203040506 Signature=010203040506}
Value={ID=7e0b9c6c-aabc-4985-949e-2680e577b48b OwnerID=NQHKh7fKGieCPrPuiEkY58ucRFwWMyU1Mc Verb=Search Address=11111111111111111111111111111111/7e0b9c6c-aabc-4985-949e-2680e577b48b Created=1 ValidUntil=2 SessionKey=010203040506 Signature=010203040506}
- Type=HomoHash
Value=1111111111111111111111111111111111111111111111111111111111111111
- Type=PayloadChecksum
@ -192,11 +193,23 @@ func TestObject_Copy(t *testing.T) {
},
})
cp := obj.Copy()
{ // Copying
cp := obj.Copy()
_, h := cp.LastHeader(HeaderType(TokenHdr))
require.NotNil(t, h)
require.Equal(t, token, h.GetValue().(*Header_Token).Token)
_, h := cp.LastHeader(HeaderType(TokenHdr))
require.NotNil(t, h)
require.Equal(t, token, h.GetValue().(*Header_Token).Token)
}
{ // Cloning
cl := proto.Clone(obj).(*Object)
require.Equal(t, obj, cl)
_, h := cl.LastHeader(HeaderType(TokenHdr))
h.GetToken().SetID(service.TokenID{3, 2, 1})
require.NotEqual(t, token, h.GetToken())
}
})
}

View file

@ -4,6 +4,7 @@ import (
"crypto/sha256"
"strings"
"github.com/gogo/protobuf/proto"
"github.com/nspcc-dev/neofs-api-go/internal"
)
@ -66,3 +67,14 @@ func (m Address) Hash() ([]byte, error) {
h := sha256.Sum256(append(m.ObjectID.Bytes(), m.CID.Bytes()...))
return h[:], nil
}
// Merge used by proto.Clone
func (m *Address) Merge(src proto.Message) {
if addr, ok := src.(*Address); ok {
cid := proto.Clone(&addr.CID).(*CID)
oid := proto.Clone(&addr.ObjectID).(*ObjectID)
m.CID = *cid
m.ObjectID = *oid
}
}

View file

@ -4,6 +4,7 @@ import (
"bytes"
"crypto/sha256"
"github.com/gogo/protobuf/proto"
"github.com/mr-tron/base58"
"github.com/pkg/errors"
)
@ -94,3 +95,10 @@ func (c CID) Verify(data []byte) error {
}
return nil
}
// Merge used by proto.Clone
func (c *CID) Merge(src proto.Message) {
if cid, ok := src.(*CID); ok {
*c = *cid
}
}

View file

@ -4,23 +4,28 @@ import (
"bytes"
"crypto/ecdsa"
"github.com/gogo/protobuf/proto"
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-api-go/chain"
"github.com/pkg/errors"
)
// NewOwnerID returns generated OwnerID from passed public keys.
func NewOwnerID(keys ...*ecdsa.PublicKey) (owner OwnerID, err error) {
if len(keys) == 0 {
// NewOwnerID returns generated OwnerID from passed public key.
func NewOwnerID(key *ecdsa.PublicKey) (owner OwnerID, err error) {
if key == nil {
return
}
var d []byte
d, err = base58.Decode(chain.KeysToAddress(keys...))
d, err = base58.Decode(chain.KeyToAddress(key))
if err != nil {
return
}
copy(owner[:], d)
return owner, nil
return
}
// Size returns OwnerID size in bytes (OwnerIDSize).
@ -63,3 +68,10 @@ func (o *OwnerID) Unmarshal(data []byte) error {
copy((*o)[:], data)
return nil
}
// Merge used by proto.Clone
func (o *OwnerID) Merge(src proto.Message) {
if uid, ok := src.(*OwnerID); ok {
*o = *uid
}
}

View file

@ -23,6 +23,19 @@ func TestSGID(t *testing.T) {
require.NoError(t, sgid2.Unmarshal(data))
require.Equal(t, sgid1, sgid2)
})
t.Run("check that proto.Clone works like expected", func(t *testing.T) {
var (
sgid1 UUID
sgid2 *UUID
)
sgid1, err := NewSGID()
require.NoError(t, err)
sgid2 = proto.Clone(&sgid1).(*SGID)
require.Equal(t, sgid1, *sgid2)
})
}
func TestUUID(t *testing.T) {
@ -66,7 +79,7 @@ func TestOwnerID(t *testing.T) {
t.Run("check that marshal/unmarshal works like expected", func(t *testing.T) {
var u1, u2 OwnerID
owner, err := NewOwnerID()
owner, err := NewOwnerID(nil)
require.NoError(t, err)
require.True(t, owner.Empty())
@ -80,6 +93,18 @@ func TestOwnerID(t *testing.T) {
require.NoError(t, u2.Unmarshal(data))
require.Equal(t, u1, u2)
})
t.Run("check that proto.Clone works like expected", func(t *testing.T) {
var u2 *OwnerID
key := test.DecodeKey(0)
u1, err := NewOwnerID(&key.PublicKey)
require.NoError(t, err)
u2 = proto.Clone(&u1).(*OwnerID)
require.Equal(t, u1, *u2)
})
}
func TestAddress(t *testing.T) {
@ -109,4 +134,8 @@ func TestAddress(t *testing.T) {
actual, err := ParseAddress(expect)
require.NoError(t, err)
require.Equal(t, expect, actual.String())
addr := proto.Clone(actual).(*Address)
require.Equal(t, actual, addr)
require.Equal(t, expect, addr.String())
}

View file

@ -4,6 +4,7 @@ import (
"bytes"
"encoding/hex"
"github.com/gogo/protobuf/proto"
"github.com/google/uuid"
"github.com/pkg/errors"
)
@ -74,3 +75,10 @@ func (u *UUID) Parse(id string) error {
copy((*u)[:], tmp[:])
return nil
}
// Merge used by proto.Clone
func (u *UUID) Merge(src proto.Message) {
if tmp, ok := src.(*UUID); ok {
*u = *tmp
}
}

View file

@ -4,6 +4,7 @@ import (
"crypto/ecdsa"
"io"
"github.com/gogo/protobuf/proto"
"github.com/nspcc-dev/neofs-api-go/internal"
crypto "github.com/nspcc-dev/neofs-crypto"
)
@ -109,6 +110,13 @@ func (t testCustomField) MarshalTo(data []byte) (int, error) { return 0, nil }
// Marshal skip, it's for test usage only.
func (t testCustomField) Marshal() ([]byte, error) { return nil, nil }
// Merge used by proto.Clone
func (t *testCustomField) Merge(src proto.Message) {
if tmp, ok := src.(*testCustomField); ok {
*t = *tmp
}
}
// GetBearerToken wraps Bearer field and return BearerToken interface.
//
// If Bearer field value is nil, nil returns.