github.com/diadata-org/diadata@v1.4.593/pkg/dia/helpers/substrate-helper/gsrpc/registry/retriever/extrinsic_retriever.go (about) 1 package retriever 2 3 import ( 4 "time" 5 6 "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/registry" 7 "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/registry/exec" 8 "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/rpc/chain" 9 "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/rpc/state" 10 "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/types" 11 "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/types/block" 12 ) 13 14 //nolint:lll 15 //go:generate mockery --name ExtrinsicRetriever --structname ExtrinsicRetrieverMock --filename extrinsic_retriever_mock.go --inpackage 16 17 // ExtrinsicRetriever is the interface used for retrieving and decoding extrinsic information 18 // from a particular block. 19 type ExtrinsicRetriever interface { 20 GetExtrinsics(blockHash types.Hash) ([]*registry.DecodedExtrinsic, error) 21 } 22 23 // extrinsicRetriever implements the ExtrinsicRetriever interface. 24 type extrinsicRetriever struct { 25 chainRPC chain.Chain 26 stateRPC state.State 27 28 registryFactory registry.Factory 29 30 chainExecutor exec.RetryableExecutor[*block.SignedBlock] 31 extrinsicDecodingExecutor exec.RetryableExecutor[[]*registry.DecodedExtrinsic] 32 33 extrinsicDecoder *registry.ExtrinsicDecoder 34 } 35 36 // NewExtrinsicRetriever creates a new ExtrinsicRetriever. 37 func NewExtrinsicRetriever( 38 chainRPC chain.Chain, 39 stateRPC state.State, 40 registryFactory registry.Factory, 41 chainExecutor exec.RetryableExecutor[*block.SignedBlock], 42 extrinsicDecodingExecutor exec.RetryableExecutor[[]*registry.DecodedExtrinsic], 43 ) (ExtrinsicRetriever, error) { 44 retriever := &extrinsicRetriever{ 45 chainRPC: chainRPC, 46 stateRPC: stateRPC, 47 registryFactory: registryFactory, 48 chainExecutor: chainExecutor, 49 extrinsicDecodingExecutor: extrinsicDecodingExecutor, 50 } 51 52 if err := retriever.updateInternalState(nil); err != nil { 53 return nil, ErrInternalStateUpdate.Wrap(err) 54 } 55 56 return retriever, nil 57 } 58 59 // NewDefaultExtrinsicRetriever returns an ExtrinsicRetriever with default values for the factory and executors. 60 func NewDefaultExtrinsicRetriever( 61 chainRPC chain.Chain, 62 stateRPC state.State, 63 fieldOverrides ...registry.FieldOverride, 64 ) (ExtrinsicRetriever, error) { 65 registryFactory := registry.NewFactory(fieldOverrides...) 66 67 chainExecutor := exec.NewRetryableExecutor[*block.SignedBlock](exec.WithRetryTimeout(1 * time.Second)) 68 extrinsicDecodingExecutor := exec.NewRetryableExecutor[[]*registry.DecodedExtrinsic](exec.WithMaxRetryCount(1)) 69 70 return NewExtrinsicRetriever( 71 chainRPC, 72 stateRPC, 73 registryFactory, 74 chainExecutor, 75 extrinsicDecodingExecutor, 76 ) 77 } 78 79 // GetExtrinsics retrieves a generic.SignedBlock and then parses the extrinsics found in it. 80 // 81 // Both the block retrieval and the extrinsic parsing are handled via the exec.RetryableExecutor 82 // in order to ensure retries in case of network errors or parsing errors due to an outdated extrinsic decoder. 83 func (e *extrinsicRetriever) GetExtrinsics(blockHash types.Hash) ([]*registry.DecodedExtrinsic, error) { 84 block, err := e.chainExecutor.ExecWithFallback( 85 func() (*block.SignedBlock, error) { 86 return e.chainRPC.GetBlock(blockHash) 87 }, 88 func() error { 89 return nil 90 }, 91 ) 92 93 if err != nil { 94 return nil, ErrBlockRetrieval.Wrap(err) 95 } 96 97 calls, err := e.extrinsicDecodingExecutor.ExecWithFallback( 98 func() ([]*registry.DecodedExtrinsic, error) { 99 return block.DecodeExtrinsics(e.extrinsicDecoder) 100 }, 101 func() error { 102 return e.updateInternalState(&blockHash) 103 }, 104 ) 105 106 if err != nil { 107 return nil, ErrExtrinsicDecoding.Wrap(err) 108 } 109 110 return calls, nil 111 } 112 113 // updateInternalState will retrieve the metadata at the provided blockHash, if provided, 114 // create an extrinsic decoder based on this metadata and store both. 115 func (e *extrinsicRetriever) updateInternalState(blockHash *types.Hash) error { 116 var ( 117 meta *types.Metadata 118 err error 119 ) 120 121 if blockHash == nil { 122 meta, err = e.stateRPC.GetMetadataLatest() 123 } else { 124 meta, err = e.stateRPC.GetMetadata(*blockHash) 125 } 126 127 if err != nil { 128 return ErrMetadataRetrieval.Wrap(err) 129 } 130 131 extrinsicDecoder, err := e.registryFactory.CreateExtrinsicDecoder(meta) 132 133 if err != nil { 134 return ErrExtrinsicDecoderCreation.Wrap(err) 135 } 136 137 e.extrinsicDecoder = extrinsicDecoder 138 139 return nil 140 }