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 }