Skip to content

Commit

Permalink
Initial Add confidence levels to CR GetLatestValue
Browse files Browse the repository at this point in the history
  • Loading branch information
ilija42 committed Jul 1, 2024
1 parent 3f8c00a commit 4082aea
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 43 deletions.
11 changes: 6 additions & 5 deletions core/capabilities/targets/mocks/chain_reader.go

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

3 changes: 2 additions & 1 deletion core/capabilities/targets/write_target.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/types"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
"github.com/smartcontractkit/chainlink-common/pkg/values"
"github.com/smartcontractkit/chainlink/v2/core/logger"
)
Expand Down Expand Up @@ -112,7 +113,7 @@ func (cap *WriteTarget) Execute(ctx context.Context, request capabilities.Capabi
ReportId: inputs.ID,
}
var transmitter common.Address
if err = cap.cr.GetLatestValue(ctx, "forwarder", "getTransmitter", queryInputs, &transmitter); err != nil {
if err = cap.cr.GetLatestValue(ctx, "forwarder", "getTransmitter", primitives.Finalized, queryInputs, &transmitter); err != nil {
return nil, err
}
if transmitter != common.HexToAddress("0x0") {
Expand Down
4 changes: 2 additions & 2 deletions core/capabilities/targets/write_target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestWriteTarget(t *testing.T) {
})
require.NoError(t, err)

cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
transmitter := args.Get(4).(*common.Address)
*transmitter = common.HexToAddress("0x0")
}).Once()
Expand Down Expand Up @@ -100,7 +100,7 @@ func TestWriteTarget(t *testing.T) {
Config: config,
Inputs: validInputs,
}
cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything).Return(errors.New("reader error"))
cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("reader error"))

_, err = writeTarget.Execute(ctx, req)
require.Error(t, err)
Expand Down
7 changes: 4 additions & 3 deletions core/services/registrysyncer/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
"github.com/smartcontractkit/chainlink/v2/core/logger"
Expand Down Expand Up @@ -167,7 +168,7 @@ func (s *registrySyncer) syncLoop() {

func (s *registrySyncer) state(ctx context.Context) (State, error) {
dons := []kcr.CapabilitiesRegistryDONInfo{}
err := s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getDONs", nil, &dons)
err := s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getDONs", primitives.Finalized, nil, &dons)
if err != nil {
return State{}, err
}
Expand All @@ -178,7 +179,7 @@ func (s *registrySyncer) state(ctx context.Context) (State, error) {
}

caps := []kcr.CapabilitiesRegistryCapabilityInfo{}
err = s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getCapabilities", nil, &caps)
err = s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getCapabilities", primitives.Finalized, nil, &caps)
if err != nil {
return State{}, err
}
Expand All @@ -189,7 +190,7 @@ func (s *registrySyncer) state(ctx context.Context) (State, error) {
}

nodes := []kcr.CapabilitiesRegistryNodeInfo{}
err = s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getNodes", nil, &nodes)
err = s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getNodes", primitives.Finalized, nil, &nodes)
if err != nil {
return State{}, err
}
Expand Down
3 changes: 2 additions & 1 deletion core/services/relay/evm/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import (

commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
)

type readBinding interface {
Bind(ctx context.Context, binding commontypes.BoundContract) error
SetCodec(codec commontypes.RemoteCodec)
Register(ctx context.Context) error
Unregister(ctx context.Context) error
GetLatestValue(ctx context.Context, params, returnVal any) error
GetLatestValue(ctx context.Context, confidenceLevel primitives.ConfidenceLevel, params, returnVal any) error
QueryKey(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) ([]commontypes.Sequence, error)
}
16 changes: 11 additions & 5 deletions core/services/relay/evm/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ func (cr *chainReader) HealthReport() map[string]error {
return map[string]error{cr.Name(): nil}
}

func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method string, params any, returnVal any) error {
func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method string, confidenceLevel primitives.ConfidenceLevel, params, returnVal any) error {
b, err := cr.contractBindings.GetReadBinding(contractName, method)
if err != nil {
return err
}

return b.GetLatestValue(ctx, params, returnVal)
return b.GetLatestValue(ctx, confidenceLevel, params, returnVal)
}

func (cr *chainReader) Bind(ctx context.Context, bindings []commontypes.BoundContract) error {
Expand Down Expand Up @@ -204,10 +204,16 @@ func (cr *chainReader) addMethod(
return fmt.Errorf("%w: method %s doesn't exist", commontypes.ErrInvalidConfig, chainReaderDefinition.ChainSpecificName)
}

confirmations, err := confirmationsFromConfig(chainReaderDefinition.ConfidenceConfirmations)
if err != nil {
return err
}

cr.contractBindings.AddReadBinding(contractName, methodName, &methodBinding{
contractName: contractName,
method: methodName,
client: cr.client,
contractName: contractName,
method: methodName,
client: cr.client,
confirmationsMapping: confirmations,
})

if err := cr.addEncoderDef(contractName, methodName, method.Inputs, method.ID, chainReaderDefinition); err != nil {
Expand Down
18 changes: 6 additions & 12 deletions core/services/relay/evm/event_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ type eventBinding struct {
// filterRegisterer in eventBinding is to be used as an override for lp filter defined in the contract binding.
// If filterRegisterer is nil, this event should be registered with the lp filter defined in the contract binding.
*filterRegisterer
hash common.Hash
codec commontypes.RemoteCodec
pending bool
hash common.Hash
codec commontypes.RemoteCodec
// bound determines if address is set to the contract binding.
bound bool
bindLock sync.Mutex
Expand Down Expand Up @@ -72,7 +71,6 @@ func (e *eventBinding) Bind(ctx context.Context, binding commontypes.BoundContra
}

e.address = common.HexToAddress(binding.Address)
e.pending = binding.Pending

// filterRegisterer isn't required here because the event can also be polled for by the contractBinding common filter.
if e.filterRegisterer != nil {
Expand Down Expand Up @@ -136,22 +134,18 @@ func (e *eventBinding) Unregister(ctx context.Context) error {
return nil
}

func (e *eventBinding) GetLatestValue(ctx context.Context, params, into any) error {
func (e *eventBinding) GetLatestValue(ctx context.Context, confidenceLevel primitives.ConfidenceLevel, params, into any) error {
if err := e.validateBound(); err != nil {
return err
}

// TODO BCF-3247 change GetLatestValue to use chain agnostic confidence levels
confs := evmtypes.Finalized
if e.pending {
confs = evmtypes.Unconfirmed
}
confirmations := e.confirmationsFrom(confidenceLevel)

if len(e.inputInfo.Args()) == 0 {
return e.getLatestValueWithoutFilters(ctx, confs, into)
return e.getLatestValueWithoutFilters(ctx, confirmations, into)
}

return e.getLatestValueWithFilters(ctx, confs, params, into)
return e.getLatestValueWithFilters(ctx, confirmations, params, into)
}

func (e *eventBinding) QueryKey(ctx context.Context, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) ([]commontypes.Sequence, error) {
Expand Down
2 changes: 1 addition & 1 deletion core/services/relay/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp
return nil, err
}

boundContracts := []commontypes.BoundContract{{Name: "median", Pending: true, Address: contractID.String()}}
boundContracts := []commontypes.BoundContract{{Name: "median", Address: contractID.String()}}
if err = chainReaderService.Bind(context.Background(), boundContracts); err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ func (it *EVMChainReaderInterfaceTester[T]) TriggerEvent(t T, testStruct *TestSt

func (it *EVMChainReaderInterfaceTester[T]) GetBindings(_ T) []clcommontypes.BoundContract {
return []clcommontypes.BoundContract{
{Name: AnyContractName, Address: it.address, Pending: true},
{Name: AnySecondContractName, Address: it.address2, Pending: true},
{Name: AnyContractName, Address: it.address},
{Name: AnySecondContractName, Address: it.address2},
}
}

Expand Down
7 changes: 4 additions & 3 deletions core/services/relay/evm/evmtesting/run_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"

clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

. "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with .

Expand Down Expand Up @@ -42,7 +43,7 @@ func RunChainReaderEvmTests[T TestingT[T]](t T, it *EVMChainReaderInterfaceTeste
rOutput := reflect.Indirect(reflect.ValueOf(output))

require.Eventually(t, func() bool {
return cr.GetLatestValue(ctx, AnyContractName, triggerWithDynamicTopic, input, output) == nil
return cr.GetLatestValue(ctx, AnyContractName, triggerWithDynamicTopic, primitives.Unconfirmed, input, output) == nil
}, it.MaxWaitTimeForEvents(), 100*time.Millisecond)

assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface())
Expand All @@ -67,7 +68,7 @@ func RunChainReaderEvmTests[T TestingT[T]](t T, it *EVMChainReaderInterfaceTeste

time.Sleep(it.MaxWaitTimeForEvents())

require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, params, &latest))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, primitives.Unconfirmed, params, &latest))
assert.Equal(t, int32(1), latest.Field1)
assert.Equal(t, int32(2), latest.Field2)
assert.Equal(t, int32(3), latest.Field3)
Expand All @@ -80,7 +81,7 @@ func RunChainReaderEvmTests[T TestingT[T]](t T, it *EVMChainReaderInterfaceTeste
reader := it.GetChainReader(t)

ctx := it.Helper.Context(t)
err := reader.Bind(ctx, []clcommontypes.BoundContract{{Name: AnyContractName, Address: addr.Hex(), Pending: true}})
err := reader.Bind(ctx, []clcommontypes.BoundContract{{Name: AnyContractName, Address: addr.Hex()}})

require.ErrorIs(t, err, evm.NoContractExistsError{Address: addr})
})
Expand Down
35 changes: 27 additions & 8 deletions core/services/relay/evm/method_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"

evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
)
Expand All @@ -22,12 +24,13 @@ func (e NoContractExistsError) Error() string {
}

type methodBinding struct {
address common.Address
contractName string
method string
client evmclient.Client
codec commontypes.Codec
bound bool
address common.Address
contractName string
method string
client evmclient.Client
codec commontypes.Codec
bound bool
confirmationsMapping map[primitives.ConfidenceLevel]evmtypes.Confirmations
}

var _ readBinding = &methodBinding{}
Expand Down Expand Up @@ -63,7 +66,7 @@ func (m *methodBinding) Unregister(_ context.Context) error {
return nil
}

func (m *methodBinding) GetLatestValue(ctx context.Context, params, returnValue any) error {
func (m *methodBinding) GetLatestValue(ctx context.Context, _ primitives.ConfidenceLevel, params, returnVal any) error {
if !m.bound {
return fmt.Errorf("%w: method not bound", commontypes.ErrInvalidType)
}
Expand All @@ -79,14 +82,30 @@ func (m *methodBinding) GetLatestValue(ctx context.Context, params, returnValue
Data: data,
}

// TODO when BCI-2874 use headtracker to get block number to use here
//blockNumber := m.blockNumberFromConfidence(confidence.ConfidenceLevel)

bytes, err := m.client.CallContract(ctx, callMsg, nil)
if err != nil {
return fmt.Errorf("%w: %w", commontypes.ErrInternal, err)
}

return m.codec.Decode(ctx, bytes, returnValue, wrapItemType(m.contractName, m.method, false))
return m.codec.Decode(ctx, bytes, returnVal, wrapItemType(m.contractName, m.method, false))
}

func (m *methodBinding) QueryKey(_ context.Context, _ query.KeyFilter, _ query.LimitAndSort, _ any) ([]commontypes.Sequence, error) {
return nil, nil
}

// TODO when BCI-2874 use headtracker to get block number to use here
//func (m *methodBinding) blockNumberFromConfidence(confidenceLevel primitives.ConfidenceLevel) *big.Int {
// value, ok := m.confirmationsMapping[confidence]
// if ok {
// return value
// }
//
// ...
//
// // if the mapping doesn't exist, default to finalized for safety
// return ...
//}

0 comments on commit 4082aea

Please sign in to comment.