user: Refactor user.ID
structure #323
2 changed files with 37 additions and 43 deletions
77
user/id.go
77
user/id.go
|
@ -12,9 +12,8 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
const idSize = 25
|
||||
|
||||
var zeroSlice = bytes.Repeat([]byte{0}, idSize)
|
||||
// idFullSize is the size of ID in bytes, including prefix and checksum.
|
||||
const idFullSize = util.Uint160Size + 5
|
||||
|
||||
// ID identifies users of the FrostFS system.
|
||||
//
|
||||
|
@ -25,7 +24,7 @@ var zeroSlice = bytes.Repeat([]byte{0}, idSize)
|
|||
// so it MUST be initialized using some modifying function (e.g. SetScriptHash,
|
||||
// IDFromKey, etc.).
|
||||
type ID struct {
|
||||
w []byte
|
||||
w util.Uint160
|
||||
}
|
||||
|
||||
// ReadFromV2 reads ID from the refs.OwnerID message. Returns an error if
|
||||
|
@ -33,22 +32,7 @@ type ID struct {
|
|||
//
|
||||
// See also WriteToV2.
|
||||
func (x *ID) ReadFromV2(m refs.OwnerID) error {
|
||||
w := m.GetValue()
|
||||
if len(w) != idSize {
|
||||
return fmt.Errorf("invalid length %d, expected %d", len(w), idSize)
|
||||
}
|
||||
|
||||
if w[0] != address.NEO3Prefix {
|
||||
return fmt.Errorf("invalid prefix byte 0x%X, expected 0x%X", w[0], address.NEO3Prefix)
|
||||
}
|
||||
|
||||
if !bytes.Equal(w[21:], hash.Checksum(w[:21])) {
|
||||
return errors.New("checksum mismatch")
|
||||
}
|
||||
|
||||
x.w = w
|
||||
|
||||
return nil
|
||||
return x.setUserID(m.GetValue())
|
||||
}
|
||||
|
||||
// WriteToV2 writes ID to the refs.OwnerID message.
|
||||
|
@ -56,25 +40,17 @@ func (x *ID) ReadFromV2(m refs.OwnerID) error {
|
|||
//
|
||||
// See also ReadFromV2.
|
||||
func (x ID) WriteToV2(m *refs.OwnerID) {
|
||||
m.SetValue(x.w)
|
||||
m.SetValue(x.WalletBytes())
|
||||
}
|
||||
|
||||
// SetScriptHash forms user ID from wallet address scripthash.
|
||||
func (x *ID) SetScriptHash(scriptHash util.Uint160) {
|
||||
if cap(x.w) < idSize {
|
||||
x.w = make([]byte, idSize)
|
||||
} else if len(x.w) < idSize {
|
||||
x.w = x.w[:idSize]
|
||||
}
|
||||
|
||||
x.w[0] = address.Prefix
|
||||
copy(x.w[1:], scriptHash.BytesBE())
|
||||
copy(x.w[21:], hash.Checksum(x.w[:21]))
|
||||
x.w = scriptHash
|
||||
}
|
||||
|
||||
// ScriptHash calculates and returns script hash of ID.
|
||||
func (x *ID) ScriptHash() (util.Uint160, error) {
|
||||
return util.Uint160DecodeBytesBE(x.w[1:21])
|
||||
func (x *ID) ScriptHash() util.Uint160 {
|
||||
return x.w
|
||||
}
|
||||
|
||||
// WalletBytes returns FrostFS user ID as Neo3 wallet address in a binary format.
|
||||
|
@ -83,14 +59,18 @@ func (x *ID) ScriptHash() (util.Uint160, error) {
|
|||
//
|
||||
// See also Neo3 wallet docs.
|
||||
func (x ID) WalletBytes() []byte {
|
||||
return x.w
|
||||
v := make([]byte, idFullSize)
|
||||
|
||||
v[0] = address.Prefix
|
||||
copy(v[1:], x.w[:])
|
||||
copy(v[21:], hash.Checksum(v[:21]))
|
||||
return v
|
||||
}
|
||||
|
||||
// EncodeToString encodes ID into FrostFS API V2 protocol string.
|
||||
//
|
||||
// See also DecodeString.
|
||||
func (x ID) EncodeToString() string {
|
||||
return base58.Encode(x.w)
|
||||
return base58.Encode(x.WalletBytes())
|
||||
fyrchik
commented
One way to achieve this is to move encoding to a function `EncodeToString()` makes 3 allocations. One of them (inside `WalletBytes()`) can be avoided with little cost.
```
$ go build -gcflags "-m -l" ./user
...
user/id.go:62:11: make([]byte, 25) escapes to heap
```
One way to achieve this is to move encoding to a function `(ID).encode([]byte)`.
Both `WalletBytes()` and `EncodeToString()` methods will create new slice and `encode` to it.
fyrchik
commented
We can do this in another PR, though. We can do this in another PR, though.
|
||||
}
|
||||
|
||||
// DecodeString decodes FrostFS API V2 protocol string. Returns an error
|
||||
|
@ -100,14 +80,11 @@ func (x ID) EncodeToString() string {
|
|||
//
|
||||
// See also EncodeToString.
|
||||
func (x *ID) DecodeString(s string) error {
|
||||
var err error
|
||||
|
||||
x.w, err = base58.Decode(s)
|
||||
w, err := base58.Decode(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode base58: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return x.setUserID(w)
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer.
|
||||
|
@ -121,10 +98,28 @@ func (x ID) String() string {
|
|||
|
||||
// Equals defines a comparison relation between two ID instances.
|
||||
func (x ID) Equals(x2 ID) bool {
|
||||
return bytes.Equal(x.w, x2.w)
|
||||
return x.w == x2.w
|
||||
}
|
||||
|
||||
// IsEmpty returns True, if ID is empty value.
|
||||
func (x ID) IsEmpty() bool {
|
||||
return bytes.Equal(zeroSlice, x.w)
|
||||
return x.w == util.Uint160{}
|
||||
}
|
||||
|
||||
func (x *ID) setUserID(w []byte) error {
|
||||
if len(w) != idFullSize {
|
||||
return fmt.Errorf("invalid length %d, expected %d", len(w), idFullSize)
|
||||
}
|
||||
|
||||
if w[0] != address.NEO3Prefix {
|
||||
return fmt.Errorf("invalid prefix byte 0x%X, expected 0x%X", w[0], address.NEO3Prefix)
|
||||
}
|
||||
|
||||
if !bytes.Equal(w[21:], hash.Checksum(w[:21])) {
|
||||
return errors.New("checksum mismatch")
|
||||
}
|
||||
|
||||
copy(x.w[:], w[1:21])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -51,8 +51,7 @@ func TestID_SetScriptHash(t *testing.T) {
|
|||
func TestID_ScriptHash(t *testing.T) {
|
||||
userID := usertest.ID()
|
||||
|
||||
scriptHash, err := userID.ScriptHash()
|
||||
require.NoError(t, err)
|
||||
scriptHash := userID.ScriptHash()
|
||||
|
||||
ownerAddress := userID.EncodeToString()
|
||||
decodedScriptHash, err := address.StringToUint160(ownerAddress)
|
||||
|
|
Loading…
Add table
Reference in a new issue
The comment about
MUST NOT be mutated
can be removed now.