Skip to content
Merged
Show file tree
Hide file tree
Changes from 81 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
ba3fe12
Create WorkflowLib Plugin
DylanTinianov Jun 23, 2025
840e0cc
Merge branch 'main' into CAPPL-902-don-time-plugin
DylanTinianov Jun 25, 2025
ff81a2f
Add test coverage
DylanTinianov Jun 25, 2025
49703b2
Update plugin.go
DylanTinianov Jun 25, 2025
f46c7a6
Update config
DylanTinianov Jun 25, 2025
305a1c7
Update ocr3.go
DylanTinianov Jun 26, 2025
4b4edb0
Extract transmitter
DylanTinianov Jun 26, 2025
315f146
Merge branch 'main' into CAPPL-902-don-time-plugin
DylanTinianov Jun 26, 2025
5c260c1
Handle request expiry
DylanTinianov Jun 26, 2025
6fa74b4
Make DonTimeResponse fields public
DylanTinianov Jun 26, 2025
3d5dd66
Make DonTimeResponse fields public
DylanTinianov Jun 26, 2025
e749b17
Add donTimeStore singleton
DylanTinianov Jun 26, 2025
e8af6ec
Link time call
DylanTinianov Jun 26, 2025
bb4e9c9
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 26, 2025
9e7682f
Update wasip1.go
DylanTinianov Jun 26, 2025
63b3d2e
Update timeout handling
DylanTinianov Jun 26, 2025
548c5b9
Merge branch 'main' into CAPPL-902-don-time-plugin
DylanTinianov Jun 26, 2025
9eddae0
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 26, 2025
55c06ce
Update plugin
DylanTinianov Jun 26, 2025
cc295dd
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 26, 2025
7bbfda6
close channel on error
DylanTinianov Jun 26, 2025
895b6fc
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 26, 2025
2115a92
Add WorkflowLib plugin
DylanTinianov Jun 26, 2025
8486858
Add context
DylanTinianov Jun 26, 2025
6523485
Update factory.go
DylanTinianov Jun 26, 2025
6b15a3d
Fix map read
DylanTinianov Jun 27, 2025
95806d1
Address comments
DylanTinianov Jun 30, 2025
4b71758
Address comments
DylanTinianov Jun 30, 2025
8f78db8
Collect valid requests
DylanTinianov Jun 30, 2025
472fd41
Verify sequence numbers
DylanTinianov Jun 30, 2025
c551eb6
Merge branch 'main' into CAPPL-902-don-time-plugin
DylanTinianov Jun 30, 2025
741f7cc
Add Range test
DylanTinianov Jun 30, 2025
f7ac127
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 30, 2025
e5537c1
Update store_test.go
DylanTinianov Jun 30, 2025
d9a6a0b
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 30, 2025
592e261
DontimePlugin
DylanTinianov Jun 30, 2025
d8f54cc
Add DonTimePlugin
DylanTinianov Jun 30, 2025
13c473a
Fix naming
DylanTinianov Jun 30, 2025
050b0fa
Export default timeout
DylanTinianov Jun 30, 2025
3177456
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 30, 2025
8418468
Fix tests
DylanTinianov Jun 30, 2025
f4f6fe2
Update store_test.go
DylanTinianov Jun 30, 2025
d0c19ef
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jun 30, 2025
d2bd602
Remove ctx when sending responses
DylanTinianov Jul 2, 2025
0b3a882
Add optimization comment
DylanTinianov Jul 2, 2025
1710351
Remove consensus on Finished Executions
DylanTinianov Jul 2, 2025
0f65579
Add batching test
DylanTinianov Jul 2, 2025
9ab2496
Fix tests
DylanTinianov Jul 2, 2025
5b16fad
Trigger CI
DylanTinianov Jul 2, 2025
7af3786
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jul 2, 2025
eec86b0
Implement pollOneoff
DylanTinianov Jul 2, 2025
1691120
Merge branch 'main' into CAPPL-902-don-time-plugin
DylanTinianov Jul 2, 2025
44c8dea
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jul 2, 2025
3517ae0
Fix generics
DylanTinianov Jul 2, 2025
56fa544
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jul 2, 2025
f1e3140
Update store.go
DylanTinianov Jul 2, 2025
1b47971
Update store.go
DylanTinianov Jul 2, 2025
9e5ebb9
Merge branch 'CAPPL-902-don-time-plugin' of https://github.com/smartc…
DylanTinianov Jul 2, 2025
add6f06
Merge branch 'main' of https://github.com/smartcontractkit/chainlink-…
DylanTinianov Jul 3, 2025
27dcee2
Fix naming
DylanTinianov Jul 3, 2025
147af5e
Remove batch size
DylanTinianov Jul 4, 2025
b0f24dc
Merge branch 'main' into CAPPL-903-module-time-hook
DylanTinianov Jul 4, 2025
8c7a60f
Rename
DylanTinianov Jul 4, 2025
4cf1220
Merge branch 'CAPPL-903-module-time-hook' of https://github.com/smart…
DylanTinianov Jul 4, 2025
d208d52
Create provider.go
DylanTinianov Jul 4, 2025
2db04d9
Update provider.go
DylanTinianov Jul 4, 2025
9f72dc5
Merge branch 'main' into CAPPL-903-module-time-hook
DylanTinianov Jul 4, 2025
5f4c0b7
Merge branch 'main' into CAPPL-903-module-time-hook
DylanTinianov Jul 4, 2025
adbd2d4
Remove trap
DylanTinianov Jul 4, 2025
79e3dcf
Merge branch 'CAPPL-903-module-time-hook' of https://github.com/smart…
DylanTinianov Jul 4, 2025
ebed436
Merge branch 'main' into CAPPL-903-module-time-hook
DylanTinianov Jul 7, 2025
017d9e3
Merge branch 'main' into CAPPL-903-module-time-hook
DylanTinianov Jul 9, 2025
f9e2142
Create time fetcher and mock time calls
DylanTinianov Jul 9, 2025
a962b78
Update time.go
DylanTinianov Jul 9, 2025
39f2a19
Optional time calls
DylanTinianov Jul 9, 2025
f7d7fed
Update execution.go
DylanTinianov Jul 9, 2025
fa9f13a
add comment
DylanTinianov Jul 9, 2025
435030f
Add baseTime and fix tests
DylanTinianov Jul 9, 2025
1220c7a
Update tests
DylanTinianov Jul 10, 2025
dad9bc0
Verify time call sequence
DylanTinianov Jul 10, 2025
e3e05aa
Merge branch 'main' of https://github.com/smartcontractkit/chainlink-…
DylanTinianov Jul 10, 2025
b8f9758
Update standard_test.go
DylanTinianov Jul 10, 2025
f2e4dfa
Update standard_test.go
DylanTinianov Jul 10, 2025
1a04fce
Merge branch 'main' into CAPPL-903-module-time-hook
nolag Jul 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pkg/workflows/dontime/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Factory struct {
func NewFactory(s *Store, lggr logger.Logger) (*Factory, error) {
return &Factory{
store: s,
lggr: logger.Named(lggr, "OCR3WorkflowLibFactory"),
lggr: logger.Named(lggr, "OCR3DonTimeFactory"),
}, nil
}

Expand Down Expand Up @@ -84,13 +84,13 @@ func (o *Factory) NewReportingPlugin(_ context.Context, config ocr3types.Reporti
}

func (o *Factory) Start(ctx context.Context) error {
return o.StartOnce("OCR3WorkflowLibPlugin", func() error {
return o.StartOnce("OCR3DonTimePlugin", func() error {
return nil
})
}

func (o *Factory) Close() error {
return o.StopOnce("OCR3WorkflowLibPlugin", func() error {
return o.StopOnce("OCR3DonTimePlugin", func() error {
return nil
})
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflows/dontime/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ func TestPlugin_FinishedExecutions(t *testing.T) {
config := newTestPluginConfig(t)
ctx := t.Context()

transmitter := NewTransmitter(lggr, store, defaultBatchSize)
transmitter := NewTransmitter(lggr, store)
plugin, err := NewPlugin(store, config, lggr)
require.NoError(t, err)

Expand Down
45 changes: 45 additions & 0 deletions pkg/workflows/dontime/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dontime

import (
"context"

"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
)

// Provider wraps an existing OCR3 plugin provider (from the relayer)
// and overrides the plugin factory and contract transmitter for DonTime.
type Provider struct {
Comment on lines +10 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Contributor Author

@DylanTinianov DylanTinianov Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's needed for initializing the plugin since we create a custom transmitter.

Factory ocr3types.ReportingPluginFactory[struct{}]
Transmitter ocr3types.ContractTransmitter[struct{}]
}

var _ services.Service = &Provider{}

func (p *Provider) Start(_ context.Context) error {
return nil
}

func (p *Provider) Close() error {
return nil
}

func (p *Provider) Name() string {
return "DonTimeOCR3Provider"
}

func (p *Provider) HealthReport() map[string]error {
return map[string]error{p.Name(): nil}
}

func (p *Provider) Ready() error {
return nil
}

func (p *Provider) ReportingPluginFactory() ocr3types.ReportingPluginFactory[struct{}] {
return p.Factory
}

func (p *Provider) ContractTransmitter() ocr3types.ContractTransmitter[struct{}] {
return p.Transmitter
}
9 changes: 4 additions & 5 deletions pkg/workflows/dontime/transmitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ var _ ocr3types.ContractTransmitter[struct{}] = (*Transmitter)(nil)
// When called it will transmit DonTime requests back to the caller
// and handle deletion of finished executionIDs.
type Transmitter struct {
lggr logger.Logger
store *Store
batchSize int
lggr logger.Logger
store *Store
}

func NewTransmitter(lggr logger.Logger, store *Store, batchSize int) *Transmitter {
return &Transmitter{lggr: lggr, store: store, batchSize: batchSize}
func NewTransmitter(lggr logger.Logger, store *Store) *Transmitter {
return &Transmitter{lggr: lggr, store: store}
}

func (t *Transmitter) Transmit(_ context.Context, _ types.ConfigDigest, _ uint64, r ocr3types.ReportWithInfo[struct{}], _ []types.AttributedOnchainSignature) error {
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflows/dontime/transmitter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestTransmitter_TransmitDonTimeRequest(t *testing.T) {
store := NewStore(DefaultRequestTimeout)
ctx := t.Context()

transmitter := NewTransmitter(lggr, store, defaultBatchSize)
transmitter := NewTransmitter(lggr, store)

// Create request for second donTime in sequence
executionID := "workflow-123"
Expand Down
112 changes: 112 additions & 0 deletions pkg/workflows/wasm/host/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package host

import (
"context"
"encoding/binary"
"fmt"
"sync"
"time"

"github.com/bytecodealliance/wasmtime-go/v28"
sdkpb "github.com/smartcontractkit/chainlink-common/pkg/workflows/sdk/v2/pb"
Expand All @@ -18,6 +20,8 @@ type execution[T any] struct {
lock sync.RWMutex
module *module
executor ExecutionHelper
timeFetcher *timeFetcher
baseTime *time.Time
hasRun bool
mode sdkpb.Mode
donSeed int64
Expand Down Expand Up @@ -161,3 +165,111 @@ func (e *execution[T]) switchModes(_ *wasmtime.Caller, mode int32) {
e.hasRun = true
e.mode = sdkpb.Mode(mode)
}

func (e *execution[T]) clockTimeGet(caller *wasmtime.Caller, id int32, precision int64, resultTimestamp int32) int32 {
donTime, err := e.timeFetcher.GetTime(e.mode)
if err != nil {
return ErrnoInval
}

if e.baseTime == nil {
// baseTime must be before the first poll or Go panics
t := donTime.Add(-time.Nanosecond)
e.baseTime = &t
}

var val int64
switch id {
case clockIDMonotonic:
val = donTime.Sub(*e.baseTime).Nanoseconds()
case clockIDRealtime:
val = donTime.UnixNano()
default:
return ErrnoInval
}

uint64Size := int32(8)
trg := make([]byte, uint64Size)
binary.LittleEndian.PutUint64(trg, uint64(val))
wasmWrite(caller, trg, resultTimestamp, uint64Size)
return ErrnoSuccess
}

// Loosely based off the implementation here:
// https://github.com/tetratelabs/wazero/blob/main/imports/wasi_snapshot_preview1/poll.go#L52
// For an overview of the spec, including the datatypes being referred to, see:
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
// This implementation only responds to clock events, not to file descriptor notifications.
// It sleeps based on the largest timeout
func (e *execution[T]) pollOneoff(caller *wasmtime.Caller, subscriptionptr int32, eventsptr int32, nsubscriptions int32, resultNevents int32) int32 {
if nsubscriptions == 0 {
return ErrnoInval
}

subs, err := wasmRead(caller, subscriptionptr, nsubscriptions*subscriptionLen)
if err != nil {
return ErrnoFault
}

events := make([]byte, nsubscriptions*eventsLen)
timeout := time.Duration(0)

for i := int32(0); i < nsubscriptions; i++ {
inOffset := i * subscriptionLen
userData := subs[inOffset : inOffset+8]
eventType := subs[inOffset+8]
argBuf := subs[inOffset+8+8:]

slot, err := getSlot(events, i)
if err != nil {
return ErrnoFault
}

switch eventType {
case eventTypeClock:
newTimeout := binary.LittleEndian.Uint64(argBuf[8:16])
flag := binary.LittleEndian.Uint16(argBuf[24:32])

var errno Errno
switch flag {
case 0: // relative
errno = ErrnoSuccess
if timeout < time.Duration(newTimeout) {
timeout = time.Duration(newTimeout)
}
default:
errno = ErrnoNotsup
}
writeEvent(slot, userData, errno, eventTypeClock)

case eventTypeFDRead, eventTypeFDWrite:
writeEvent(slot, userData, ErrnoBadf, int(eventType))

default:
writeEvent(slot, userData, ErrnoInval, int(eventType))
}
}

if timeout > 0 {
select {
case <-time.After(timeout):
case <-e.ctx.Done():
// If context was cancelled, there will be a trap from the engine
// which will halt execution, therefore the return value isn't read
return 0
}
}

uint32Size := int32(4)
rne := make([]byte, uint32Size)
binary.LittleEndian.PutUint32(rne, uint32(nsubscriptions))

if wasmWrite(caller, rne, resultNevents, uint32Size) == -1 {
return ErrnoFault
}
if wasmWrite(caller, events, eventsptr, nsubscriptions*eventsLen) == -1 {
return ErrnoFault
}

return ErrnoSuccess
}
37 changes: 24 additions & 13 deletions pkg/workflows/wasm/host/mock_execution_helper_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/workflows/wasm/host/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ type ExecutionHelper interface {

GetNodeTime() time.Time

GetDONTime() time.Time
GetDONTime(ctx context.Context) (time.Time, error)

EmitUserLog(log string) error
}
Expand Down
5 changes: 2 additions & 3 deletions pkg/workflows/wasm/host/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package host
import (
"context"
"encoding/binary"
"sync"
"testing"

"github.com/bytecodealliance/wasmtime-go/v28"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"sync"
"testing"

"github.com/smartcontractkit/chainlink-common/pkg/custmsg"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
Expand Down
Loading
Loading