Skip to content

Commit

Permalink
Advanced Querying for ChainReader
Browse files Browse the repository at this point in the history
  • Loading branch information
silaslenihan committed Sep 24, 2024
1 parent ae41018 commit da45a6b
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 113 deletions.
41 changes: 28 additions & 13 deletions contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,41 @@ struct TestStruct {
address Account;
address[] Accounts;
int192 BigField;
MidLevelTestStruct NestedStruct;
MidLevelDynamicTestStruct NestedDynamicStruct;
MidLevelStaticTestStruct NestedStaticStruct;
}

struct MidLevelTestStruct {
struct MidLevelDynamicTestStruct {
bytes2 FixedBytes;
InnerTestStruct Inner;
InnerDynamicTestStruct Inner;
}

struct InnerTestStruct {
struct InnerDynamicTestStruct {
int64 IntVal;
string S;
}

struct MidLevelStaticTestStruct {
bytes2 FixedBytes;
InnerStaticTestStruct Inner;
}

struct InnerStaticTestStruct {
int64 IntVal;
address A;
}

contract ChainReaderTester {
event Triggered(
int32 indexed field,
uint8 oracleId,
MidLevelDynamicTestStruct nestedDynamicStruct,
MidLevelStaticTestStruct nestedStaticStruct,
uint8[32] oracleIds,
address Account,
address[] Accounts,
string differentField,
int192 bigField,
MidLevelTestStruct nestedStruct
int192 bigField
);

event TriggeredEventWithDynamicTopic(string indexed fieldHash, string field);
Expand Down Expand Up @@ -61,9 +73,10 @@ contract ChainReaderTester {
address account,
address[] calldata accounts,
int192 bigField,
MidLevelTestStruct calldata nestedStruct
MidLevelDynamicTestStruct calldata nestedDynamicStruct,
MidLevelStaticTestStruct calldata nestedStaticStruct
) public {
s_seen.push(TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct));
s_seen.push(TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedDynamicStruct, nestedStaticStruct));
}

function setAlterablePrimitiveValue(uint64 value) public {
Expand All @@ -78,9 +91,10 @@ contract ChainReaderTester {
address account,
address[] calldata accounts,
int192 bigField,
MidLevelTestStruct calldata nestedStruct
MidLevelDynamicTestStruct calldata nestedDynamicStruct,
MidLevelStaticTestStruct calldata nestedStaticStruct
) public pure returns (TestStruct memory) {
return TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct);
return TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedDynamicStruct, nestedStaticStruct);
}

function getElementAtIndex(uint256 i) public view returns (TestStruct memory) {
Expand Down Expand Up @@ -110,14 +124,15 @@ contract ChainReaderTester {
function triggerEvent(
int32 field,
uint8 oracleId,
MidLevelDynamicTestStruct calldata nestedDynamicStruct,
MidLevelStaticTestStruct calldata nestedStaticStruct,
uint8[32] calldata oracleIds,
address account,
address[] calldata accounts,
string calldata differentField,
int192 bigField,
MidLevelTestStruct calldata nestedStruct
int192 bigField
) public {
emit Triggered(field, oracleId, oracleIds, account, accounts, differentField, bigField, nestedStruct);
emit Triggered(field, oracleId, nestedDynamicStruct, nestedStaticStruct, oracleIds, account, accounts, differentField, bigField);
}

function triggerEventWithDynamicTopic(string calldata field) public {
Expand Down
1 change: 0 additions & 1 deletion core/chains/evm/logpoller/orm.go
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,6 @@ func (o *DSORM) FilteredLogs(ctx context.Context, filter []query.Expression, lim
if err = o.ds.SelectContext(ctx, &logs, query, sqlArgs...); err != nil {
return nil, err
}

return logs, nil
}

Expand Down
100 changes: 56 additions & 44 deletions core/gethwrappers/generated/chain_reader_tester/chain_reader_tester.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/Batc
batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin f13715b38b5b9084b08bffa571fb1c8ef686001535902e1255052f074b31ad4e
blockhash_store: ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.19/BlockhashStore/BlockhashStore.bin 31b118f9577240c8834c35f8b5a1440e82a6ca8aea702970de2601824b6ab0e1
chain_module_base: ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.abi ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.bin 7a82cc28014761090185c2650239ad01a0901181f1b2b899b42ca293bcda3741
chain_reader_tester: ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin 84c4223c4dbd51aafd77a6787f4b84ce80f661ce86a907c1431c5b82d633f2ad
chain_reader_tester: ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin b9a488fc786f584a617764d8dc1722acdb30defb6b8f638e0ae03442795eaf3e
chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin 66eb30b0717fefe05672df5ec863c0b9a5a654623c4757307a2726d8f31e26b1
counter: ../../contracts/solc/v0.8.6/Counter/Counter.abi ../../contracts/solc/v0.8.6/Counter/Counter.bin 6ca06e000e8423573ffa0bdfda749d88236ab3da2a4cbb4a868c706da90488c9
cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7
Expand Down
68 changes: 52 additions & 16 deletions core/services/relay/evm/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,11 @@ func (cr *chainReader) initDWQuerying(contractName, eventName string, eventDWs m
dWsDetail := make(map[string]read.DataWordDetail)

for genericName, onChainName := range dWDefs {
for _, dWDetail := range eventDWs {
if dWDetail.Name == onChainName {
for eventId, dWDetail := range eventDWs {
// Extract field name in this manner to account for nested fields
fieldName := strings.Join(strings.Split(eventId, ".")[1:], ".")
if fieldName == onChainName {

dWsDetail[genericName] = dWDetail

dwTypeID := eventName + "." + genericName
Expand Down Expand Up @@ -375,24 +378,11 @@ func getEventTypes(event abi.Event) ([]abi.Argument, types.CodecEntry, map[strin
indexedAsUnIndexedTypes := make([]abi.Argument, 0, types.MaxTopicFields)
indexedTypes := make([]abi.Argument, 0, len(event.Inputs))
dataWords := make(map[string]read.DataWordDetail)
hadDynamicType := false
var dwIndex uint8

for _, input := range event.Inputs {
if !input.Indexed {
// there are some cases where we can calculate the exact data word index even if there was a dynamic type before, but it is complex and probably not needed.
if input.Type.T == abi.TupleTy || input.Type.T == abi.SliceTy || input.Type.T == abi.StringTy || input.Type.T == abi.BytesTy {
hadDynamicType = true
}
if hadDynamicType {
continue
}

dataWords[event.Name+"."+input.Name] = read.DataWordDetail{
Index: dwIndex,
Argument: input,
}
dwIndex++
dwIndex = findFieldIndex(input, event.Name+"."+input.Name, dataWords, dwIndex)
continue
}

Expand All @@ -406,6 +396,52 @@ func getEventTypes(event abi.Event) ([]abi.Argument, types.CodecEntry, map[strin
return indexedAsUnIndexedTypes, types.NewCodecEntry(indexedTypes, nil, nil), dataWords
}

func findFieldIndex(arg abi.Argument, fieldPath string, dataWords map[string]read.DataWordDetail, index uint8) uint8 {
if isDynamic(arg.Type) {
return index + 1
}

return processFields(arg.Type, fieldPath, dataWords, index)
}

func processFields(fieldType abi.Type, parentFieldPath string, dataWords map[string]read.DataWordDetail, index uint8) uint8 {
switch fieldType.T {
case abi.TupleTy:
// Recursively process tuple elements
for i, tupleElem := range fieldType.TupleElems {
fieldName := fieldType.TupleRawNames[i]
fullFieldPath := fmt.Sprintf("%s.%s", parentFieldPath, fieldName)
index = processFields(*tupleElem, fullFieldPath, dataWords, index)
}
return index
case abi.ArrayTy:
// Static arrays are not searchable, however, we can reliably calculate their size so that the fields
// after them can be searched.
return index + uint8(fieldType.Size)
default:
dataWords[parentFieldPath] = read.DataWordDetail{
Index: index,
Argument: abi.Argument{Type: fieldType},
}
return index + 1
}
}

func isDynamic(fieldType abi.Type) bool {
switch fieldType.T {
case abi.StringTy, abi.SliceTy, abi.BytesTy:
return true
case abi.TupleTy:
// If one element in a struct is dynamic, the whole struct is treated as dynamic.
for _, elem := range fieldType.TupleElems {
if isDynamic(*elem) {
return true
}
}
}
return false
}

// ConfirmationsFromConfig maps chain agnostic confidence levels defined in config to predefined EVM finality.
func ConfirmationsFromConfig(values map[string]int) (map[primitives.ConfidenceLevel]evmtypes.Confirmations, error) {
mappings := map[primitives.ConfidenceLevel]evmtypes.Confirmations{
Expand Down
7 changes: 4 additions & 3 deletions core/services/relay/evm/codec/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ func (it *codecInterfaceTester) GetCodec(t *testing.T) commontypes.Codec {

if k != sizeItemType && k != NilType {
entry.ModifierConfigs = commoncodec.ModifiersConfig{
&commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
}
}

Expand Down Expand Up @@ -298,7 +298,7 @@ var ts = []abi.ArgumentMarshaling{
{Name: "Account", Type: "address"},
{Name: "Accounts", Type: "address[]"},
{Name: "BigField", Type: "int192"},
{Name: "NestedStruct", Type: "tuple", Components: nested},
{Name: "NestedDynamicStruct", Type: "tuple", Components: nested},
}

const sizeItemType = "item for size"
Expand Down Expand Up @@ -355,6 +355,7 @@ func argsFromTestStruct(ts TestStruct) []any {
common.Address(ts.Account),
getAccounts(ts),
ts.BigField,
evmtesting.MidToInternalType(ts.NestedStruct),
evmtesting.MidDynamicToInternalType(ts.NestedDynamicStruct),
evmtesting.MidStaticToInternalType(ts.NestedStaticStruct),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) {
methodTakingLatestParamsReturningTestStructConfig := types.ChainReaderDefinition{
ChainSpecificName: "getElementAtIndex",
OutputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
}

Expand All @@ -136,11 +137,15 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) {
ChainSpecificName: "Triggered",
ReadType: types.Event,
EventDefinitions: &types.EventDefinitions{
GenericTopicNames: map[string]string{"field": "Field"},
GenericDataWordNames: map[string]string{"OracleID": "oracleId"},
GenericTopicNames: map[string]string{"field": "Field"},
GenericDataWordNames: map[string]string{
"OracleID": "oracleId",
"NestedStaticStruct.Inner.IntVal": "nestedStaticStruct.Inner.IntVal",
},
},
OutputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
},
EventWithFilterName: {
Expand Down Expand Up @@ -183,11 +188,13 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) {
"Account": hexutil.Encode(testStruct.Account),
},
},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
OutputModifications: codec.ModifiersConfig{
&codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": AnyExtraValue}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
},
},
Expand Down Expand Up @@ -217,7 +224,8 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) {
GasLimit: 2_000_000,
Checker: "simulate",
InputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
},
"setAlterablePrimitiveValue": {
Expand All @@ -232,7 +240,8 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) {
GasLimit: 2_000_000,
Checker: "simulate",
InputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
},
"triggerEventWithDynamicTopic": {
Expand Down Expand Up @@ -264,7 +273,8 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) {
GasLimit: 2_000_000,
Checker: "simulate",
InputModifications: codec.ModifiersConfig{
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
},
},
},
Expand Down Expand Up @@ -425,23 +435,34 @@ func ConvertAccounts(accounts [][]byte) []common.Address {

func ToInternalType(testStruct TestStruct) chain_reader_tester.TestStruct {
return chain_reader_tester.TestStruct{
Field: *testStruct.Field,
DifferentField: testStruct.DifferentField,
OracleId: byte(testStruct.OracleID),
OracleIds: OracleIDsToBytes(testStruct.OracleIDs),
Account: common.Address(testStruct.Account),
Accounts: ConvertAccounts(testStruct.Accounts),
BigField: testStruct.BigField,
NestedStruct: MidToInternalType(testStruct.NestedStruct),
Field: *testStruct.Field,
DifferentField: testStruct.DifferentField,
OracleId: byte(testStruct.OracleID),
OracleIds: OracleIDsToBytes(testStruct.OracleIDs),
Account: common.Address(testStruct.Account),
Accounts: ConvertAccounts(testStruct.Accounts),
BigField: testStruct.BigField,
NestedDynamicStruct: MidDynamicToInternalType(testStruct.NestedDynamicStruct),
NestedStaticStruct: MidStaticToInternalType(testStruct.NestedStaticStruct),
}
}

func MidToInternalType(m MidLevelTestStruct) chain_reader_tester.MidLevelTestStruct {
return chain_reader_tester.MidLevelTestStruct{
func MidDynamicToInternalType(m MidLevelDynamicTestStruct) chain_reader_tester.MidLevelDynamicTestStruct {
return chain_reader_tester.MidLevelDynamicTestStruct{
FixedBytes: m.FixedBytes,
Inner: chain_reader_tester.InnerTestStruct{
Inner: chain_reader_tester.InnerDynamicTestStruct{
IntVal: int64(m.Inner.I),
S: m.Inner.S,
},
}
}

func MidStaticToInternalType(m MidLevelStaticTestStruct) chain_reader_tester.MidLevelStaticTestStruct {
return chain_reader_tester.MidLevelStaticTestStruct{
FixedBytes: m.FixedBytes,
Inner: chain_reader_tester.InnerStaticTestStruct{
IntVal: int64(m.Inner.I),
A: common.BytesToAddress(m.Inner.A),
},
}
}
Loading

0 comments on commit da45a6b

Please sign in to comment.