github.com/onflow/flow-go@v0.33.17/module/execution/registers_async.go (about)

     1  package execution
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"go.uber.org/atomic"
     7  
     8  	"github.com/onflow/flow-go/model/flow"
     9  	"github.com/onflow/flow-go/module/state_synchronization/indexer"
    10  	"github.com/onflow/flow-go/storage"
    11  )
    12  
    13  // RegistersAsyncStore wraps an underlying register store so it can be used before the index is
    14  // initialized.
    15  type RegistersAsyncStore struct {
    16  	registerIndex *atomic.Pointer[storage.RegisterIndex]
    17  }
    18  
    19  func NewRegistersAsyncStore() *RegistersAsyncStore {
    20  	return &RegistersAsyncStore{
    21  		registerIndex: atomic.NewPointer[storage.RegisterIndex](nil),
    22  	}
    23  }
    24  
    25  // Initialize initializes the underlying storage.RegisterIndex
    26  // This method can be called at any time after the RegisterStore object is created. and before RegisterValues is called
    27  // since we can't disambiguate between the underlying store before bootstrapping or just simply being behind sync
    28  func (r *RegistersAsyncStore) Initialize(registers storage.RegisterIndex) error {
    29  	if r.registerIndex.CompareAndSwap(nil, &registers) {
    30  		return nil
    31  	}
    32  	return fmt.Errorf("registers already initialized")
    33  }
    34  
    35  // RegisterValues gets the register values from the underlying storage.RegisterIndex
    36  // Expected errors:
    37  //   - indexer.ErrIndexNotInitialized if the store is still bootstrapping
    38  //   - storage.ErrHeightNotIndexed if the values at the height is not indexed yet
    39  //   - storage.ErrNotFound if the register does not exist at the height
    40  func (r *RegistersAsyncStore) RegisterValues(ids flow.RegisterIDs, height uint64) ([]flow.RegisterValue, error) {
    41  	registerStore, err := r.getRegisterStore()
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	if height > registerStore.LatestHeight() || height < registerStore.FirstHeight() {
    47  		return nil, storage.ErrHeightNotIndexed
    48  	}
    49  
    50  	result := make([]flow.RegisterValue, len(ids))
    51  	for i, regID := range ids {
    52  		val, err := registerStore.Get(regID, height)
    53  		if err != nil {
    54  			return nil, fmt.Errorf("failed to get register value for id %d: %w", i, err)
    55  		}
    56  		result[i] = val
    57  	}
    58  	return result, nil
    59  }
    60  
    61  func (r *RegistersAsyncStore) getRegisterStore() (storage.RegisterIndex, error) {
    62  	registerStore := r.registerIndex.Load()
    63  	if registerStore == nil {
    64  		return nil, indexer.ErrIndexNotInitialized
    65  	}
    66  
    67  	return *registerStore, nil
    68  }