Skip to content

Commit 7722f4f

Browse files
sameh-faroukclaude
andauthored
fix(go-client): resolve errors from runtime metadata instead of hardcoded list (#1086)
* fix(go-client): resolve errors from runtime metadata instead of hardcoded list Replace the static moduleErrors/tfgridModuleErrors/smartContractModuleErrors/ tftBridgeModuleErrors arrays with a single call to metadata.FindError(). The hardcoded lists required manual updates after every runtime upgrade that added, removed, or reordered pallet errors. Missing entries caused the client to return unhelpful "unknown code" messages instead of the actual error name. The runtime metadata (V14+) already contains all pallet error definitions. The go-substrate-rpc-client library provides FindError(moduleIndex, errorIndex) which resolves to the error variant name from metadata at connect time. This is not a breaking change — the public API still returns error with the same error name strings (e.g. "NodeHasRentContract"). The only difference is the source: metadata instead of a static array. Fixes #778 * style(go-client): gofmt utils.go (remove extra blank line) Removing the hardcoded module-error var block left a double blank line before CallResponse, failing the gofmt lint check. Run gofmt -w. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent cf2c8d1 commit 7722f4f

1 file changed

Lines changed: 11 additions & 282 deletions

File tree

clients/tfchain-client-go/utils.go

Lines changed: 11 additions & 282 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package substrate
22

33
import (
4-
"encoding/binary"
54
"fmt"
65
"time"
76

@@ -17,275 +16,6 @@ var (
1716
Gigabyte = 1024 * 1024 * 1024
1817
)
1918

20-
// map from module index to error list
21-
// https://github.com/threefoldtech/tfchain/blob/development/substrate-node/runtime/src/lib.rs#L697
22-
var moduleErrors = [][]string{
23-
nil, // 0 -> System
24-
nil, // 1 -> Timestamp
25-
nil, // 2
26-
nil, // 3 -> Utility
27-
nil, // 4 -> Scheduler
28-
nil, // 5
29-
nil, // 6
30-
nil, // 7
31-
nil, // 8
32-
nil, // 9
33-
nil, // 10 -> ValidatorSet
34-
nil, // 11 Session
35-
nil, // 12 -> Aura
36-
nil, // 13 -> Grandpa
37-
nil, // 14 -> Historical
38-
nil, // 15 -> Authorship
39-
nil, // 16
40-
nil, // 17
41-
nil, // 18
42-
nil, // 19
43-
nil, // 20 -> Balances
44-
nil, // 21 -> TransactionPayment
45-
nil, // 22
46-
nil, // 23
47-
nil, // 24
48-
tfgridModuleErrors, // 25 -> TfgridModule
49-
smartContractModuleErrors, // 26 -> SmartContractModule
50-
tftBridgeModuleErrors, // 27 -> TFTBridgeModule
51-
nil, // 28 -> TftPriceModule
52-
nil, // 29 -> BurningModule
53-
nil, // 30 -> TFKVStore
54-
nil, // 31 -> RuntimeUpgrade
55-
nil, // 32
56-
nil, // 33
57-
nil, // 34
58-
nil, // 35
59-
nil, // 36
60-
nil, // 37
61-
nil, // 38
62-
nil, // 39
63-
nil, // 40 -> Council
64-
nil, // 41 -> CouncilMembership
65-
nil, // 42
66-
nil, // 43 -> Dao
67-
nil, // 44
68-
nil, // 45
69-
nil, // 46
70-
nil, // 47
71-
nil, // 48
72-
nil, // 49
73-
nil, // 50 -> Validator
74-
}
75-
76-
// https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-smart-contract/src/lib.rs#L336
77-
var smartContractModuleErrors = []string{
78-
"TwinNotExists",
79-
"NodeNotExists",
80-
"FarmNotExists",
81-
"FarmHasNotEnoughPublicIPs",
82-
"FarmHasNotEnoughPublicIPsFree",
83-
"FailedToReserveIP",
84-
"FailedToFreeIPs",
85-
"ContractNotExists",
86-
"TwinNotAuthorizedToUpdateContract",
87-
"TwinNotAuthorizedToCancelContract",
88-
"NodeNotAuthorizedToDeployContract",
89-
"NodeNotAuthorizedToComputeReport",
90-
"PricingPolicyNotExists",
91-
"ContractIsNotUnique",
92-
"ContractWrongBillingLoopIndex",
93-
"NameExists",
94-
"NameNotValid",
95-
"InvalidContractType",
96-
"TFTPriceValueError",
97-
"NotEnoughResourcesOnNode",
98-
"NodeNotAuthorizedToReportResources",
99-
"MethodIsDeprecated",
100-
"NodeHasActiveContracts",
101-
"NodeHasRentContract",
102-
"FarmIsNotDedicated",
103-
"NodeNotAvailableToDeploy",
104-
"CannotUpdateContractInGraceState",
105-
"NumOverflow",
106-
"OffchainSignedTxCannotSign",
107-
"OffchainSignedTxAlreadySent",
108-
"OffchainSignedTxNoLocalAccountAvailable",
109-
"NameContractNameTooShort",
110-
"NameContractNameTooLong",
111-
"InvalidProviderConfiguration",
112-
"NoSuchSolutionProvider",
113-
"SolutionProviderNotApproved",
114-
"TwinNotAuthorized",
115-
"ServiceContractNotExists",
116-
"ServiceContractCreationNotAllowed",
117-
"ServiceContractModificationNotAllowed",
118-
"ServiceContractApprovalNotAllowed",
119-
"ServiceContractRejectionNotAllowed",
120-
"ServiceContractBillingNotApprovedByBoth",
121-
"ServiceContractBillingVariableAmountTooHigh",
122-
"ServiceContractBillMetadataTooLong",
123-
"ServiceContractMetadataTooLong",
124-
"ServiceContractNotEnoughFundsToPayBill",
125-
"CanOnlyIncreaseFrequency",
126-
"IsNotAnAuthority",
127-
"WrongAuthority",
128-
"UnauthorizedToChangeSolutionProviderId",
129-
"UnauthorizedToSetExtraFee",
130-
"RewardDistributionError",
131-
"ContractPaymentStateNotExists",
132-
"OnlyTwinAdminCanDeployOnThisNode",
133-
}
134-
135-
// https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-tfgrid/src/lib.rs#L442
136-
var tfgridModuleErrors = []string{
137-
"NoneValue",
138-
"StorageOverflow",
139-
"CannotCreateNode",
140-
"NodeNotExists",
141-
"NodeWithTwinIdExists",
142-
"CannotDeleteNode",
143-
"NodeDeleteNotAuthorized",
144-
"NodeUpdateNotAuthorized",
145-
"FarmExists",
146-
"FarmNotExists",
147-
"CannotCreateFarmWrongTwin",
148-
"CannotUpdateFarmWrongTwin",
149-
"CannotDeleteFarm",
150-
"CannotDeleteFarmWithPublicIPs",
151-
"CannotDeleteFarmWithNodesAssigned",
152-
"CannotDeleteFarmWrongTwin",
153-
"IpExists",
154-
"IpNotExists",
155-
"EntityWithNameExists",
156-
"EntityWithPubkeyExists",
157-
"EntityNotExists",
158-
"EntitySignatureDoesNotMatch",
159-
"EntityWithSignatureAlreadyExists",
160-
"CannotUpdateEntity",
161-
"CannotDeleteEntity",
162-
"SignatureLengthIsIncorrect",
163-
"TwinExists",
164-
"TwinNotExists",
165-
"TwinWithPubkeyExists",
166-
"CannotCreateTwin",
167-
"UnauthorizedToUpdateTwin",
168-
"TwinCannotBoundToItself",
169-
"PricingPolicyExists",
170-
"PricingPolicyNotExists",
171-
"PricingPolicyWithDifferentIdExists",
172-
"CertificationCodeExists",
173-
"FarmingPolicyAlreadyExists",
174-
"FarmPayoutAdressAlreadyRegistered",
175-
"FarmerDoesNotHaveEnoughFunds",
176-
"UserDidNotSignTermsAndConditions",
177-
"FarmerDidNotSignTermsAndConditions",
178-
"FarmerNotAuthorized",
179-
"InvalidFarmName",
180-
"AlreadyCertifier",
181-
"NotCertifier",
182-
"NotAllowedToCertifyNode",
183-
"FarmingPolicyNotExists",
184-
"RelayTooShort",
185-
"RelayTooLong",
186-
"InvalidRelay",
187-
"FarmNameTooShort",
188-
"FarmNameTooLong",
189-
"InvalidPublicIP",
190-
"PublicIPTooShort",
191-
"PublicIPTooLong",
192-
"GatewayIPTooShort",
193-
"GatewayIPTooLong",
194-
"IP4TooShort",
195-
"IP4TooLong",
196-
"InvalidIP4",
197-
"GW4TooShort",
198-
"GW4TooLong",
199-
"InvalidGW4",
200-
"IP6TooShort",
201-
"IP6TooLong",
202-
"InvalidIP6",
203-
"GW6TooShort",
204-
"GW6TooLong",
205-
"InvalidGW6",
206-
"DomainTooShort",
207-
"DomainTooLong",
208-
"InvalidDomain",
209-
"MethodIsDeprecated",
210-
"InterfaceNameTooShort",
211-
"InterfaceNameTooLong",
212-
"InvalidInterfaceName",
213-
"InterfaceMacTooShort",
214-
"InterfaceMacTooLong",
215-
"InvalidMacAddress",
216-
"InterfaceIpTooShort",
217-
"InterfaceIpTooLong",
218-
"InvalidInterfaceIP",
219-
"InvalidZosVersion",
220-
"FarmingPolicyExpired",
221-
"InvalidHRUInput",
222-
"InvalidSRUInput",
223-
"InvalidCRUInput",
224-
"InvalidMRUInput",
225-
"LatitudeInputTooShort",
226-
"LatitudeInputTooLong",
227-
"InvalidLatitudeInput",
228-
"LongitudeInputTooShort",
229-
"LongitudeInputTooLong",
230-
"InvalidLongitudeInput",
231-
"CountryNameTooShort",
232-
"CountryNameTooLong",
233-
"InvalidCountryName",
234-
"CityNameTooShort",
235-
"CityNameTooLong",
236-
"InvalidCityName",
237-
"InvalidCountryCityPair",
238-
"SerialNumberTooShort",
239-
"SerialNumberTooLong",
240-
"InvalidSerialNumber",
241-
"DocumentLinkInputTooShort",
242-
"DocumentLinkInputTooLong",
243-
"InvalidDocumentLinkInput",
244-
"DocumentHashInputTooShort",
245-
"DocumentHashInputTooLong",
246-
"InvalidDocumentHashInput",
247-
"InvalidPublicConfig",
248-
"UnauthorizedToChangePowerTarget",
249-
"NodeHasActiveContracts",
250-
"InvalidRelayAddress",
251-
"InvalidTimestampHint",
252-
"InvalidStorageInput",
253-
"TwinTransferRequestNotFound",
254-
"TwinTransferNewAccountHasTwin",
255-
"TwinTransferPendingExists",
256-
"NodeV3BillingOptOutAlreadyEnabled",
257-
"AlreadyTwinAdmin",
258-
"NotTwinAdmin",
259-
"TwinAdminListFull",
260-
"NodeNotOptedOutOfV3Billing",
261-
"NodeV3OptOutMetadataTooLong",
262-
}
263-
264-
// https://github.com/threefoldtech/tfchain/blob/development/substrate-node/pallets/pallet-tft-bridge/src/lib.rs#L152
265-
var tftBridgeModuleErrors = []string{
266-
"ValidatorExists",
267-
"ValidatorNotExists",
268-
"TransactionValidatorExists",
269-
"TransactionValidatorNotExists",
270-
"MintTransactionExists",
271-
"MintTransactionAlreadyExecuted",
272-
"MintTransactionNotExists",
273-
"BurnTransactionExists",
274-
"BurnTransactionNotExists",
275-
"BurnSignatureExists",
276-
"EnoughBurnSignaturesPresent",
277-
"RefundSignatureExists",
278-
"BurnTransactionAlreadyExecuted",
279-
"RefundTransactionNotExists",
280-
"RefundTransactionAlreadyExecuted",
281-
"EnoughRefundSignaturesPresent",
282-
"NotEnoughBalanceToSwap",
283-
"AmountIsLessThanWithdrawFee",
284-
"AmountIsLessThanDepositFee",
285-
"WrongParametersProvided",
286-
"InvalidStellarPublicKey",
287-
}
288-
28919
type CallResponse struct {
29020
Hash types.Hash
29121
Events *EventRecords
@@ -536,20 +266,19 @@ func (s *Substrate) checkForError(callResponse *CallResponse) error {
536266
if err != nil {
537267
return err
538268
}
539-
b := make([]byte, 4)
540-
for i, v := range e.DispatchError.ModuleError.Error {
541-
b[i] = byte(v)
542-
}
543-
errIndex := binary.LittleEndian.Uint32(b[:])
544269
if *accId == who {
545-
if int(e.DispatchError.ModuleError.Index) < len(moduleErrors) {
546-
if int(errIndex) >= len(moduleErrors[e.DispatchError.ModuleError.Index]) || moduleErrors[e.DispatchError.ModuleError.Index] == nil {
547-
return fmt.Errorf("module error (%d) with unknown code %d occurred, please update the module error list", e.DispatchError.ModuleError.Index, e.DispatchError.ModuleError.Error)
548-
}
549-
return errors.New(moduleErrors[e.DispatchError.ModuleError.Index][errIndex])
550-
} else {
551-
return fmt.Errorf("unknown module error (%d) with code %d occurred, please create the module error list", e.DispatchError.ModuleError.Index, e.DispatchError.ModuleError.Error)
270+
metaErr, err := s.meta.FindError(
271+
types.U8(e.DispatchError.ModuleError.Index),
272+
e.DispatchError.ModuleError.Error,
273+
)
274+
if err != nil {
275+
return fmt.Errorf("module %d error index %v: %w",
276+
e.DispatchError.ModuleError.Index,
277+
e.DispatchError.ModuleError.Error,
278+
err,
279+
)
552280
}
281+
return errors.New(metaErr.Name)
553282
}
554283
}
555284
}

0 commit comments

Comments
 (0)