Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MultiAddressReference type #514

Merged
merged 4 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions address.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
var (
// ErrUnknownAddrType gets returned for unknown address types.
ErrUnknownAddrType = ierrors.New("unknown address type")
// ErrInvalidAddressType gets returned when an address type is invalid.
ErrInvalidAddressType = ierrors.New("invalid address type")
// ErrInvalidNestedAddressType gets returned when a nested address inside a MultiAddress or RestrictedAddress is invalid.
ErrInvalidNestedAddressType = ierrors.New("invalid nested address type")
// ErrImplicitAccountCreationAddressInInvalidUnlockCondition gets returned when a Implicit Account Creation Address
Expand Down Expand Up @@ -93,7 +95,6 @@ type NetworkPrefix string
// Network prefixes.
const (
PrefixMainnet NetworkPrefix = "iota"
PrefixDevnet NetworkPrefix = "atoi"
PrefixShimmer NetworkPrefix = "smr"
PrefixTestnet NetworkPrefix = "rms"
)
Expand Down Expand Up @@ -213,16 +214,34 @@ func ParseBech32(s string) (NetworkPrefix, Address, error) {
//nolint:exhaustive
switch addrType {
case AddressMulti:
// return the HRP so we can at least check for correct network
return NetworkPrefix(hrp), nil, ErrMultiAddrCannotBeReconstructedViaBech32
multiAddrRef, _, err := MultiAddressReferenceFromBytes(addrData)
if err != nil {
return "", nil, ierrors.Errorf("invalid multi address: %w", err)
}

return NetworkPrefix(hrp), multiAddrRef, nil

case AddressRestricted:
if len(addrData) == 1 {
return "", nil, serializer.ErrDeserializationNotEnoughData
}
underlyingAddrType := AddressType(addrData[1])
if underlyingAddrType == AddressMulti {
// return the HRP so we can at least check for correct network
return NetworkPrefix(hrp), nil, ErrMultiAddrCannotBeReconstructedViaBech32
multiAddrRef, consumed, err := MultiAddressReferenceFromBytes(addrData[1:])
if err != nil {
return "", nil, ierrors.Errorf("invalid multi address: %w", err)
}

// get the address capabilities from the remaining bytes
capabilities, _, err := AddressCapabilitiesBitMaskFromBytes(addrData[1+consumed:])
if err != nil {
return "", nil, ierrors.Errorf("invalid address capabilities: %w", err)
}

return NetworkPrefix(hrp), &RestrictedAddress{
Address: multiAddrRef,
AllowedCapabilities: capabilities,
}, nil
}
}

Expand Down
8 changes: 8 additions & 0 deletions address_capabilities_bitmask.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package iotago

import (
"context"

"github.com/iotaledger/hive.go/runtime/options"
"github.com/iotaledger/hive.go/serializer/v2"
)
Expand Down Expand Up @@ -91,6 +93,12 @@ func WithAddressCanReceiveDelegationOutputs(canReceiveDelegationOutputs bool) op

type AddressCapabilitiesBitMask []byte

func AddressCapabilitiesBitMaskFromBytes(bytes []byte) (AddressCapabilitiesBitMask, int, error) {
var result AddressCapabilitiesBitMask
consumed, err := CommonSerixAPI().Decode(context.TODO(), bytes, &result)
return result, consumed, err
}

func AddressCapabilitiesBitMaskWithCapabilities(opts ...options.Option[AddressCapabilitiesOptions]) AddressCapabilitiesBitMask {
options := options.Apply(new(AddressCapabilitiesOptions), opts)

Expand Down
9 changes: 5 additions & 4 deletions address_multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ import (
"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/hive.go/lo"
"github.com/iotaledger/hive.go/serializer/v2"
"github.com/iotaledger/hive.go/serializer/v2/byteutils"
"github.com/iotaledger/iota.go/v4/hexutil"
)

const (
AddressWeightSerializedBytesSize = serializer.OneByte
AddressMultiIDLength = serializer.OneByte + blake2b.Size256
)

var (
ErrMultiAddrCannotBeReconstructedViaBech32 = ierrors.New("multi address cannot be reconstructed via bech32")
ErrMultiAddressWeightInvalid = ierrors.New("multi address weight invalid")
ErrMultiAddressThresholdInvalid = ierrors.New("multi address treshold invalid")
ErrMultiAddressWeightInvalid = ierrors.New("multi address weight invalid")
ErrMultiAddressThresholdInvalid = ierrors.New("multi address treshold invalid")
)

// AddressWithWeight is an Address with a weight used for threshold calculation in a MultiAddress.
Expand Down Expand Up @@ -67,7 +68,7 @@ func (addr *MultiAddress) ID() []byte {
hash := blake2b.Sum256(lo.PanicOnErr(CommonSerixAPI().Encode(context.TODO(), addr)))

// prefix the hash of the multi address bytes with the AddressType
return append([]byte{byte(AddressMulti)}, hash[:]...)
return byteutils.ConcatBytes([]byte{byte(AddressMulti)}, hash[:])
}

func (addr *MultiAddress) Key() string {
Expand Down
77 changes: 77 additions & 0 deletions address_multi_reference.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package iotago

import (
"bytes"

"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/hive.go/lo"
"github.com/iotaledger/iota.go/v4/hexutil"
)

// MultiAddressReference is a reference to a MultiAddress.
// HINT: This is not an actual AddressType that is used in the protocol, so it should not be registered in serix.
// It should only be used internally or in APIs.
type MultiAddressReference struct {
MultiAddressID []byte
}

func (addr *MultiAddressReference) Clone() Address {
return &MultiAddressReference{
MultiAddressID: lo.CopySlice(addr.MultiAddressID),
}
}

func (addr *MultiAddressReference) VBytes(_ *RentStructure, _ VBytesFunc) VBytes {
panic("not used")
}

func (addr *MultiAddressReference) ID() []byte {
return addr.MultiAddressID
}

func (addr *MultiAddressReference) Key() string {
return string(addr.ID())
}

func (addr *MultiAddressReference) Equal(other Address) bool {
otherAddr, is := other.(*MultiAddressReference)
if !is {
return false
}

return bytes.Equal(addr.MultiAddressID, otherAddr.MultiAddressID)
}

func (addr *MultiAddressReference) Type() AddressType {
return AddressMulti
}

func (addr *MultiAddressReference) Bech32(hrp NetworkPrefix) string {
return bech32StringBytes(hrp, addr.ID())
}

func (addr *MultiAddressReference) String() string {
return hexutil.EncodeHex(addr.ID())
}

func (addr *MultiAddressReference) Size() int {
panic("not used")
}

func MultiAddressReferenceFromBytes(bytes []byte) (*MultiAddressReference, int, error) {
if len(bytes) < AddressMultiIDLength {
return nil, 0, ierrors.New("invalid multi address ID length")
}

if bytes[0] != byte(AddressMulti) {
return nil, 0, ErrInvalidAddressType
}

return &MultiAddressReference{MultiAddressID: bytes[:AddressMultiIDLength]}, AddressMultiIDLength, nil
}

func NewMultiAddressReferenceFromMultiAddress(address *MultiAddress) *MultiAddressReference {
return &MultiAddressReference{
MultiAddressID: address.ID(),
}
}
Loading