From 5e64283a123935bb2513a70d12ec4713b94aff18 Mon Sep 17 00:00:00 2001 From: Matt K <1036969+mkrump@users.noreply.github.com> Date: Mon, 11 Dec 2017 15:08:00 -0600 Subject: [PATCH] Get logs for a contract (#99) * Add ability to fetch logs for a contract and a block * Test contract related code against Infura, so can run on Travis * Add godo task for getLogs --- Gododir/main.go | 16 +++ README.md | 6 ++ cmd/get_logs/main.go | 40 ++++++++ cmd/show_contract_summary/main.go | 14 +-- cmd/utils.go | 12 +++ environments/infura.toml | 7 ++ integration_test/contract_test.go | 142 ++++++++++++++++++++++++++ pkg/config/config.go | 31 +++++- pkg/config/config_test.go | 10 ++ pkg/core/blockchain.go | 1 + pkg/core/log.go | 9 ++ pkg/fakes/blockchain.go | 6 ++ pkg/geth/contract_test.go | 101 ------------------ pkg/geth/geth_blockchain.go | 21 ++++ pkg/geth/geth_log_to_core_log.go | 32 ++++++ pkg/geth/geth_log_to_core_log_test.go | 91 +++++++++++++++++ 16 files changed, 420 insertions(+), 119 deletions(-) create mode 100644 cmd/get_logs/main.go create mode 100644 environments/infura.toml create mode 100644 integration_test/contract_test.go create mode 100644 pkg/core/log.go delete mode 100644 pkg/geth/contract_test.go create mode 100644 pkg/geth/geth_log_to_core_log.go create mode 100644 pkg/geth/geth_log_to_core_log_test.go diff --git a/Gododir/main.go b/Gododir/main.go index 29277924..44456216 100644 --- a/Gododir/main.go +++ b/Gododir/main.go @@ -36,6 +36,22 @@ func tasks(p *do.Project) { do.M{"environment": environment, "startingNumber": startingNumber, "$in": "cmd/populate_blocks"}) }) + p.Task("getLogs", nil, func(context *do.Context) { + environment := parseEnvironment(context) + blockNumber := context.Args.MayInt(-1, "block-number", "b") + contractHash := context.Args.MayString("", "contract-hash", "c") + if contractHash == "" { + log.Fatalln("--contract-hash required") + } + context.Start(`go run main.go --environment={{.environment}} --contract-hash={{.contractHash}} --block-number={{.blockNumber}}`, + do.M{ + "environment": environment, + "contractHash": contractHash, + "blockNumber": blockNumber, + "$in": "cmd/get_logs", + }) + }) + p.Task("watchContract", nil, func(context *do.Context) { environment := parseEnvironment(context) contractHash := context.Args.MayString("", "contract-hash", "c") diff --git a/README.md b/README.md index 5e6ffe66..96267f1c 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,12 @@ The name of the JSON file should correspond the contract's address. 2. Start watching the contract `godo watchContract -- --environment= --contract-hash=` 3. Request summary data `godo showContractSummary -- --environment= --contract-hash=` + +## Retrieving Contract Logs + +1. Get the logs + - `godo getLogs -- --environment= --contract-hash= --starting-number=` + ### Configuring Additional Environments You can create configuration files for additional environments. diff --git a/cmd/get_logs/main.go b/cmd/get_logs/main.go new file mode 100644 index 00000000..0de21e99 --- /dev/null +++ b/cmd/get_logs/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "log" + + "flag" + + "github.com/8thlight/vulcanizedb/cmd" + "github.com/8thlight/vulcanizedb/pkg/core" + "github.com/8thlight/vulcanizedb/pkg/geth" +) + +func main() { + environment := flag.String("environment", "", "Environment name") + contractHash := flag.String("contract-hash", "", "Contract hash to show summary") + _blockNumber := flag.Int64("block-number", -1, "Block number of summary") + flag.Parse() + config := cmd.LoadConfig(*environment) + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + blockNumber := cmd.RequestedBlockNumber(_blockNumber) + + logs, err := blockchain.GetLogs(core.Contract{Hash: *contractHash}, blockNumber) + if err != nil { + log.Fatalln(err) + } + for _, l := range logs { + fmt.Println("\tAddress: ", l.Address) + fmt.Println("\tTxHash: ", l.TxHash) + fmt.Println("\tBlockNumber ", l.BlockNumber) + fmt.Println("\tTopics: ") + for i, topic := range l.Topics { + fmt.Printf("\t\tTopic %d: %s\n", i, topic) + } + fmt.Printf("\tData: %s", l.Data) + fmt.Print("\n\n") + + } + +} diff --git a/cmd/show_contract_summary/main.go b/cmd/show_contract_summary/main.go index 1d4730b6..4cf89ab8 100644 --- a/cmd/show_contract_summary/main.go +++ b/cmd/show_contract_summary/main.go @@ -7,8 +7,6 @@ import ( "fmt" - "math/big" - "github.com/8thlight/vulcanizedb/cmd" "github.com/8thlight/vulcanizedb/pkg/contract_summary" "github.com/8thlight/vulcanizedb/pkg/geth" @@ -22,7 +20,7 @@ func main() { config := cmd.LoadConfig(*environment) blockchain := geth.NewGethBlockchain(config.Client.IPCPath) repository := cmd.LoadPostgres(config.Database, blockchain.Node()) - blockNumber := requestedBlockNumber(_blockNumber) + blockNumber := cmd.RequestedBlockNumber(_blockNumber) contractSummary, err := contract_summary.NewSummary(blockchain, repository, *contractHash, blockNumber) if err != nil { @@ -31,13 +29,3 @@ func main() { output := contract_summary.GenerateConsoleOutput(contractSummary) fmt.Println(output) } - -func requestedBlockNumber(blockNumber *int64) *big.Int { - var _blockNumber *big.Int - if *blockNumber == -1 { - _blockNumber = nil - } else { - _blockNumber = big.NewInt(*blockNumber) - } - return _blockNumber -} diff --git a/cmd/utils.go b/cmd/utils.go index cd23dfa4..f4963b04 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -7,6 +7,8 @@ import ( "fmt" + "math/big" + "github.com/8thlight/vulcanizedb/pkg/config" "github.com/8thlight/vulcanizedb/pkg/core" "github.com/8thlight/vulcanizedb/pkg/geth" @@ -55,3 +57,13 @@ func GetAbi(abiFilepath string, contractHash string) string { } return contractAbiString } + +func RequestedBlockNumber(blockNumber *int64) *big.Int { + var _blockNumber *big.Int + if *blockNumber == -1 { + _blockNumber = nil + } else { + _blockNumber = big.NewInt(*blockNumber) + } + return _blockNumber +} diff --git a/environments/infura.toml b/environments/infura.toml new file mode 100644 index 00000000..bd273b20 --- /dev/null +++ b/environments/infura.toml @@ -0,0 +1,7 @@ +[database] +name = "vulcanize_private" +hostname = "localhost" +port = 5432 + +[client] +ipcPath = "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL" diff --git a/integration_test/contract_test.go b/integration_test/contract_test.go new file mode 100644 index 00000000..319df901 --- /dev/null +++ b/integration_test/contract_test.go @@ -0,0 +1,142 @@ +package integration + +import ( + "math/big" + + "log" + + cfg "github.com/8thlight/vulcanizedb/pkg/config" + "github.com/8thlight/vulcanizedb/pkg/core" + "github.com/8thlight/vulcanizedb/pkg/geth" + "github.com/8thlight/vulcanizedb/pkg/geth/testing" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Reading contracts", func() { + + Describe("Reading the list of attributes", func() { + It("returns a string attribute for a real contract", func() { + config, err := cfg.NewConfig("infura") + if err != nil { + log.Fatalln(err) + } + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + contractAttributes, err := blockchain.GetAttributes(contract) + + Expect(err).To(BeNil()) + Expect(len(contractAttributes)).NotTo(Equal(0)) + symbolAttribute := *testing.FindAttribute(contractAttributes, "symbol") + Expect(symbolAttribute.Name).To(Equal("symbol")) + Expect(symbolAttribute.Type).To(Equal("string")) + }) + + It("does not return an attribute that takes an input", func() { + config, err := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + contractAttributes, err := blockchain.GetAttributes(contract) + + Expect(err).To(BeNil()) + attribute := testing.FindAttribute(contractAttributes, "balanceOf") + Expect(attribute).To(BeNil()) + }) + + It("does not return an attribute that is not constant", func() { + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + contractAttributes, err := blockchain.GetAttributes(contract) + + Expect(err).To(BeNil()) + attribute := testing.FindAttribute(contractAttributes, "unpause") + Expect(attribute).To(BeNil()) + }) + }) + + Describe("Getting a contract attribute", func() { + It("returns the correct attribute for a real contract", func() { + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + + contract := testing.SampleContract() + name, err := blockchain.GetAttribute(contract, "name", nil) + + Expect(err).To(BeNil()) + Expect(name).To(Equal("OMGToken")) + }) + + It("returns the correct attribute for a real contract", func() { + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + name, err := blockchain.GetAttribute(contract, "name", nil) + + Expect(err).To(BeNil()) + Expect(name).To(Equal("OMGToken")) + }) + + It("returns the correct attribute for a real contract at a specific block height", func() { + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + name, err := blockchain.GetAttribute(contract, "name", big.NewInt(4701536)) + + Expect(name).To(Equal("OMGToken")) + Expect(err).To(BeNil()) + }) + + It("returns an error when asking for an attribute that does not exist", func() { + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + name, err := blockchain.GetAttribute(contract, "missing_attribute", nil) + + Expect(err).To(Equal(geth.ErrInvalidStateAttribute)) + Expect(name).To(BeNil()) + }) + + It("retrieves the event log for a specific block and contract", func() { + expectedLogZero := core.Log{ + BlockNumber: 4703824, + TxHash: "0xf896bfd1eb539d881a1a31102b78de9f25cd591bf1fe1924b86148c0b205fd5d", + Address: "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", + Topics: []string{ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000fbb1b73c4f0bda4f67dca266ce6ef42f520fbb98", + "0x000000000000000000000000d26114cd6ee289accf82350c8d8487fedb8a0c07", + }, + Data: "0x0000000000000000000000000000000000000000000000000c7d713b49da0000"} + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + contract := testing.SampleContract() + + logs, err := blockchain.GetLogs(contract, big.NewInt(4703824)) + + Expect(err).To(BeNil()) + Expect(len(logs)).To(Equal(3)) + Expect(logs[0]).To(Equal(expectedLogZero)) + + }) + + It("returns and empty log array when no events for a given block / contract combo", func() { + config, _ := cfg.NewConfig("infura") + blockchain := geth.NewGethBlockchain(config.Client.IPCPath) + + logs, err := blockchain.GetLogs(core.Contract{Hash: "x123"}, big.NewInt(4703824)) + + Expect(err).To(BeNil()) + Expect(len(logs)).To(Equal(0)) + + }) + + }) + +}) diff --git a/pkg/config/config.go b/pkg/config/config.go index 69a0835f..ad8374b0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -12,6 +12,8 @@ import ( "errors" + "net/url" + "github.com/BurntSushi/toml" ) @@ -24,6 +26,10 @@ var NewErrConfigFileNotFound = func(environment string) error { return errors.New(fmt.Sprintf("No configuration found for environment: %v", environment)) } +var NewErrBadConnectionString = func(connectionString string) error { + return errors.New(fmt.Sprintf("connection string is invalid: %v", connectionString)) +} + func NewConfig(environment string) (Config, error) { filenameWithExtension := fmt.Sprintf("%s.toml", environment) absolutePath := filepath.Join(ProjectRoot(), "environments", filenameWithExtension) @@ -31,7 +37,7 @@ func NewConfig(environment string) (Config, error) { if err != nil { return Config{}, NewErrConfigFileNotFound(environment) } else { - if !filepath.IsAbs(config.Client.IPCPath) { + if !filepath.IsAbs(config.Client.IPCPath) && !isUrl(config.Client.IPCPath) { config.Client.IPCPath = filepath.Join(ProjectRoot(), config.Client.IPCPath) } return config, nil @@ -43,16 +49,31 @@ func ProjectRoot() string { return path.Join(path.Dir(filename), "..", "..") } +func isUrl(s string) bool { + _, err := url.ParseRequestURI(s) + if err == nil { + return true + } + return false +} + +func fileExists(s string) bool { + _, err := os.Stat(s) + if err == nil { + return true + } + return false +} + func parseConfigFile(filePath string) (Config, error) { var cfg Config - _, err := os.Stat(filePath) - if err != nil { - return Config{}, err + if !isUrl(filePath) && !fileExists(filePath) { + return Config{}, NewErrBadConnectionString(filePath) } else { _, err := toml.DecodeFile(filePath, &cfg) if err != nil { return Config{}, err } - return cfg, err + return cfg, nil } } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index f5745292..0504e8a1 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -28,4 +28,14 @@ var _ = Describe("Loading the config", func() { Expect(err).NotTo(BeNil()) }) + It("reads the infura config using the environment", func() { + infuraConfig, err := cfg.NewConfig("infura") + + Expect(err).To(BeNil()) + Expect(infuraConfig.Database.Hostname).To(Equal("localhost")) + Expect(infuraConfig.Database.Name).To(Equal("vulcanize_private")) + Expect(infuraConfig.Database.Port).To(Equal(5432)) + Expect(infuraConfig.Client.IPCPath).To(Equal("https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL")) + }) + }) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 2bb550d0..ef9f7767 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -10,4 +10,5 @@ type Blockchain interface { StopListening() GetAttributes(contract Contract) (ContractAttributes, error) GetAttribute(contract Contract, attributeName string, blockNumber *big.Int) (interface{}, error) + GetLogs(contract Contract, blockNumber *big.Int) ([]Log, error) } diff --git a/pkg/core/log.go b/pkg/core/log.go new file mode 100644 index 00000000..3e864fcf --- /dev/null +++ b/pkg/core/log.go @@ -0,0 +1,9 @@ +package core + +type Log struct { + BlockNumber int64 + TxHash string + Address string + Topics []string + Data string +} diff --git a/pkg/fakes/blockchain.go b/pkg/fakes/blockchain.go index e9b90e3b..5c5049bd 100644 --- a/pkg/fakes/blockchain.go +++ b/pkg/fakes/blockchain.go @@ -9,6 +9,7 @@ import ( ) type Blockchain struct { + logs map[string][]core.Log blocks map[int64]core.Block contractAttributes map[string]map[string]string blocksChannel chan core.Block @@ -16,6 +17,10 @@ type Blockchain struct { node core.Node } +func (blockchain *Blockchain) GetLogs(contract core.Contract, blockNumber *big.Int) ([]core.Log, error) { + return blockchain.logs[contract.Hash], nil +} + func (blockchain *Blockchain) Node() core.Node { return blockchain.node } @@ -33,6 +38,7 @@ func (blockchain *Blockchain) GetAttribute(contract core.Contract, attributeName func NewBlockchain() *Blockchain { return &Blockchain{ blocks: make(map[int64]core.Block), + logs: make(map[string][]core.Log), contractAttributes: make(map[string]map[string]string), node: core.Node{GenesisBlock: "GENESIS"}, } diff --git a/pkg/geth/contract_test.go b/pkg/geth/contract_test.go deleted file mode 100644 index 487024dc..00000000 --- a/pkg/geth/contract_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package geth_test - -//import ( -// "math/big" -// -// cfg "github.com/8thlight/vulcanizedb/pkg/config" -// "github.com/8thlight/vulcanizedb/pkg/geth" -// "github.com/8thlight/vulcanizedb/pkg/geth/testing" -// . "github.com/onsi/ginkgo" -// . "github.com/onsi/gomega" -//) -// -//var _ = Describe("Reading contracts", func() { -// -// Describe("Reading the list of attributes", func() { -// It("returns a string attribute for a real contract", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// contract := testing.SampleContract() -// -// contractAttributes, err := blockchain.GetAttributes(contract) -// -// Expect(err).To(BeNil()) -// Expect(len(contractAttributes)).NotTo(Equal(0)) -// symbolAttribute := *testing.FindAttribute(contractAttributes, "symbol") -// Expect(symbolAttribute.Name).To(Equal("symbol")) -// Expect(symbolAttribute.Type).To(Equal("string")) -// }) -// -// It("does not return an attribute that takes an input", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// contract := testing.SampleContract() -// -// contractAttributes, err := blockchain.GetAttributes(contract) -// -// Expect(err).To(BeNil()) -// attribute := testing.FindAttribute(contractAttributes, "balanceOf") -// Expect(attribute).To(BeNil()) -// }) -// -// It("does not return an attribute that is not constant", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// contract := testing.SampleContract() -// -// contractAttributes, err := blockchain.GetAttributes(contract) -// -// Expect(err).To(BeNil()) -// attribute := testing.FindAttribute(contractAttributes, "unpause") -// Expect(attribute).To(BeNil()) -// }) -// }) -// -// Describe("Getting a contract attribute", func() { -// It("returns the correct attribute for a real contract", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// -// contract := testing.SampleContract() -// name, err := blockchain.GetAttribute(contract, "name", nil) -// -// Expect(err).To(BeNil()) -// Expect(name).To(Equal("OMGToken")) -// }) -// -// It("returns the correct attribute for a real contract", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// contract := testing.SampleContract() -// -// name, err := blockchain.GetAttribute(contract, "name", nil) -// -// Expect(err).To(BeNil()) -// Expect(name).To(Equal("OMGToken")) -// }) -// -// It("returns the correct attribute for a real contract at a specific block height", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// contract := testing.SampleContract() -// -// name, err := blockchain.GetAttribute(contract, "name", big.NewInt(4652791)) -// -// Expect(name).To(Equal("OMGToken")) -// Expect(err).To(BeNil()) -// }) -// -// It("returns an error when asking for an attribute that does not exist", func() { -// config, _ := cfg.NewConfig("public") -// blockchain := geth.NewGethBlockchain(config.Client.IPCPath) -// contract := testing.SampleContract() -// -// name, err := blockchain.GetAttribute(contract, "missing_attribute", nil) -// -// Expect(err).To(Equal(geth.ErrInvalidStateAttribute)) -// Expect(name).To(BeNil()) -// }) -// }) -// -//}) diff --git a/pkg/geth/geth_blockchain.go b/pkg/geth/geth_blockchain.go index 6a01496b..5fdac192 100644 --- a/pkg/geth/geth_blockchain.go +++ b/pkg/geth/geth_blockchain.go @@ -8,6 +8,7 @@ import ( "github.com/8thlight/vulcanizedb/pkg/core" "github.com/8thlight/vulcanizedb/pkg/geth/node" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" @@ -22,6 +23,21 @@ type GethBlockchain struct { node core.Node } +func (blockchain *GethBlockchain) GetLogs(contract core.Contract, blockNumber *big.Int) ([]core.Log, error) { + contractAddress := common.HexToAddress(contract.Hash) + fc := ethereum.FilterQuery{ + FromBlock: blockNumber, + ToBlock: blockNumber, + Addresses: []common.Address{contractAddress}, + } + gethLogs, err := blockchain.client.FilterLogs(context.Background(), fc) + if err != nil { + return []core.Log{}, err + } + logs := GethLogsToCoreLogs(gethLogs) + return logs, nil +} + func (blockchain *GethBlockchain) Node() core.Node { return blockchain.node } @@ -60,3 +76,8 @@ func (blockchain *GethBlockchain) StartListening() { func (blockchain *GethBlockchain) StopListening() { blockchain.newHeadSubscription.Unsubscribe() } + +func (blockchain *GethBlockchain) latestBlock() *big.Int { + block, _ := blockchain.client.HeaderByNumber(context.Background(), nil) + return block.Number +} diff --git a/pkg/geth/geth_log_to_core_log.go b/pkg/geth/geth_log_to_core_log.go new file mode 100644 index 00000000..5bdabd57 --- /dev/null +++ b/pkg/geth/geth_log_to_core_log.go @@ -0,0 +1,32 @@ +package geth + +import ( + "github.com/8thlight/vulcanizedb/pkg/core" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +func GethLogToCoreLog(gethLog types.Log) core.Log { + topics := gethLog.Topics + var hexTopics []string + for _, topic := range topics { + hexTopics = append(hexTopics, topic.Hex()) + } + return core.Log{ + Address: gethLog.Address.Hex(), + + BlockNumber: int64(gethLog.BlockNumber), + Topics: hexTopics, + TxHash: gethLog.TxHash.Hex(), + Data: hexutil.Encode(gethLog.Data), + } +} + +func GethLogsToCoreLogs(gethLogs []types.Log) []core.Log { + var logs []core.Log + for _, log := range gethLogs { + log := GethLogToCoreLog(log) + logs = append(logs, log) + } + return logs +} diff --git a/pkg/geth/geth_log_to_core_log_test.go b/pkg/geth/geth_log_to_core_log_test.go new file mode 100644 index 00000000..4fe595d7 --- /dev/null +++ b/pkg/geth/geth_log_to_core_log_test.go @@ -0,0 +1,91 @@ +package geth_test + +import ( + "github.com/8thlight/vulcanizedb/pkg/core" + "github.com/8thlight/vulcanizedb/pkg/geth" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Conversion of GethLog to core.Log", func() { + + It("converts geth log to internal log format", func() { + gethLog := types.Log{ + Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"), + BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"), + BlockNumber: 2019236, + Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"), + Index: 2, + TxIndex: 3, + TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"), + Topics: []common.Hash{ + common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"), + }, + } + + expected := core.Log{ + Address: gethLog.Address.Hex(), + BlockNumber: int64(gethLog.BlockNumber), + Data: hexutil.Encode(gethLog.Data), + TxHash: gethLog.TxHash.Hex(), + Topics: []string{ + common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef").Hex(), + common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615").Hex(), + }, + } + + coreLog := geth.GethLogToCoreLog(gethLog) + + Expect(coreLog.Address).To(Equal(expected.Address)) + Expect(coreLog.BlockNumber).To(Equal(expected.BlockNumber)) + Expect(coreLog.Data).To(Equal(expected.Data)) + Expect(coreLog.Topics[0]).To(Equal(expected.Topics[0])) + Expect(coreLog.Topics[1]).To(Equal(expected.Topics[1])) + Expect(coreLog.TxHash).To(Equal(expected.TxHash)) + }) + + It("converts geth log array to array of internal logs", func() { + gethLogOne := types.Log{ + Address: common.HexToAddress("0xecf8f87f810ecf450940c9f60066b4a7a501d6a7"), + BlockHash: common.HexToHash("0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056"), + BlockNumber: 2019236, + Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000001a055690d9db80000"), + Index: 2, + TxIndex: 3, + TxHash: common.HexToHash("0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e"), + Topics: []common.Hash{ + common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + common.HexToHash("0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615"), + }, + } + + gethLogTwo := types.Log{ + Address: common.HexToAddress("0x123"), + BlockHash: common.HexToHash("0x576"), + BlockNumber: 2019236, + Data: hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000001"), + Index: 3, + TxIndex: 4, + TxHash: common.HexToHash("0x134"), + Topics: []common.Hash{ + common.HexToHash("0xaaa"), + common.HexToHash("0xbbb"), + }, + } + + expectedOne := geth.GethLogToCoreLog(gethLogOne) + expectedTwo := geth.GethLogToCoreLog(gethLogTwo) + + coreLogs := geth.GethLogsToCoreLogs([]types.Log{gethLogOne, gethLogTwo}) + + Expect(len(coreLogs)).To(Equal(2)) + Expect(coreLogs[0]).To(Equal(expectedOne)) + Expect(coreLogs[1]).To(Equal(expectedTwo)) + + }) + +})