diff --git a/CHANGELOG.md b/CHANGELOG.md index 898dcce..2cafb35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 4c768b2..31c87f6 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/acl/extended/enum.go b/acl/extended/enum.go new file mode 100644 index 0000000..e803476 --- /dev/null +++ b/acl/extended/enum.go @@ -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" +) + diff --git a/acl/extended/marshal.go b/acl/extended/marshal.go new file mode 100644 index 0000000..d1fac07 --- /dev/null +++ b/acl/extended/marshal.go @@ -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 +} diff --git a/acl/extended.go b/acl/extended/types.go similarity index 53% rename from acl/extended.go rename to acl/extended/types.go index df8402a..6b1b74b 100644 --- a/acl/extended.go +++ b/acl/extended/types.go @@ -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 -) diff --git a/acl/extended/wrappers.go b/acl/extended/wrappers.go new file mode 100644 index 0000000..2c8ff2e --- /dev/null +++ b/acl/extended/wrappers.go @@ -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) +} + + diff --git a/acl/wrappers_test.go b/acl/extended/wrappers_test.go similarity index 75% rename from acl/wrappers_test.go rename to acl/extended/wrappers_test.go index b7dbbe0..b139e59 100644 --- a/acl/wrappers_test.go +++ b/acl/extended/wrappers_test.go @@ -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()) } diff --git a/acl/types.go b/acl/types.go index c80c9cd..4aaf8fb 100644 --- a/acl/types.go +++ b/acl/types.go @@ -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) { diff --git a/acl/wrappers.go b/acl/wrappers.go deleted file mode 100644 index 30c2ee3..0000000 --- a/acl/wrappers.go +++ /dev/null @@ -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) -} diff --git a/chain/address.go b/chain/address.go index e10301f..0a56b8e 100644 --- a/chain/address.go +++ b/chain/address.go @@ -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() } diff --git a/chain/address_test.go b/chain/address_test.go index f83b1dd..a998a11 100644 --- a/chain/address_test.go +++ b/chain/address_test.go @@ -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)) }) } } diff --git a/container/types.go b/container/types.go index 38bdcff..be06b53 100644 --- a/container/types.go +++ b/container/types.go @@ -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) diff --git a/go.mod b/go.mod index eae84be..df12fcf 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index a3ed30b..ec6cd1f 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/hash/hash.go b/hash/hash.go index 9d75278..4e2fb05 100644 --- a/hash/hash.go +++ b/hash/hash.go @@ -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) } diff --git a/internal/proto.go b/internal/proto.go index 951168b..9a924b5 100644 --- a/internal/proto.go +++ b/internal/proto.go @@ -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 } diff --git a/object/types.go b/object/types.go index 058cd70..392e624 100644 --- a/object/types.go +++ b/object/types.go @@ -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. diff --git a/object/types_test.go b/object/types_test.go index 0a7085f..4a2ca92 100644 --- a/object/types_test.go +++ b/object/types_test.go @@ -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()) + } }) } diff --git a/refs/address.go b/refs/address.go index f07e317..ad5f420 100644 --- a/refs/address.go +++ b/refs/address.go @@ -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 + } +} diff --git a/refs/cid.go b/refs/cid.go index 4f0cf39..83450a9 100644 --- a/refs/cid.go +++ b/refs/cid.go @@ -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 + } +} diff --git a/refs/owner.go b/refs/owner.go index 1aed00c..0e599e9 100644 --- a/refs/owner.go +++ b/refs/owner.go @@ -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 + } +} diff --git a/refs/types_test.go b/refs/types_test.go index 2fd3ced..948a48b 100644 --- a/refs/types_test.go +++ b/refs/types_test.go @@ -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()) } diff --git a/refs/uuid.go b/refs/uuid.go index 2ffc525..5a49b92 100644 --- a/refs/uuid.go +++ b/refs/uuid.go @@ -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 + } +} diff --git a/service/verify.go b/service/verify.go index 7691220..2aca7cb 100644 --- a/service/verify.go +++ b/service/verify.go @@ -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.