|
| 1 | +package common |
| 2 | + |
| 3 | +import ( |
| 4 | + "sync" |
| 5 | + |
| 6 | + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" |
| 7 | +) |
| 8 | + |
| 9 | +// Ensure ExtraDataCodecRegistry implements the ExtraDataCodecBundle interface from chainlink-common |
| 10 | +var _ cciptypes.ExtraDataCodecBundle = (*ExtraDataCodecRegistry)(nil) |
| 11 | + |
| 12 | +// ExtraDataCodecRegistry is a singleton registry that manages SourceChainExtraDataCodec instances |
| 13 | +// for different chain families. It implements the ExtraDataCodecBundle interface from chainlink-common |
| 14 | +// by delegating to the existing ExtraDataCodec implementation. |
| 15 | +type ExtraDataCodecRegistry struct { |
| 16 | + extraDataCodec cciptypes.ExtraDataCodecMap |
| 17 | + mu sync.RWMutex |
| 18 | +} |
| 19 | + |
| 20 | +var ( |
| 21 | + registryInstance *ExtraDataCodecRegistry |
| 22 | + registryOnce sync.Once |
| 23 | +) |
| 24 | + |
| 25 | +type NoOpSourceChainExtraDataCodec struct{} |
| 26 | + |
| 27 | +func (n NoOpSourceChainExtraDataCodec) DecodeExtraArgsToMap(extraArgs cciptypes.Bytes) (map[string]any, error) { |
| 28 | + return make(map[string]any), nil |
| 29 | +} |
| 30 | + |
| 31 | +func (n NoOpSourceChainExtraDataCodec) DecodeDestExecDataToMap(destExecData cciptypes.Bytes) (map[string]any, error) { |
| 32 | + return make(map[string]any), nil |
| 33 | +} |
| 34 | + |
| 35 | +// GetExtraDataCodecRegistry returns the singleton instance of ExtraDataCodecRegistry. This is only called |
| 36 | +// in core node. |
| 37 | +func GetExtraDataCodecRegistry() *ExtraDataCodecRegistry { |
| 38 | + registryOnce.Do(func() { |
| 39 | + registryInstance = &ExtraDataCodecRegistry{ |
| 40 | + extraDataCodec: make(cciptypes.ExtraDataCodecMap), |
| 41 | + } |
| 42 | + }) |
| 43 | + return registryInstance |
| 44 | +} |
| 45 | + |
| 46 | +// RegisterFamily registers a chain family with a no-op SourceChainExtraDataCodec if not already registered. |
| 47 | +// This is used when we know which chain families we want to support but don't have a specific codec |
| 48 | +// implementation initialized for it yet. This should only be called from core node, not over gRPC. |
| 49 | +func (r *ExtraDataCodecRegistry) RegisterFamily(chainFamily string) { |
| 50 | + r.mu.Lock() |
| 51 | + defer r.mu.Unlock() |
| 52 | + if _, exists := r.extraDataCodec[chainFamily]; !exists { |
| 53 | + r.extraDataCodec[chainFamily] = NoOpSourceChainExtraDataCodec{} |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +// RegisterCodec registers a SourceChainExtraDataCodec for a specific chain family and is only called |
| 58 | +// within core node, not over gRPC. |
| 59 | +func (r *ExtraDataCodecRegistry) RegisterCodec(chainFamily string, codec SourceChainExtraDataCodec) { |
| 60 | + r.mu.Lock() |
| 61 | + defer r.mu.Unlock() |
| 62 | + r.extraDataCodec[chainFamily] = codec |
| 63 | +} |
| 64 | + |
| 65 | +// DecodeExtraArgs can be called either over gRPC or not. It is used to decode extra args for a specific |
| 66 | +// source chain family |
| 67 | +func (r *ExtraDataCodecRegistry) DecodeExtraArgs( |
| 68 | + extraArgs cciptypes.Bytes, |
| 69 | + sourceChainSelector cciptypes.ChainSelector, |
| 70 | +) (map[string]any, error) { |
| 71 | + r.mu.RLock() |
| 72 | + defer r.mu.RUnlock() |
| 73 | + return r.extraDataCodec.DecodeExtraArgs(extraArgs, sourceChainSelector) |
| 74 | +} |
| 75 | + |
| 76 | +// DecodeTokenAmountDestExecData can be called either over gRPC or not. It is used to decode dest exec |
| 77 | +// data for a specific source chain family. |
| 78 | +func (r *ExtraDataCodecRegistry) DecodeTokenAmountDestExecData( |
| 79 | + destExecData cciptypes.Bytes, |
| 80 | + sourceChainSelector cciptypes.ChainSelector, |
| 81 | +) (map[string]any, error) { |
| 82 | + r.mu.RLock() |
| 83 | + defer r.mu.RUnlock() |
| 84 | + return r.extraDataCodec.DecodeTokenAmountDestExecData(destExecData, sourceChainSelector) |
| 85 | +} |
0 commit comments