Add Filters (#133)

* Add LogFilter struct

* Add log_filters table

* Add view for events watching

* Add cmd line "add_filter" to mimic eventual endpoint

* Allow multiple filters in config
This commit is contained in:
Matt K
2018-01-23 12:43:35 -06:00
committed by GitHub
parent 3f06c7374b
commit c00b8a5a98
19 changed files with 514 additions and 26 deletions
+64
View File
@@ -0,0 +1,64 @@
package filters
import (
"encoding/json"
"errors"
"github.com/8thlight/vulcanizedb/pkg/core"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
type LogFilters []LogFilter
type LogFilter struct {
Name string `json:"name"`
FromBlock int64 `json:"fromBlock"`
ToBlock int64 `json:"toBlock"`
Address string `json:"address"`
core.Topics `json:"topics"`
}
func (filterQuery *LogFilter) UnmarshalJSON(input []byte) error {
type Alias LogFilter
var err error
aux := &struct {
ToBlock string `json:"toBlock"`
FromBlock string `json:"fromBlock"`
*Alias
}{
Alias: (*Alias)(filterQuery),
}
if err := json.Unmarshal(input, &aux); err != nil {
return err
}
if filterQuery.Name == "" {
return errors.New("filters: must provide name for logfilter")
}
filterQuery.ToBlock, err = filterQuery.unmarshalFromToBlock(aux.ToBlock)
if err != nil {
return errors.New("filters: invalid fromBlock")
}
filterQuery.FromBlock, err = filterQuery.unmarshalFromToBlock(aux.FromBlock)
if err != nil {
return errors.New("filters: invalid fromBlock")
}
if !common.IsHexAddress(filterQuery.Address) {
return errors.New("filters: invalid address")
}
return nil
}
func (filterQuery *LogFilter) unmarshalFromToBlock(auxBlock string) (int64, error) {
if auxBlock == "" {
return -1, nil
}
block, err := hexutil.DecodeUint64(auxBlock)
if err != nil {
return 0, errors.New("filters: invalid block arg")
}
return int64(block), nil
}
+125
View File
@@ -0,0 +1,125 @@
package filters_test
import (
"encoding/json"
"github.com/8thlight/vulcanizedb/pkg/core"
"github.com/8thlight/vulcanizedb/pkg/filters"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Log filters", func() {
It("decodes web3 filter to LogFilter", func() {
var logFilter filters.LogFilter
jsonFilter := []byte(
`{
"name": "TestEvent",
"fromBlock": "0x1",
"toBlock": "0x488290",
"address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]
}`)
err := json.Unmarshal(jsonFilter, &logFilter)
Expect(err).ToNot(HaveOccurred())
Expect(logFilter.Name).To(Equal("TestEvent"))
Expect(logFilter.FromBlock).To(Equal(int64(1)))
Expect(logFilter.ToBlock).To(Equal(int64(4752016)))
Expect(logFilter.Address).To(Equal("0x8888f1f195afa192cfee860698584c030f4c9db1"))
Expect(logFilter.Topics).To(Equal(
core.Topics{
"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"",
"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
""}))
})
It("decodes array of web3 filters to []LogFilter", func() {
logFilters := make([]filters.LogFilter, 0)
jsonFilter := []byte(
`[{
"name": "TestEvent",
"fromBlock": "0x1",
"toBlock": "0x488290",
"address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]
},
{
"name": "TestEvent2",
"fromBlock": "0x3",
"toBlock": "0x4",
"address": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07",
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000006b0949d4c6edfe467db78241b7d5566f3c2bb43e", "0x0000000000000000000000005e44c3e467a49c9ca0296a9f130fc433041aaa28"]
}]`)
err := json.Unmarshal(jsonFilter, &logFilters)
Expect(err).ToNot(HaveOccurred())
Expect(len(logFilters)).To(Equal(2))
Expect(logFilters[0].Name).To(Equal("TestEvent"))
Expect(logFilters[1].Name).To(Equal("TestEvent2"))
})
It("requires valid ethereum address", func() {
var logFilter filters.LogFilter
jsonFilter := []byte(
`{
"name": "TestEvent",
"fromBlock": "0x1",
"toBlock": "0x2",
"address": "0x8888f1f195afa192cf84c030f4c9db1",
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]
}`)
err := json.Unmarshal(jsonFilter, &logFilter)
Expect(err).To(HaveOccurred())
})
It("requires name", func() {
var logFilter filters.LogFilter
jsonFilter := []byte(
`{
"fromBlock": "0x1",
"toBlock": "0x2",
"address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]
}`)
err := json.Unmarshal(jsonFilter, &logFilter)
Expect(err).To(HaveOccurred())
})
It("maps missing fromBlock to -1", func() {
var logFilter filters.LogFilter
jsonFilter := []byte(
`{
"name": "TestEvent",
"toBlock": "0x2",
"address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]
}`)
err := json.Unmarshal(jsonFilter, &logFilter)
Expect(err).ToNot(HaveOccurred())
Expect(logFilter.FromBlock).To(Equal(int64(-1)))
})
It("maps missing toBlock to -1", func() {
var logFilter filters.LogFilter
jsonFilter := []byte(
`{
"name": "TestEvent",
"address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
"topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]
}`)
err := json.Unmarshal(jsonFilter, &logFilter)
Expect(err).ToNot(HaveOccurred())
Expect(logFilter.ToBlock).To(Equal(int64(-1)))
})
})
+13
View File
@@ -0,0 +1,13 @@
package filters_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestQueryBuilder(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "QueryBuilder Suite")
}