Skip to content

Commit

Permalink
Remove pending from boundContract and use confidence instead for CR
Browse files Browse the repository at this point in the history
  • Loading branch information
ilija42 committed Jun 13, 2024
1 parent 0abd7de commit baa671f
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 248 deletions.
437 changes: 220 additions & 217 deletions pkg/loop/internal/pb/chain_reader.pb.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/loop/internal/pb/chain_reader.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ message GetLatestValueRequest {
string contract_name = 1;
string method = 2;
VersionedBytes params = 3;
Confidence confidence = 4;
}

// QueryKeyRequest has arguments for [github.com/smartcontractkit/chainlink-common/pkg/types.ChainReader.QueryKey].
Expand Down Expand Up @@ -60,7 +61,6 @@ message Sequence {
message BoundContract {
string address = 1;
string name = 2;
bool pending = 3;
}

enum ComparisonOperator {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,20 @@ func DecodeVersionedBytes(res any, vData *pb.VersionedBytes) error {
return nil
}

func (c *Client) GetLatestValue(ctx context.Context, contractName, method string, params, retVal any) error {
func (c *Client) GetLatestValue(ctx context.Context, contractName, method string, params, retVal any, confidenceLevel primitives.ConfidenceLevel) error {
versionedParams, err := EncodeVersionedBytes(params, CurrentEncodingVersion)
if err != nil {
return err
}

reply, err := c.grpc.GetLatestValue(ctx, &pb.GetLatestValueRequest{ContractName: contractName, Method: method, Params: versionedParams})
var pbConfidence pb.Confidence
if confidenceLevel == primitives.Finalized {
pbConfidence = pb.Confidence_Finalized
} else {
pbConfidence = pb.Confidence_Unconfirmed
}

reply, err := c.grpc.GetLatestValue(ctx, &pb.GetLatestValueRequest{ContractName: contractName, Method: method, Params: versionedParams, Confidence: pbConfidence})
if err != nil {
return net.WrapRPCErr(err)
}
Expand Down Expand Up @@ -137,7 +144,7 @@ func (c *Client) QueryKey(ctx context.Context, contractName string, filter query
func (c *Client) Bind(ctx context.Context, bindings []types.BoundContract) error {
pbBindings := make([]*pb.BoundContract, len(bindings))
for i, b := range bindings {
pbBindings[i] = &pb.BoundContract{Address: b.Address, Name: b.Name, Pending: b.Pending}
pbBindings[i] = &pb.BoundContract{Address: b.Address, Name: b.Name}
}
_, err := c.grpc.Bind(ctx, &pb.BindRequest{Bindings: pbBindings})
return net.WrapRPCErr(err)
Expand Down Expand Up @@ -168,7 +175,15 @@ func (c *Server) GetLatestValue(ctx context.Context, request *pb.GetLatestValueR
if err != nil {
return nil, err
}
err = c.impl.GetLatestValue(ctx, request.ContractName, request.Method, params, retVal)

var confidenceLevel primitives.ConfidenceLevel
if request.Confidence == pb.Confidence_Finalized {
confidenceLevel = primitives.Finalized
} else {
confidenceLevel = primitives.Unconfirmed
}

err = c.impl.GetLatestValue(ctx, request.ContractName, request.Method, params, retVal, confidenceLevel)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -213,7 +228,7 @@ func (c *Server) QueryKey(ctx context.Context, request *pb.QueryKeyRequest) (*pb
func (c *Server) Bind(ctx context.Context, bindings *pb.BindRequest) (*emptypb.Empty, error) {
tBindings := make([]types.BoundContract, len(bindings.Bindings))
for i, b := range bindings.Bindings {
tBindings[i] = types.BoundContract{Address: b.Address, Name: b.Name, Pending: b.Pending}
tBindings[i] = types.BoundContract{Address: b.Address, Name: b.Name}
}

return &emptypb.Empty{}, c.impl.Bind(ctx, tBindings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/chainreader/test"
"github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"

. "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint
Expand Down Expand Up @@ -97,15 +98,15 @@ func TestGetLatestValue(t *testing.T) {
nilTester.Setup(t)
nilCr := nilTester.GetChainReader(t)

err := nilCr.GetLatestValue(ctx, "", "method", "anything", "anything")
err := nilCr.GetLatestValue(ctx, "", "method", "anything", "anything", primitives.Finalized)
assert.Equal(t, codes.Unimplemented, status.Convert(err).Code())
})

for _, errorType := range errorTypes {
es.err = errorType
t.Run("GetLatestValue unwraps errors from server "+errorType.Error(), func(t *testing.T) {
ctx := tests.Context(t)
err := chainReader.GetLatestValue(ctx, "", "method", nil, "anything")
err := chainReader.GetLatestValue(ctx, "", "method", nil, "anything", primitives.Finalized)
assert.True(t, errors.Is(err, errorType))
})
}
Expand All @@ -114,7 +115,7 @@ func TestGetLatestValue(t *testing.T) {
es.err = nil
t.Run("GetLatestValue returns error if type cannot be encoded in the wire format", func(t *testing.T) {
ctx := tests.Context(t)
err := chainReader.GetLatestValue(ctx, "", "method", &cannotEncode{}, &TestStruct{})
err := chainReader.GetLatestValue(ctx, "", "method", &cannotEncode{}, &TestStruct{}, primitives.Finalized)
assert.True(t, errors.Is(err, types.ErrInvalidType))
})
}
Expand Down Expand Up @@ -237,7 +238,7 @@ func (f *fakeChainReader) SetLatestValue(ts *TestStruct) {
f.stored = append(f.stored, *ts)
}

func (f *fakeChainReader) GetLatestValue(_ context.Context, contractName, method string, params, returnVal any) error {
func (f *fakeChainReader) GetLatestValue(_ context.Context, contractName, method string, params, returnVal any, _ primitives.ConfidenceLevel) error {
if method == MethodReturningUint64 {
r := returnVal.(*uint64)
if contractName == AnyContractName {
Expand Down Expand Up @@ -331,7 +332,7 @@ func (e *errChainReader) Name() string { panic("unimplemented") }

func (e *errChainReader) HealthReport() map[string]error { panic("unimplemented") }

func (e *errChainReader) GetLatestValue(_ context.Context, _, _ string, _, _ any) error {
func (e *errChainReader) GetLatestValue(_ context.Context, _, _ string, _, _ any, _ primitives.ConfidenceLevel) error {
return e.err
}

Expand Down Expand Up @@ -359,7 +360,7 @@ func (pc *protoConversionTestChainReader) Name() string { panic("unimplemented")

func (pc *protoConversionTestChainReader) HealthReport() map[string]error { panic("unimplemented") }

func (pc *protoConversionTestChainReader) GetLatestValue(_ context.Context, _, _ string, _, _ any) error {
func (pc *protoConversionTestChainReader) GetLatestValue(_ context.Context, _, _ string, _, _ any, _ primitives.ConfidenceLevel) error {
return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
testtypes "github.com/smartcontractkit/chainlink-common/pkg/loop/internal/test/types"
"github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
)

var (
Expand Down Expand Up @@ -47,7 +48,7 @@ func (c staticChainReader) Bind(_ context.Context, _ []types.BoundContract) erro
return nil
}

func (c staticChainReader) GetLatestValue(_ context.Context, contractName, method string, params, returnVal any) error {
func (c staticChainReader) GetLatestValue(_ context.Context, contractName, method string, params, returnVal any, _ primitives.ConfidenceLevel) error {
if !assert.ObjectsAreEqual(contractName, c.contractName) {
return fmt.Errorf("%w: expected report context %v but got %v", types.ErrInvalidType, c.contractName, contractName)
}
Expand Down Expand Up @@ -80,7 +81,7 @@ func (c staticChainReader) QueryKey(_ context.Context, _ string, _ query.KeyFilt

func (c staticChainReader) Evaluate(ctx context.Context, cr types.ContractReader) error {
gotLatestValue := make(map[string]any)
err := cr.GetLatestValue(ctx, c.contractName, c.contractMethod, &c.params, &gotLatestValue)
err := cr.GetLatestValue(ctx, c.contractName, c.contractMethod, &c.params, &gotLatestValue, primitives.Finalized)
if err != nil {
return fmt.Errorf("failed to call GetLatestValue(): %w", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/smartcontractkit/chainlink-common/pkg/loop/internal/goplugin"
"github.com/smartcontractkit/chainlink-common/pkg/loop/internal/relayer/pluginprovider/chainreader"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

"github.com/smartcontractkit/chainlink-common/pkg/loop/internal/net"
"github.com/smartcontractkit/chainlink-common/pkg/loop/internal/pb"
Expand Down Expand Up @@ -46,7 +47,7 @@ func NewProviderClient(b *net.BrokerExt, cc grpc.ClientConnInterface) *ProviderC

maybeCr := chainreader.NewClient(b, cc)
var anyRetVal int
err := maybeCr.GetLatestValue(context.Background(), "", "", nil, &anyRetVal)
err := maybeCr.GetLatestValue(context.Background(), "", "", nil, &anyRetVal, primitives.Finalized)
if status.Convert(err).Code() != codes.Unimplemented {
m.chainReader = maybeCr
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/types/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

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

// Errors exposed to product plugins
Expand All @@ -21,7 +22,7 @@ type ContractReader = ChainReader
// Deprecated: use ContractReader. New naming should clear up confusion around the usage of this interface which should strictly be contract reading related.
type ChainReader interface {
services.Service
// GetLatestValue gets the latest value....
// GetLatestValue gets the latest value with a certain confidence level that maps to blockchain finality....
// The params argument can be any object which maps a set of generic parameters into chain specific parameters defined in RelayConfig.
// It must encode as an object via [json.Marshal] and [github.com/fxamacker/cbor/v2.Marshal].
// Typically, would be either a struct with field names mapping to arguments, or anonymous map such as `map[string]any{"baz": 42, "test": true}}`
Expand All @@ -37,14 +38,14 @@ type ChainReader interface {
// Bar *big.Int `json:"bar"`
// }
// func do(ctx context.Context, cr ChainReader) (resp ProductReturn, err error) {
// err = cr.GetLatestValue(ctx, "FooContract", "GetProduct", ProductParams{ID:1}, &resp)
// err = cr.GetLatestValue(ctx, "FooContract", "GetProduct", ProductParams{ID:1}, &resp, primitives.Finalized)
// return
// }
//
// Note that implementations should ignore extra fields in params that are not expected in the call to allow easier
// use across chains and contract versions.
// Similarly, when using a struct for returnVal, fields in the return value that are not on-chain will not be set.
GetLatestValue(ctx context.Context, contractName, method string, params, returnVal any) error
GetLatestValue(ctx context.Context, contractName, method string, params, returnVal any, confidenceLevel primitives.ConfidenceLevel) error

// Bind will override current bindings for the same contract, if one has been set and will return an error if the
// contract is not known by the ChainReader, or if the Address is invalid
Expand Down Expand Up @@ -72,7 +73,6 @@ type Sequence struct {
type BoundContract struct {
Address string
Name string
Pending bool
}

func (bc BoundContract) Key() string {
Expand Down
25 changes: 13 additions & 12 deletions pkg/types/interfacetests/chain_reader_interface_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

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

Expand Down Expand Up @@ -65,12 +66,12 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain

actual := &TestStruct{}
params := &LatestParams{I: 1}
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodTakingLatestParamsReturningTestStruct, params, actual))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodTakingLatestParamsReturningTestStruct, params, actual, primitives.Finalized))
assert.Equal(t, &firstItem, actual)

params.I = 2
actual = &TestStruct{}
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodTakingLatestParamsReturningTestStruct, params, actual))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodTakingLatestParamsReturningTestStruct, params, actual, primitives.Finalized))
assert.Equal(t, &secondItem, actual)
},
},
Expand All @@ -82,7 +83,7 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
require.NoError(t, cr.Bind(ctx, tester.GetBindings(t)))

var prim uint64
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodReturningUint64, nil, &prim))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodReturningUint64, nil, &prim, primitives.Finalized))

assert.Equal(t, AnyValueToReadWithoutAnArgument, prim)
},
Expand All @@ -95,13 +96,13 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
require.NoError(t, cr.Bind(ctx, tester.GetBindings(t)))

var prim uint64
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, DifferentMethodReturningUint64, nil, &prim))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, DifferentMethodReturningUint64, nil, &prim, primitives.Finalized))

assert.Equal(t, AnyDifferentValueToReadWithoutAnArgument, prim)
},
},
{
name: "Get latest value allows multiple constract names to have the same function name",
name: "Get latest value allows multiple contract names to have the same function name",
test: func(t T) {
ctx := tests.Context(t)
cr := tester.GetChainReader(t)
Expand All @@ -115,7 +116,7 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
require.NoError(t, cr.Bind(ctx, bindings))

var prim uint64
require.NoError(t, cr.GetLatestValue(ctx, AnySecondContractName, MethodReturningUint64, nil, &prim))
require.NoError(t, cr.GetLatestValue(ctx, AnySecondContractName, MethodReturningUint64, nil, &prim, primitives.Finalized))

assert.Equal(t, AnyDifferentValueToReadWithoutAnArgument, prim)
},
Expand All @@ -128,7 +129,7 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
require.NoError(t, cr.Bind(ctx, tester.GetBindings(t)))

var slice []uint64
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodReturningUint64Slice, nil, &slice))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodReturningUint64Slice, nil, &slice, primitives.Finalized))

assert.Equal(t, AnySliceToReadWithoutAnArgument, slice)
},
Expand All @@ -144,7 +145,7 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
require.NoError(t, cr.Bind(ctx, tester.GetBindings(t)))

actual := &TestStructWithExtraField{}
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodReturningSeenStruct, testStruct, actual))
require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, MethodReturningSeenStruct, testStruct, actual, primitives.Finalized))

expected := &TestStructWithExtraField{
ExtraField: AnyExtraValue,
Expand All @@ -167,7 +168,7 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain

result := &TestStruct{}
assert.Eventually(t, func() bool {
err := cr.GetLatestValue(ctx, AnyContractName, EventName, nil, &result)
err := cr.GetLatestValue(ctx, AnyContractName, EventName, nil, &result, primitives.Finalized)
return err == nil && reflect.DeepEqual(result, &ts)
}, tester.MaxWaitTimeForEvents(), time.Millisecond*10)
},
Expand All @@ -180,7 +181,7 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
require.NoError(t, cr.Bind(ctx, tester.GetBindings(t)))

result := &TestStruct{}
err := cr.GetLatestValue(ctx, AnyContractName, EventName, nil, &result)
err := cr.GetLatestValue(ctx, AnyContractName, EventName, nil, &result, primitives.Finalized)
assert.True(t, errors.Is(err, types.ErrNotFound))
},
},
Expand All @@ -198,13 +199,13 @@ func runChainReaderGetLatestValueInterfaceTests[T TestingT[T]](t T, tester Chain
filterParams := &FilterEventParams{Field: *ts0.Field}
assert.Never(t, func() bool {
result := &TestStruct{}
err := cr.GetLatestValue(ctx, AnyContractName, EventWithFilterName, filterParams, &result)
err := cr.GetLatestValue(ctx, AnyContractName, EventWithFilterName, filterParams, &result, primitives.Finalized)
return err == nil && reflect.DeepEqual(result, &ts1)
}, tester.MaxWaitTimeForEvents(), time.Millisecond*10)
// get the result one more time to verify it.
// Using the result from the Never statement by creating result outside the block is a data race
result := &TestStruct{}
err := cr.GetLatestValue(ctx, AnyContractName, EventWithFilterName, filterParams, &result)
err := cr.GetLatestValue(ctx, AnyContractName, EventWithFilterName, filterParams, &result, primitives.Finalized)
require.NoError(t, err)
assert.Equal(t, &ts0, result)
},
Expand Down

0 comments on commit baa671f

Please sign in to comment.