-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create NewContractReader in RegisterTrigger flow of the trigger capab…
…ility
- Loading branch information
1 parent
0ff783b
commit 1b617a6
Showing
6 changed files
with
184 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,20 @@ | ||
package log_event_trigger | ||
package logeventtrigger | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/smartcontractkit/chainlink-common/pkg/capabilities" | ||
"github.com/smartcontractkit/chainlink-common/pkg/logger" | ||
"github.com/smartcontractkit/chainlink-common/pkg/services" | ||
"github.com/smartcontractkit/chainlink-common/pkg/types/core" | ||
|
||
evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" | ||
) | ||
|
||
const ID = "cron-[email protected]" | ||
const ID = "log-event-trigger-%s-%d@1.0.0" | ||
|
||
const defaultSendChannelBufferSize = 1000 | ||
|
||
|
@@ -20,8 +24,15 @@ var logEventTriggerInfo = capabilities.MustNewCapabilityInfo( | |
"A trigger that listens for specific contract log events and starts a workflow run.", | ||
) | ||
|
||
// Log Event Trigger Capability Config | ||
type Config struct { | ||
// Log Event Trigger Capability RequestConfig | ||
type RequestConfig struct { | ||
ContractName string `json:"contractName"` | ||
ContractAddress common.Address `json:"contractAddress"` | ||
ContractReaderConfig evmtypes.ChainReaderConfig `json:"contractReaderConfig"` | ||
} | ||
|
||
// Log Event Trigger Capability Input | ||
type Input struct { | ||
} | ||
|
||
// Log Event Trigger Capability Payload | ||
|
@@ -37,21 +48,29 @@ type Response struct { | |
Payload Payload | ||
} | ||
|
||
type logEventTrigger struct { | ||
ch chan<- capabilities.TriggerResponse | ||
} | ||
|
||
// Log Event Trigger Capabilities Manager | ||
// Manages different log event triggers using an underlying triggerStore | ||
type LogEventTriggerService struct { | ||
capabilities.CapabilityInfo | ||
capabilities.Validator[Config, struct{}, capabilities.TriggerResponse] | ||
lggr logger.Logger | ||
triggers CapabilitiesStore[logEventTrigger, capabilities.TriggerResponse] | ||
capabilities.Validator[RequestConfig, Input, capabilities.TriggerResponse] | ||
lggr logger.Logger | ||
triggers CapabilitiesStore[logEventTrigger, capabilities.TriggerResponse] | ||
relayer core.Relayer | ||
logEventConfig LogEventConfig | ||
} | ||
|
||
// Common capability level config across all workflows | ||
type LogEventConfig struct { | ||
ChainId uint64 `json:"chainId"` | ||
Network string `json:"network"` | ||
LookbackBlocks uint64 `json:"lookbakBlocks"` | ||
PollPeriod uint64 `json:"pollPeriod"` | ||
} | ||
|
||
type Params struct { | ||
Logger logger.Logger | ||
Logger logger.Logger | ||
Relayer core.Relayer | ||
LogEventConfig LogEventConfig | ||
} | ||
|
||
var _ capabilities.TriggerCapability = (*LogEventTriggerService)(nil) | ||
|
@@ -68,24 +87,32 @@ func NewLogEventTriggerService(p Params) *LogEventTriggerService { | |
CapabilityInfo: logEventTriggerInfo, | ||
lggr: l, | ||
triggers: logEventStore, | ||
relayer: p.Relayer, | ||
logEventConfig: p.LogEventConfig, | ||
} | ||
} | ||
|
||
func (s *LogEventTriggerService) Info(ctx context.Context) (capabilities.CapabilityInfo, error) { | ||
return capabilities.NewCapabilityInfo( | ||
fmt.Sprintf(ID, s.logEventConfig.Network, s.logEventConfig.ChainId), | ||
capabilities.CapabilityTypeTrigger, | ||
"A trigger that listens for specific contract log events and starts a workflow run.", | ||
) | ||
} | ||
|
||
// Register a new trigger | ||
// Can register triggers before the service is actively scheduling | ||
func (s *LogEventTriggerService) RegisterTrigger(ctx context.Context, req capabilities.TriggerRegistrationRequest) (<-chan capabilities.TriggerResponse, error) { | ||
if req.Config == nil { | ||
return nil, errors.New("config is required to register a log event trigger") | ||
} | ||
_, err := s.ValidateConfig(req.Config) | ||
reqConfig, err := s.ValidateConfig(req.Config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
respCh, err := s.triggers.InsertIfNotExists(req.TriggerID, func() (logEventTrigger, chan capabilities.TriggerResponse) { | ||
callbackCh := make(chan capabilities.TriggerResponse, defaultSendChannelBufferSize) | ||
return logEventTrigger{ | ||
ch: callbackCh, | ||
}, callbackCh | ||
// Add log event trigger with Contract details to CapabilitiesStore | ||
respCh, err := s.triggers.InsertIfNotExists(req.TriggerID, func() (*logEventTrigger, chan capabilities.TriggerResponse, error) { | ||
return newLogEventTrigger(ctx, reqConfig, s.logEventConfig, s.relayer) | ||
}) | ||
if err != nil { | ||
return nil, fmt.Errorf("log_event_trigger %v", err) | ||
|
@@ -109,6 +136,10 @@ func (s *LogEventTriggerService) UnregisterTrigger(ctx context.Context, req capa | |
|
||
// Start the service. | ||
func (s *LogEventTriggerService) Start(ctx context.Context) error { | ||
if s.relayer == nil { | ||
return errors.New("service has shutdown, it must be built again to restart") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
|
29 changes: 16 additions & 13 deletions
29
core/capabilities/log_event_trigger/store.go → core/capabilities/logeventtrigger/store.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package logeventtrigger | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/smartcontractkit/chainlink-common/pkg/capabilities" | ||
"github.com/smartcontractkit/chainlink-common/pkg/types" | ||
"github.com/smartcontractkit/chainlink-common/pkg/types/core" | ||
|
||
evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" | ||
) | ||
|
||
type logEventTrigger struct { | ||
ch chan<- capabilities.TriggerResponse | ||
|
||
// Contract address and Event Signature to monitor for | ||
contractName string | ||
contractAddress common.Address | ||
contractReaderConfig evmtypes.ChainReaderConfig | ||
contractReader types.ContractReader | ||
|
||
// Log Event Trigger config with pollPeriod and lookbackBlocks | ||
logEventConfig LogEventConfig | ||
ticker *time.Ticker | ||
done chan bool | ||
} | ||
|
||
// Construct for logEventTrigger struct | ||
func newLogEventTrigger(ctx context.Context, | ||
reqConfig *RequestConfig, | ||
logEventConfig LogEventConfig, | ||
relayer core.Relayer) (*logEventTrigger, chan capabilities.TriggerResponse, error) { | ||
jsonBytes, err := json.Marshal(reqConfig.ContractReaderConfig) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
// Create a New Contract Reader client, which brings a corresponding ContractReader gRPC service | ||
// in Chainlink Core service | ||
contractReader, err := relayer.NewContractReader(ctx, jsonBytes) | ||
if err != nil { | ||
return nil, nil, | ||
fmt.Errorf("error fetching contractReader for chainID %d from relayerSet: %v", logEventConfig.ChainId, err) | ||
} | ||
|
||
// Bind Contract in ContractReader | ||
boundContracts := []types.BoundContract{{Name: reqConfig.ContractName, Address: reqConfig.ContractAddress.Hex()}} | ||
err = contractReader.Bind(ctx, boundContracts) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
callbackCh := make(chan capabilities.TriggerResponse, defaultSendChannelBufferSize) | ||
ticker := time.NewTicker(time.Duration(logEventConfig.PollPeriod) * time.Millisecond) | ||
done := make(chan bool) | ||
|
||
// Initialise a Log Event Trigger | ||
l := &logEventTrigger{ | ||
ch: callbackCh, | ||
contractName: reqConfig.ContractName, | ||
contractAddress: reqConfig.ContractAddress, | ||
contractReaderConfig: reqConfig.ContractReaderConfig, | ||
contractReader: contractReader, | ||
logEventConfig: logEventConfig, | ||
ticker: ticker, | ||
done: done, | ||
} | ||
go l.Listen() | ||
|
||
return l, callbackCh, nil | ||
} | ||
|
||
// Listen to contract events and trigger workflow runs | ||
func (l *logEventTrigger) Listen() { | ||
// Listen for events from lookbackPeriod | ||
for { | ||
select { | ||
case <-l.done: | ||
return | ||
case t := <-l.ticker.C: | ||
fmt.Println("Tick at", t) | ||
} | ||
} | ||
} | ||
|
||
// Stop contract event listener for the current contract | ||
func (l *logEventTrigger) Stop() { | ||
l.done <- true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters