Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DNM WIP for smoke test] #11576

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
282bfeb
Add smoke test for chain reader and codec
nolag Dec 11, 2023
107298f
not found fix
nolag Dec 14, 2023
365242f
WIP
nolag Dec 14, 2023
82fb436
bytes32
nolag Dec 14, 2023
08477d0
Add a bit more info in logging to make it easier to see results
nolag Dec 15, 2023
82ce318
Use better logging form libocr
nolag Dec 15, 2023
fa460ba
more logging from libocr and use my mapstrcture, like common does
nolag Dec 15, 2023
481bc42
Even more logging from libocr :D
nolag Dec 15, 2023
83c0776
update test with new framework
nolag Dec 15, 2023
fef7edd
latest
nolag Dec 15, 2023
750ce74
core/internal/features/ocr2: add chain reader sub-test to TestIntegra…
jmank88 Dec 16, 2023
0ebd5dd
WIP - check if any RoundRequested events were emitted by contract
reductionista Dec 18, 2023
7fbbc35
fix types in the new feature test's assertion
nolag Dec 18, 2023
50f1b55
Update to use my logger again for new median factory. The version wa…
nolag Dec 18, 2023
4e8f88c
Point back to logging for -common, after merging in the time hook
nolag Dec 18, 2023
174f39d
Update chainlink-feeds for LatestRoundReported->LatestRoundRequested fix
reductionista Dec 18, 2023
d1ef734
Add more logging on config
nolag Dec 18, 2023
627b398
10 5 again :D
nolag Dec 18, 2023
6d17425
Update ChainReaderDefinitions, & add block range to RoundRequested query
reductionista Dec 18, 2023
1d2acb1
WIP
reductionista Dec 19, 2023
fe8ec89
bump chainlink-feeds; rm moved wrapper
jmank88 Dec 18, 2023
9d315cb
Fix misleading LogPoller logging
reductionista Dec 19, 2023
1530c04
Add second trial run to OCR2 feature test
reductionista Dec 19, 2023
69a18bd
More logging
nolag Dec 19, 2023
574ffe0
Import more logging that uses cmp to find diffs between old and new m…
nolag Dec 19, 2023
978e43b
import one more log line
nolag Dec 19, 2023
8ca7b93
import change to use logger
nolag Dec 19, 2023
dee584a
Use newer logging from median
nolag Dec 19, 2023
8acbccb
Update to log diffs twice, once with a call before and once after to …
nolag Dec 19, 2023
7999d45
More debug stuff
nolag Dec 19, 2023
e08fc14
Try passing MinConfirmations=1 like LogBroadcaster does
reductionista Dec 20, 2023
79fa968
Fix integration test, and add debug output
reductionista Dec 20, 2023
0271622
Update integration test
reductionista Dec 20, 2023
66fe7e7
Track NewTransmission and Transmitted events in OCR2 integration test
reductionista Dec 21, 2023
19c20b3
Try to fix bug in StartNewOCRRound()
reductionista Dec 21, 2023
0a701cc
Try adding 5s sleep
reductionista Dec 21, 2023
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
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ require (
github.com/shirou/gopsutil/v3 v3.23.11 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213203435-f213bca2982d // indirect
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231214161317-be5f8947cf55 // indirect
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231128204301-ee4297eff679 // indirect
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect
github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1148,8 +1148,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv
github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M=
github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk=
github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213203435-f213bca2982d h1:azq9Vi7aWsq7HOUIYKFCD3Xksuz03q+UFUUkhPwYByc=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231213203435-f213bca2982d/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231214161317-be5f8947cf55 h1:p1Q9M8xAhLgemHi155g/0MEwTltBTIouyIBAs3GpsLE=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231214161317-be5f8947cf55/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231128204301-ee4297eff679 h1:iu1pNbUoSDTrp+7BUtfTygZ2C0f5C2ZOBQhIoJjp+S0=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231128204301-ee4297eff679/go.mod h1:2Jx7bTEk4ujFQdsZpZq3A0BydvaVPs6mX8clUfxHOEM=
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ=
Expand Down
21 changes: 20 additions & 1 deletion core/services/job/models.go
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't grok what is going here. The extra escaping of the JSON should only be from embedding in TOML. Why are the two layers mixed together in a way that requires this custom code?

Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,21 @@ type JSONConfig map[string]interface{}

// Bytes returns the raw bytes
func (r JSONConfig) Bytes() []byte {
b, _ := json.Marshal(r)
var retCopy = make(JSONConfig, len(r))
for key, value := range r {
copiedVal := value
// If the value is a json structure string, unmarshal it to preserve JSON structure
// e.g. instead of this {"key":"{\"nestedKey\":{\"nestedValue\":123}}"}
// we want this {"key":{"nestedKey":{"nestedValue":123}}},
if strValue, ok := copiedVal.(string); ok {
if object, ok := asObject(strValue); ok {
copiedVal = object
}
}
retCopy[key] = copiedVal
}

b, _ := json.Marshal(retCopy)
return b
}

Expand Down Expand Up @@ -306,6 +320,11 @@ func (r JSONConfig) MercuryCredentialName() (string, error) {
return name, nil
}

func asObject(s string) (any, bool) {
var js map[string]interface{}
return js, json.Unmarshal([]byte(s), &js) == nil
}

var ForwardersSupportedPlugins = []types.OCR2PluginType{types.Median, types.DKG, types.OCR2VRF, types.OCR2Keeper, types.Functions}

// OCR2OracleSpec defines the job spec for OCR2 jobs.
Expand Down
23 changes: 12 additions & 11 deletions core/services/ocr2/plugins/median/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,28 +199,29 @@ type medianContract struct {
}

type latestTransmissionDetailsResponse struct {
configDigest ocr2types.ConfigDigest
epoch uint32
round uint8
latestAnswer *big.Int
latestTimestamp time.Time
ConfigDigest ocr2types.ConfigDigest
Epoch uint32
Round uint8
LatestAnswer *big.Int
LatestTimestamp time.Time
}

type latestRoundRequested struct {
configDigest ocr2types.ConfigDigest
epoch uint32
round uint8
ConfigDigest ocr2types.ConfigDigest
Epoch uint32
Round uint8
}

func (m *medianContract) LatestTransmissionDetails(ctx context.Context) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, latestAnswer *big.Int, latestTimestamp time.Time, err error) {
var resp latestTransmissionDetailsResponse
// init the LatestAnswer so that it's not nil if there have been no events yet
resp := latestTransmissionDetailsResponse{LatestAnswer: new(big.Int)}

err = m.chainReader.GetLatestValue(ctx, m.contract.Name, "LatestTransmissionDetails", nil, &resp)
if err != nil {
return
}

return resp.configDigest, resp.epoch, resp.round, resp.latestAnswer, resp.latestTimestamp, err
return resp.ConfigDigest, resp.Epoch, resp.Round, resp.LatestAnswer, resp.LatestTimestamp, err
}

func (m *medianContract) LatestRoundRequested(ctx context.Context, lookback time.Duration) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, err error) {
Expand All @@ -231,7 +232,7 @@ func (m *medianContract) LatestRoundRequested(ctx context.Context, lookback time
return
}

return resp.configDigest, resp.epoch, resp.round, err
return resp.ConfigDigest, resp.Epoch, resp.Round, err
}

func newMedianContract(chainReader types.ChainReader, address common.Address) *medianContract {
Expand Down
35 changes: 31 additions & 4 deletions core/services/relay/evm/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package evm
import (
"context"
"fmt"
"runtime"
"strings"

"github.com/ethereum/go-ethereum"
Expand Down Expand Up @@ -63,8 +64,13 @@ func (cr *chainReader) Name() string { return cr.lggr.Name() }
var _ commontypes.ContractTypeProvider = &chainReader{}

func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method string, params any, returnVal any) error {
b := make([]byte, 2048) // adjust buffer size to be larger than expected stack
n := runtime.Stack(b, false)
s := string(b[:n])
cr.lggr.Infof("!!!!!!!!!!\nEVM CR\n%s.%s\n%#v\n%s\n!!!!!!!!!!\n", contractName, method, params, s)
ae, err := cr.bindings.getBinding(contractName, method, false)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM CR err:\n%v\n!!!!!!!!!!\n", err)
return err
}

Expand All @@ -76,29 +82,43 @@ func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method
}

func (cr *chainReader) getLatestValueFromLogPoller(ctx context.Context, contractName, method string, hash common.Hash, returnVal any) error {
cr.lggr.Infof("!!!!!!!!!!\nEVM latest from log poller\n!!!!!!!!!!\n")
ae, err := cr.bindings.getBinding(contractName, method, false)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM no binding err:\n%v\n!!!!!!!!!!\n", err)
return err
}

log, err := cr.lp.LatestLogByEventSigWithConfs(hash, ae.addr, logpoller.Finalized)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return fmt.Errorf("%w: %w", commontypes.ErrNotFound, err)
errStr := err.Error()
if strings.Contains(errStr, "not found") || strings.Contains(errStr, "no rows") {
cr.lggr.Infof("!!!!!!!!!!\nReturning no error when nothing is found\n!!!!!!!!!!\n")
return nil
}
cr.lggr.Errorf("!!!!!!!!!!\nNo sig err:\n%v\n!!!!!!!!!!\n", err)
return fmt.Errorf("%w: %w", commontypes.ErrInternal, err)
}
return cr.codec.Decode(ctx, log.Data, returnVal, wrapItemType(contractName, method, false))
err = cr.codec.Decode(ctx, log.Data, returnVal, wrapItemType(contractName, method, false))
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM decode err:\n%v\n!!!!!!!!!!\n", err)
} else {
cr.lggr.Infof("!!!!!!!!!!\nEVM decode success\n%#v\n!!!!!!!!!!\n", returnVal)
}
return err
}

func (cr *chainReader) getLatestValueFromContract(ctx context.Context, contractName, method string, params any, returnVal any) error {
cr.lggr.Infof("!!!!!!!!!!\nEVM latest from contract\n!!!!!!!!!!\n")
data, err := cr.codec.Encode(ctx, params, wrapItemType(contractName, method, true))
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM encode err:\n%v\n!!!!!!!!!!\n", err)
return err
}

ae, err := cr.bindings.getBinding(contractName, method, true)
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM no binding err:\n%v\n!!!!!!!!!!\n", err)
return err
}
callMsg := ethereum.CallMsg{
Expand All @@ -110,10 +130,17 @@ func (cr *chainReader) getLatestValueFromContract(ctx context.Context, contractN
output, err := cr.client.CallContract(ctx, callMsg, nil)

if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM call err:\n%v\n!!!!!!!!!!\n", err)
return err
}

return cr.codec.Decode(ctx, output, returnVal, wrapItemType(contractName, method, false))
err = cr.codec.Decode(ctx, output, returnVal, wrapItemType(contractName, method, false))
if err != nil {
cr.lggr.Errorf("!!!!!!!!!!\nEVM decode err:\n%v\n!!!!!!!!!!\n", err)
} else {
cr.lggr.Infof("!!!!!!!!!!\nEVM decode success\n%#v\n!!!!!!!!!!\n", returnVal)
}
return err
}

func (cr *chainReader) Start(_ context.Context) error {
Expand Down
26 changes: 13 additions & 13 deletions core/services/relay/evm/chain_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ func (it *chainReaderInterfaceTester) Name() string {
}

func (it *chainReaderInterfaceTester) GetAccountBytes(i int) []byte {
account := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2}
account[i%32] += byte(i)
account[(i+3)%32] += byte(i + 3)
return account
account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
account[i%20] += byte(i)
account[(i+3)%20] += byte(i + 3)
return account[:]
}

func (it *chainReaderInterfaceTester) GetChainReader(t *testing.T) clcommontypes.ChainReader {
Expand Down Expand Up @@ -176,7 +176,7 @@ func (it *chainReaderInterfaceTester) TriggerEvent(t *testing.T, testStruct *Tes
it.sendTxWithTestStruct(t, testStruct, (*testfiles.TestfilesTransactor).TriggerEvent)
}

type testStructFn = func(*testfiles.TestfilesTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, [32]byte, [][32]byte, *big.Int, testfiles.MidLevelTestStruct) (*evmtypes.Transaction, error)
type testStructFn = func(*testfiles.TestfilesTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, common.Address, []common.Address, *big.Int, testfiles.MidLevelTestStruct) (*evmtypes.Transaction, error)

func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStruct *TestStruct, fn testStructFn) {
tx, err := fn(
Expand All @@ -186,7 +186,7 @@ func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStr
testStruct.DifferentField,
uint8(testStruct.OracleID),
convertOracleIDs(testStruct.OracleIDs),
[32]byte(testStruct.Account),
common.Address(testStruct.Account),
convertAccounts(testStruct.Accounts),
testStruct.BigField,
midToInternalType(testStruct.NestedStruct),
Expand All @@ -205,10 +205,10 @@ func convertOracleIDs(oracleIDs [32]commontypes.OracleID) [32]byte {
return convertedIds
}

func convertAccounts(accounts [][]byte) [][32]byte {
convertedAccounts := make([][32]byte, len(accounts))
func convertAccounts(accounts [][]byte) []common.Address {
convertedAccounts := make([]common.Address, len(accounts))
for i, a := range accounts {
convertedAccounts[i] = [32]byte(a)
convertedAccounts[i] = common.Address(a)
}
return convertedAccounts
}
Expand Down Expand Up @@ -267,10 +267,10 @@ func (it *chainReaderInterfaceTester) incNonce() {
}
}

func getAccounts(first TestStruct) [][32]byte {
accountBytes := make([][32]byte, len(first.Accounts))
func getAccounts(first TestStruct) []common.Address {
accountBytes := make([]common.Address, len(first.Accounts))
for i, account := range first.Accounts {
accountBytes[i] = [32]byte(account)
accountBytes[i] = common.Address(account)
}
return accountBytes
}
Expand Down Expand Up @@ -302,7 +302,7 @@ func toInternalType(testStruct TestStruct) testfiles.TestStruct {
DifferentField: testStruct.DifferentField,
OracleId: byte(testStruct.OracleID),
OracleIds: convertOracleIDs(testStruct.OracleIDs),
Account: [32]byte(testStruct.Account),
Account: common.Address(testStruct.Account),
Accounts: convertAccounts(testStruct.Accounts),
BigField: testStruct.BigField,
NestedStruct: midToInternalType(testStruct.NestedStruct),
Expand Down
19 changes: 14 additions & 5 deletions core/services/relay/evm/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"reflect"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/mitchellh/mapstructure"

Expand All @@ -24,9 +25,10 @@ import (
// SliceToArrayVerifySizeHook verifies that slices have the correct size when converting to an array
// sizeVerifyBigIntHook allows our custom types that verify the number fits in the on-chain type to be converted as-if
// it was a *big.Int
var evmDecoderHooks = []mapstructure.DecodeHookFunc{decodeAccountHook, codec.BigIntHook, codec.SliceToArrayVerifySizeHook, sizeVerifyBigIntHook}
var evmDecoderHooks = []mapstructure.DecodeHookFunc{decodeAccountHook, codec.EpochToTimeHook, codec.BigIntHook, codec.SliceToArrayVerifySizeHook, sizeVerifyBigIntHook}

func NewCodec(conf types.CodecConfig) (commontypes.RemoteCodec, error) {
fmt.Printf("!!!!!!!!!!\nNewCodec\n%#v\n!!!!!!!!!!\n", conf.ChainCodecConfigs)
parsed := &parsedTypes{
encoderDefs: map[string]*codecEntry{},
decoderDefs: map[string]*codecEntry{},
Expand All @@ -35,16 +37,19 @@ func NewCodec(conf types.CodecConfig) (commontypes.RemoteCodec, error) {
for k, v := range conf.ChainCodecConfigs {
args := abi.Arguments{}
if err := json.Unmarshal(([]byte)(v.TypeAbi), &args); err != nil {
fmt.Printf("!!!!!!!!!!\nNewCodec json abi/n%s/n err\n%#v\n!!!!!!!!!!\n%", v.TypeAbi, err)
return nil, err
}

mod, err := v.ModifierConfigs.ToModifier(evmDecoderHooks...)
if err != nil {
fmt.Printf("!!!!!!!!!!\nNewCodec mod err\n%#v\n!!!!!!!!!!\n%", err)
return nil, err
}

item := &codecEntry{Args: args, mod: mod}
if err := item.Init(); err != nil {
if err = item.Init(); err != nil {
fmt.Printf("!!!!!!!!!!\nNewCodec init err\n%#v\n!!!!!!!!!!\n%", err)
return nil, err
}

Expand Down Expand Up @@ -106,13 +111,17 @@ func sizeVerifyBigIntHook(from, to reflect.Type, data any) (any, error) {
}

func decodeAccountHook(from, to reflect.Type, data any) (any, error) {
b32, _ := types.GetType("bytes32")
if from.Kind() == reflect.String && to == b32.Checked {
if from.Kind() == reflect.String && to == reflect.TypeOf(common.Address{}) {
decoded, err := hexutil.Decode(data.(string))
if err != nil {
return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err)
} else if len(decoded) != common.AddressLength {
return nil, fmt.Errorf(
"%w: wrong number size for address expected %v got %v",
commontypes.ErrWrongNumberOfElements,
common.AddressLength, len(decoded))
}
return [32]byte(decoded), nil
return common.Address(decoded), nil
}
return data, nil
}
4 changes: 4 additions & 0 deletions core/services/relay/evm/codec_entry.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evm

import (
"fmt"
"reflect"
"strings"

Expand Down Expand Up @@ -116,6 +117,9 @@ func getNativeAndCheckedTypes(curType *abi.Type) (reflect.Type, reflect.Type, er

func createTupleType(curType *abi.Type, converter func(reflect.Type) reflect.Type) (reflect.Type, reflect.Type, error) {
if len(curType.TupleElems) == 0 {
if curType.TupleType == nil {
return nil, nil, fmt.Errorf("%w: unsupported solitidy type: %v", commontypes.ErrInvalidType, curType.String())
}
return curType.TupleType, curType.TupleType, nil
}

Expand Down
16 changes: 16 additions & 0 deletions core/services/relay/evm/codec_entry_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evm

import (
"fmt"
"math/big"
"reflect"
"testing"
Expand Down Expand Up @@ -136,4 +137,19 @@ func TestCodecEntry(t *testing.T) {
iNative := reflect.Indirect(native)
iNative.FieldByName("Field1").Set(reflect.ValueOf([3]int16{2, 3, 30}))
})

t.Run("Not return values makes struct{}", func(t *testing.T) {
entry := codecEntry{Args: abi.Arguments{}}
require.NoError(t, entry.Init())
assert.Equal(t, reflect.TypeOf(struct{}{}), entry.nativeType)
assert.Equal(t, reflect.TypeOf(struct{}{}), entry.checkedType)
})

t.Run("Address works", func(t *testing.T) {
address, err := abi.NewType("address", "", []abi.ArgumentMarshaling{})
require.NoError(t, err)
entry := codecEntry{Args: abi.Arguments{{Name: "foo", Type: address}}}
fmt.Printf("%+v\n", address.GetType())
require.NoError(t, entry.Init())
})
}
Loading