github.com/diadata-org/diadata@v1.4.593/pkg/dia/helpers/substrate-helper/gsrpc/registry/retriever/event_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/registry/parser"
     9  	regState "github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/registry/state"
    10  	"github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/rpc/state"
    11  	"github.com/diadata-org/diadata/pkg/dia/helpers/substrate-helper/gsrpc/types"
    12  )
    13  
    14  //nolint:lll
    15  //go:generate mockery --name EventRetriever --structname EventRetrieverMock --filename event_retriever_mock.go --inpackage
    16  
    17  // EventRetriever is the interface used for retrieving and decoding events.
    18  type EventRetriever interface {
    19  	GetEvents(blockHash types.Hash) ([]*parser.Event, error)
    20  }
    21  
    22  // eventRetriever implements the EventRetriever interface.
    23  type eventRetriever struct {
    24  	eventParser parser.EventParser
    25  
    26  	eventProvider regState.EventProvider
    27  	stateRPC      state.State
    28  
    29  	registryFactory registry.Factory
    30  
    31  	eventStorageExecutor exec.RetryableExecutor[*types.StorageDataRaw]
    32  	eventParsingExecutor exec.RetryableExecutor[[]*parser.Event]
    33  
    34  	eventRegistry registry.EventRegistry
    35  	meta          *types.Metadata
    36  }
    37  
    38  // NewEventRetriever creates a new EventRetriever.
    39  func NewEventRetriever(
    40  	eventParser parser.EventParser,
    41  	eventProvider regState.EventProvider,
    42  	stateRPC state.State,
    43  	registryFactory registry.Factory,
    44  	eventStorageExecutor exec.RetryableExecutor[*types.StorageDataRaw],
    45  	eventParsingExecutor exec.RetryableExecutor[[]*parser.Event],
    46  ) (EventRetriever, error) {
    47  	retriever := &eventRetriever{
    48  		eventParser:          eventParser,
    49  		eventProvider:        eventProvider,
    50  		stateRPC:             stateRPC,
    51  		registryFactory:      registryFactory,
    52  		eventStorageExecutor: eventStorageExecutor,
    53  		eventParsingExecutor: eventParsingExecutor,
    54  	}
    55  
    56  	if err := retriever.updateInternalState(nil); err != nil {
    57  		return nil, ErrInternalStateUpdate.Wrap(err)
    58  	}
    59  
    60  	return retriever, nil
    61  }
    62  
    63  // NewDefaultEventRetriever creates a new EventRetriever using defaults for:
    64  //
    65  // - parser.EventParser
    66  // - registry.Factory
    67  // - exec.RetryableExecutor - used for retrieving event storage data.
    68  // - exec.RetryableExecutor - used for parsing events.
    69  func NewDefaultEventRetriever(
    70  	eventProvider regState.EventProvider,
    71  	stateRPC state.State,
    72  	fieldOverrides ...registry.FieldOverride,
    73  ) (EventRetriever, error) {
    74  	eventParser := parser.NewEventParser()
    75  	registryFactory := registry.NewFactory(fieldOverrides...)
    76  
    77  	eventStorageExecutor := exec.NewRetryableExecutor[*types.StorageDataRaw](exec.WithRetryTimeout(1 * time.Second))
    78  	eventParsingExecutor := exec.NewRetryableExecutor[[]*parser.Event](exec.WithMaxRetryCount(1))
    79  
    80  	return NewEventRetriever(
    81  		eventParser,
    82  		eventProvider,
    83  		stateRPC,
    84  		registryFactory,
    85  		eventStorageExecutor,
    86  		eventParsingExecutor,
    87  	)
    88  }
    89  
    90  // GetEvents retrieves the storage data for an Event and then parses it.
    91  //
    92  // Both the event storage data retrieval and the event parsing are handled via the exec.RetryableExecutor
    93  // in order to ensure retries in case of network errors or parsing errors due to an outdated event registry.
    94  func (e *eventRetriever) GetEvents(blockHash types.Hash) ([]*parser.Event, error) {
    95  	storageEvents, err := e.eventStorageExecutor.ExecWithFallback(
    96  		func() (*types.StorageDataRaw, error) {
    97  			return e.eventProvider.GetStorageEvents(e.meta, blockHash)
    98  		},
    99  		func() error {
   100  			return e.updateInternalState(&blockHash)
   101  		},
   102  	)
   103  
   104  	if err != nil {
   105  		return nil, ErrStorageEventRetrieval.Wrap(err)
   106  	}
   107  
   108  	events, err := e.eventParsingExecutor.ExecWithFallback(
   109  		func() ([]*parser.Event, error) {
   110  			return e.eventParser.ParseEvents(e.eventRegistry, storageEvents)
   111  		},
   112  		func() error {
   113  			return e.updateInternalState(&blockHash)
   114  		},
   115  	)
   116  
   117  	if err != nil {
   118  		return nil, ErrEventParsing.Wrap(err)
   119  	}
   120  
   121  	return events, nil
   122  }
   123  
   124  // updateInternalState will retrieve the metadata at the provided blockHash, if provided,
   125  // create an event registry based on this metadata and store both.
   126  func (e *eventRetriever) updateInternalState(blockHash *types.Hash) error {
   127  	var (
   128  		meta *types.Metadata
   129  		err  error
   130  	)
   131  
   132  	if blockHash == nil {
   133  		meta, err = e.stateRPC.GetMetadataLatest()
   134  	} else {
   135  		meta, err = e.stateRPC.GetMetadata(*blockHash)
   136  	}
   137  
   138  	if err != nil {
   139  		return ErrMetadataRetrieval.Wrap(err)
   140  	}
   141  
   142  	eventRegistry, err := e.registryFactory.CreateEventRegistry(meta)
   143  
   144  	if err != nil {
   145  		return ErrEventRegistryCreation.Wrap(err)
   146  	}
   147  
   148  	e.meta = meta
   149  	e.eventRegistry = eventRegistry
   150  
   151  	return nil
   152  }