-
Notifications
You must be signed in to change notification settings - Fork 95
/
api_common.go
192 lines (168 loc) · 8.49 KB
/
api_common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package iotago
import (
"context"
"fmt"
"github.com/iotaledger/hive.go/ierrors"
"github.com/iotaledger/hive.go/serializer/v2/serix"
)
type (
PrefixedStringUint8 string
PrefixedStringUint16 string
PrefixedStringUint32 string
PrefixedStringUint64 string
)
var (
// the addresses need to be unique and lexically ordered to calculate a deterministic bech32 address for a MultiAddress.
// HINT: the uniqueness is checked within a custom validator function, which is on MultiAddress level.
addressesWithWeightArrRules = &serix.ArrayRules{
Min: 2,
Max: 10,
}
// multiAddressValidatorFunc is a validator which checks that:
// 1. ImplicitAccountCreationAddress, MultiAddresses, RestrictedAddress are not nested inside the MultiAddress.
// 2. The weight of each address is at least 1.
// 3. The threshold is smaller or equal to the cumulative weight of all addresses.
multiAddressValidatorFunc = func(_ context.Context, addr MultiAddress) error {
var cumulativeWeight uint16
for idx, address := range addr.Addresses {
switch addr := address.Address.(type) {
case *Ed25519Address:
case *AccountAddress:
case *NFTAddress:
case *AnchorAddress:
case *ImplicitAccountCreationAddress:
return ierrors.WithMessagef(ErrInvalidNestedAddressType, "address with index %d is an implicit account creation address inside a multi address", idx)
case *MultiAddress:
return ierrors.WithMessagef(ErrInvalidNestedAddressType, "address with index %d is a multi address inside a multi address", idx)
case *RestrictedAddress:
return ierrors.WithMessagef(ErrInvalidNestedAddressType, "address with index %d is a restricted address inside a multi address", idx)
default:
// We're switching on the Go address type here, so we can only run into the default case
// if we added a new address type and have not handled it above or a user passed a type
// implementing the address interface (only possible when iota.go is used as a library).
// In both cases we want to panic.
panic(fmt.Sprintf("address with index %d has an unknown address type (%T) inside a multi address", idx, addr))
}
// check for minimum address weight
if address.Weight == 0 {
return ierrors.WithMessagef(ErrMultiAddressWeightInvalid, "address with index %d needs to have at least weight=1", idx)
}
cumulativeWeight += uint16(address.Weight)
}
// check for valid threshold
if addr.Threshold > cumulativeWeight {
return ierrors.WithMessagef(ErrMultiAddressThresholdInvalid, "the threshold value exceeds the cumulative weight of all addresses (%d>%d)", addr.Threshold, cumulativeWeight)
}
if addr.Threshold < 1 {
return ierrors.WithMessage(ErrMultiAddressThresholdInvalid, "multi addresses need to have at least threshold=1")
}
return nil
}
// restrictedAddressValidatorFunc is a validator which checks that:
// 1. ImplicitAccountCreationAddress are not nested inside the RestrictedAddress.
// 2. RestrictedAddresses are not nested inside the RestrictedAddress.
// 3. The bitmask does not contain trailing zero bytes.
restrictedAddressValidatorFunc = func(_ context.Context, addr RestrictedAddress) error {
if err := BitMaskNonTrailingZeroBytesValidatorFunc(addr.AllowedCapabilities); err != nil {
return ierrors.WithMessagef(ErrInvalidRestrictedAddress, "invalid allowed capabilities bitmask: %w", err)
}
switch addr.Address.(type) {
case *Ed25519Address, *AccountAddress, *NFTAddress, *AnchorAddress, *MultiAddress:
// allowed address types
case *ImplicitAccountCreationAddress:
return ierrors.WithMessage(ErrInvalidNestedAddressType, "underlying address is an implicit account creation address inside a restricted address")
case *RestrictedAddress:
return ierrors.WithMessage(ErrInvalidNestedAddressType, "underlying address is a restricted address inside a restricted address")
default:
// We're switching on the Go address type here, so we can only run into the default case
// if we added a new address type and have not handled it above or a user passed a type
// implementing the address interface (only possible when iota.go is used as a library).
// In both cases we want to panic.
panic(fmt.Sprintf("underlying address of the restricted address is of unknown address type (%T)", addr))
}
return nil
}
blockIssuerKeysArrRules = &serix.ArrayRules{
Min: MinBlockIssuerKeysCount,
Max: MaxBlockIssuerKeysCount,
}
)
func CommonSerixAPI() *serix.API {
api := serix.NewAPI()
{
must(api.RegisterTypeSettings(PrefixedStringUint8(""), serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsByte)))
must(api.RegisterTypeSettings(PrefixedStringUint16(""), serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsUint16)))
must(api.RegisterTypeSettings(PrefixedStringUint32(""), serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsUint32)))
must(api.RegisterTypeSettings(PrefixedStringUint64(""), serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsUint64)))
}
{
must(api.RegisterTypeSettings(Ed25519Address{},
serix.TypeSettings{}.WithObjectType(uint8(AddressEd25519)).WithFieldKey("pubKeyHash")),
)
must(api.RegisterTypeSettings(AccountAddress{},
serix.TypeSettings{}.WithObjectType(uint8(AddressAccount)).WithFieldKey("accountId")),
)
must(api.RegisterTypeSettings(NFTAddress{},
serix.TypeSettings{}.WithObjectType(uint8(AddressNFT)).WithFieldKey("nftId")),
)
must(api.RegisterTypeSettings(AnchorAddress{},
serix.TypeSettings{}.WithObjectType(uint8(AddressAnchor)).WithFieldKey("anchorId")),
)
must(api.RegisterTypeSettings(ImplicitAccountCreationAddress{},
serix.TypeSettings{}.WithObjectType(uint8(AddressImplicitAccountCreation)).WithFieldKey("pubKeyHash")),
)
must(api.RegisterTypeSettings(MultiAddress{},
serix.TypeSettings{}.WithObjectType(uint8(AddressMulti))),
)
must(api.RegisterValidator(MultiAddress{}, multiAddressValidatorFunc))
must(api.RegisterTypeSettings(AddressesWithWeight{},
serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsByte).WithArrayRules(addressesWithWeightArrRules),
))
must(api.RegisterValidator(AddressesWithWeight{}, func(_ context.Context, keys AddressesWithWeight) error {
return SliceValidator(keys, LexicalOrderAndUniquenessValidator[*AddressWithWeight]())
}))
must(api.RegisterTypeSettings(RestrictedAddress{},
serix.TypeSettings{}.WithObjectType(uint8(AddressRestricted))),
)
must(api.RegisterValidator(RestrictedAddress{}, restrictedAddressValidatorFunc))
must(api.RegisterTypeSettings(AddressCapabilitiesBitMask{},
serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsByte).WithMaxLen(2),
))
must(api.RegisterInterfaceObjects((*Address)(nil), (*Ed25519Address)(nil)))
must(api.RegisterInterfaceObjects((*Address)(nil), (*AccountAddress)(nil)))
must(api.RegisterInterfaceObjects((*Address)(nil), (*NFTAddress)(nil)))
must(api.RegisterInterfaceObjects((*Address)(nil), (*AnchorAddress)(nil)))
must(api.RegisterInterfaceObjects((*Address)(nil), (*ImplicitAccountCreationAddress)(nil)))
must(api.RegisterInterfaceObjects((*Address)(nil), (*MultiAddress)(nil)))
must(api.RegisterInterfaceObjects((*Address)(nil), (*RestrictedAddress)(nil)))
// All versions of the protocol need to be able to parse older protocol parameter versions.
{
must(api.RegisterTypeSettings(StorageScoreStructure{}, serix.TypeSettings{}))
must(api.RegisterTypeSettings(V3ProtocolParameters{},
serix.TypeSettings{}.WithObjectType(uint8(ProtocolParametersV3))),
)
must(api.RegisterInterfaceObjects((*ProtocolParameters)(nil), (*V3ProtocolParameters)(nil)))
}
{
must(api.RegisterTypeSettings(Ed25519PublicKeyHashBlockIssuerKey{},
serix.TypeSettings{}.WithObjectType(byte(BlockIssuerKeyPublicKeyHash)),
))
must(api.RegisterInterfaceObjects((*BlockIssuerKey)(nil), (*Ed25519PublicKeyHashBlockIssuerKey)(nil)))
must(api.RegisterValidator(BlockIssuerKeys{}, func(_ context.Context, keys BlockIssuerKeys) error {
return SliceValidator(keys, LexicalOrderAndUniquenessValidator[BlockIssuerKey]())
}))
must(api.RegisterTypeSettings(BlockIssuerKeys{},
serix.TypeSettings{}.WithLengthPrefixType(serix.LengthPrefixTypeAsByte).WithArrayRules(blockIssuerKeysArrRules),
))
}
}
return api
}
func ProtocolParametersFromBytes(bytes []byte) (params ProtocolParameters, bytesRead int, err error) {
var protocolParameters ProtocolParameters
n, err := CommonSerixAPI().Decode(context.TODO(), bytes, &protocolParameters, serix.WithValidation())
if err != nil {
return nil, 0, err
}
return protocolParameters, n, nil
}