diff --git a/pkg/transformers/shared/log_chunker.go b/pkg/transformers/shared/log_chunker.go index 6caaac9f..b6feb866 100644 --- a/pkg/transformers/shared/log_chunker.go +++ b/pkg/transformers/shared/log_chunker.go @@ -19,9 +19,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" ) +// TODO Add unit tests for LogChunker + type LogChunker struct { - addressToNames map[string][]string - nameToTopic0 map[string]common.Hash + AddressToNames map[string][]string + NameToTopic0 map[string]common.Hash } // Initialises a chunker by creating efficient lookup maps @@ -37,21 +39,22 @@ func NewLogChunker(transformerConfigs []TransformerConfig) LogChunker { } return LogChunker{ - addressToNames, - nameToTopic0, + AddressToNames: addressToNames, + NameToTopic0: nameToTopic0, } } -// Goes through an array of logs, associating relevant logs with transformers -func (chunker LogChunker) ChunkLogs(logs []types.Log) (chunks map[string][]types.Log) { +// Goes through an array of logs, associating relevant logs (matching addresses and topic) with transformers +func (chunker LogChunker) ChunkLogs(logs []types.Log) map[string][]types.Log { + chunks := map[string][]types.Log{} for _, log := range logs { // Topic0 is not unique to each transformer, also need to consider the contract address - relevantTransformers := chunker.addressToNames[log.Address.String()] + relevantTransformers := chunker.AddressToNames[log.Address.String()] for _, transformer := range relevantTransformers { - if chunker.nameToTopic0[transformer] == log.Topics[0] { + if chunker.NameToTopic0[transformer] == log.Topics[0] { chunks[transformer] = append(chunks[transformer], log) } } } - return + return chunks } diff --git a/pkg/transformers/shared/log_chunker_test.go b/pkg/transformers/shared/log_chunker_test.go new file mode 100644 index 00000000..96c1cf96 --- /dev/null +++ b/pkg/transformers/shared/log_chunker_test.go @@ -0,0 +1,122 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shared_test + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" +) + +var _ = Describe("Log chunker", func() { + var ( + configs []shared.TransformerConfig + chunker shared.LogChunker + ) + + BeforeEach(func() { + configA := shared.TransformerConfig{ + TransformerName: "TransformerA", + ContractAddresses: []string{"0x00000000000000000000000000000000000000A1", "0x00000000000000000000000000000000000000A2"}, + Topic: "0xA", + } + configB := shared.TransformerConfig{ + TransformerName: "TransformerB", + ContractAddresses: []string{"0x00000000000000000000000000000000000000B1"}, + Topic: "0xB", + } + + configC := shared.TransformerConfig{ + TransformerName: "TransformerC", + ContractAddresses: []string{"0x00000000000000000000000000000000000000A2"}, + Topic: "0xC", + } + + configs = []shared.TransformerConfig{configA, configB, configC} + chunker = shared.NewLogChunker(configs) + }) + + Describe("initialisation", func() { + It("creates lookup maps correctly", func() { + Expect(chunker.AddressToNames).To(Equal(map[string][]string{ + "0x00000000000000000000000000000000000000A1": []string{"TransformerA"}, + "0x00000000000000000000000000000000000000A2": []string{"TransformerA", "TransformerC"}, + "0x00000000000000000000000000000000000000B1": []string{"TransformerB"}, + })) + + Expect(chunker.NameToTopic0).To(Equal(map[string]common.Hash{ + "TransformerA": common.HexToHash("0xA"), + "TransformerB": common.HexToHash("0xB"), + "TransformerC": common.HexToHash("0xC"), + })) + }) + }) + + Describe("ChunkLogs", func() { + It("only associates logs with relevant topic0 and address to transformers", func() { + logs := []types.Log{log1, log2, log3, log4, log5} + chunks := chunker.ChunkLogs(logs) + + Expect(chunks["TransformerA"]).To(And(ContainElement(log1),ContainElement(log4))) + Expect(chunks["TransformerB"]).To(BeEmpty()) + Expect(chunks["TransformerC"]).To(ContainElement(log5)) + }) + }) +}) + +var ( + // Match TransformerA + log1 = types.Log{ + Address: common.HexToAddress("0xA1"), + Topics: []common.Hash{ + common.HexToHash("0xA"), + common.HexToHash("0xLogTopic1"), + }, + } + // Match TransformerA address, but not topic0 + log2 = types.Log{ + Address: common.HexToAddress("0xA1"), + Topics: []common.Hash{ + common.HexToHash("0xB"), + common.HexToHash("0xLogTopic2"), + }, + } + // Match TransformerA topic, but TransformerB address + log3 = types.Log{ + Address: common.HexToAddress("0xB1"), + Topics: []common.Hash{ + common.HexToHash("0xA"), + common.HexToHash("0xLogTopic3"), + }, + } + // Match TransformerA, with the other address + log4 = types.Log{ + Address: common.HexToAddress("0xA2"), + Topics: []common.Hash{ + common.HexToHash("0xA"), + common.HexToHash("0xLogTopic4"), + }, + } + // Match TransformerC, which shares address with TransformerA + log5 = types.Log{ + Address: common.HexToAddress("0xA2"), + Topics: []common.Hash{ + common.HexToHash("0xC"), + common.HexToHash("0xLogTopic5"), + }, + } +) \ No newline at end of file