refactor omni code; rename omniWatcher => contractWatcher; use config instead of excessive number of CLI flags
This commit is contained in:
parent
84b65caedd
commit
8174ce4aee
123
cmd/contractWatcher.go
Normal file
123
cmd/contractWatcher.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2018 Vulcanize
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
st "github.com/vulcanize/vulcanizedb/libraries/shared/transformer"
|
||||||
|
ft "github.com/vulcanize/vulcanizedb/pkg/omni/full/transformer"
|
||||||
|
lt "github.com/vulcanize/vulcanizedb/pkg/omni/light/transformer"
|
||||||
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// contractWatcherCmd represents the contractWatcher command
|
||||||
|
var contractWatcherCmd = &cobra.Command{
|
||||||
|
Use: "contractWatcher",
|
||||||
|
Short: "Watches events at the provided contract address using fully synced vDB",
|
||||||
|
Long: `Uses input contract address and event filters to watch events
|
||||||
|
|
||||||
|
Expects an ethereum node to be running
|
||||||
|
Expects an archival node synced into vulcanizeDB
|
||||||
|
Requires a .toml config file:
|
||||||
|
|
||||||
|
[database]
|
||||||
|
name = "vulcanize_public"
|
||||||
|
hostname = "localhost"
|
||||||
|
port = 5432
|
||||||
|
|
||||||
|
[client]
|
||||||
|
ipcPath = "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL"
|
||||||
|
|
||||||
|
[contract]
|
||||||
|
network = ""
|
||||||
|
addresses = [
|
||||||
|
"contractAddress1",
|
||||||
|
"contractAddress2"
|
||||||
|
]
|
||||||
|
[contract.contractAddress1]
|
||||||
|
abi = 'ABI for contract 1'
|
||||||
|
startingBlock = 982463
|
||||||
|
[contract.contractAddress2]
|
||||||
|
abi = 'ABI for contract 2'
|
||||||
|
events = [
|
||||||
|
"event1",
|
||||||
|
"event2"
|
||||||
|
]
|
||||||
|
eventArgs = [
|
||||||
|
"arg1",
|
||||||
|
"arg2"
|
||||||
|
]
|
||||||
|
methods = [
|
||||||
|
"method1",
|
||||||
|
"method2"
|
||||||
|
]
|
||||||
|
methodArgs = [
|
||||||
|
"arg1",
|
||||||
|
"arg2"
|
||||||
|
]
|
||||||
|
startingBlock = 4448566
|
||||||
|
piping = true
|
||||||
|
`,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
contractWatcher()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mode string
|
||||||
|
)
|
||||||
|
|
||||||
|
func contractWatcher() {
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
blockChain := getBlockChain()
|
||||||
|
db := utils.LoadPostgres(databaseConfig, blockChain.Node())
|
||||||
|
|
||||||
|
var t st.GenericTransformer
|
||||||
|
con := config.ContractConfig{}
|
||||||
|
con.PrepConfig()
|
||||||
|
switch mode {
|
||||||
|
case "light":
|
||||||
|
t = lt.NewTransformer(con, blockChain, &db)
|
||||||
|
case "full":
|
||||||
|
t = ft.NewTransformer(con, blockChain, &db)
|
||||||
|
default:
|
||||||
|
log.Fatal("Invalid mode")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := t.Init()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(fmt.Sprintf("Failed to initialized transformer\r\nerr: %v\r\n", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
t.Execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(contractWatcherCmd)
|
||||||
|
|
||||||
|
contractWatcherCmd.Flags().StringVarP(&mode, "mode", "o", "light", "'light' or 'full' mode to work with either light synced or fully synced vDB (default is light)")
|
||||||
|
}
|
@ -1,121 +0,0 @@
|
|||||||
// VulcanizeDB
|
|
||||||
// Copyright © 2019 Vulcanize
|
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
ft "github.com/vulcanize/vulcanizedb/pkg/omni/full/transformer"
|
|
||||||
lt "github.com/vulcanize/vulcanizedb/pkg/omni/light/transformer"
|
|
||||||
st "github.com/vulcanize/vulcanizedb/pkg/omni/shared/transformer"
|
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
// omniWatcherCmd represents the omniWatcher command
|
|
||||||
var omniWatcherCmd = &cobra.Command{
|
|
||||||
Use: "omniWatcher",
|
|
||||||
Short: "Watches events at the provided contract address using fully synced vDB",
|
|
||||||
Long: `Uses input contract address and event filters to watch events
|
|
||||||
|
|
||||||
Expects an ethereum node to be running
|
|
||||||
Expects an archival node synced into vulcanizeDB
|
|
||||||
Requires a .toml config file:
|
|
||||||
|
|
||||||
[database]
|
|
||||||
name = "vulcanize_public"
|
|
||||||
hostname = "localhost"
|
|
||||||
port = 5432
|
|
||||||
|
|
||||||
[client]
|
|
||||||
ipcPath = "/Users/user/Library/Ethereum/geth.ipc"
|
|
||||||
`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
omniWatcher()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
network string
|
|
||||||
contractAddress string
|
|
||||||
contractAddresses []string
|
|
||||||
contractEvents []string
|
|
||||||
contractMethods []string
|
|
||||||
eventArgs []string
|
|
||||||
methodArgs []string
|
|
||||||
methodPiping bool
|
|
||||||
mode string
|
|
||||||
)
|
|
||||||
|
|
||||||
func omniWatcher() {
|
|
||||||
if contractAddress == "" && len(contractAddresses) == 0 {
|
|
||||||
log.Fatal("Contract address required")
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker := time.NewTicker(5 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
blockChain := getBlockChain()
|
|
||||||
db := utils.LoadPostgres(databaseConfig, blockChain.Node())
|
|
||||||
|
|
||||||
var t st.Transformer
|
|
||||||
switch mode {
|
|
||||||
case "light":
|
|
||||||
t = lt.NewTransformer(network, blockChain, &db)
|
|
||||||
case "full":
|
|
||||||
t = ft.NewTransformer(network, blockChain, &db)
|
|
||||||
default:
|
|
||||||
log.Fatal("Invalid mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
contractAddresses = append(contractAddresses, contractAddress)
|
|
||||||
for _, addr := range contractAddresses {
|
|
||||||
t.SetEvents(addr, contractEvents)
|
|
||||||
t.SetMethods(addr, contractMethods)
|
|
||||||
t.SetEventArgs(addr, eventArgs)
|
|
||||||
t.SetMethodArgs(addr, methodArgs)
|
|
||||||
t.SetPiping(addr, methodPiping)
|
|
||||||
t.SetStartingBlock(addr, startingBlockNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := t.Init()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(fmt.Sprintf("Failed to initialized transformer\r\nerr: %v\r\n", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
for range ticker.C {
|
|
||||||
t.Execute()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(omniWatcherCmd)
|
|
||||||
|
|
||||||
omniWatcherCmd.Flags().StringVarP(&mode, "mode", "o", "light", "'light' or 'full' mode to work with either light synced or fully synced vDB (default is light)")
|
|
||||||
omniWatcherCmd.Flags().StringVarP(&contractAddress, "contract-address", "a", "", "Single address to generate watchers for")
|
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&contractAddresses, "contract-addresses", "l", []string{}, "list of addresses to use; warning: watcher targets the same events and methods for each address")
|
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&contractEvents, "events", "e", []string{}, "Subset of events to watch; by default all events are watched")
|
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&contractMethods, "methods", "m", nil, "Subset of methods to poll; by default no methods are polled")
|
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&eventArgs, "event-args", "f", []string{}, "Argument values to filter event logs for; will only persist event logs that emit at least one of the value specified")
|
|
||||||
omniWatcherCmd.Flags().StringArrayVarP(&methodArgs, "method-args", "g", []string{}, "Argument values to limit methods to; will only call methods with emitted values that were specified here")
|
|
||||||
omniWatcherCmd.Flags().StringVarP(&network, "network", "n", "", `Network the contract is deployed on; options: "ropsten", "kovan", and "rinkeby"; default is mainnet"`)
|
|
||||||
omniWatcherCmd.Flags().Int64VarP(&startingBlockNumber, "starting-block-number", "s", 0, "Block to begin watching- default is first block the contract exists")
|
|
||||||
omniWatcherCmd.Flags().BoolVarP(&methodPiping, "piping", "p", false, "Turn on method output piping: methods listed first will be polled first and their output used as input to subsequent methods")
|
|
||||||
}
|
|
@ -2,6 +2,7 @@ package integration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -41,8 +42,7 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
It("Initializes transformer's contract objects", func() {
|
It("Initializes transformer's contract objects", func() {
|
||||||
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1)
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1)
|
||||||
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2)
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2)
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -64,9 +64,7 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Transforms watched contract data into custom repositories", func() {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -85,9 +83,12 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
testConf = mocks.TusdConfig
|
||||||
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -119,9 +120,12 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Polls given methods using generated token holder address", func() {
|
It("Polls given methods using generated token holder address", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
testConf = mocks.TusdConfig
|
||||||
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -145,9 +149,7 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Fails if initialization has not been done", func() {
|
It("Fails if initialization has not been done", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
|
||||||
|
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
@ -161,9 +163,7 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Transforms watched contract data into custom repositories", func() {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.ENSConfig, blockChain, db)
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
|
||||||
t.SetMethods(constants.EnsContractAddress, nil)
|
|
||||||
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -183,9 +183,12 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() {
|
It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -210,9 +213,12 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Polls given methods using generated token holder address", func() {
|
It("Polls given methods using generated token holder address", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -235,10 +241,12 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("It does not perist events if they do not pass the emitted arg filter", func() {
|
It("It does not perist events if they do not pass the emitted arg filter", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, nil)
|
testConf.EventArgs = map[string][]string{
|
||||||
t.SetEventArgs(constants.EnsContractAddress, []string{"fake_filter_value"})
|
ensAddr: {"fake_filter_value"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -252,10 +260,15 @@ var _ = Describe("Omni full transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("If a method arg filter is applied, only those arguments are used in polling", func() {
|
It("If a method arg filter is applied, only those arguments are used in polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.MethodArgs = map[string][]string{
|
||||||
t.SetMethodArgs(constants.EnsContractAddress, []string{"0x0000000000000000000000000000000000000000000000000000c02aaa39b223"})
|
ensAddr: {"0x0000000000000000000000000000000000000000000000000000c02aaa39b223"},
|
||||||
|
}
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package integration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -39,8 +40,7 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
It("Initializes transformer's contract objects", func() {
|
It("Initializes transformer's contract objects", func() {
|
||||||
headerRepository.CreateOrUpdateHeader(mocks.MockHeader1)
|
headerRepository.CreateOrUpdateHeader(mocks.MockHeader1)
|
||||||
headerRepository.CreateOrUpdateHeader(mocks.MockHeader3)
|
headerRepository.CreateOrUpdateHeader(mocks.MockHeader3)
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
@ -70,9 +70,7 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Transforms watched contract data into custom repositories", func() {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -89,9 +87,12 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
testConf = mocks.TusdConfig
|
||||||
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
c, ok := t.Contracts[tusdAddr]
|
c, ok := t.Contracts[tusdAddr]
|
||||||
@ -131,9 +132,12 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Polls given methods using generated token holder address", func() {
|
It("Polls given methods using generated token holder address", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
testConf = mocks.TusdConfig
|
||||||
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -150,9 +154,7 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Fails if initialization has not been done", func() {
|
It("Fails if initialization has not been done", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
@ -173,9 +175,7 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Transforms watched contract data into custom repositories", func() {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.ENSConfig, blockChain, db)
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
|
||||||
t.SetMethods(constants.EnsContractAddress, nil)
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -192,9 +192,12 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() {
|
It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
c, ok := t.Contracts[ensAddr]
|
c, ok := t.Contracts[ensAddr]
|
||||||
@ -218,9 +221,12 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Polls given method using list of collected hashes", func() {
|
It("Polls given method using list of collected hashes", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -242,10 +248,12 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("It does not persist events if they do not pass the emitted arg filter", func() {
|
It("It does not persist events if they do not pass the emitted arg filter", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, nil)
|
testConf.EventArgs = map[string][]string{
|
||||||
t.SetEventArgs(constants.EnsContractAddress, []string{"fake_filter_value"})
|
ensAddr: {"fake_filter_value"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -257,10 +265,15 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("If a method arg filter is applied, only those arguments are used in polling", func() {
|
It("If a method arg filter is applied, only those arguments are used in polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.MethodArgs = map[string][]string{
|
||||||
t.SetMethodArgs(constants.EnsContractAddress, []string{"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"})
|
ensAddr: {"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"},
|
||||||
|
}
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -302,11 +315,7 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Transforms watched contract data into custom repositories", func() {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
t := transformer.NewTransformer(mocks.ENSandTusdConfig, blockChain, db)
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
|
||||||
t.SetMethods(constants.EnsContractAddress, nil)
|
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
|
||||||
t.SetMethods(constants.TusdContractAddress, nil)
|
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
@ -332,11 +341,13 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Keeps track of contract-related hashes and addresses while transforming event data if they need to be used for later method polling", func() {
|
It("Keeps track of contract-related hashes and addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSandTusdConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.Methods = map[string][]string{
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
ensAddr: {"owner"},
|
||||||
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
ens, ok := t.Contracts[ensAddr]
|
ens, ok := t.Contracts[ensAddr]
|
||||||
@ -376,11 +387,13 @@ var _ = Describe("Omnit light transformer", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("Polls given methods for each contract, using list of collected values", func() {
|
It("Polls given methods for each contract, using list of collected values", func() {
|
||||||
t := transformer.NewTransformer("", blockChain, db)
|
var testConf config.ContractConfig
|
||||||
t.SetEvents(constants.EnsContractAddress, []string{"NewOwner"})
|
testConf = mocks.ENSandTusdConfig
|
||||||
t.SetMethods(constants.EnsContractAddress, []string{"owner"})
|
testConf.Methods = map[string][]string{
|
||||||
t.SetEvents(constants.TusdContractAddress, []string{"Transfer"})
|
ensAddr: {"owner"},
|
||||||
t.SetMethods(constants.TusdContractAddress, []string{"balanceOf"})
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
err = t.Init()
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = t.Execute()
|
err = t.Execute()
|
||||||
|
177
pkg/config/contract.go
Normal file
177
pkg/config/contract.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// VulcanizeDB
|
||||||
|
// Copyright © 2018 Vulcanize
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config struct for generic contract transformer
|
||||||
|
type ContractConfig struct {
|
||||||
|
// Name for the transformer
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Ethereum network name; default "" is mainnet
|
||||||
|
Network string
|
||||||
|
|
||||||
|
// List of contract addresses (map to ensure no duplicates)
|
||||||
|
Addresses map[string]bool
|
||||||
|
|
||||||
|
// Map of contract address to abi
|
||||||
|
// If an address has no associated abi the parser will attempt to fetch one from etherscan
|
||||||
|
Abis map[string]string
|
||||||
|
|
||||||
|
// Map of contract address to slice of events
|
||||||
|
// Used to set which addresses to watch
|
||||||
|
// If any events are listed in the slice only those will be watched
|
||||||
|
// Otherwise all events in the contract ABI are watched
|
||||||
|
Events map[string][]string
|
||||||
|
|
||||||
|
// Map of contract address to slice of methods
|
||||||
|
// If any methods are listed in the slice only those will be polled
|
||||||
|
// Otherwise no methods will be polled
|
||||||
|
Methods map[string][]string
|
||||||
|
|
||||||
|
// Map of contract address to slice of event arguments to filter for
|
||||||
|
// If arguments are provided then only events which emit those arguments are watched
|
||||||
|
// Otherwise arguments are not filtered on events
|
||||||
|
EventArgs map[string][]string
|
||||||
|
|
||||||
|
// Map of contract address to slice of method arguments to limit polling to
|
||||||
|
// If arguments are provided then only those arguments are allowed as arguments in method polling
|
||||||
|
// Otherwise any argument of the right type seen emitted from events at that contract will be used in method polling
|
||||||
|
MethodArgs map[string][]string
|
||||||
|
|
||||||
|
// Map of contract address to their starting block
|
||||||
|
StartingBlocks map[string]int64
|
||||||
|
|
||||||
|
// Map of contract address to whether or not to pipe method polling results forward into subsequent method calls
|
||||||
|
Piping map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oc *ContractConfig) PrepConfig() {
|
||||||
|
addrs := viper.GetStringSlice("contract.addresses")
|
||||||
|
oc.Network = viper.GetString("contract.network")
|
||||||
|
oc.Addresses = make(map[string]bool, len(addrs))
|
||||||
|
oc.Abis = make(map[string]string, len(addrs))
|
||||||
|
oc.Methods = make(map[string][]string, len(addrs))
|
||||||
|
oc.EventArgs = make(map[string][]string, len(addrs))
|
||||||
|
oc.MethodArgs = make(map[string][]string, len(addrs))
|
||||||
|
oc.EventArgs = make(map[string][]string, len(addrs))
|
||||||
|
oc.StartingBlocks = make(map[string]int64, len(addrs))
|
||||||
|
oc.Piping = make(map[string]bool, len(addrs))
|
||||||
|
// De-dupe addresses
|
||||||
|
for _, addr := range addrs {
|
||||||
|
oc.Addresses[strings.ToLower(addr)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over addresses to pull out config info for each contract
|
||||||
|
for _, addr := range addrs {
|
||||||
|
transformer := viper.GetStringMap("contract." + addr)
|
||||||
|
|
||||||
|
// Get and check abi
|
||||||
|
abi, abiOK := transformer["abi"]
|
||||||
|
if !abiOK || abi == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `abi` value")
|
||||||
|
}
|
||||||
|
abiRef, abiOK := abi.(string)
|
||||||
|
if !abiOK {
|
||||||
|
log.Fatal(addr, "transformer `events` not of type []string")
|
||||||
|
}
|
||||||
|
oc.Abis[strings.ToLower(addr)] = abiRef
|
||||||
|
|
||||||
|
// Get and check events
|
||||||
|
events, eventsOK := transformer["events"]
|
||||||
|
if !eventsOK || events == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `events` value")
|
||||||
|
}
|
||||||
|
eventsRef, eventsOK := events.([]string)
|
||||||
|
if !eventsOK {
|
||||||
|
log.Fatal(addr, "transformer `events` not of type []string")
|
||||||
|
}
|
||||||
|
if eventsRef == nil {
|
||||||
|
eventsRef = []string{}
|
||||||
|
}
|
||||||
|
oc.Events[strings.ToLower(addr)] = eventsRef
|
||||||
|
|
||||||
|
// Get and check methods
|
||||||
|
methods, methodsOK := transformer["methods"]
|
||||||
|
if !methodsOK || methods == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `methods` value")
|
||||||
|
}
|
||||||
|
methodsRef, methodsOK := methods.([]string)
|
||||||
|
if !methodsOK {
|
||||||
|
log.Fatal(addr, "transformer `methods` not of type []string")
|
||||||
|
}
|
||||||
|
if methodsRef == nil {
|
||||||
|
methodsRef = []string{}
|
||||||
|
}
|
||||||
|
oc.Methods[strings.ToLower(addr)] = methodsRef
|
||||||
|
|
||||||
|
// Get and check eventArgs
|
||||||
|
eventArgs, eventArgsOK := transformer["eventArgs"]
|
||||||
|
if !eventArgsOK || eventArgs == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `eventArgs` value")
|
||||||
|
}
|
||||||
|
eventArgsRef, eventArgsOK := eventArgs.([]string)
|
||||||
|
if !eventArgsOK {
|
||||||
|
log.Fatal(addr, "transformer `eventArgs` not of type []string")
|
||||||
|
}
|
||||||
|
if eventArgsRef == nil {
|
||||||
|
eventArgsRef = []string{}
|
||||||
|
}
|
||||||
|
oc.EventArgs[strings.ToLower(addr)] = eventArgsRef
|
||||||
|
|
||||||
|
// Get and check methodArgs
|
||||||
|
methodArgs, methodArgsOK := transformer["methodArgs"]
|
||||||
|
if !methodArgsOK || methodArgs == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `methodArgs` value")
|
||||||
|
}
|
||||||
|
methodArgsRef, methodArgsOK := methodArgs.([]string)
|
||||||
|
if !methodArgsOK {
|
||||||
|
log.Fatal(addr, "transformer `methodArgs` not of type []string")
|
||||||
|
}
|
||||||
|
if methodArgsRef == nil {
|
||||||
|
methodArgsRef = []string{}
|
||||||
|
}
|
||||||
|
oc.MethodArgs[strings.ToLower(addr)] = methodArgsRef
|
||||||
|
|
||||||
|
// Get and check startingBlock
|
||||||
|
start, startOK := transformer["startingBlock"]
|
||||||
|
if !startOK || start == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `startingBlock` value")
|
||||||
|
}
|
||||||
|
startRef, startOK := start.(int64)
|
||||||
|
if !startOK {
|
||||||
|
log.Fatal(addr, "transformer `startingBlock` not of type int")
|
||||||
|
}
|
||||||
|
oc.StartingBlocks[strings.ToLower(addr)] = startRef
|
||||||
|
|
||||||
|
// Get pipping
|
||||||
|
pipe, pipeOK := transformer["pipping"]
|
||||||
|
if !pipeOK || pipe == nil {
|
||||||
|
log.Fatal(addr, "transformer config is missing `pipping` value")
|
||||||
|
}
|
||||||
|
pipeRef, pipeOK := pipe.(bool)
|
||||||
|
if !pipeOK {
|
||||||
|
log.Fatal(addr, "transformer `piping` not of type bool")
|
||||||
|
}
|
||||||
|
oc.Piping[strings.ToLower(addr)] = pipeRef
|
||||||
|
}
|
||||||
|
}
|
@ -55,10 +55,10 @@ func (c *converter) Update(info *contract.Contract) {
|
|||||||
|
|
||||||
// Convert the given watched event log into a types.Log for the given event
|
// Convert the given watched event log into a types.Log for the given event
|
||||||
func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (*types.Log, error) {
|
func (c *converter) Convert(watchedEvent core.WatchedEvent, event types.Event) (*types.Log, error) {
|
||||||
boundContract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
||||||
values := make(map[string]interface{})
|
values := make(map[string]interface{})
|
||||||
log := helpers.ConvertToLog(watchedEvent)
|
log := helpers.ConvertToLog(watchedEvent)
|
||||||
err := boundContract.UnpackLogIntoMap(values, event.Name, log)
|
err := contract.UnpackLogIntoMap(values, event.Name, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@ -34,7 +34,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Requires a fully synced vDB and a running eth node (or infura)
|
// Requires a fully synced vDB and a running eth node (or infura)
|
||||||
type Transformer struct {
|
type transformer struct {
|
||||||
// Database interfaces
|
// Database interfaces
|
||||||
datastore.FilterRepository // Log filters repo; accepts filters generated by Contract.GenerateFilters()
|
datastore.FilterRepository // Log filters repo; accepts filters generated by Contract.GenerateFilters()
|
||||||
datastore.WatchedEventRepository // Watched event log views, created by the log filters
|
datastore.WatchedEventRepository // Watched event log views, created by the log filters
|
||||||
@ -48,52 +48,25 @@ type Transformer struct {
|
|||||||
converter.Converter // Converts watched event logs into custom log
|
converter.Converter // Converts watched event logs into custom log
|
||||||
poller.Poller // Polls methods using contract's token holder addresses and persists them using method datastore
|
poller.Poller // Polls methods using contract's token holder addresses and persists them using method datastore
|
||||||
|
|
||||||
// Ethereum network name; default "" is mainnet
|
// Store contract configuration information
|
||||||
Network string
|
Config config.ContractConfig
|
||||||
|
|
||||||
// Store contract info as mapping to contract address
|
// Store contract info as mapping to contract address
|
||||||
Contracts map[string]*contract.Contract
|
Contracts map[string]*contract.Contract
|
||||||
|
|
||||||
// Targeted subset of events/methods
|
|
||||||
// Stored as map sof contract address to events/method names of interest
|
|
||||||
WatchedEvents map[string][]string // Default/empty event list means all are watched
|
|
||||||
WantedMethods map[string][]string // Default/empty method list means none are polled
|
|
||||||
|
|
||||||
// Starting block for contracts
|
|
||||||
ContractStart map[string]int64
|
|
||||||
|
|
||||||
// Lists of addresses to filter event or method data
|
|
||||||
// before persisting; if empty no filter is applied
|
|
||||||
EventArgs map[string][]string
|
|
||||||
MethodArgs map[string][]string
|
|
||||||
|
|
||||||
// Whether or not to create a list of emitted address or hashes for the contract in postgres
|
|
||||||
CreateAddrList map[string]bool
|
|
||||||
CreateHashList map[string]bool
|
|
||||||
|
|
||||||
// Method piping on/off for a contract
|
|
||||||
Piping map[string]bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transformer takes in config for blockchain, database, and network id
|
// Transformer takes in config for blockchain, database, and network id
|
||||||
func NewTransformer(network string, BC core.BlockChain, DB *postgres.DB) *Transformer {
|
func NewTransformer(con config.ContractConfig, BC core.BlockChain, DB *postgres.DB) *transformer {
|
||||||
return &Transformer{
|
return &transformer{
|
||||||
Poller: poller.NewPoller(BC, DB, types.FullSync),
|
Poller: poller.NewPoller(BC, DB, types.FullSync),
|
||||||
Parser: parser.NewParser(network),
|
Parser: parser.NewParser(con.Network),
|
||||||
BlockRetriever: retriever.NewBlockRetriever(DB),
|
BlockRetriever: retriever.NewBlockRetriever(DB),
|
||||||
Converter: converter.NewConverter(&contract.Contract{}),
|
Converter: converter.NewConverter(&contract.Contract{}),
|
||||||
Contracts: map[string]*contract.Contract{},
|
Contracts: map[string]*contract.Contract{},
|
||||||
WatchedEventRepository: repositories.WatchedEventRepository{DB: DB},
|
WatchedEventRepository: repositories.WatchedEventRepository{DB: DB},
|
||||||
FilterRepository: repositories.FilterRepository{DB: DB},
|
FilterRepository: repositories.FilterRepository{DB: DB},
|
||||||
EventRepository: repository.NewEventRepository(DB, types.FullSync),
|
EventRepository: repository.NewEventRepository(DB, types.FullSync),
|
||||||
WatchedEvents: map[string][]string{},
|
Config: con,
|
||||||
WantedMethods: map[string][]string{},
|
|
||||||
ContractStart: map[string]int64{},
|
|
||||||
EventArgs: map[string][]string{},
|
|
||||||
MethodArgs: map[string][]string{},
|
|
||||||
CreateAddrList: map[string]bool{},
|
|
||||||
CreateHashList: map[string]bool{},
|
|
||||||
Piping: map[string]bool{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,59 +74,66 @@ func NewTransformer(network string, BC core.BlockChain, DB *postgres.DB) *Transf
|
|||||||
// Loops over all of the addr => filter sets
|
// Loops over all of the addr => filter sets
|
||||||
// Uses parser to pull event info from abi
|
// Uses parser to pull event info from abi
|
||||||
// Use this info to generate event filters
|
// Use this info to generate event filters
|
||||||
func (transformer *Transformer) Init() error {
|
func (tr *transformer) Init() error {
|
||||||
for contractAddr, subset := range transformer.WatchedEvents {
|
for contractAddr := range tr.Config.Addresses {
|
||||||
// Get Abi
|
// Configure Abi
|
||||||
err := transformer.Parser.Parse(contractAddr)
|
if tr.Config.Abis[contractAddr] == "" {
|
||||||
|
// If no abi is given in the config, this method will try fetching from internal look-up table and etherscan
|
||||||
|
err := tr.Parser.Parse(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If we have an abi from the config, load that into the parser
|
||||||
|
err := tr.Parser.ParseAbiStr(tr.Config.Abis[contractAddr])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get first block and most recent block number in the header repo
|
// Get first block and most recent block number in the header repo
|
||||||
firstBlock, err := transformer.BlockRetriever.RetrieveFirstBlock(contractAddr)
|
firstBlock, err := tr.BlockRetriever.RetrieveFirstBlock(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
lastBlock, err := transformer.BlockRetriever.RetrieveMostRecentBlock()
|
lastBlock, err := tr.BlockRetriever.RetrieveMostRecentBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set to specified range if it falls within the bounds
|
// Set to specified range if it falls within the bounds
|
||||||
if firstBlock < transformer.ContractStart[contractAddr] {
|
if firstBlock < tr.Config.StartingBlocks[contractAddr] {
|
||||||
firstBlock = transformer.ContractStart[contractAddr]
|
firstBlock = tr.Config.StartingBlocks[contractAddr]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get contract name if it has one
|
// Get contract name if it has one
|
||||||
var name = new(string)
|
var name = new(string)
|
||||||
transformer.Poller.FetchContractData(transformer.Abi(), contractAddr, "name", nil, name, lastBlock)
|
tr.FetchContractData(tr.Abi(), contractAddr, "name", nil, &name, lastBlock)
|
||||||
|
|
||||||
// Remove any potential accidental duplicate inputs in arg filter values
|
// Remove any potential accidental duplicate inputs in arg filter values
|
||||||
eventArgs := map[string]bool{}
|
eventArgs := map[string]bool{}
|
||||||
for _, arg := range transformer.EventArgs[contractAddr] {
|
for _, arg := range tr.Config.EventArgs[contractAddr] {
|
||||||
eventArgs[arg] = true
|
eventArgs[arg] = true
|
||||||
}
|
}
|
||||||
methodArgs := map[string]bool{}
|
methodArgs := map[string]bool{}
|
||||||
for _, arg := range transformer.MethodArgs[contractAddr] {
|
for _, arg := range tr.Config.MethodArgs[contractAddr] {
|
||||||
methodArgs[arg] = true
|
methodArgs[arg] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate info into contract object
|
// Aggregate info into contract object
|
||||||
info := contract.Contract{
|
info := contract.Contract{
|
||||||
Name: *name,
|
Name: *name,
|
||||||
Network: transformer.Network,
|
Network: tr.Config.Network,
|
||||||
Address: contractAddr,
|
Address: contractAddr,
|
||||||
Abi: transformer.Parser.Abi(),
|
Abi: tr.Parser.Abi(),
|
||||||
ParsedAbi: transformer.Parser.ParsedAbi(),
|
ParsedAbi: tr.Parser.ParsedAbi(),
|
||||||
StartingBlock: firstBlock,
|
StartingBlock: firstBlock,
|
||||||
LastBlock: lastBlock,
|
LastBlock: lastBlock,
|
||||||
Events: transformer.Parser.GetEvents(subset),
|
Events: tr.Parser.GetEvents(tr.Config.Events[contractAddr]),
|
||||||
Methods: transformer.Parser.GetSelectMethods(transformer.WantedMethods[contractAddr]),
|
Methods: tr.Parser.GetSelectMethods(tr.Config.Methods[contractAddr]),
|
||||||
FilterArgs: eventArgs,
|
FilterArgs: eventArgs,
|
||||||
MethodArgs: methodArgs,
|
MethodArgs: methodArgs,
|
||||||
CreateAddrList: transformer.CreateAddrList[contractAddr],
|
Piping: tr.Config.Piping[contractAddr],
|
||||||
CreateHashList: transformer.CreateHashList[contractAddr],
|
|
||||||
Piping: transformer.Piping[contractAddr],
|
|
||||||
}.Init()
|
}.Init()
|
||||||
|
|
||||||
// Use info to create filters
|
// Use info to create filters
|
||||||
@ -164,14 +144,14 @@ func (transformer *Transformer) Init() error {
|
|||||||
|
|
||||||
// Iterate over filters and push them to the repo using filter repository interface
|
// Iterate over filters and push them to the repo using filter repository interface
|
||||||
for _, filter := range info.Filters {
|
for _, filter := range info.Filters {
|
||||||
err = transformer.FilterRepository.CreateFilter(filter)
|
err = tr.CreateFilter(filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store contract info for further processing
|
// Store contract info for further processing
|
||||||
transformer.Contracts[contractAddr] = info
|
tr.Contracts[contractAddr] = info
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -182,18 +162,18 @@ func (transformer *Transformer) Init() error {
|
|||||||
// Uses converter to convert logs into custom log type
|
// Uses converter to convert logs into custom log type
|
||||||
// Persists converted logs into custuom postgres tables
|
// Persists converted logs into custuom postgres tables
|
||||||
// Calls selected methods, using token holder address generated during event log conversion
|
// Calls selected methods, using token holder address generated during event log conversion
|
||||||
func (transformer Transformer) Execute() error {
|
func (tr *transformer) Execute() error {
|
||||||
if len(transformer.Contracts) == 0 {
|
if len(tr.Contracts) == 0 {
|
||||||
return errors.New("error: transformer has no initialized contracts to work with")
|
return errors.New("error: transformer has no initialized contracts to work with")
|
||||||
}
|
}
|
||||||
// Iterate through all internal contracts
|
// Iterate through all internal contracts
|
||||||
for _, con := range transformer.Contracts {
|
for _, con := range tr.Contracts {
|
||||||
// Update converter with current contract
|
// Update converter with current contract
|
||||||
transformer.Update(con)
|
tr.Update(con)
|
||||||
|
|
||||||
// Iterate through contract filters and get watched event logs
|
// Iterate through contract filters and get watched event logs
|
||||||
for eventSig, filter := range con.Filters {
|
for eventSig, filter := range con.Filters {
|
||||||
watchedEvents, err := transformer.GetWatchedEvents(filter.Name)
|
watchedEvents, err := tr.GetWatchedEvents(filter.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -201,7 +181,7 @@ func (transformer Transformer) Execute() error {
|
|||||||
// Iterate over watched event logs
|
// Iterate over watched event logs
|
||||||
for _, we := range watchedEvents {
|
for _, we := range watchedEvents {
|
||||||
// Convert them to our custom log type
|
// Convert them to our custom log type
|
||||||
cstm, err := transformer.Converter.Convert(*we, con.Events[eventSig])
|
cstm, err := tr.Converter.Convert(*we, con.Events[eventSig])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -211,7 +191,7 @@ func (transformer Transformer) Execute() error {
|
|||||||
|
|
||||||
// If log is not empty, immediately persist in repo
|
// If log is not empty, immediately persist in repo
|
||||||
// Run this in seperate goroutine?
|
// Run this in seperate goroutine?
|
||||||
err = transformer.PersistLogs([]types.Log{*cstm}, con.Events[eventSig], con.Address, con.Name)
|
err = tr.PersistLogs([]types.Log{*cstm}, con.Events[eventSig], con.Address, con.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -222,7 +202,7 @@ func (transformer Transformer) Execute() error {
|
|||||||
// poller polls select contract methods
|
// poller polls select contract methods
|
||||||
// and persists the results into custom pg tables
|
// and persists the results into custom pg tables
|
||||||
// Run this in seperate goroutine?
|
// Run this in seperate goroutine?
|
||||||
if err := transformer.PollContract(*con); err != nil {
|
if err := tr.PollContract(*con); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,42 +210,6 @@ func (transformer Transformer) Execute() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their events to watch
|
func (tr *transformer) GetConfig() config.ContractConfig {
|
||||||
func (transformer *Transformer) SetEvents(contractAddr string, filterSet []string) {
|
return tr.Config
|
||||||
transformer.WatchedEvents[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set subset of account addresses to watch events for
|
|
||||||
func (transformer *Transformer) SetEventArgs(contractAddr string, filterSet []string) {
|
|
||||||
transformer.EventArgs[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their methods to call
|
|
||||||
func (transformer *Transformer) SetMethods(contractAddr string, filterSet []string) {
|
|
||||||
transformer.WantedMethods[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set subset of account addresses to poll methods on
|
|
||||||
func (transformer *Transformer) SetMethodArgs(contractAddr string, filterSet []string) {
|
|
||||||
transformer.MethodArgs[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set the block range to watch for a given address
|
|
||||||
func (transformer *Transformer) SetStartingBlock(contractAddr string, start int64) {
|
|
||||||
transformer.ContractStart[strings.ToLower(contractAddr)] = start
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set whether or not to persist an account address list
|
|
||||||
func (transformer *Transformer) SetCreateAddrList(contractAddr string, on bool) {
|
|
||||||
transformer.CreateAddrList[strings.ToLower(contractAddr)] = on
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set whether or not to persist an hash list
|
|
||||||
func (transformer *Transformer) SetCreateHashList(contractAddr string, on bool) {
|
|
||||||
transformer.CreateHashList[strings.ToLower(contractAddr)] = on
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to turn method piping on for a contract
|
|
||||||
func (transformer *Transformer) SetPiping(contractAddr string, on bool) {
|
|
||||||
transformer.Piping[strings.ToLower(contractAddr)] = on
|
|
||||||
}
|
}
|
||||||
|
@ -17,160 +17,307 @@
|
|||||||
package transformer_test
|
package transformer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/full/retriever"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/full/transformer"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/full/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Transformer", func() {
|
var _ = Describe("Transformer", func() {
|
||||||
var fakeAddress = "0x1234567890abcdef"
|
var db *postgres.DB
|
||||||
|
var err error
|
||||||
|
var blockChain core.BlockChain
|
||||||
|
var blockRepository repositories.BlockRepository
|
||||||
|
var ensAddr = strings.ToLower(constants.EnsContractAddress)
|
||||||
|
var tusdAddr = strings.ToLower(constants.TusdContractAddress)
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
Describe("SetEvents", func() {
|
BeforeEach(func() {
|
||||||
It("Sets which events to watch from the given contract address", func() {
|
db, blockChain = test_helpers.SetupDBandBC()
|
||||||
watchedEvents := []string{"Transfer", "Mint"}
|
blockRepository = *repositories.NewBlockRepository(db)
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetEvents(fakeAddress, watchedEvents)
|
|
||||||
Expect(t.WatchedEvents[fakeAddress]).To(Equal(watchedEvents))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("SetEventAddrs", func() {
|
AfterEach(func() {
|
||||||
It("Sets which account addresses to watch events for", func() {
|
test_helpers.TearDown(db)
|
||||||
eventAddrs := []string{"test1", "test2"}
|
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetEventArgs(fakeAddress, eventAddrs)
|
|
||||||
Expect(t.EventArgs[fakeAddress]).To(Equal(eventAddrs))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetMethods", func() {
|
|
||||||
It("Sets which methods to poll at the given contract address", func() {
|
|
||||||
watchedMethods := []string{"balanceOf", "totalSupply"}
|
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetMethods(fakeAddress, watchedMethods)
|
|
||||||
Expect(t.WantedMethods[fakeAddress]).To(Equal(watchedMethods))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetMethodAddrs", func() {
|
|
||||||
It("Sets which account addresses to poll methods against", func() {
|
|
||||||
methodAddrs := []string{"test1", "test2"}
|
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetMethodArgs(fakeAddress, methodAddrs)
|
|
||||||
Expect(t.MethodArgs[fakeAddress]).To(Equal(methodAddrs))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetStartingBlock", func() {
|
|
||||||
It("Sets the block range that the contract should be watched within", func() {
|
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetStartingBlock(fakeAddress, 11)
|
|
||||||
Expect(t.ContractStart[fakeAddress]).To(Equal(int64(11)))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetCreateAddrList", func() {
|
|
||||||
It("Sets the block range that the contract should be watched within", func() {
|
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetCreateAddrList(fakeAddress, true)
|
|
||||||
Expect(t.CreateAddrList[fakeAddress]).To(Equal(true))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetCreateHashList", func() {
|
|
||||||
It("Sets the block range that the contract should be watched within", func() {
|
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetCreateHashList(fakeAddress, true)
|
|
||||||
Expect(t.CreateHashList[fakeAddress]).To(Equal(true))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Init", func() {
|
Describe("Init", func() {
|
||||||
It("Initializes transformer's contract objects", func() {
|
It("Initializes transformer's contract objects", func() {
|
||||||
blockRetriever := &fakes.MockFullBlockRetriever{}
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1)
|
||||||
firstBlock := int64(1)
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2)
|
||||||
mostRecentBlock := int64(2)
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
blockRetriever.FirstBlock = firstBlock
|
err = t.Init()
|
||||||
blockRetriever.MostRecentBlock = mostRecentBlock
|
|
||||||
|
|
||||||
parsr := &fakes.MockParser{}
|
|
||||||
fakeAbi := "fake_abi"
|
|
||||||
eventName := "Transfer"
|
|
||||||
event := types.Event{}
|
|
||||||
parsr.AbiToReturn = fakeAbi
|
|
||||||
parsr.EventName = eventName
|
|
||||||
parsr.Event = event
|
|
||||||
|
|
||||||
pollr := &fakes.MockPoller{}
|
|
||||||
fakeContractName := "fake_contract_name"
|
|
||||||
pollr.ContractName = fakeContractName
|
|
||||||
|
|
||||||
t := getTransformer(blockRetriever, parsr, pollr)
|
|
||||||
t.SetEvents(fakeAddress, []string{"Transfer"})
|
|
||||||
|
|
||||||
err := t.Init()
|
|
||||||
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
c, ok := t.Contracts[fakeAddress]
|
c, ok := t.Contracts[tusdAddr]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
Expect(c.StartingBlock).To(Equal(firstBlock))
|
Expect(c.StartingBlock).To(Equal(int64(6194633)))
|
||||||
Expect(c.LastBlock).To(Equal(mostRecentBlock))
|
Expect(c.LastBlock).To(Equal(int64(6194634)))
|
||||||
Expect(c.Abi).To(Equal(fakeAbi))
|
Expect(c.Abi).To(Equal(constants.TusdAbiString))
|
||||||
Expect(c.Name).To(Equal(fakeContractName))
|
Expect(c.Name).To(Equal("TrueUSD"))
|
||||||
Expect(c.Address).To(Equal(fakeAddress))
|
Expect(c.Address).To(Equal(tusdAddr))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Fails to initialize if first and most recent blocks cannot be fetched from vDB", func() {
|
It("Fails to initialize if first and most recent blocks cannot be fetched from vDB", func() {
|
||||||
blockRetriever := &fakes.MockFullBlockRetriever{}
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
blockRetriever.FirstBlockErr = fakes.FakeError
|
err = t.Init()
|
||||||
t := getTransformer(blockRetriever, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetEvents(fakeAddress, []string{"Transfer"})
|
|
||||||
|
|
||||||
err := t.Init()
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Does nothing if watched events are unset", func() {
|
It("Does nothing if watched events are unset", func() {
|
||||||
t := getTransformer(&fakes.MockFullBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1)
|
||||||
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2)
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.TusdConfig
|
||||||
|
testConf.Events = nil
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
|
||||||
err := t.Init()
|
_, ok := t.Contracts[tusdAddr]
|
||||||
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
_, ok := t.Contracts[fakeAddress]
|
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("Execute", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock1)
|
||||||
|
blockRepository.CreateOrUpdateBlock(mocks.TransferBlock2)
|
||||||
})
|
})
|
||||||
|
|
||||||
func getTransformer(blockRetriever retriever.BlockRetriever, parsr parser.Parser, pollr poller.Poller) transformer.Transformer {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
return transformer.Transformer{
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
FilterRepository: &fakes.MockFilterRepository{},
|
err = t.Init()
|
||||||
Parser: parsr,
|
Expect(err).ToNot(HaveOccurred())
|
||||||
BlockRetriever: blockRetriever,
|
|
||||||
Poller: pollr,
|
err = t.Execute()
|
||||||
Contracts: map[string]*contract.Contract{},
|
Expect(err).ToNot(HaveOccurred())
|
||||||
WatchedEvents: map[string][]string{},
|
|
||||||
WantedMethods: map[string][]string{},
|
log := test_helpers.TransferLog{}
|
||||||
ContractStart: map[string]int64{},
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.transfer_event WHERE block = 6194634", tusdAddr)).StructScan(&log)
|
||||||
EventArgs: map[string][]string{},
|
|
||||||
MethodArgs: map[string][]string{},
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
CreateAddrList: map[string]bool{},
|
Expect(log.Tx).To(Equal("0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654eee"))
|
||||||
CreateHashList: map[string]bool{},
|
Expect(log.Block).To(Equal(int64(6194634)))
|
||||||
|
Expect(log.From).To(Equal("0x000000000000000000000000000000000000Af21"))
|
||||||
|
Expect(log.To).To(Equal("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391"))
|
||||||
|
Expect(log.Value).To(Equal("1097077688018008265106216665536940668749033598146"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.TusdConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
}
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
c, ok := t.Contracts[tusdAddr]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
b, ok := c.EmittedAddrs[common.HexToAddress("0x000000000000000000000000000000000000Af21")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843bCE061BA391")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843b1234567890")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[""]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Polls given methods using generated token holder address", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.TusdConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
}
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
res := test_helpers.BalanceOf{}
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0x000000000000000000000000000000000000Af21' AND block = '6194634'", tusdAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Balance).To(Equal("0"))
|
||||||
|
Expect(res.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843bCE061BA391' AND block = '6194634'", tusdAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Balance).To(Equal("0"))
|
||||||
|
Expect(res.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.balanceof_method WHERE who_ = '0xfE9e8709d3215310075d67E3ed32A380CCf451C8' AND block = '6194634'", tusdAddr)).StructScan(&res)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Fails if initialization has not been done", func() {
|
||||||
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Execute- against ENS registry contract", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
blockRepository.CreateOrUpdateBlock(mocks.NewOwnerBlock1)
|
||||||
|
blockRepository.CreateOrUpdateBlock(mocks.NewOwnerBlock2)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
|
t := transformer.NewTransformer(mocks.ENSConfig, blockChain, db)
|
||||||
|
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
log := test_helpers.NewOwnerLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
|
|
||||||
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
|
Expect(log.Tx).To(Equal("0x135391a0962a63944e5908e6fedfff90fb4be3e3290a21017861099bad654bbb"))
|
||||||
|
Expect(log.Block).To(Equal(int64(6194635)))
|
||||||
|
Expect(log.Node).To(Equal("0x0000000000000000000000000000000000000000000000000000c02aaa39b223"))
|
||||||
|
Expect(log.Label).To(Equal("0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391"))
|
||||||
|
Expect(log.Owner).To(Equal("0x000000000000000000000000000000000000Af21"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
c, ok := t.Contracts[ensAddr]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(len(c.EmittedHashes)).To(Equal(3))
|
||||||
|
|
||||||
|
b, ok := c.EmittedHashes[common.HexToHash("0x0000000000000000000000000000000000000000000000000000c02aaa39b223")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedHashes[common.HexToHash("0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
// Doesn't keep track of address since it wouldn't be used in calling the 'owner' method
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x000000000000000000000000000000000000Af21")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Polls given methods using generated token holder address", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
res := test_helpers.Owner{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x0000000000000000000000000000000000000000000000000000c02aaa39b223' AND block = '6194636'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391' AND block = '6194636'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x9THIS110dcc444fIS242510c09bbAbe21aFAKEcacNODE82f7b843HASH61ba391' AND block = '6194636'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("It does not perist events if they do not pass the emitted arg filter", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.EventArgs = map[string][]string{
|
||||||
|
ensAddr: {"fake_filter_value"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
log := test_helpers.LightNewOwnerLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("If a method arg filter is applied, only those arguments are used in polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
testConf.MethodArgs = map[string][]string{
|
||||||
|
ensAddr: {"0x0000000000000000000000000000000000000000000000000000c02aaa39b223"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
res := test_helpers.Owner{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x0000000000000000000000000000000000000000000000000000c02aaa39b223' AND block = '6194636'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM full_%s.owner_method WHERE node_ = '0x9dd48110dcc444fdc242510c09bbbbe21a5975cac061d82f7b843bce061ba391' AND block = '6194636'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -54,7 +54,7 @@ func (c *converter) Update(info *contract.Contract) {
|
|||||||
|
|
||||||
// Convert the given watched event log into a types.Log for the given event
|
// Convert the given watched event log into a types.Log for the given event
|
||||||
func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID int64) ([]types.Log, error) {
|
func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID int64) ([]types.Log, error) {
|
||||||
boundContract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
||||||
returnLogs := make([]types.Log, 0, len(logs))
|
returnLogs := make([]types.Log, 0, len(logs))
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
values := make(map[string]interface{})
|
values := make(map[string]interface{})
|
||||||
@ -63,7 +63,7 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
values[field.Name] = i
|
values[field.Name] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
err := boundContract.UnpackLogIntoMap(values, event.Name, log)
|
err := contract.UnpackLogIntoMap(values, event.Name, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ func (c *converter) Convert(logs []gethTypes.Log, event types.Event, headerID in
|
|||||||
|
|
||||||
// Convert the given watched event logs into types.Logs; returns a map of event names to a slice of their converted logs
|
// Convert the given watched event logs into types.Logs; returns a map of event names to a slice of their converted logs
|
||||||
func (c *converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) {
|
func (c *converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.Event, headerID int64) (map[string][]types.Log, error) {
|
||||||
boundContract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
contract := bind.NewBoundContract(common.HexToAddress(c.ContractInfo.Address), c.ContractInfo.ParsedAbi, nil, nil, nil)
|
||||||
eventsToLogs := make(map[string][]types.Log)
|
eventsToLogs := make(map[string][]types.Log)
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
eventsToLogs[event.Name] = make([]types.Log, 0, len(logs))
|
eventsToLogs[event.Name] = make([]types.Log, 0, len(logs))
|
||||||
@ -142,7 +142,7 @@ func (c *converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.E
|
|||||||
// If the log is of this event type, process it as such
|
// If the log is of this event type, process it as such
|
||||||
if event.Sig() == log.Topics[0] {
|
if event.Sig() == log.Topics[0] {
|
||||||
values := make(map[string]interface{})
|
values := make(map[string]interface{})
|
||||||
err := boundContract.UnpackLogIntoMap(values, event.Name, log)
|
err := contract.UnpackLogIntoMap(values, event.Name, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
|
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ func (r *headerRepository) MarkHeaderCheckedForAll(headerID int64, ids []string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *headerRepository) MarkHeadersCheckedForAll(headers []core.Header, ids []string) error {
|
func (r *headerRepository) MarkHeadersCheckedForAll(headers []core.Header, ids []string) error {
|
||||||
tx, err := r.db.Beginx()
|
tx, err := r.db.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -250,7 +250,7 @@ func (r *headerRepository) CheckCache(key string) (interface{}, bool) {
|
|||||||
return r.columns.Get(key)
|
return r.columns.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarkHeaderCheckedInTransaction(headerID int64, tx *sqlx.Tx, eventID string) error {
|
func MarkHeaderCheckedInTransaction(headerID int64, tx *sql.Tx, eventID string) error {
|
||||||
_, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+eventID+`)
|
_, err := tx.Exec(`INSERT INTO public.checked_headers (header_id, `+eventID+`)
|
||||||
VALUES ($1, $2)
|
VALUES ($1, $2)
|
||||||
ON CONFLICT (header_id) DO
|
ON CONFLICT (header_id) DO
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
|
|
||||||
func TestRetriever(t *testing.T) {
|
func TestRetriever(t *testing.T) {
|
||||||
RegisterFailHandler(Fail)
|
RegisterFailHandler(Fail)
|
||||||
RunSpecs(t, "Light Block Number Retriever Suite Test")
|
RunSpecs(t, "Light BLock Number Retriever Suite Test")
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = BeforeSuite(func() {
|
var _ = BeforeSuite(func() {
|
||||||
|
@ -18,6 +18,7 @@ package transformer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -37,7 +38,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Requires a light synced vDB (headers) and a running eth node (or infura)
|
// Requires a light synced vDB (headers) and a running eth node (or infura)
|
||||||
type Transformer struct {
|
type transformer struct {
|
||||||
// Database interfaces
|
// Database interfaces
|
||||||
srep.EventRepository // Holds transformed watched event log data
|
srep.EventRepository // Holds transformed watched event log data
|
||||||
repository.HeaderRepository // Interface for interaction with header repositories
|
repository.HeaderRepository // Interface for interaction with header repositories
|
||||||
@ -51,32 +52,12 @@ type Transformer struct {
|
|||||||
converter.Converter // Converts watched event logs into custom log
|
converter.Converter // Converts watched event logs into custom log
|
||||||
poller.Poller // Polls methods using arguments collected from events and persists them using a method datastore
|
poller.Poller // Polls methods using arguments collected from events and persists them using a method datastore
|
||||||
|
|
||||||
// Ethereum network name; default "" is mainnet
|
// Store contract configuration information
|
||||||
Network string
|
Config config.ContractConfig
|
||||||
|
|
||||||
// Store contract info as mapping to contract address
|
// Store contract info as mapping to contract address
|
||||||
Contracts map[string]*contract.Contract
|
Contracts map[string]*contract.Contract
|
||||||
|
|
||||||
// Targeted subset of events/methods
|
|
||||||
// Stored as maps of contract address to events/method names of interest
|
|
||||||
WatchedEvents map[string][]string // Default/empty event list means all are watched
|
|
||||||
WantedMethods map[string][]string // Default/empty method list means none are polled
|
|
||||||
|
|
||||||
// Starting block number for each contract
|
|
||||||
ContractStart map[string]int64
|
|
||||||
|
|
||||||
// Lists of argument values to filter event or
|
|
||||||
// method data with; if empty no filter is applied
|
|
||||||
EventArgs map[string][]string
|
|
||||||
MethodArgs map[string][]string
|
|
||||||
|
|
||||||
// Whether or not to create a list of emitted address or hashes for the contract in postgres
|
|
||||||
CreateAddrList map[string]bool
|
|
||||||
CreateHashList map[string]bool
|
|
||||||
|
|
||||||
// Method piping on/off for a contract
|
|
||||||
Piping map[string]bool
|
|
||||||
|
|
||||||
// Internally configured transformer variables
|
// Internally configured transformer variables
|
||||||
contractAddresses []string // Holds all contract addresses, for batch fetching of logs
|
contractAddresses []string // Holds all contract addresses, for batch fetching of logs
|
||||||
sortedEventIds map[string][]string // Map to sort event column ids by contract, for post fetch processing and persisting of logs
|
sortedEventIds map[string][]string // Map to sort event column ids by contract, for post fetch processing and persisting of logs
|
||||||
@ -93,26 +74,18 @@ type Transformer struct {
|
|||||||
// 4. Execute
|
// 4. Execute
|
||||||
|
|
||||||
// Transformer takes in config for blockchain, database, and network id
|
// Transformer takes in config for blockchain, database, and network id
|
||||||
func NewTransformer(network string, bc core.BlockChain, db *postgres.DB) *Transformer {
|
func NewTransformer(con config.ContractConfig, bc core.BlockChain, db *postgres.DB) *transformer {
|
||||||
|
|
||||||
return &Transformer{
|
return &transformer{
|
||||||
Poller: poller.NewPoller(bc, db, types.LightSync),
|
Poller: poller.NewPoller(bc, db, types.LightSync),
|
||||||
Fetcher: fetcher.NewFetcher(bc),
|
Fetcher: fetcher.NewFetcher(bc),
|
||||||
Parser: parser.NewParser(network),
|
Parser: parser.NewParser(con.Network),
|
||||||
HeaderRepository: repository.NewHeaderRepository(db),
|
HeaderRepository: repository.NewHeaderRepository(db),
|
||||||
BlockRetriever: retriever.NewBlockRetriever(db),
|
BlockRetriever: retriever.NewBlockRetriever(db),
|
||||||
Converter: converter.NewConverter(&contract.Contract{}),
|
Converter: converter.NewConverter(&contract.Contract{}),
|
||||||
Contracts: map[string]*contract.Contract{},
|
Contracts: map[string]*contract.Contract{},
|
||||||
EventRepository: srep.NewEventRepository(db, types.LightSync),
|
EventRepository: srep.NewEventRepository(db, types.LightSync),
|
||||||
WatchedEvents: map[string][]string{},
|
Config: con,
|
||||||
WantedMethods: map[string][]string{},
|
|
||||||
ContractStart: map[string]int64{},
|
|
||||||
EventArgs: map[string][]string{},
|
|
||||||
MethodArgs: map[string][]string{},
|
|
||||||
CreateAddrList: map[string]bool{},
|
|
||||||
CreateHashList: map[string]bool{},
|
|
||||||
Piping: map[string]bool{},
|
|
||||||
Network: network,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +93,7 @@ func NewTransformer(network string, bc core.BlockChain, db *postgres.DB) *Transf
|
|||||||
// Loops over all of the addr => filter sets
|
// Loops over all of the addr => filter sets
|
||||||
// Uses parser to pull event info from abi
|
// Uses parser to pull event info from abi
|
||||||
// Use this info to generate event filters
|
// Use this info to generate event filters
|
||||||
func (tr *Transformer) Init() error {
|
func (tr *transformer) Init() error {
|
||||||
// Initialize internally configured transformer settings
|
// Initialize internally configured transformer settings
|
||||||
tr.contractAddresses = make([]string, 0) // Holds all contract addresses, for batch fetching of logs
|
tr.contractAddresses = make([]string, 0) // Holds all contract addresses, for batch fetching of logs
|
||||||
tr.sortedEventIds = make(map[string][]string) // Map to sort event column ids by contract, for post fetch processing and persisting of logs
|
tr.sortedEventIds = make(map[string][]string) // Map to sort event column ids by contract, for post fetch processing and persisting of logs
|
||||||
@ -130,12 +103,21 @@ func (tr *Transformer) Init() error {
|
|||||||
tr.start = 100000000000 // Hold the lowest starting block and the highest ending block
|
tr.start = 100000000000 // Hold the lowest starting block and the highest ending block
|
||||||
|
|
||||||
// Iterate through all internal contract addresses
|
// Iterate through all internal contract addresses
|
||||||
for contractAddr, subset := range tr.WatchedEvents {
|
for contractAddr := range tr.Config.Addresses {
|
||||||
// Get Abi
|
// Configure Abi
|
||||||
|
if tr.Config.Abis[contractAddr] == "" {
|
||||||
|
// If no abi is given in the config, this method will try fetching from internal look-up table and etherscan
|
||||||
err := tr.Parser.Parse(contractAddr)
|
err := tr.Parser.Parse(contractAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If we have an abi from the config, load that into the parser
|
||||||
|
err := tr.Parser.ParseAbiStr(tr.Config.Abis[contractAddr])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get first block and most recent block number in the header repo
|
// Get first block and most recent block number in the header repo
|
||||||
firstBlock, err := tr.BlockRetriever.RetrieveFirstBlock()
|
firstBlock, err := tr.BlockRetriever.RetrieveFirstBlock()
|
||||||
@ -148,40 +130,38 @@ func (tr *Transformer) Init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set to specified range if it falls within the bounds
|
// Set to specified range if it falls within the bounds
|
||||||
if firstBlock < tr.ContractStart[contractAddr] {
|
if firstBlock < tr.Config.StartingBlocks[contractAddr] {
|
||||||
firstBlock = tr.ContractStart[contractAddr]
|
firstBlock = tr.Config.StartingBlocks[contractAddr]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get contract name if it has one
|
// Get contract name if it has one
|
||||||
var name = new(string)
|
var name = new(string)
|
||||||
tr.Poller.FetchContractData(tr.Abi(), contractAddr, "name", nil, name, lastBlock)
|
tr.FetchContractData(tr.Abi(), contractAddr, "name", nil, &name, lastBlock)
|
||||||
|
|
||||||
// Remove any potential accidental duplicate inputs in arg filter values
|
// Remove any potential accidental duplicate inputs
|
||||||
eventArgs := map[string]bool{}
|
eventArgs := map[string]bool{}
|
||||||
for _, arg := range tr.EventArgs[contractAddr] {
|
for _, arg := range tr.Config.EventArgs[contractAddr] {
|
||||||
eventArgs[arg] = true
|
eventArgs[arg] = true
|
||||||
}
|
}
|
||||||
methodArgs := map[string]bool{}
|
methodArgs := map[string]bool{}
|
||||||
for _, arg := range tr.MethodArgs[contractAddr] {
|
for _, arg := range tr.Config.MethodArgs[contractAddr] {
|
||||||
methodArgs[arg] = true
|
methodArgs[arg] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate info into contract object and store for execution
|
// Aggregate info into contract object and store for execution
|
||||||
con := contract.Contract{
|
con := contract.Contract{
|
||||||
Name: *name,
|
Name: *name,
|
||||||
Network: tr.Network,
|
Network: tr.Config.Network,
|
||||||
Address: contractAddr,
|
Address: contractAddr,
|
||||||
Abi: tr.Parser.Abi(),
|
Abi: tr.Parser.Abi(),
|
||||||
ParsedAbi: tr.Parser.ParsedAbi(),
|
ParsedAbi: tr.Parser.ParsedAbi(),
|
||||||
StartingBlock: firstBlock,
|
StartingBlock: firstBlock,
|
||||||
LastBlock: -1,
|
LastBlock: -1,
|
||||||
Events: tr.Parser.GetEvents(subset),
|
Events: tr.Parser.GetEvents(tr.Config.Events[contractAddr]),
|
||||||
Methods: tr.Parser.GetSelectMethods(tr.WantedMethods[contractAddr]),
|
Methods: tr.Parser.GetSelectMethods(tr.Config.Methods[contractAddr]),
|
||||||
FilterArgs: eventArgs,
|
FilterArgs: eventArgs,
|
||||||
MethodArgs: methodArgs,
|
MethodArgs: methodArgs,
|
||||||
CreateAddrList: tr.CreateAddrList[contractAddr],
|
Piping: tr.Config.Piping[contractAddr],
|
||||||
CreateHashList: tr.CreateHashList[contractAddr],
|
|
||||||
Piping: tr.Piping[contractAddr],
|
|
||||||
}.Init()
|
}.Init()
|
||||||
tr.Contracts[contractAddr] = con
|
tr.Contracts[contractAddr] = con
|
||||||
tr.contractAddresses = append(tr.contractAddresses, con.Address)
|
tr.contractAddresses = append(tr.contractAddresses, con.Address)
|
||||||
@ -221,7 +201,7 @@ func (tr *Transformer) Init() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *Transformer) Execute() error {
|
func (tr *transformer) Execute() error {
|
||||||
if len(tr.Contracts) == 0 {
|
if len(tr.Contracts) == 0 {
|
||||||
return errors.New("error: transformer has no initialized contracts")
|
return errors.New("error: transformer has no initialized contracts")
|
||||||
}
|
}
|
||||||
@ -311,7 +291,7 @@ func (tr *Transformer) Execute() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used to poll contract methods at a given header
|
// Used to poll contract methods at a given header
|
||||||
func (tr *Transformer) methodPolling(header core.Header, sortedMethodIds map[string][]string) error {
|
func (tr *transformer) methodPolling(header core.Header, sortedMethodIds map[string][]string) error {
|
||||||
for _, con := range tr.Contracts {
|
for _, con := range tr.Contracts {
|
||||||
// Skip method polling processes if no methods are specified
|
// Skip method polling processes if no methods are specified
|
||||||
// Also don't try to poll methods below this contract's specified starting block
|
// Also don't try to poll methods below this contract's specified starting block
|
||||||
@ -335,42 +315,6 @@ func (tr *Transformer) methodPolling(header core.Header, sortedMethodIds map[str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their events to watch
|
func (tr *transformer) GetConfig() config.ContractConfig {
|
||||||
func (tr *Transformer) SetEvents(contractAddr string, filterSet []string) {
|
return tr.Config
|
||||||
tr.WatchedEvents[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set subset of account addresses to watch events for
|
|
||||||
func (tr *Transformer) SetEventArgs(contractAddr string, filterSet []string) {
|
|
||||||
tr.EventArgs[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set which contract addresses and which of their methods to call
|
|
||||||
func (tr *Transformer) SetMethods(contractAddr string, filterSet []string) {
|
|
||||||
tr.WantedMethods[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set subset of account addresses to poll methods on
|
|
||||||
func (tr *Transformer) SetMethodArgs(contractAddr string, filterSet []string) {
|
|
||||||
tr.MethodArgs[strings.ToLower(contractAddr)] = filterSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set the block range to watch for a given address
|
|
||||||
func (tr *Transformer) SetStartingBlock(contractAddr string, start int64) {
|
|
||||||
tr.ContractStart[strings.ToLower(contractAddr)] = start
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set whether or not to persist an account address list
|
|
||||||
func (tr *Transformer) SetCreateAddrList(contractAddr string, on bool) {
|
|
||||||
tr.CreateAddrList[strings.ToLower(contractAddr)] = on
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to set whether or not to persist an hash list
|
|
||||||
func (tr *Transformer) SetCreateHashList(contractAddr string, on bool) {
|
|
||||||
tr.CreateHashList[strings.ToLower(contractAddr)] = on
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to turn method piping on for a contract
|
|
||||||
func (tr *Transformer) SetPiping(contractAddr string, on bool) {
|
|
||||||
tr.Piping[strings.ToLower(contractAddr)] = on
|
|
||||||
}
|
}
|
||||||
|
@ -17,150 +17,446 @@
|
|||||||
package transformer_test
|
package transformer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/light/retriever"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/light/transformer"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/light/transformer"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/contract"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/parser"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/poller"
|
"github.com/vulcanize/vulcanizedb/pkg/omni/shared/helpers/test_helpers/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Transformer", func() {
|
var _ = Describe("Transformer", func() {
|
||||||
var fakeAddress = "0x1234567890abcdef"
|
var db *postgres.DB
|
||||||
|
var err error
|
||||||
|
var blockChain core.BlockChain
|
||||||
|
var headerRepository repositories.HeaderRepository
|
||||||
|
var headerID, headerID2 int64
|
||||||
|
var ensAddr = strings.ToLower(constants.EnsContractAddress)
|
||||||
|
var tusdAddr = strings.ToLower(constants.TusdContractAddress)
|
||||||
|
|
||||||
Describe("SetEvents", func() {
|
BeforeEach(func() {
|
||||||
It("Sets which events to watch from the given contract address", func() {
|
db, blockChain = test_helpers.SetupDBandBC()
|
||||||
watchedEvents := []string{"Transfer", "Mint"}
|
headerRepository = repositories.NewHeaderRepository(db)
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetEvents(fakeAddress, watchedEvents)
|
|
||||||
Expect(t.WatchedEvents[fakeAddress]).To(Equal(watchedEvents))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("SetEventAddrs", func() {
|
AfterEach(func() {
|
||||||
It("Sets which account addresses to watch events for", func() {
|
test_helpers.TearDown(db)
|
||||||
eventAddrs := []string{"test1", "test2"}
|
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetEventArgs(fakeAddress, eventAddrs)
|
|
||||||
Expect(t.EventArgs[fakeAddress]).To(Equal(eventAddrs))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetMethods", func() {
|
|
||||||
It("Sets which methods to poll at the given contract address", func() {
|
|
||||||
watchedMethods := []string{"balanceOf", "totalSupply"}
|
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetMethods(fakeAddress, watchedMethods)
|
|
||||||
Expect(t.WantedMethods[fakeAddress]).To(Equal(watchedMethods))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetMethodAddrs", func() {
|
|
||||||
It("Sets which account addresses to poll methods against", func() {
|
|
||||||
methodAddrs := []string{"test1", "test2"}
|
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetMethodArgs(fakeAddress, methodAddrs)
|
|
||||||
Expect(t.MethodArgs[fakeAddress]).To(Equal(methodAddrs))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetStartingBlock", func() {
|
|
||||||
It("Sets the block range that the contract should be watched within", func() {
|
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetStartingBlock(fakeAddress, 11)
|
|
||||||
Expect(t.ContractStart[fakeAddress]).To(Equal(int64(11)))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetCreateAddrList", func() {
|
|
||||||
It("Sets the block range that the contract should be watched within", func() {
|
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetCreateAddrList(fakeAddress, true)
|
|
||||||
Expect(t.CreateAddrList[fakeAddress]).To(Equal(true))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("SetCreateHashList", func() {
|
|
||||||
It("Sets the block range that the contract should be watched within", func() {
|
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetCreateHashList(fakeAddress, true)
|
|
||||||
Expect(t.CreateHashList[fakeAddress]).To(Equal(true))
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
Describe("Init", func() {
|
Describe("Init", func() {
|
||||||
It("Initializes transformer's contract objects", func() {
|
It("Initializes transformer's contract objects", func() {
|
||||||
blockRetriever := &fakes.MockLightBlockRetriever{}
|
headerRepository.CreateOrUpdateHeader(mocks.MockHeader1)
|
||||||
firstBlock := int64(1)
|
headerRepository.CreateOrUpdateHeader(mocks.MockHeader3)
|
||||||
blockRetriever.FirstBlock = firstBlock
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
parsr := &fakes.MockParser{}
|
|
||||||
fakeAbi := "fake_abi"
|
|
||||||
parsr.AbiToReturn = fakeAbi
|
|
||||||
|
|
||||||
pollr := &fakes.MockPoller{}
|
|
||||||
fakeContractName := "fake_contract_name"
|
|
||||||
pollr.ContractName = fakeContractName
|
|
||||||
|
|
||||||
t := getFakeTransformer(blockRetriever, parsr, pollr)
|
|
||||||
t.SetEvents(fakeAddress, []string{"Transfer"})
|
|
||||||
|
|
||||||
err := t.Init()
|
|
||||||
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
c, ok := t.Contracts[fakeAddress]
|
c, ok := t.Contracts[tusdAddr]
|
||||||
Expect(ok).To(Equal(true))
|
Expect(ok).To(Equal(true))
|
||||||
|
|
||||||
Expect(c.StartingBlock).To(Equal(firstBlock))
|
Expect(c.StartingBlock).To(Equal(int64(6194632)))
|
||||||
Expect(c.LastBlock).To(Equal(int64(-1)))
|
Expect(c.LastBlock).To(Equal(int64(-1)))
|
||||||
Expect(c.Abi).To(Equal(fakeAbi))
|
Expect(c.Abi).To(Equal(constants.TusdAbiString))
|
||||||
Expect(c.Name).To(Equal(fakeContractName))
|
Expect(c.Name).To(Equal("TrueUSD"))
|
||||||
Expect(c.Address).To(Equal(fakeAddress))
|
Expect(c.Address).To(Equal(tusdAddr))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Fails to initialize if first and most recent block numbers cannot be fetched from vDB headers table", func() {
|
It("Fails to initialize if first and most recent block numbers cannot be fetched from vDB headers table", func() {
|
||||||
blockRetriever := &fakes.MockLightBlockRetriever{}
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
blockRetriever.FirstBlockErr = fakes.FakeError
|
err = t.Init()
|
||||||
t := getFakeTransformer(blockRetriever, &fakes.MockParser{}, &fakes.MockPoller{})
|
|
||||||
t.SetEvents(fakeAddress, []string{"Transfer"})
|
|
||||||
|
|
||||||
err := t.Init()
|
|
||||||
|
|
||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).To(MatchError(fakes.FakeError))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Does nothing if watched events are unset", func() {
|
It("Does nothing if nothing if no addresses are configured", func() {
|
||||||
t := getFakeTransformer(&fakes.MockLightBlockRetriever{}, &fakes.MockParser{}, &fakes.MockPoller{})
|
headerRepository.CreateOrUpdateHeader(mocks.MockHeader1)
|
||||||
|
headerRepository.CreateOrUpdateHeader(mocks.MockHeader3)
|
||||||
err := t.Init()
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.TusdConfig
|
||||||
|
testConf.Addresses = nil
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
_, ok := t.Contracts[fakeAddress]
|
_, ok := t.Contracts[tusdAddr]
|
||||||
Expect(ok).To(Equal(false))
|
Expect(ok).To(Equal(false))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("Execute- against TrueUSD contract", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
header1, err := blockChain.GetHeaderByNumber(6791668)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header2, err := blockChain.GetHeaderByNumber(6791669)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header3, err := blockChain.GetHeaderByNumber(6791670)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header1)
|
||||||
|
headerID, err = headerRepository.CreateOrUpdateHeader(header2)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header3)
|
||||||
})
|
})
|
||||||
|
|
||||||
func getFakeTransformer(blockRetriever retriever.BlockRetriever, parsr parser.Parser, pollr poller.Poller) transformer.Transformer {
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
return transformer.Transformer{
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
Parser: parsr,
|
err = t.Init()
|
||||||
BlockRetriever: blockRetriever,
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Poller: pollr,
|
err = t.Execute()
|
||||||
HeaderRepository: &fakes.MockLightHeaderRepository{},
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Contracts: map[string]*contract.Contract{},
|
|
||||||
WatchedEvents: map[string][]string{},
|
log := test_helpers.LightTransferLog{}
|
||||||
WantedMethods: map[string][]string{},
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.transfer_event", tusdAddr)).StructScan(&log)
|
||||||
ContractStart: map[string]int64{},
|
Expect(err).ToNot(HaveOccurred())
|
||||||
EventArgs: map[string][]string{},
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
MethodArgs: map[string][]string{},
|
Expect(log.HeaderID).To(Equal(headerID))
|
||||||
CreateAddrList: map[string]bool{},
|
Expect(log.From).To(Equal("0x1062a747393198f70F71ec65A582423Dba7E5Ab3"))
|
||||||
CreateHashList: map[string]bool{},
|
Expect(log.To).To(Equal("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0"))
|
||||||
|
Expect(log.Value).To(Equal("9998940000000000000000"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Keeps track of contract-related addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.TusdConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
}
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
c, ok := t.Contracts[tusdAddr]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(len(c.EmittedAddrs)).To(Equal(4))
|
||||||
|
Expect(len(c.EmittedHashes)).To(Equal(0))
|
||||||
|
|
||||||
|
b, ok := c.EmittedAddrs[common.HexToAddress("0x1062a747393198f70F71ec65A582423Dba7E5Ab3")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedAddrs[common.HexToAddress("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedAddrs[common.HexToAddress("0x571A326f5B15E16917dC17761c340c1ec5d06f6d")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedAddrs[common.HexToAddress("0xFBb1b73C4f0BDa4f67dcA266ce6Ef42f520fBB98")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09BbBBE21a5975cAc061D82f7b843b1234567890")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[""]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x09THISE21a5IS5cFAKE1D82fAND43bCE06MADEUP")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Polls given methods using generated token holder address", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.TusdConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
}
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
res := test_helpers.BalanceOf{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", tusdAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Balance).To(Equal("55849938025000000000000"))
|
||||||
|
Expect(res.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6791669'", tusdAddr)).StructScan(&res)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Fails if initialization has not been done", func() {
|
||||||
|
t := transformer.NewTransformer(mocks.TusdConfig, blockChain, db)
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Execute- against ENS registry contract", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
header1, err := blockChain.GetHeaderByNumber(6885695)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header2, err := blockChain.GetHeaderByNumber(6885696)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header3, err := blockChain.GetHeaderByNumber(6885697)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header1)
|
||||||
|
headerID, err = headerRepository.CreateOrUpdateHeader(header2)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header3)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
|
t := transformer.NewTransformer(mocks.ENSConfig, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
log := test_helpers.LightNewOwnerLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
|
Expect(log.HeaderID).To(Equal(headerID))
|
||||||
|
Expect(log.Node).To(Equal("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"))
|
||||||
|
Expect(log.Label).To(Equal("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047"))
|
||||||
|
Expect(log.Owner).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Keeps track of contract-related hashes while transforming event data if they need to be used for later method polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
c, ok := t.Contracts[ensAddr]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(len(c.EmittedHashes)).To(Equal(2))
|
||||||
|
Expect(len(c.EmittedAddrs)).To(Equal(0))
|
||||||
|
|
||||||
|
b, ok := c.EmittedHashes[common.HexToHash("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = c.EmittedHashes[common.HexToHash("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
// Doesn't keep track of address since it wouldn't be used in calling the 'owner' method
|
||||||
|
_, ok = c.EmittedAddrs[common.HexToAddress("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef")]
|
||||||
|
Expect(ok).To(Equal(false))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Polls given method using list of collected hashes", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
res := test_helpers.Owner{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x9THIS110dcc444fIS242510c09bbAbe21aFAKEcacNODE82f7b843HASH61ba391' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("It does not persist events if they do not pass the emitted arg filter", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.EventArgs = map[string][]string{
|
||||||
|
ensAddr: {"fake_filter_value"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
log := test_helpers.LightNewOwnerLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&log)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("If a method arg filter is applied, only those arguments are used in polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
}
|
||||||
|
testConf.MethodArgs = map[string][]string{
|
||||||
|
ensAddr: {"0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
res := test_helpers.Owner{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(res.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
|
Expect(res.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&res)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("Execute- against both ENS and TrueUSD", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
header1, err := blockChain.GetHeaderByNumber(6791668)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header2, err := blockChain.GetHeaderByNumber(6791669)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header3, err := blockChain.GetHeaderByNumber(6791670)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header4, err := blockChain.GetHeaderByNumber(6885695)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header5, err := blockChain.GetHeaderByNumber(6885696)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
header6, err := blockChain.GetHeaderByNumber(6885697)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header1)
|
||||||
|
headerID, err = headerRepository.CreateOrUpdateHeader(header2)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header3)
|
||||||
|
headerRepository.CreateOrUpdateHeader(header4)
|
||||||
|
headerID2, err = headerRepository.CreateOrUpdateHeader(header5)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
headerRepository.CreateOrUpdateHeader(header6)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Transforms watched contract data into custom repositories", func() {
|
||||||
|
t := transformer.NewTransformer(mocks.ENSandTusdConfig, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
newOwnerLog := test_helpers.LightNewOwnerLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.newowner_event", ensAddr)).StructScan(&newOwnerLog)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
|
Expect(newOwnerLog.HeaderID).To(Equal(headerID2))
|
||||||
|
Expect(newOwnerLog.Node).To(Equal("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae"))
|
||||||
|
Expect(newOwnerLog.Label).To(Equal("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047"))
|
||||||
|
Expect(newOwnerLog.Owner).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
|
|
||||||
|
transferLog := test_helpers.LightTransferLog{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.transfer_event", tusdAddr)).StructScan(&transferLog)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// We don't know vulcID, so compare individual fields instead of complete structures
|
||||||
|
Expect(transferLog.HeaderID).To(Equal(headerID))
|
||||||
|
Expect(transferLog.From).To(Equal("0x1062a747393198f70F71ec65A582423Dba7E5Ab3"))
|
||||||
|
Expect(transferLog.To).To(Equal("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0"))
|
||||||
|
Expect(transferLog.Value).To(Equal("9998940000000000000000"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Keeps track of contract-related hashes and addresses while transforming event data if they need to be used for later method polling", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSandTusdConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
ens, ok := t.Contracts[ensAddr]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
tusd, ok := t.Contracts[tusdAddr]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(len(ens.EmittedHashes)).To(Equal(2))
|
||||||
|
Expect(len(ens.EmittedAddrs)).To(Equal(0))
|
||||||
|
Expect(len(tusd.EmittedAddrs)).To(Equal(4))
|
||||||
|
Expect(len(tusd.EmittedHashes)).To(Equal(0))
|
||||||
|
|
||||||
|
b, ok := ens.EmittedHashes[common.HexToHash("0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = ens.EmittedHashes[common.HexToHash("0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = tusd.EmittedAddrs[common.HexToAddress("0x1062a747393198f70F71ec65A582423Dba7E5Ab3")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = tusd.EmittedAddrs[common.HexToAddress("0x2930096dB16b4A44Ecd4084EA4bd26F7EeF1AEf0")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = tusd.EmittedAddrs[common.HexToAddress("0x571A326f5B15E16917dC17761c340c1ec5d06f6d")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
|
||||||
|
b, ok = tusd.EmittedAddrs[common.HexToAddress("0xFBb1b73C4f0BDa4f67dcA266ce6Ef42f520fBB98")]
|
||||||
|
Expect(ok).To(Equal(true))
|
||||||
|
Expect(b).To(Equal(true))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Polls given methods for each contract, using list of collected values", func() {
|
||||||
|
var testConf config.ContractConfig
|
||||||
|
testConf = mocks.ENSandTusdConfig
|
||||||
|
testConf.Methods = map[string][]string{
|
||||||
|
ensAddr: {"owner"},
|
||||||
|
tusdAddr: {"balanceOf"},
|
||||||
|
}
|
||||||
|
t := transformer.NewTransformer(testConf, blockChain, db)
|
||||||
|
err = t.Init()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = t.Execute()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
owner := test_helpers.Owner{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(owner.Address).To(Equal("0x6090A6e47849629b7245Dfa1Ca21D94cd15878Ef"))
|
||||||
|
Expect(owner.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ce695797aaf402b1c186bad9eca28842625b5047' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(owner.Address).To(Equal("0x0000000000000000000000000000000000000000"))
|
||||||
|
Expect(owner.TokenName).To(Equal(""))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.owner_method WHERE node_ = '0x95832c7a47ff8a7840e28b78ceMADEUPaaf4HASHc186badTHItransformers.8IS625bFAKE' AND block = '6885696'", ensAddr)).StructScan(&owner)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
|
||||||
|
bal := test_helpers.BalanceOf{}
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x1062a747393198f70F71ec65A582423Dba7E5Ab3' AND block = '6791669'", tusdAddr)).StructScan(&bal)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(bal.Balance).To(Equal("55849938025000000000000"))
|
||||||
|
Expect(bal.TokenName).To(Equal("TrueUSD"))
|
||||||
|
|
||||||
|
err = db.QueryRowx(fmt.Sprintf("SELECT * FROM light_%s.balanceof_method WHERE who_ = '0x09BbBBE21a5975cAc061D82f7b843b1234567890' AND block = '6791669'", tusdAddr)).StructScan(&bal)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -72,7 +72,6 @@ var TusdContractAddress = "0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E"
|
|||||||
var EnsContractAddress = "0x314159265dD8dbb310642f98f50C066173C1259b"
|
var EnsContractAddress = "0x314159265dD8dbb310642f98f50C066173C1259b"
|
||||||
var PublicResolverAddress = "0x1da022710dF5002339274AaDEe8D58218e9D6AB5"
|
var PublicResolverAddress = "0x1da022710dF5002339274AaDEe8D58218e9D6AB5"
|
||||||
|
|
||||||
// TODO: Consider whether these should be moved to plugins
|
|
||||||
// Contract Owner
|
// Contract Owner
|
||||||
var DaiContractOwner = "0x0000000000000000000000000000000000000000"
|
var DaiContractOwner = "0x0000000000000000000000000000000000000000"
|
||||||
var TusdContractOwner = "0x9978d2d229a69b3aef93420d132ab22b44e3578f"
|
var TusdContractOwner = "0x9978d2d229a69b3aef93420d132ab22b44e3578f"
|
||||||
|
@ -64,12 +64,6 @@ func (c Contract) Init() *Contract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are creating an address list in postgres
|
|
||||||
// we initialize the map despite what method call, if any
|
|
||||||
if c.CreateAddrList {
|
|
||||||
c.EmittedAddrs = map[interface{}]bool{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,6 @@ type Owner struct {
|
|||||||
Address string `db:"returned"`
|
Address string `db:"returned"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider whether this should be moved to libraries/shared
|
|
||||||
func SetupBC() core.BlockChain {
|
func SetupBC() core.BlockChain {
|
||||||
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
|
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
|
||||||
rawRpcClient, err := rpc.Dial(infuraIPC)
|
rawRpcClient, err := rpc.Dial(infuraIPC)
|
||||||
@ -114,9 +113,9 @@ func SetupBC() core.BlockChain {
|
|||||||
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
|
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
|
||||||
ethClient := ethclient.NewClient(rawRpcClient)
|
ethClient := ethclient.NewClient(rawRpcClient)
|
||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
blockChainNode := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, blockChainNode, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
|
|
||||||
return blockChain
|
return blockChain
|
||||||
}
|
}
|
||||||
@ -128,9 +127,9 @@ func SetupDBandBC() (*postgres.DB, core.BlockChain) {
|
|||||||
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
|
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
|
||||||
ethClient := ethclient.NewClient(rawRpcClient)
|
ethClient := ethclient.NewClient(rawRpcClient)
|
||||||
blockChainClient := client.NewEthClient(ethClient)
|
blockChainClient := client.NewEthClient(ethClient)
|
||||||
blockChainNode := node.MakeNode(rpcClient)
|
node := node.MakeNode(rpcClient)
|
||||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, blockChainNode, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
|
|
||||||
db, err := postgres.NewDB(config.Database{
|
db, err := postgres.NewDB(config.Database{
|
||||||
Hostname: "localhost",
|
Hostname: "localhost",
|
||||||
@ -189,7 +188,6 @@ func SetupTusdContract(wantedEvents, wantedMethods []string) *contract.Contract
|
|||||||
}.Init()
|
}.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider whether this can be moved to plugin or libraries/shared
|
|
||||||
func SetupENSRepo(vulcanizeLogId *int64, wantedEvents, wantedMethods []string) (*postgres.DB, *contract.Contract) {
|
func SetupENSRepo(vulcanizeLogId *int64, wantedEvents, wantedMethods []string) (*postgres.DB, *contract.Contract) {
|
||||||
db, err := postgres.NewDB(config.Database{
|
db, err := postgres.NewDB(config.Database{
|
||||||
Hostname: "localhost",
|
Hostname: "localhost",
|
||||||
@ -238,7 +236,7 @@ func SetupENSContract(wantedEvents, wantedMethods []string) *contract.Contract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TearDown(db *postgres.DB) {
|
func TearDown(db *postgres.DB) {
|
||||||
tx, err := db.Beginx()
|
tx, err := db.Begin()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
_, err = tx.Exec(`DELETE FROM blocks`)
|
_, err = tx.Exec(`DELETE FROM blocks`)
|
||||||
|
@ -18,6 +18,8 @@ package mocks
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
@ -249,3 +251,78 @@ var MockNewOwnerLog2 = types.Log{
|
|||||||
},
|
},
|
||||||
Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000af21"),
|
Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000af21"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ens = strings.ToLower(constants.EnsContractAddress)
|
||||||
|
var tusd = strings.ToLower(constants.TusdContractAddress)
|
||||||
|
|
||||||
|
var TusdConfig = config.ContractConfig{
|
||||||
|
Network: "",
|
||||||
|
Addresses: map[string]bool{
|
||||||
|
tusd: true,
|
||||||
|
},
|
||||||
|
Abis: map[string]string{
|
||||||
|
tusd: "",
|
||||||
|
},
|
||||||
|
Events: map[string][]string{
|
||||||
|
tusd: []string{"Transfer"},
|
||||||
|
},
|
||||||
|
Methods: map[string][]string{
|
||||||
|
tusd: nil,
|
||||||
|
},
|
||||||
|
MethodArgs: map[string][]string{
|
||||||
|
tusd: nil,
|
||||||
|
},
|
||||||
|
EventArgs: map[string][]string{
|
||||||
|
tusd: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var ENSConfig = config.ContractConfig{
|
||||||
|
Network: "",
|
||||||
|
Addresses: map[string]bool{
|
||||||
|
ens: true,
|
||||||
|
},
|
||||||
|
Abis: map[string]string{
|
||||||
|
ens: "",
|
||||||
|
},
|
||||||
|
Events: map[string][]string{
|
||||||
|
ens: []string{"NewOwner"},
|
||||||
|
},
|
||||||
|
Methods: map[string][]string{
|
||||||
|
ens: nil,
|
||||||
|
},
|
||||||
|
MethodArgs: map[string][]string{
|
||||||
|
ens: nil,
|
||||||
|
},
|
||||||
|
EventArgs: map[string][]string{
|
||||||
|
ens: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var ENSandTusdConfig = config.ContractConfig{
|
||||||
|
Network: "",
|
||||||
|
Addresses: map[string]bool{
|
||||||
|
ens: true,
|
||||||
|
tusd: true,
|
||||||
|
},
|
||||||
|
Abis: map[string]string{
|
||||||
|
ens: "",
|
||||||
|
tusd: "",
|
||||||
|
},
|
||||||
|
Events: map[string][]string{
|
||||||
|
ens: []string{"NewOwner"},
|
||||||
|
tusd: []string{"Transfer"},
|
||||||
|
},
|
||||||
|
Methods: map[string][]string{
|
||||||
|
ens: nil,
|
||||||
|
tusd: nil,
|
||||||
|
},
|
||||||
|
MethodArgs: map[string][]string{
|
||||||
|
ens: nil,
|
||||||
|
tusd: nil,
|
||||||
|
},
|
||||||
|
EventArgs: map[string][]string{
|
||||||
|
ens: nil,
|
||||||
|
tusd: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -97,7 +97,7 @@ func (r *eventRepository) persistLogs(logs []types.Log, eventInfo types.Event, c
|
|||||||
|
|
||||||
// Creates a custom postgres command to persist logs for the given event (compatible with light synced vDB)
|
// Creates a custom postgres command to persist logs for the given event (compatible with light synced vDB)
|
||||||
func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error {
|
func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error {
|
||||||
tx, err := r.db.Beginx()
|
tx, err := r.db.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ func (r *eventRepository) persistLightSyncLogs(logs []types.Log, eventInfo types
|
|||||||
|
|
||||||
// Creates a custom postgres command to persist logs for the given event (compatible with fully synced vDB)
|
// Creates a custom postgres command to persist logs for the given event (compatible with fully synced vDB)
|
||||||
func (r *eventRepository) persistFullSyncLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error {
|
func (r *eventRepository) persistFullSyncLogs(logs []types.Log, eventInfo types.Event, contractAddr, contractName string) error {
|
||||||
tx, err := r.db.Beginx()
|
tx, err := r.db.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (r *methodRepository) PersistResults(results []types.Result, methodInfo typ
|
|||||||
|
|
||||||
// Creates a custom postgres command to persist logs for the given event
|
// Creates a custom postgres command to persist logs for the given event
|
||||||
func (r *methodRepository) persistResults(results []types.Result, methodInfo types.Method, contractAddr, contractName string) error {
|
func (r *methodRepository) persistResults(results []types.Result, methodInfo types.Method, contractAddr, contractName string) error {
|
||||||
tx, err := r.DB.Beginx()
|
tx, err := r.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
// VulcanizeDB
|
|
||||||
// Copyright © 2019 Vulcanize
|
|
||||||
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package transformer
|
|
||||||
|
|
||||||
// Used to extract any/all events and a subset of method (state variable)
|
|
||||||
// data for any contract and persists it to custom postgres tables in vDB
|
|
||||||
type Transformer interface {
|
|
||||||
SetEvents(contractAddr string, filterSet []string)
|
|
||||||
SetEventArgs(contractAddr string, filterSet []string)
|
|
||||||
SetMethods(contractAddr string, filterSet []string)
|
|
||||||
SetMethodArgs(contractAddr string, filterSet []string)
|
|
||||||
SetStartingBlock(contractAddr string, start int64)
|
|
||||||
SetCreateAddrList(contractAddr string, on bool)
|
|
||||||
SetCreateHashList(contractAddr string, on bool)
|
|
||||||
SetPiping(contractAddr string, on bool)
|
|
||||||
Init() error
|
|
||||||
Execute() error
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user