github.com/diadata-org/diadata@v1.4.593/pkg/dia/helpers/substrate-helper/gsrpc/registry/factory.go (about)

     1  package registry
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/types"
     9  )
    10  
    11  //go:generate mockery --name Factory --structname FactoryMock --filename factory_mock.go --inpackage
    12  
    13  // Factory is the interface responsible for generating the according registries from the metadata.
    14  type Factory interface {
    15  	CreateCallRegistry(meta *types.Metadata) (CallRegistry, error)
    16  	CreateErrorRegistry(meta *types.Metadata) (ErrorRegistry, error)
    17  	CreateEventRegistry(meta *types.Metadata) (EventRegistry, error)
    18  	CreateExtrinsicDecoder(meta *types.Metadata) (*ExtrinsicDecoder, error)
    19  }
    20  
    21  // CallRegistry maps a call name to its TypeDecoder.
    22  type CallRegistry map[types.CallIndex]*TypeDecoder
    23  
    24  // ErrorID is the type using for identifying an error in the metadata.
    25  type ErrorID struct {
    26  	ModuleIndex types.U8
    27  	ErrorIndex  [4]types.U8
    28  }
    29  
    30  // ErrorRegistry maps an error name to its TypeDecoder.
    31  type ErrorRegistry map[ErrorID]*TypeDecoder
    32  
    33  // EventRegistry maps an event ID to its TypeDecoder.
    34  type EventRegistry map[types.EventID]*TypeDecoder
    35  
    36  // FieldOverride is used to override the default FieldDecoder for a particular type.
    37  type FieldOverride struct {
    38  	FieldLookupIndex int64
    39  	FieldDecoder     FieldDecoder
    40  }
    41  
    42  type factory struct {
    43  	fieldStorage          map[int64]FieldDecoder
    44  	recursiveFieldStorage map[int64]*RecursiveDecoder
    45  	fieldOverrides        []FieldOverride
    46  }
    47  
    48  // NewFactory creates a new Factory using the provided overrides, if any.
    49  func NewFactory(fieldOverrides ...FieldOverride) Factory {
    50  	f := &factory{}
    51  	f.fieldOverrides = fieldOverrides
    52  
    53  	return f
    54  }
    55  
    56  func (f *factory) resetStorages() {
    57  	f.fieldStorage = make(map[int64]FieldDecoder)
    58  	f.recursiveFieldStorage = make(map[int64]*RecursiveDecoder)
    59  
    60  	for _, fieldOverride := range f.fieldOverrides {
    61  		f.fieldStorage[fieldOverride.FieldLookupIndex] = fieldOverride.FieldDecoder
    62  	}
    63  }
    64  
    65  // CreateErrorRegistry creates the registry that contains the types for errors.
    66  // nolint:dupl
    67  func (f *factory) CreateErrorRegistry(meta *types.Metadata) (ErrorRegistry, error) {
    68  	f.resetStorages()
    69  
    70  	errorRegistry := make(map[ErrorID]*TypeDecoder)
    71  
    72  	for _, mod := range meta.AsMetadataV14.Pallets {
    73  		if !mod.HasErrors {
    74  			continue
    75  		}
    76  
    77  		errorsType, ok := meta.AsMetadataV14.EfficientLookup[mod.Errors.Type.Int64()]
    78  
    79  		if !ok {
    80  			return nil, ErrErrorsTypeNotFound.WithMsg("errors type '%d', module '%s'", mod.Errors.Type.Int64(), mod.Name)
    81  		}
    82  
    83  		if !errorsType.Def.IsVariant {
    84  			return nil, ErrErrorsTypeNotVariant.WithMsg("errors type '%d', module '%s'", mod.Errors.Type.Int64(), mod.Name)
    85  		}
    86  
    87  		for _, errorVariant := range errorsType.Def.Variant.Variants {
    88  			errorName := fmt.Sprintf("%s.%s", mod.Name, errorVariant.Name)
    89  
    90  			errorFields, err := f.getTypeFields(meta, errorVariant.Fields)
    91  
    92  			if err != nil {
    93  				return nil, ErrErrorFieldsRetrieval.WithMsg(errorName).Wrap(err)
    94  			}
    95  
    96  			errorID := ErrorID{
    97  				ModuleIndex: mod.Index,
    98  				ErrorIndex:  [4]types.U8{errorVariant.Index},
    99  			}
   100  
   101  			errorRegistry[errorID] = &TypeDecoder{
   102  				Name:   errorName,
   103  				Fields: errorFields,
   104  			}
   105  		}
   106  	}
   107  
   108  	if err := f.resolveRecursiveDecoders(); err != nil {
   109  		return nil, ErrRecursiveDecodersResolving.Wrap(err)
   110  	}
   111  
   112  	return errorRegistry, nil
   113  }
   114  
   115  // CreateCallRegistry creates the registry that contains the types for calls.
   116  // nolint:dupl
   117  func (f *factory) CreateCallRegistry(meta *types.Metadata) (CallRegistry, error) {
   118  	f.resetStorages()
   119  
   120  	callRegistry := make(map[types.CallIndex]*TypeDecoder)
   121  
   122  	for _, mod := range meta.AsMetadataV14.Pallets {
   123  		if !mod.HasCalls {
   124  			continue
   125  		}
   126  
   127  		callsType, ok := meta.AsMetadataV14.EfficientLookup[mod.Calls.Type.Int64()]
   128  
   129  		if !ok {
   130  			return nil, ErrCallsTypeNotFound.WithMsg("calls type '%d', module '%s'", mod.Calls.Type.Int64(), mod.Name)
   131  		}
   132  
   133  		if !callsType.Def.IsVariant {
   134  			return nil, ErrCallsTypeNotVariant.WithMsg("calls type '%d', module '%s'", mod.Calls.Type.Int64(), mod.Name)
   135  		}
   136  
   137  		for _, callVariant := range callsType.Def.Variant.Variants {
   138  			callIndex := types.CallIndex{
   139  				SectionIndex: uint8(mod.Index),
   140  				MethodIndex:  uint8(callVariant.Index),
   141  			}
   142  
   143  			callName := fmt.Sprintf("%s.%s", mod.Name, callVariant.Name)
   144  
   145  			callFields, err := f.getTypeFields(meta, callVariant.Fields)
   146  
   147  			if err != nil {
   148  				return nil, ErrCallFieldsRetrieval.WithMsg(callName).Wrap(err)
   149  			}
   150  
   151  			callRegistry[callIndex] = &TypeDecoder{
   152  				Name:   callName,
   153  				Fields: callFields,
   154  			}
   155  		}
   156  	}
   157  
   158  	if err := f.resolveRecursiveDecoders(); err != nil {
   159  		return nil, ErrRecursiveDecodersResolving.Wrap(err)
   160  	}
   161  
   162  	return callRegistry, nil
   163  }
   164  
   165  // CreateEventRegistry creates the registry that contains the types for events.
   166  func (f *factory) CreateEventRegistry(meta *types.Metadata) (EventRegistry, error) {
   167  	f.resetStorages()
   168  
   169  	eventRegistry := make(map[types.EventID]*TypeDecoder)
   170  
   171  	for _, mod := range meta.AsMetadataV14.Pallets {
   172  		if !mod.HasEvents {
   173  			continue
   174  		}
   175  
   176  		eventsType, ok := meta.AsMetadataV14.EfficientLookup[mod.Events.Type.Int64()]
   177  
   178  		if !ok {
   179  			return nil, ErrEventsTypeNotFound.WithMsg("events type '%d', module '%s'", mod.Events.Type.Int64(), mod.Name)
   180  		}
   181  
   182  		if !eventsType.Def.IsVariant {
   183  			return nil, ErrEventsTypeNotVariant.WithMsg("events type '%d', module '%s'", mod.Events.Type.Int64(), mod.Name)
   184  		}
   185  
   186  		for _, eventVariant := range eventsType.Def.Variant.Variants {
   187  			eventID := types.EventID{byte(mod.Index), byte(eventVariant.Index)}
   188  
   189  			eventName := fmt.Sprintf("%s.%s", mod.Name, eventVariant.Name)
   190  
   191  			eventFields, err := f.getTypeFields(meta, eventVariant.Fields)
   192  
   193  			if err != nil {
   194  				return nil, ErrEventFieldsRetrieval.WithMsg(eventName).Wrap(err)
   195  			}
   196  
   197  			eventRegistry[eventID] = &TypeDecoder{
   198  				Name:   eventName,
   199  				Fields: eventFields,
   200  			}
   201  		}
   202  	}
   203  
   204  	if err := f.resolveRecursiveDecoders(); err != nil {
   205  		return nil, ErrRecursiveDecodersResolving.Wrap(err)
   206  	}
   207  
   208  	return eventRegistry, nil
   209  }
   210  
   211  // CreateExtrinsicDecoder creates an ExtrinsicDecoder based on the Extrinsic information provided in the metadata.
   212  func (f *factory) CreateExtrinsicDecoder(meta *types.Metadata) (*ExtrinsicDecoder, error) {
   213  	f.resetStorages()
   214  
   215  	extrinsicLookupID := meta.AsMetadataV14.Extrinsic.Type
   216  
   217  	extrinsicType := meta.AsMetadataV14.EfficientLookup[extrinsicLookupID.Int64()]
   218  
   219  	extrinsicParams, err := extractExtrinsicParams(extrinsicType, meta)
   220  
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	if err := validateExtrinsicParams(extrinsicParams); err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	extrinsicFields, err := f.getTypeParams(meta, extrinsicParams)
   230  
   231  	if err != nil {
   232  		return nil, ErrExtrinsicFieldRetrieval
   233  	}
   234  
   235  	if err := f.resolveRecursiveDecoders(); err != nil {
   236  		return nil, ErrRecursiveDecodersResolving.Wrap(err)
   237  	}
   238  
   239  	return &ExtrinsicDecoder{
   240  		Fields: extrinsicFields,
   241  	}, nil
   242  }
   243  
   244  const (
   245  	ExtrinsicAddressName   = "Address"
   246  	ExtrinsicSignatureName = "Signature"
   247  	ExtrinsicExtraName     = "Extra"
   248  	ExtrinsicCallName      = "Call"
   249  )
   250  
   251  var expectedExtrinsicParams = map[string]struct{}{
   252  	ExtrinsicAddressName:   {},
   253  	ExtrinsicSignatureName: {},
   254  	ExtrinsicExtraName:     {},
   255  	ExtrinsicCallName:      {},
   256  }
   257  
   258  func validateExtrinsicParams(params []types.Si1TypeParameter) error {
   259  	if len(params) != ExpectedExtrinsicParamsCount {
   260  		return ErrInvalidExtrinsicParams
   261  	}
   262  
   263  	for _, param := range params {
   264  		if _, ok := expectedExtrinsicParams[string(param.Name)]; !ok {
   265  			return ErrUnexpectedExtrinsicParam.WithMsg("param - '%s'", param.Name)
   266  		}
   267  	}
   268  
   269  	return nil
   270  }
   271  
   272  // resolveRecursiveDecoders resolves all recursive decoders with their according FieldDecoder.
   273  // nolint:lll
   274  func (f *factory) resolveRecursiveDecoders() error {
   275  	for recursiveFieldLookupIndex, recursiveFieldDecoder := range f.recursiveFieldStorage {
   276  		if recursiveFieldDecoder.FieldDecoder != nil {
   277  			// Skip if the inner FieldDecoder is present, this could be an override.
   278  			continue
   279  		}
   280  
   281  		fieldDecoder, ok := f.fieldStorage[recursiveFieldLookupIndex]
   282  
   283  		if !ok {
   284  			return ErrFieldDecoderForRecursiveFieldNotFound.
   285  				WithMsg(
   286  					"recursive field lookup index %d",
   287  					recursiveFieldLookupIndex,
   288  				)
   289  		}
   290  
   291  		if _, ok := fieldDecoder.(*RecursiveDecoder); ok {
   292  			return ErrRecursiveFieldResolving.
   293  				WithMsg(
   294  					"recursive field lookup index %d",
   295  					recursiveFieldLookupIndex,
   296  				)
   297  		}
   298  
   299  		recursiveFieldDecoder.FieldDecoder = fieldDecoder
   300  	}
   301  
   302  	return nil
   303  }
   304  
   305  // getTypeFields returns a list of fields and their respective decoders from the provided parameters.
   306  func (f *factory) getTypeParams(meta *types.Metadata, params []types.Si1TypeParameter) ([]*Field, error) {
   307  	var typeFields []*Field
   308  
   309  	for _, param := range params {
   310  		paramType, ok := meta.AsMetadataV14.EfficientLookup[param.Type.Int64()]
   311  
   312  		if !ok {
   313  			return nil, ErrFieldTypeNotFound.WithMsg(string(param.Name))
   314  		}
   315  
   316  		paramName := string(param.Name)
   317  
   318  		if storedFieldDecoder, ok := f.getStoredFieldDecoder(param.Type.Int64()); ok {
   319  			typeFields = append(typeFields, &Field{
   320  				Name:         paramName,
   321  				FieldDecoder: storedFieldDecoder,
   322  				LookupIndex:  param.Type.Int64(),
   323  			})
   324  			continue
   325  		}
   326  
   327  		paramTypeDef := paramType.Def
   328  
   329  		fieldDecoder, err := f.getFieldDecoder(meta, paramName, paramTypeDef)
   330  
   331  		if err != nil {
   332  			return nil, ErrFieldDecoderRetrieval.WithMsg(paramName).Wrap(err)
   333  		}
   334  
   335  		f.fieldStorage[param.Type.Int64()] = fieldDecoder
   336  
   337  		typeFields = append(typeFields, &Field{
   338  			Name:         paramName,
   339  			FieldDecoder: fieldDecoder,
   340  			LookupIndex:  param.Type.Int64(),
   341  		})
   342  	}
   343  
   344  	return typeFields, nil
   345  }
   346  
   347  // getTypeFields parses and returns all Field(s) for a type.
   348  func (f *factory) getTypeFields(meta *types.Metadata, fields []types.Si1Field) ([]*Field, error) {
   349  	var typeFields []*Field
   350  
   351  	for _, field := range fields {
   352  		fieldType, ok := meta.AsMetadataV14.EfficientLookup[field.Type.Int64()]
   353  
   354  		if !ok {
   355  			return nil, ErrFieldTypeNotFound.WithMsg(string(field.Name))
   356  		}
   357  
   358  		fieldName := getFullFieldName(field, fieldType)
   359  
   360  		if storedFieldDecoder, ok := f.getStoredFieldDecoder(field.Type.Int64()); ok {
   361  			typeFields = append(typeFields, &Field{
   362  				Name:         fieldName,
   363  				FieldDecoder: storedFieldDecoder,
   364  				LookupIndex:  field.Type.Int64(),
   365  			})
   366  			continue
   367  		}
   368  
   369  		fieldTypeDef := fieldType.Def
   370  
   371  		fieldDecoder, err := f.getFieldDecoder(meta, fieldName, fieldTypeDef)
   372  
   373  		if err != nil {
   374  			return nil, ErrFieldDecoderRetrieval.WithMsg(fieldName).Wrap(err)
   375  		}
   376  
   377  		f.fieldStorage[field.Type.Int64()] = fieldDecoder
   378  
   379  		typeFields = append(typeFields, &Field{
   380  			Name:         fieldName,
   381  			FieldDecoder: fieldDecoder,
   382  			LookupIndex:  field.Type.Int64(),
   383  		})
   384  	}
   385  
   386  	return typeFields, nil
   387  }
   388  
   389  // getFieldDecoder returns the FieldDecoder based on the provided type definition.
   390  // nolint:funlen
   391  func (f *factory) getFieldDecoder(
   392  	meta *types.Metadata,
   393  	fieldName string,
   394  	typeDef types.Si1TypeDef,
   395  ) (FieldDecoder, error) {
   396  	switch {
   397  	case typeDef.IsCompact:
   398  		compactFieldType, ok := meta.AsMetadataV14.EfficientLookup[typeDef.Compact.Type.Int64()]
   399  
   400  		if !ok {
   401  			return nil, ErrCompactFieldTypeNotFound.WithMsg(fieldName)
   402  		}
   403  
   404  		return f.getCompactFieldDecoder(meta, fieldName, compactFieldType.Def)
   405  	case typeDef.IsComposite:
   406  		compositeDecoder := &CompositeDecoder{
   407  			FieldName: fieldName,
   408  		}
   409  
   410  		fields, err := f.getTypeFields(meta, typeDef.Composite.Fields)
   411  
   412  		if err != nil {
   413  			return nil, ErrCompositeTypeFieldsRetrieval.WithMsg(fieldName).Wrap(err)
   414  		}
   415  
   416  		compositeDecoder.Fields = fields
   417  
   418  		return compositeDecoder, nil
   419  	case typeDef.IsVariant:
   420  		return f.getVariantFieldDecoder(meta, typeDef)
   421  	case typeDef.IsPrimitive:
   422  		return getPrimitiveDecoder(typeDef.Primitive.Si0TypeDefPrimitive)
   423  	case typeDef.IsArray:
   424  		arrayFieldType, ok := meta.AsMetadataV14.EfficientLookup[typeDef.Array.Type.Int64()]
   425  
   426  		if !ok {
   427  			return nil, ErrArrayFieldTypeNotFound.WithMsg(fieldName)
   428  		}
   429  
   430  		return f.getArrayFieldDecoder(uint(typeDef.Array.Len), meta, fieldName, arrayFieldType.Def)
   431  	case typeDef.IsSequence:
   432  		vectorFieldType, ok := meta.AsMetadataV14.EfficientLookup[typeDef.Sequence.Type.Int64()]
   433  
   434  		if !ok {
   435  			return nil, ErrVectorFieldTypeNotFound.WithMsg(fieldName)
   436  		}
   437  
   438  		return f.getSliceFieldDecoder(meta, fieldName, vectorFieldType.Def)
   439  	case typeDef.IsTuple:
   440  		if typeDef.Tuple == nil {
   441  			return &NoopDecoder{}, nil
   442  		}
   443  
   444  		return f.getTupleFieldDecoder(meta, fieldName, typeDef.Tuple)
   445  	case typeDef.IsBitSequence:
   446  		return f.getBitSequenceDecoder(meta, fieldName, typeDef.BitSequence)
   447  	default:
   448  		return nil, ErrFieldTypeDefinitionNotSupported.WithMsg(fieldName)
   449  	}
   450  }
   451  
   452  // getVariantFieldDecoder parses a variant type definition and returns a VariantDecoder.
   453  func (f *factory) getVariantFieldDecoder(meta *types.Metadata, typeDef types.Si1TypeDef) (FieldDecoder, error) {
   454  	variantDecoder := &VariantDecoder{}
   455  
   456  	fieldDecoderMap := make(map[byte]FieldDecoder)
   457  
   458  	for _, variant := range typeDef.Variant.Variants {
   459  		if len(variant.Fields) == 0 {
   460  			fieldDecoderMap[byte(variant.Index)] = &NoopDecoder{}
   461  			continue
   462  		}
   463  
   464  		variantName := getVariantName(variant)
   465  
   466  		compositeDecoder := &CompositeDecoder{
   467  			FieldName: variantName,
   468  		}
   469  
   470  		fields, err := f.getTypeFields(meta, variant.Fields)
   471  
   472  		if err != nil {
   473  			return nil, ErrVariantTypeFieldsRetrieval.WithMsg("variant '%d'", variant.Index).Wrap(err)
   474  		}
   475  
   476  		compositeDecoder.Fields = fields
   477  
   478  		fieldDecoderMap[byte(variant.Index)] = compositeDecoder
   479  	}
   480  
   481  	variantDecoder.FieldDecoderMap = fieldDecoderMap
   482  
   483  	return variantDecoder, nil
   484  }
   485  
   486  const (
   487  	variantItemFieldNameFormat = "variant_item_%d"
   488  )
   489  
   490  func getVariantName(variant types.Si1Variant) string {
   491  	if variant.Name != "" {
   492  		return string(variant.Name)
   493  	}
   494  
   495  	return fmt.Sprintf(variantItemFieldNameFormat, variant.Index)
   496  }
   497  
   498  const (
   499  	tupleItemFieldNameFormat = "tuple_item_%d"
   500  )
   501  
   502  // getCompactFieldDecoder parses a compact type definition and returns the according field decoder.
   503  // nolint:funlen,lll
   504  func (f *factory) getCompactFieldDecoder(meta *types.Metadata, fieldName string, typeDef types.Si1TypeDef) (FieldDecoder, error) {
   505  	switch {
   506  	case typeDef.IsPrimitive:
   507  		return &ValueDecoder[types.UCompact]{}, nil
   508  	case typeDef.IsTuple:
   509  		if typeDef.Tuple == nil {
   510  			return &NoopDecoder{}, nil
   511  		}
   512  
   513  		compositeDecoder := &CompositeDecoder{
   514  			FieldName: fieldName,
   515  		}
   516  
   517  		for i, item := range typeDef.Tuple {
   518  			itemTypeDef, ok := meta.AsMetadataV14.EfficientLookup[item.Int64()]
   519  
   520  			if !ok {
   521  				return nil, ErrCompactTupleItemTypeNotFound.WithMsg("tuple item '%d'", item.Int64())
   522  			}
   523  
   524  			fieldName := fmt.Sprintf(tupleItemFieldNameFormat, i)
   525  
   526  			itemFieldDecoder, err := f.getCompactFieldDecoder(meta, fieldName, itemTypeDef.Def)
   527  
   528  			if err != nil {
   529  				return nil, ErrCompactTupleItemFieldDecoderRetrieval.
   530  					WithMsg("tuple item '%d'", item.Int64()).
   531  					Wrap(err)
   532  			}
   533  
   534  			compositeDecoder.Fields = append(compositeDecoder.Fields, &Field{
   535  				Name:         fieldName,
   536  				FieldDecoder: itemFieldDecoder,
   537  				LookupIndex:  item.Int64(),
   538  			})
   539  		}
   540  
   541  		return compositeDecoder, nil
   542  	case typeDef.IsComposite:
   543  		compactCompositeFields := typeDef.Composite.Fields
   544  
   545  		compositeDecoder := &CompositeDecoder{
   546  			FieldName: fieldName,
   547  		}
   548  
   549  		for _, compactCompositeField := range compactCompositeFields {
   550  			compactCompositeFieldType, ok := meta.AsMetadataV14.EfficientLookup[compactCompositeField.Type.Int64()]
   551  
   552  			if !ok {
   553  				return nil, ErrCompactCompositeFieldTypeNotFound
   554  			}
   555  
   556  			compactFieldName := getFullFieldName(compactCompositeField, compactCompositeFieldType)
   557  
   558  			compactCompositeDecoder, err := f.getCompactFieldDecoder(meta, compactFieldName, compactCompositeFieldType.Def)
   559  
   560  			if err != nil {
   561  				return nil, ErrCompactCompositeFieldDecoderRetrieval.Wrap(err)
   562  			}
   563  
   564  			compositeDecoder.Fields = append(compositeDecoder.Fields, &Field{
   565  				Name:         compactFieldName,
   566  				FieldDecoder: compactCompositeDecoder,
   567  				LookupIndex:  compactCompositeField.Type.Int64(),
   568  			})
   569  		}
   570  
   571  		return compositeDecoder, nil
   572  	default:
   573  		return nil, errors.New("unsupported compact field type")
   574  	}
   575  }
   576  
   577  // getArrayFieldDecoder parses an array type definition and returns an ArrayDecoder.
   578  // nolint:lll
   579  func (f *factory) getArrayFieldDecoder(arrayLen uint, meta *types.Metadata, fieldName string, typeDef types.Si1TypeDef) (FieldDecoder, error) {
   580  	itemFieldDecoder, err := f.getFieldDecoder(meta, fieldName, typeDef)
   581  
   582  	if err != nil {
   583  		return nil, ErrArrayItemFieldDecoderRetrieval.Wrap(err)
   584  	}
   585  
   586  	return &ArrayDecoder{Length: arrayLen, ItemDecoder: itemFieldDecoder}, nil
   587  }
   588  
   589  // getSliceFieldDecoder parses a slice type definition and returns an SliceDecoder.
   590  func (f *factory) getSliceFieldDecoder(
   591  	meta *types.Metadata,
   592  	fieldName string,
   593  	typeDef types.Si1TypeDef,
   594  ) (FieldDecoder, error) {
   595  	itemFieldDecoder, err := f.getFieldDecoder(meta, fieldName, typeDef)
   596  
   597  	if err != nil {
   598  		return nil, ErrSliceItemFieldDecoderRetrieval.Wrap(err)
   599  	}
   600  
   601  	return &SliceDecoder{itemFieldDecoder}, nil
   602  }
   603  
   604  // getTupleFieldDecoder parses a tuple type definition and returns a CompositeDecoder.
   605  func (f *factory) getTupleFieldDecoder(
   606  	meta *types.Metadata,
   607  	fieldName string,
   608  	tuple types.Si1TypeDefTuple,
   609  ) (FieldDecoder, error) {
   610  	compositeDecoder := &CompositeDecoder{
   611  		FieldName: fieldName,
   612  	}
   613  
   614  	for i, item := range tuple {
   615  		itemTypeDef, ok := meta.AsMetadataV14.EfficientLookup[item.Int64()]
   616  
   617  		if !ok {
   618  			return nil, ErrTupleItemTypeNotFound.WithMsg("tuple item '%d'", i)
   619  		}
   620  
   621  		tupleFieldName := fmt.Sprintf(tupleItemFieldNameFormat, i)
   622  
   623  		itemFieldDecoder, err := f.getFieldDecoder(meta, tupleFieldName, itemTypeDef.Def)
   624  
   625  		if err != nil {
   626  			return nil, ErrTupleItemFieldDecoderRetrieval.Wrap(err)
   627  		}
   628  
   629  		compositeDecoder.Fields = append(compositeDecoder.Fields, &Field{
   630  			Name:         tupleFieldName,
   631  			FieldDecoder: itemFieldDecoder,
   632  			LookupIndex:  item.Int64(),
   633  		})
   634  	}
   635  
   636  	return compositeDecoder, nil
   637  }
   638  
   639  func (f *factory) getBitSequenceDecoder(
   640  	meta *types.Metadata,
   641  	fieldName string,
   642  	bitSequenceTypeDef types.Si1TypeDefBitSequence,
   643  ) (FieldDecoder, error) {
   644  	bitStoreType, ok := meta.AsMetadataV14.EfficientLookup[bitSequenceTypeDef.BitStoreType.Int64()]
   645  
   646  	if !ok {
   647  		return nil, ErrBitStoreTypeNotFound.WithMsg(fieldName)
   648  	}
   649  
   650  	if bitStoreType.Def.Primitive.Si0TypeDefPrimitive != types.IsU8 {
   651  		return nil, ErrBitStoreTypeNotSupported.WithMsg(fieldName)
   652  	}
   653  
   654  	bitOrderType, ok := meta.AsMetadataV14.EfficientLookup[bitSequenceTypeDef.BitOrderType.Int64()]
   655  
   656  	if !ok {
   657  		return nil, ErrBitOrderTypeNotFound.WithMsg(fieldName)
   658  	}
   659  
   660  	bitOrder, err := types.NewBitOrderFromString(getBitOrderString(bitOrderType.Path))
   661  
   662  	if err != nil {
   663  		return nil, ErrBitOrderCreation.Wrap(err)
   664  	}
   665  
   666  	bitSequenceDecoder := &BitSequenceDecoder{
   667  		FieldName: fieldName,
   668  		BitOrder:  bitOrder,
   669  	}
   670  
   671  	return bitSequenceDecoder, nil
   672  }
   673  
   674  // getStoredFieldDecoder will attempt to return a FieldDecoder from storage,
   675  // and perform an extra check for recursive decoders.
   676  func (f *factory) getStoredFieldDecoder(fieldLookupIndex int64) (FieldDecoder, bool) {
   677  	if ft, ok := f.fieldStorage[fieldLookupIndex]; ok {
   678  		if rt, ok := ft.(*RecursiveDecoder); ok {
   679  			f.recursiveFieldStorage[fieldLookupIndex] = rt
   680  		}
   681  
   682  		return ft, ok
   683  	}
   684  
   685  	// Ensure that a recursive type such as Xcm::TransferReserveAsset does not cause an infinite loop
   686  	// by adding the RecursiveDecoder the first time the field is encountered.
   687  	f.fieldStorage[fieldLookupIndex] = &RecursiveDecoder{}
   688  
   689  	return nil, false
   690  }
   691  
   692  const (
   693  	// ExpectedExtrinsicParamsCount is the count of generic params that we expect for a
   694  	// generic Extrinsic type from the metadata.
   695  	//
   696  	// The parameters are expected to be in the following order:
   697  	// 1. Address
   698  	// 2. Call
   699  	// 3. Signature
   700  	// 4. Extra
   701  	ExpectedExtrinsicParamsCount = 4
   702  )
   703  
   704  // genericExtrinsicPath represents the expected metadata path of a generic extrinsic.
   705  var genericExtrinsicPath = types.Si1Path{
   706  	"sp_runtime",
   707  	"generic",
   708  	"unchecked_extrinsic",
   709  	"UncheckedExtrinsic",
   710  }
   711  
   712  // isGenericExtrinsic checks if the metadata path of the extrinsic path matches the one of the
   713  // generic extrinsic.
   714  func isGenericExtrinsic(path types.Si1Path) bool {
   715  	if len(path) != len(genericExtrinsicPath) {
   716  		return false
   717  	}
   718  
   719  	for i := range path {
   720  		if path[i] != genericExtrinsicPath[i] {
   721  			return false
   722  		}
   723  	}
   724  
   725  	return true
   726  }
   727  
   728  // extractExtrinsicParams returns the extrinsic params if the provided extrinsic type is generic, otherwise,
   729  // it extracts the generic extrinsic and then returns its params.
   730  func extractExtrinsicParams(extrinsicType *types.Si1Type, meta *types.Metadata) ([]types.Si1TypeParameter, error) {
   731  	if isGenericExtrinsic(extrinsicType.Path) {
   732  		return extrinsicType.Params, nil
   733  	}
   734  
   735  	// If the metadata extrinsic type is not generic, its type is expected to be a composite with 1 field.
   736  	if !extrinsicType.Def.IsComposite || len(extrinsicType.Def.Composite.Fields) != 1 {
   737  		return nil, ErrInvalidExtrinsicType
   738  	}
   739  
   740  	// This composite field is the `sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic`.
   741  	genericUncheckedExtrinsic := extrinsicType.Def.Composite.Fields[0]
   742  
   743  	genericUncheckedExtrinsicType := meta.AsMetadataV14.EfficientLookup[genericUncheckedExtrinsic.Type.Int64()]
   744  
   745  	if !isGenericExtrinsic(genericUncheckedExtrinsicType.Path) {
   746  		return nil, ErrInvalidGenericExtrinsicType
   747  	}
   748  
   749  	return genericUncheckedExtrinsicType.Params, nil
   750  }
   751  
   752  func getBitOrderString(path types.Si1Path) string {
   753  	pathLen := len(path)
   754  
   755  	if pathLen == 0 {
   756  		return ""
   757  	}
   758  
   759  	return string(path[pathLen-1])
   760  }
   761  
   762  const (
   763  	fieldSeparator    = "."
   764  	lookupIndexFormat = "lookup_index_%d"
   765  )
   766  
   767  func getFieldPath(fieldType *types.Si1Type) string {
   768  	var nameParts []string
   769  
   770  	for _, pathEntry := range fieldType.Path {
   771  		nameParts = append(nameParts, string(pathEntry))
   772  	}
   773  
   774  	return strings.Join(nameParts, fieldSeparator)
   775  }
   776  
   777  func getFullFieldName(field types.Si1Field, fieldType *types.Si1Type) string {
   778  	fieldName := getFieldName(field)
   779  
   780  	if fieldPath := getFieldPath(fieldType); fieldPath != "" {
   781  		return fmt.Sprintf("%s%s%s", fieldPath, fieldSeparator, fieldName)
   782  	}
   783  
   784  	return getFieldName(field)
   785  }
   786  
   787  func getFieldName(field types.Si1Field) string {
   788  	switch {
   789  	case field.HasName:
   790  		return string(field.Name)
   791  	case field.HasTypeName:
   792  		return string(field.TypeName)
   793  	default:
   794  		return fmt.Sprintf(lookupIndexFormat, field.Type.Int64())
   795  	}
   796  }