From 66ad7e302112cdb8eac0ba5834b757e210a3d793 Mon Sep 17 00:00:00 2001 From: Elizabeth Date: Thu, 16 Aug 2018 16:36:35 -0500 Subject: [PATCH] Transform and persist Tend log events --- ...5_add_raw_log_column_to_flip_kick.down.sql | 2 + ...915_add_raw_log_column_to_flip_kick.up.sql | 2 + .../1534295712_create_tend_table.down.sql | 1 + .../1534295712_create_tend_table.up.sql | 12 ++ db/schema.sql | 72 +++++++- pkg/transformers/flip_kick/config.go | 4 +- pkg/transformers/flip_kick/constants.go | 18 -- pkg/transformers/flip_kick/converter.go | 37 ++-- pkg/transformers/flip_kick/converter_test.go | 155 ++++++++--------- .../flip_kick/integration_test.go | 11 +- pkg/transformers/flip_kick/model.go | 1 + pkg/transformers/flip_kick/repository.go | 6 +- pkg/transformers/flip_kick/repository_test.go | 1 + pkg/transformers/flip_kick/transformer.go | 2 +- .../flip_kick/transformer_test.go | 4 +- pkg/transformers/shared/constants.go | 21 +++ pkg/transformers/tend/config.go | 25 +++ pkg/transformers/tend/converter.go | 76 +++++++++ pkg/transformers/tend/converter_test.go | 103 +++++++++++ pkg/transformers/tend/entity.go | 33 ++++ pkg/transformers/tend/integration_test.go | 86 ++++++++++ pkg/transformers/tend/model.go | 30 ++++ pkg/transformers/tend/repository.go | 61 +++++++ pkg/transformers/tend/repository_test.go | 161 ++++++++++++++++++ pkg/transformers/tend/tend_suite_test.go | 19 +++ pkg/transformers/tend/transformer.go | 85 +++++++++ pkg/transformers/tend/transformer_test.go | 141 +++++++++++++++ pkg/transformers/test_data/constants.go | 27 +++ pkg/transformers/test_data/flip_kick.go | 31 ++-- .../test_data/mocks/tend/converter.go | 46 +++++ .../test_data/mocks/tend/repository.go | 54 ++++++ pkg/transformers/test_data/tend.go | 72 ++++++++ pkg/transformers/transformers.go | 5 + pkg/transformers/utilities/utils.go | 33 ++++ 34 files changed, 1290 insertions(+), 147 deletions(-) create mode 100644 db/migrations/1534193915_add_raw_log_column_to_flip_kick.down.sql create mode 100644 db/migrations/1534193915_add_raw_log_column_to_flip_kick.up.sql create mode 100644 db/migrations/1534295712_create_tend_table.down.sql create mode 100644 db/migrations/1534295712_create_tend_table.up.sql delete mode 100644 pkg/transformers/flip_kick/constants.go create mode 100644 pkg/transformers/shared/constants.go create mode 100644 pkg/transformers/tend/config.go create mode 100644 pkg/transformers/tend/converter.go create mode 100644 pkg/transformers/tend/converter_test.go create mode 100644 pkg/transformers/tend/entity.go create mode 100644 pkg/transformers/tend/integration_test.go create mode 100644 pkg/transformers/tend/model.go create mode 100644 pkg/transformers/tend/repository.go create mode 100644 pkg/transformers/tend/repository_test.go create mode 100644 pkg/transformers/tend/tend_suite_test.go create mode 100644 pkg/transformers/tend/transformer.go create mode 100644 pkg/transformers/tend/transformer_test.go create mode 100644 pkg/transformers/test_data/constants.go create mode 100644 pkg/transformers/test_data/mocks/tend/converter.go create mode 100644 pkg/transformers/test_data/mocks/tend/repository.go create mode 100644 pkg/transformers/test_data/tend.go create mode 100644 pkg/transformers/utilities/utils.go diff --git a/db/migrations/1534193915_add_raw_log_column_to_flip_kick.down.sql b/db/migrations/1534193915_add_raw_log_column_to_flip_kick.down.sql new file mode 100644 index 00000000..6e303b91 --- /dev/null +++ b/db/migrations/1534193915_add_raw_log_column_to_flip_kick.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE maker.flip_kick + DROP COLUMN raw_log; diff --git a/db/migrations/1534193915_add_raw_log_column_to_flip_kick.up.sql b/db/migrations/1534193915_add_raw_log_column_to_flip_kick.up.sql new file mode 100644 index 00000000..a7c6cc8f --- /dev/null +++ b/db/migrations/1534193915_add_raw_log_column_to_flip_kick.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE maker.flip_kick + ADD COLUMN raw_log json; diff --git a/db/migrations/1534295712_create_tend_table.down.sql b/db/migrations/1534295712_create_tend_table.down.sql new file mode 100644 index 00000000..6c76d96d --- /dev/null +++ b/db/migrations/1534295712_create_tend_table.down.sql @@ -0,0 +1 @@ +DROP TABLE maker.tend; diff --git a/db/migrations/1534295712_create_tend_table.up.sql b/db/migrations/1534295712_create_tend_table.up.sql new file mode 100644 index 00000000..d88c2efb --- /dev/null +++ b/db/migrations/1534295712_create_tend_table.up.sql @@ -0,0 +1,12 @@ +CREATE TABLE maker.tend ( + db_id SERIAL PRIMARY KEY, + header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE, + id NUMERIC NOT NULL UNIQUE, + lot NUMERIC, + bid NUMERIC, + guy BYTEA, + tic NUMERIC, + era TIMESTAMP WITH TIME ZONE, + tx_idx INTEGER NOT NUll, + raw_log JSONB +); diff --git a/db/schema.sql b/db/schema.sql index 3b5fb120..b56c417e 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -58,7 +58,8 @@ CREATE TABLE maker.flip_kick ( "end" timestamp with time zone, era timestamp with time zone, lad character varying, - tab numeric + tab numeric, + raw_log json ); @@ -153,6 +154,44 @@ CREATE SEQUENCE maker.price_feeds_id_seq ALTER SEQUENCE maker.price_feeds_id_seq OWNED BY maker.price_feeds.id; +-- +-- Name: tend; Type: TABLE; Schema: maker; Owner: - +-- + +CREATE TABLE maker.tend ( + db_id integer NOT NULL, + header_id integer NOT NULL, + id numeric NOT NULL, + lot numeric, + bid numeric, + guy bytea, + tic numeric, + era timestamp with time zone, + tx_idx integer NOT NULL, + raw_log jsonb +); + + +-- +-- Name: tend_db_id_seq; Type: SEQUENCE; Schema: maker; Owner: - +-- + +CREATE SEQUENCE maker.tend_db_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: tend_db_id_seq; Type: SEQUENCE OWNED BY; Schema: maker; Owner: - +-- + +ALTER SEQUENCE maker.tend_db_id_seq OWNED BY maker.tend.db_id; + + -- -- Name: logs; Type: TABLE; Schema: public; Owner: - -- @@ -546,6 +585,13 @@ ALTER TABLE ONLY maker.frob ALTER COLUMN id SET DEFAULT nextval('maker.frob_id_s ALTER TABLE ONLY maker.price_feeds ALTER COLUMN id SET DEFAULT nextval('maker.price_feeds_id_seq'::regclass); +-- +-- Name: tend db_id; Type: DEFAULT; Schema: maker; Owner: - +-- + +ALTER TABLE ONLY maker.tend ALTER COLUMN db_id SET DEFAULT nextval('maker.tend_db_id_seq'::regclass); + + -- -- Name: blocks id; Type: DEFAULT; Schema: public; Owner: - -- @@ -657,6 +703,22 @@ ALTER TABLE ONLY maker.price_feeds ADD CONSTRAINT price_feeds_pkey PRIMARY KEY (id); +-- +-- Name: tend tend_id_key; Type: CONSTRAINT; Schema: maker; Owner: - +-- + +ALTER TABLE ONLY maker.tend + ADD CONSTRAINT tend_id_key UNIQUE (id); + + +-- +-- Name: tend tend_pkey; Type: CONSTRAINT; Schema: maker; Owner: - +-- + +ALTER TABLE ONLY maker.tend + ADD CONSTRAINT tend_pkey PRIMARY KEY (db_id); + + -- -- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -812,6 +874,14 @@ ALTER TABLE ONLY maker.price_feeds ADD CONSTRAINT headers_fk FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE; +-- +-- Name: tend tend_header_id_fkey; Type: FK CONSTRAINT; Schema: maker; Owner: - +-- + +ALTER TABLE ONLY maker.tend + ADD CONSTRAINT tend_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE; + + -- -- Name: transactions blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- diff --git a/pkg/transformers/flip_kick/config.go b/pkg/transformers/flip_kick/config.go index 8aef6634..6798d061 100644 --- a/pkg/transformers/flip_kick/config.go +++ b/pkg/transformers/flip_kick/config.go @@ -18,8 +18,8 @@ import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" var FlipKickConfig = shared.TransformerConfig{ ContractAddresses: "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d", //this is a temporary address deployed locally - ContractAbi: FlipperABI, - Topics: []string{FlipKickSignature}, + ContractAbi: shared.FlipperABI, + Topics: []string{shared.FlipKickSignature}, StartingBlockNumber: 0, EndingBlockNumber: 100, } diff --git a/pkg/transformers/flip_kick/constants.go b/pkg/transformers/flip_kick/constants.go deleted file mode 100644 index 4946c963..00000000 --- a/pkg/transformers/flip_kick/constants.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2018 Vulcanize -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package flip_kick - -var FlipperABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"era\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"lad\",\"type\":\"address\"},{\"name\":\"gal\",\"type\":\"address\"},{\"name\":\"tab\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"bid\",\"type\":\"uint256\"}],\"name\":\"kick\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"vat\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bids\",\"outputs\":[{\"name\":\"bid\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"guy\",\"type\":\"address\"},{\"name\":\"tic\",\"type\":\"uint48\"},{\"name\":\"end\",\"type\":\"uint48\"},{\"name\":\"lad\",\"type\":\"address\"},{\"name\":\"gal\",\"type\":\"address\"},{\"name\":\"tab\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"bid\",\"type\":\"uint256\"}],\"name\":\"tend\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"bid\",\"type\":\"uint256\"}],\"name\":\"dent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"beg\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ilk\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"deal\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tau\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"kicks\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"tick\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"vat_\",\"type\":\"address\"},{\"name\":\"ilk_\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Move\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"act\",\"type\":\"bytes32\"}],\"name\":\"Push\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"risk\",\"type\":\"int256\"}],\"name\":\"FileIlk\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"fuss\",\"type\":\"address\"}],\"name\":\"FileFuss\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"risk\",\"type\":\"int256\"}],\"name\":\"FileInt\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"risk\",\"type\":\"uint256\"}],\"name\":\"FileUint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"ink\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"art\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Frob\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"ink\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"art\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"tab\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"flip\",\"type\":\"uint256\"}],\"name\":\"Bite\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"int256\"}],\"name\":\"Slip\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"mom\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"vat\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gal\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"end\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tab\",\"type\":\"uint256\"}],\"name\":\"FlipKick\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"mom\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"pie\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"vow\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"end\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"FlopKick\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"mom\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"pie\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gal\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"end\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"FlapKick\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tic\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Tend\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tic\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Dent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Deal\",\"type\":\"event\"}]" -var FlipKickSignature = "0xc2d733c352a325d6ecf23d1cf0a189dbcc236b0636388b8c5e6953c061d7f0b3" diff --git a/pkg/transformers/flip_kick/converter.go b/pkg/transformers/flip_kick/converter.go index c5ca60dc..ca6648fa 100644 --- a/pkg/transformers/flip_kick/converter.go +++ b/pkg/transformers/flip_kick/converter.go @@ -15,8 +15,8 @@ package flip_kick import ( + "encoding/json" "errors" - "math/big" "strings" "time" @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/vulcanize/vulcanizedb/pkg/geth" + "github.com/vulcanize/vulcanizedb/pkg/transformers/utilities" ) type Converter interface { @@ -48,7 +49,7 @@ func (FlipKickConverter) ToEntity(contractAddress string, contractAbi string, et if err != nil { return entity, err } - + entity.Raw = ethLog return entity, nil } @@ -63,16 +64,21 @@ func (FlipKickConverter) ToModel(flipKick FlipKickEntity) (FlipKickModel, error) mom := strings.ToLower(flipKick.Mom.String()) vat := strings.ToLower(flipKick.Vat.String()) ilk := strings.ToLower(common.ToHex(flipKick.Ilk[:])) - lot := convertNilToEmptyString(flipKick.Lot.String()) - bid := convertNilToEmptyString(flipKick.Bid.String()) + lot := utilities.ConvertNilToEmptyString(flipKick.Lot.String()) + bid := utilities.ConvertNilToEmptyString(flipKick.Bid.String()) guy := strings.ToLower(flipKick.Guy.String()) gal := strings.ToLower(flipKick.Gal.String()) - endValue := convertNilToZeroTimeValue(flipKick.End) + endValue := utilities.ConvertNilToZeroTimeValue(flipKick.End) end := time.Unix(endValue, 0) - eraValue := convertNilToZeroTimeValue(flipKick.Era) + eraValue := utilities.ConvertNilToZeroTimeValue(flipKick.Era) era := time.Unix(eraValue, 0) lad := strings.ToLower(flipKick.Lad.String()) - tab := convertNilToEmptyString(flipKick.Tab.String()) + tab := utilities.ConvertNilToEmptyString(flipKick.Tab.String()) + rawLogJson, err := json.Marshal(flipKick.Raw) + if err != nil { + return FlipKickModel{}, err + } + rawLogString := string(rawLogJson) return FlipKickModel{ Id: id, @@ -87,21 +93,6 @@ func (FlipKickConverter) ToModel(flipKick FlipKickEntity) (FlipKickModel, error) Era: era, Lad: lad, Tab: tab, + Raw: rawLogString, }, nil } - -func convertNilToZeroTimeValue(value *big.Int) int64 { - if value == nil { - return int64(0) - } else { - return value.Int64() - } -} - -func convertNilToEmptyString(value string) string { - if value == "" { - return "" - } else { - return value - } -} diff --git a/pkg/transformers/flip_kick/converter_test.go b/pkg/transformers/flip_kick/converter_test.go index 0c418e31..b2434d62 100644 --- a/pkg/transformers/flip_kick/converter_test.go +++ b/pkg/transformers/flip_kick/converter_test.go @@ -15,96 +15,99 @@ package flip_kick_test import ( + "encoding/json" "math/big" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick" + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" ) -var _ = Describe("FlipKickEntity Converter", func() { - It("converts an Eth Log to an Entity", func() { - converter := flip_kick.FlipKickConverter{} - entity, err := converter.ToEntity(test_data.TemporaryFlipAddress, flip_kick.FlipperABI, test_data.EthFlipKickLog) +var _ = Describe("FlipKick Converter", func() { + var converter = flip_kick.FlipKickConverter{} - Expect(err).NotTo(HaveOccurred()) - Expect(entity.Id).To(Equal(test_data.FlipKickEntity.Id)) - Expect(entity.Mom).To(Equal(test_data.FlipKickEntity.Mom)) - Expect(entity.Vat).To(Equal(test_data.FlipKickEntity.Vat)) - Expect(entity.Ilk).To(Equal(test_data.FlipKickEntity.Ilk)) - Expect(entity.Lot).To(Equal(test_data.FlipKickEntity.Lot)) - Expect(entity.Bid).To(Equal(test_data.FlipKickEntity.Bid)) - Expect(entity.Guy).To(Equal(test_data.FlipKickEntity.Guy)) - Expect(entity.Gal).To(Equal(test_data.FlipKickEntity.Gal)) - Expect(entity.End).To(Equal(test_data.FlipKickEntity.End)) - Expect(entity.Era).To(Equal(test_data.FlipKickEntity.Era)) - Expect(entity.Lad).To(Equal(test_data.FlipKickEntity.Lad)) - Expect(entity.Tab).To(Equal(test_data.FlipKickEntity.Tab)) + Describe("ToEntity", func() { + It("converts an Eth Log to a FlipKickEntity", func() { + entity, err := converter.ToEntity(test_data.FlipAddress, shared.FlipperABI, test_data.EthFlipKickLog) + + Expect(err).NotTo(HaveOccurred()) + Expect(entity.Id).To(Equal(test_data.FlipKickEntity.Id)) + Expect(entity.Mom).To(Equal(test_data.FlipKickEntity.Mom)) + Expect(entity.Vat).To(Equal(test_data.FlipKickEntity.Vat)) + Expect(entity.Ilk).To(Equal(test_data.FlipKickEntity.Ilk)) + Expect(entity.Lot).To(Equal(test_data.FlipKickEntity.Lot)) + Expect(entity.Bid).To(Equal(test_data.FlipKickEntity.Bid)) + Expect(entity.Guy).To(Equal(test_data.FlipKickEntity.Guy)) + Expect(entity.Gal).To(Equal(test_data.FlipKickEntity.Gal)) + Expect(entity.End).To(Equal(test_data.FlipKickEntity.End)) + Expect(entity.Era).To(Equal(test_data.FlipKickEntity.Era)) + Expect(entity.Lad).To(Equal(test_data.FlipKickEntity.Lad)) + Expect(entity.Tab).To(Equal(test_data.FlipKickEntity.Tab)) + Expect(entity.Raw).To(Equal(test_data.FlipKickEntity.Raw)) + }) + + It("returns an error if converting log to entity fails", func() { + _, err := converter.ToEntity(test_data.FlipAddress, "error abi", test_data.EthFlipKickLog) + + Expect(err).To(HaveOccurred()) + }) }) - It("returns an error if converting log to entity fails", func() { - converter := flip_kick.FlipKickConverter{} - _, err := converter.ToEntity(test_data.TemporaryFlipAddress, "error abi", test_data.EthFlipKickLog) + Describe("ToModel", func() { + var emptyAddressHex = "0x0000000000000000000000000000000000000000" + var emptyByteArrayHex = "0x0000000000000000000000000000000000000000000000000000000000000000" + var emptyString = "" + var emptyTime = time.Unix(0, 0) + var emptyEntity = flip_kick.FlipKickEntity{} + var emptyRawLog string - Expect(err).To(HaveOccurred()) + BeforeEach(func() { + emptyEntity.Id = big.NewInt(1) + var emptyRawLogJson, err = json.Marshal(types.Log{}) + Expect(err).NotTo(HaveOccurred()) + + emptyRawLogJson, err = json.Marshal(types.Log{}) + Expect(err).NotTo(HaveOccurred()) + emptyRawLog = string(emptyRawLogJson) + }) + + It("converts an Entity to a Model", func() { + model, err := converter.ToModel(test_data.FlipKickEntity) + + Expect(err).NotTo(HaveOccurred()) + Expect(model).To(Equal(test_data.FlipKickModel)) + }) + + It("handles nil values", func() { + model, err := converter.ToModel(emptyEntity) + + Expect(err).NotTo(HaveOccurred()) + Expect(model.Id).To(Equal("1")) + Expect(model.Mom).To(Equal(emptyAddressHex)) + Expect(model.Vat).To(Equal(emptyAddressHex)) + Expect(model.Ilk).To(Equal(emptyByteArrayHex)) + Expect(model.Lot).To(Equal(emptyString)) + Expect(model.Bid).To(Equal(emptyString)) + Expect(model.Guy).To(Equal(emptyAddressHex)) + Expect(model.Gal).To(Equal(emptyAddressHex)) + Expect(model.End).To(Equal(emptyTime)) + Expect(model.Era).To(Equal(emptyTime)) + Expect(model.Lad).To(Equal(emptyAddressHex)) + Expect(model.Tab).To(Equal(emptyString)) + Expect(model.Raw).To(Equal(emptyRawLog)) + }) + + It("returns an error if the flip kick event id is nil", func() { + emptyEntity.Id = nil + entity, err := converter.ToModel(emptyEntity) + + Expect(err).To(HaveOccurred()) + Expect(entity).To(Equal(flip_kick.FlipKickModel{})) + }) }) - - It("converts and Entity to a Model", func() { - converter := flip_kick.FlipKickConverter{} - model, err := converter.ToModel(test_data.FlipKickEntity) - Expect(err).NotTo(HaveOccurred()) - Expect(model).To(Equal(test_data.FlipKickModel)) - }) - - It("handles nil", func() { - emptyAddressHex := "0x0000000000000000000000000000000000000000" - emptyByteArrayHex := "0x0000000000000000000000000000000000000000000000000000000000000000" - emptyString := "" - emptyTime := time.Unix(0, 0) - converter := flip_kick.FlipKickConverter{} - emptyEntity := flip_kick.FlipKickEntity{ - Id: big.NewInt(1), - Mom: common.Address{}, - Vat: common.Address{}, - Ilk: [32]byte{}, - Lot: nil, - Bid: nil, - Guy: common.Address{}, - Gal: common.Address{}, - End: nil, - Era: nil, - Lad: common.Address{}, - Tab: nil, - Raw: types.Log{}, - } - model, err := converter.ToModel(emptyEntity) - - Expect(err).NotTo(HaveOccurred()) - Expect(model.Id).To(Equal("1")) - Expect(model.Mom).To(Equal(emptyAddressHex)) - Expect(model.Vat).To(Equal(emptyAddressHex)) - Expect(model.Ilk).To(Equal(emptyByteArrayHex)) - Expect(model.Lot).To(Equal(emptyString)) - Expect(model.Bid).To(Equal(emptyString)) - Expect(model.Guy).To(Equal(emptyAddressHex)) - Expect(model.Gal).To(Equal(emptyAddressHex)) - Expect(model.End).To(Equal(emptyTime)) - Expect(model.Era).To(Equal(emptyTime)) - Expect(model.Lad).To(Equal(emptyAddressHex)) - Expect(model.Tab).To(Equal(emptyString)) - }) - - It("returns an error of the flip kick event id is nil", func() { - converter := flip_kick.FlipKickConverter{} - emptyEntity := flip_kick.FlipKickEntity{} - _, err := converter.ToModel(emptyEntity) - - Expect(err).To(HaveOccurred()) - }) - }) diff --git a/pkg/transformers/flip_kick/integration_test.go b/pkg/transformers/flip_kick/integration_test.go index 6963e9c7..47d52ef8 100644 --- a/pkg/transformers/flip_kick/integration_test.go +++ b/pkg/transformers/flip_kick/integration_test.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/vulcanize/vulcanizedb/pkg/geth" "github.com/vulcanize/vulcanizedb/pkg/geth/client" rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" @@ -45,10 +46,10 @@ var _ = Describe("Integration tests", func() { transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) realBlockChain := geth.NewBlockChain(blockChainClient, realNode, transactionConverter) realFetcher := shared.NewFetcher(realBlockChain) - topic0 := common.HexToHash(flip_kick.FlipKickSignature) + topic0 := common.HexToHash(shared.FlipKickSignature) topics := [][]common.Hash{{topic0}} - result, err := realFetcher.FetchLogs(test_data.TemporaryFlipAddress, topics, int64(10)) + result, err := realFetcher.FetchLogs(test_data.FlipAddress, topics, test_data.FlipKickBlockNumber) Expect(err).NotTo(HaveOccurred()) Expect(len(result) > 0).To(BeTrue()) @@ -60,8 +61,8 @@ var _ = Describe("Integration tests", func() { }) It("unpacks an event log", func() { - address := common.HexToAddress(test_data.TemporaryFlipAddress) - abi, err := geth.ParseAbi(flip_kick.FlipperABI) + address := common.HexToAddress(test_data.FlipAddress) + abi, err := geth.ParseAbi(shared.FlipperABI) Expect(err).NotTo(HaveOccurred()) contract := bind.NewBoundContract(address, abi, nil, nil, nil) @@ -78,7 +79,7 @@ var _ = Describe("Integration tests", func() { Expect(entity.Vat).To(Equal(expectedEntity.Vat)) Expect(entity.Ilk).To(Equal(expectedEntity.Ilk)) Expect(entity.Lot).To(Equal(expectedEntity.Lot)) - Expect(entity.Bid.String()).To(Equal(expectedEntity.Bid.String())) //FIXME + Expect(entity.Bid).To(Equal(expectedEntity.Bid)) Expect(entity.Guy).To(Equal(expectedEntity.Guy)) Expect(entity.Gal).To(Equal(expectedEntity.Gal)) Expect(entity.End).To(Equal(expectedEntity.End)) diff --git a/pkg/transformers/flip_kick/model.go b/pkg/transformers/flip_kick/model.go index 389e31fe..740873ef 100644 --- a/pkg/transformers/flip_kick/model.go +++ b/pkg/transformers/flip_kick/model.go @@ -29,4 +29,5 @@ type FlipKickModel struct { Era time.Time Lad string Tab string + Raw string `db:"raw_log"` } diff --git a/pkg/transformers/flip_kick/repository.go b/pkg/transformers/flip_kick/repository.go index 9fcd6fd6..9c3b25c6 100644 --- a/pkg/transformers/flip_kick/repository.go +++ b/pkg/transformers/flip_kick/repository.go @@ -35,9 +35,9 @@ func NewFlipKickRepository(db *postgres.DB) FlipKickRepository { } func (fkr FlipKickRepository) Create(headerId int64, flipKick FlipKickModel) error { _, err := fkr.DB.Exec( - `INSERT into maker.flip_kick (header_id, id, mom, vat, ilk, lot, bid, guy, gal, "end", era, lad, tab) - VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)`, - headerId, flipKick.Id, flipKick.Mom, flipKick.Vat, flipKick.Ilk, flipKick.Lot, flipKick.Bid, flipKick.Guy, flipKick.Gal, flipKick.End, flipKick.Era, flipKick.Lad, flipKick.Tab, + `INSERT into maker.flip_kick (header_id, id, mom, vat, ilk, lot, bid, guy, gal, "end", era, lad, tab, raw_log) + VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)`, + headerId, flipKick.Id, flipKick.Mom, flipKick.Vat, flipKick.Ilk, flipKick.Lot, flipKick.Bid, flipKick.Guy, flipKick.Gal, flipKick.End, flipKick.Era, flipKick.Lad, flipKick.Tab, flipKick.Raw, ) if err != nil { diff --git a/pkg/transformers/flip_kick/repository_test.go b/pkg/transformers/flip_kick/repository_test.go index f00f0f83..74f4a154 100644 --- a/pkg/transformers/flip_kick/repository_test.go +++ b/pkg/transformers/flip_kick/repository_test.go @@ -76,6 +76,7 @@ var _ = Describe("FlipKick Repository", func() { Expect(dbResult.Era.Equal(flipKick.Era)).To(BeTrue()) Expect(dbResult.Lad).To(Equal(flipKick.Lad)) Expect(dbResult.Tab).To(Equal(flipKick.Tab)) + Expect(dbResult.Raw).To(Equal(flipKick.Raw)) }) It("returns an error if inserting the flip_kick record fails", func() { diff --git a/pkg/transformers/flip_kick/transformer.go b/pkg/transformers/flip_kick/transformer.go index 16ad9f3a..0f700b57 100644 --- a/pkg/transformers/flip_kick/transformer.go +++ b/pkg/transformers/flip_kick/transformer.go @@ -80,7 +80,7 @@ func newTransformerError(err error, blockNumber int64, msg string) error { func (fkt FlipKickTransformer) Execute() error { config := fkt.Config - topics := [][]common.Hash{{common.HexToHash(FlipKickSignature)}} + topics := [][]common.Hash{{common.HexToHash(shared.FlipKickSignature)}} headers, err := fkt.Repository.MissingHeaders(config.StartingBlockNumber, config.EndingBlockNumber) if err != nil { diff --git a/pkg/transformers/flip_kick/transformer_test.go b/pkg/transformers/flip_kick/transformer_test.go index 293a1f31..0f14665a 100644 --- a/pkg/transformers/flip_kick/transformer_test.go +++ b/pkg/transformers/flip_kick/transformer_test.go @@ -56,7 +56,7 @@ var _ = Describe("FlipKick Transformer", func() { testConfig = shared.TransformerConfig{ ContractAddresses: "0x12345", ContractAbi: "test abi", - Topics: []string{flip_kick.FlipKickSignature}, + Topics: []string{shared.FlipKickSignature}, StartingBlockNumber: startingBlockNumber, EndingBlockNumber: startingBlockNumber + 5, } @@ -78,7 +78,7 @@ var _ = Describe("FlipKick Transformer", func() { }) It("fetches logs with the configured contract and topic(s) for each block", func() { - expectedTopics := [][]common.Hash{{common.HexToHash(flip_kick.FlipKickSignature)}} + expectedTopics := [][]common.Hash{{common.HexToHash(shared.FlipKickSignature)}} err := transformer.Execute() Expect(err).NotTo(HaveOccurred()) diff --git a/pkg/transformers/shared/constants.go b/pkg/transformers/shared/constants.go new file mode 100644 index 00000000..2e66e667 --- /dev/null +++ b/pkg/transformers/shared/constants.go @@ -0,0 +1,21 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shared + +var ( + FlipperABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"era\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"lad\",\"type\":\"address\"},{\"name\":\"gal\",\"type\":\"address\"},{\"name\":\"tab\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"bid\",\"type\":\"uint256\"}],\"name\":\"kick\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"vat\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"bids\",\"outputs\":[{\"name\":\"bid\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"guy\",\"type\":\"address\"},{\"name\":\"tic\",\"type\":\"uint48\"},{\"name\":\"end\",\"type\":\"uint48\"},{\"name\":\"lad\",\"type\":\"address\"},{\"name\":\"gal\",\"type\":\"address\"},{\"name\":\"tab\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"bid\",\"type\":\"uint256\"}],\"name\":\"tend\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ttl\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"},{\"name\":\"lot\",\"type\":\"uint256\"},{\"name\":\"bid\",\"type\":\"uint256\"}],\"name\":\"dent\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"beg\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"ilk\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"deal\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tau\",\"outputs\":[{\"name\":\"\",\"type\":\"uint48\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"kicks\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"tick\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"vat_\",\"type\":\"address\"},{\"name\":\"ilk_\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Move\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"act\",\"type\":\"bytes32\"}],\"name\":\"Push\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"risk\",\"type\":\"int256\"}],\"name\":\"FileIlk\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"fuss\",\"type\":\"address\"}],\"name\":\"FileFuss\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"risk\",\"type\":\"int256\"}],\"name\":\"FileInt\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"what\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"risk\",\"type\":\"uint256\"}],\"name\":\"FileUint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"ink\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"art\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Frob\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"ink\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"art\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"tab\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"flip\",\"type\":\"uint256\"}],\"name\":\"Bite\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"int256\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"int256\"}],\"name\":\"Slip\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"mom\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"vat\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gal\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"end\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"lad\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tab\",\"type\":\"uint256\"}],\"name\":\"FlipKick\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"mom\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"pie\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"vow\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"end\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"FlopKick\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"mom\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"pie\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gem\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"gal\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"end\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"FlapKick\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tic\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Tend\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"lot\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"bid\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"tic\",\"type\":\"uint48\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Dent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"id\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"era\",\"type\":\"uint48\"}],\"name\":\"Deal\",\"type\":\"event\"}]" + FlipKickSignature = "0xc2d733c352a325d6ecf23d1cf0a189dbcc236b0636388b8c5e6953c061d7f0b3" + TendSignature = "0xd4aef477d7912041a69c5b85f2d78b618c76e40a4a92b91122c85ab5b404a64a" +) diff --git a/pkg/transformers/tend/config.go b/pkg/transformers/tend/config.go new file mode 100644 index 00000000..bbb9bd92 --- /dev/null +++ b/pkg/transformers/tend/config.go @@ -0,0 +1,25 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" + +var TendConfig = shared.TransformerConfig{ + ContractAddresses: "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d", //this is a temporary address deployed locally + ContractAbi: shared.FlipperABI, + Topics: []string{shared.TendSignature}, + StartingBlockNumber: 0, + EndingBlockNumber: 100, +} diff --git a/pkg/transformers/tend/converter.go b/pkg/transformers/tend/converter.go new file mode 100644 index 00000000..dbb85485 --- /dev/null +++ b/pkg/transformers/tend/converter.go @@ -0,0 +1,76 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "encoding/json" + "errors" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/pkg/geth" + "github.com/vulcanize/vulcanizedb/pkg/transformers/utilities" +) + +type Converter interface { + ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (TendEntity, error) + ToModel(entity TendEntity) (TendModel, error) +} + +type TendConverter struct{} + +func (c TendConverter) ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (TendEntity, error) { + entity := TendEntity{} + address := common.HexToAddress(contractAddress) + abi, err := geth.ParseAbi(contractAbi) + + if err != nil { + return entity, err + } + + contract := bind.NewBoundContract(address, abi, nil, nil, nil) + err = contract.UnpackLog(&entity, "Tend", ethLog) + if err != nil { + return entity, err + } + entity.TransactionIndex = ethLog.TxIndex + entity.Raw = ethLog + return entity, nil +} + +func (c TendConverter) ToModel(entity TendEntity) (TendModel, error) { + if entity.Id == nil { + return TendModel{}, errors.New("Tend log ID cannot be nil.") + } + + rawJson, err := json.Marshal(entity.Raw) + if err != nil { + return TendModel{}, err + } + era := utilities.ConvertNilToZeroTimeValue(entity.Era) + return TendModel{ + Id: utilities.ConvertNilToEmptyString(entity.Id.String()), + Lot: utilities.ConvertNilToEmptyString(entity.Lot.String()), + Bid: utilities.ConvertNilToEmptyString(entity.Bid.String()), + Guy: entity.Guy[:], + Tic: utilities.ConvertNilToEmptyString(entity.Tic.String()), + Era: time.Unix(era, 0), + TransactionIndex: entity.TransactionIndex, + Raw: string(rawJson), + }, nil +} diff --git a/pkg/transformers/tend/converter_test.go b/pkg/transformers/tend/converter_test.go new file mode 100644 index 00000000..f327cdf0 --- /dev/null +++ b/pkg/transformers/tend/converter_test.go @@ -0,0 +1,103 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend_test + +import ( + "encoding/json" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/core/types" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" + "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" +) + +var _ = Describe("Tend TendConverter", func() { + var converter tend.TendConverter + var emptyEntity tend.TendEntity + var testEntity tend.TendEntity + + BeforeEach(func() { + converter = tend.TendConverter{} + emptyEntity = tend.TendEntity{} + testEntity = test_data.TendEntity + }) + + Describe("ToEntity", func() { + It("converts a log to an entity", func() { + entity, err := converter.ToEntity(test_data.FlipAddress, shared.FlipperABI, test_data.TendLog) + + Expect(err).NotTo(HaveOccurred()) + Expect(entity).To(Equal(testEntity)) + }) + + It("returns an error if there is a failure in parsing the abi", func() { + malformedAbi := "bad" + entity, err := converter.ToEntity(test_data.FlipAddress, malformedAbi, test_data.TendLog) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid abi")) + Expect(entity).To(Equal(emptyEntity)) + }) + + It("returns an error if there is a failure unpacking the log", func() { + incompleteAbi := "[{}]" + entity, err := converter.ToEntity(test_data.FlipAddress, incompleteAbi, test_data.TendLog) + + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("abi: could not locate")) + Expect(entity).To(Equal(emptyEntity)) + }) + }) + + Describe("ToModel", func() { + It("converts an entity to a model", func() { + model, err := converter.ToModel(testEntity) + + Expect(err).NotTo(HaveOccurred()) + Expect(model).To(Equal(test_data.TendModel)) + }) + + It("handles nil values", func() { + emptyEntity.Id = big.NewInt(1) + emptyLog, err := json.Marshal(types.Log{}) + Expect(err).NotTo(HaveOccurred()) + expectedModel := tend.TendModel{ + Id: "1", + Lot: "", + Bid: "", + Guy: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + Tic: "", + Era: time.Unix(0, 0), + Raw: string(emptyLog), + } + model, err := converter.ToModel(emptyEntity) + + Expect(err).NotTo(HaveOccurred()) + Expect(model).To(Equal(expectedModel)) + }) + + It("returns an error if the log Id is nil", func() { + model, err := converter.ToModel(emptyEntity) + + Expect(err).To(HaveOccurred()) + Expect(model).To(Equal(tend.TendModel{})) + }) + }) +}) diff --git a/pkg/transformers/tend/entity.go b/pkg/transformers/tend/entity.go new file mode 100644 index 00000000..526ecc9b --- /dev/null +++ b/pkg/transformers/tend/entity.go @@ -0,0 +1,33 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" +) + +type TendEntity struct { + Id *big.Int + Lot *big.Int + Bid *big.Int + Guy common.Address + Tic *big.Int + Era *big.Int + TransactionIndex uint + Raw types.Log +} diff --git a/pkg/transformers/tend/integration_test.go b/pkg/transformers/tend/integration_test.go new file mode 100644 index 00000000..f1d8a193 --- /dev/null +++ b/pkg/transformers/tend/integration_test.go @@ -0,0 +1,86 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend_test + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/geth" + "github.com/vulcanize/vulcanizedb/pkg/geth/client" + rpc2 "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc" + "github.com/vulcanize/vulcanizedb/pkg/geth/node" + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" + "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" + "github.com/vulcanize/vulcanizedb/test_config" +) + +// These test are pending either being able to emit a Tend event on a Ganache test chain or until the contracts are deployed to Kovan. +var _ = XDescribe("Integration tests", func() { + It("Fetches Tend event logs from a local test chain", func() { + ipcPath := test_config.TestClient.IPCPath + + rawRpcClient, err := rpc.Dial(ipcPath) + Expect(err).NotTo(HaveOccurred()) + + rpcClient := client.NewRpcClient(rawRpcClient, ipcPath) + ethClient := ethclient.NewClient(rawRpcClient) + blockChainClient := client.NewEthClient(ethClient) + realNode := node.MakeNode(rpcClient) + transactionConverter := rpc2.NewRpcTransactionConverter(ethClient) + realBlockChain := geth.NewBlockChain(blockChainClient, realNode, transactionConverter) + realFetcher := shared.NewFetcher(realBlockChain) + topic0 := common.HexToHash(shared.TendSignature) + topics := [][]common.Hash{{topic0}} + + result, err := realFetcher.FetchLogs(test_data.FlipAddress, topics, test_data.FlipKickBlockNumber) + Expect(err).NotTo(HaveOccurred()) + + Expect(len(result) > 0).To(BeTrue()) + Expect(result[0].Address).To(Equal(test_data.EthFlipKickLog.Address)) + Expect(result[0].TxHash).To(Equal(test_data.EthFlipKickLog.TxHash)) + Expect(result[0].BlockNumber).To(Equal(test_data.EthFlipKickLog.BlockNumber)) + Expect(result[0].Topics).To(Equal(test_data.EthFlipKickLog.Topics)) + Expect(result[0].Index).To(Equal(test_data.EthFlipKickLog.Index)) + }) + + It("unpacks an event log", func() { + address := common.HexToAddress(test_data.FlipAddress) + abi, err := geth.ParseAbi(shared.FlipperABI) + Expect(err).NotTo(HaveOccurred()) + + contract := bind.NewBoundContract(address, abi, nil, nil, nil) + entity := tend.TendEntity{} + + var eventLog = test_data.TendLog + + err = contract.UnpackLog(&entity, "Tend", eventLog) + Expect(err).NotTo(HaveOccurred()) + + expectedEntity := test_data.TendEntity + Expect(entity.Id).To(Equal(expectedEntity.Id)) + Expect(entity.Lot).To(Equal(expectedEntity.Lot)) + Expect(entity.Bid).To(Equal(expectedEntity.Bid)) + Expect(entity.Guy).To(Equal(expectedEntity.Guy)) + Expect(entity.Tic).To(Equal(expectedEntity.Tic)) + Expect(entity.Era).To(Equal(expectedEntity.Era)) + Expect(entity.Raw).To(Equal(expectedEntity.Raw)) + }) +}) diff --git a/pkg/transformers/tend/model.go b/pkg/transformers/tend/model.go new file mode 100644 index 00000000..45a51a5a --- /dev/null +++ b/pkg/transformers/tend/model.go @@ -0,0 +1,30 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "time" +) + +type TendModel struct { + Id string + Lot string + Bid string + Guy []byte + Tic string + Era time.Time + TransactionIndex uint `db:"tx_idx"` + Raw string `db:"raw_log"` +} diff --git a/pkg/transformers/tend/repository.go b/pkg/transformers/tend/repository.go new file mode 100644 index 00000000..21a5f5ff --- /dev/null +++ b/pkg/transformers/tend/repository.go @@ -0,0 +1,61 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" +) + +type Repository interface { + Create(headerId int64, tend TendModel) error + MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) +} + +type TendRepository struct { + DB *postgres.DB +} + +func NewTendRepository(db *postgres.DB) TendRepository { + return TendRepository{DB: db} +} + +func (r TendRepository) Create(headerId int64, tend TendModel) error { + _, err := r.DB.Exec( + `INSERT into maker.tend (header_id, id, lot, bid, guy, tic, era, tx_idx, raw_log) + VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9)`, + headerId, tend.Id, tend.Lot, tend.Bid, tend.Guy, tend.Tic, tend.Era, tend.TransactionIndex, tend.Raw, + ) + + return err +} + +func (r TendRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { + var result []core.Header + err := r.DB.Select( + &result, + `SELECT headers.id, headers.block_number FROM headers + LEFT JOIN maker.tend on headers.id = header_id + WHERE header_id ISNULL + AND headers.block_number >= $1 + AND headers.block_number <= $2 + AND headers.eth_node_fingerprint = $3`, + startingBlockNumber, + endingBlockNumber, + r.DB.Node.ID, + ) + + return result, err +} diff --git a/pkg/transformers/tend/repository_test.go b/pkg/transformers/tend/repository_test.go new file mode 100644 index 00000000..a9bc3e9c --- /dev/null +++ b/pkg/transformers/tend/repository_test.go @@ -0,0 +1,161 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend_test + +import ( + "math/rand" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" + "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" + "github.com/vulcanize/vulcanizedb/test_config" +) + +var _ = Describe("TendRepository", func() { + var db *postgres.DB + var tendRepository tend.TendRepository + var headerRepository repositories.HeaderRepository + var headerId int64 + var err error + + BeforeEach(func() { + node := test_config.NewTestNode() + db = test_config.NewTestDB(node) + test_config.CleanTestDB(db) + + headerRepository = repositories.NewHeaderRepository(db) + headerId, err = headerRepository.CreateOrUpdateHeader(core.Header{}) + Expect(err).NotTo(HaveOccurred()) + + tendRepository = tend.NewTendRepository(db) + }) + + Describe("Create", func() { + It("persists a tend record", func() { + err := tendRepository.Create(headerId, test_data.TendModel) + Expect(err).NotTo(HaveOccurred()) + + var count int + err = db.QueryRow(`SELECT count(*) from maker.tend`).Scan(&count) + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(1)) + + dbResult := tend.TendModel{} + err = db.Get(&dbResult, `SELECT id, lot, bid, guy, tic, era, tx_idx, raw_log FROM maker.tend WHERE header_id = $1`, headerId) + Expect(err).NotTo(HaveOccurred()) + + Expect(dbResult.Id).To(Equal(test_data.TendModel.Id)) + Expect(dbResult.Lot).To(Equal(test_data.TendModel.Lot)) + Expect(dbResult.Bid).To(Equal(test_data.TendModel.Bid)) + Expect(dbResult.Guy).To(Equal(test_data.TendModel.Guy)) + Expect(dbResult.Tic).To(Equal(test_data.TendModel.Tic)) + Expect(dbResult.Era.Equal(test_data.TendModel.Era)).To(BeTrue()) + Expect(dbResult.TransactionIndex).To(Equal(test_data.TendModel.TransactionIndex)) + Expect(dbResult.Raw).To(MatchJSON(test_data.RawJson)) + }) + + It("returns an error if inserting a tend record fails", func() { + err := tendRepository.Create(headerId, test_data.TendModel) + Expect(err).NotTo(HaveOccurred()) + + err = tendRepository.Create(headerId, test_data.TendModel) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint")) + }) + + It("deletes the tend record if its corresponding header record is deleted", func() { + err := tendRepository.Create(headerId, test_data.TendModel) + Expect(err).NotTo(HaveOccurred()) + + var count int + err = db.QueryRow(`SELECT count(*) from maker.tend`).Scan(&count) + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(1)) + + _, err = db.Exec(`DELETE FROM headers where id = $1`, headerId) + Expect(err).NotTo(HaveOccurred()) + + err = db.QueryRow(`SELECT count(*) from maker.tend`).Scan(&count) + Expect(err).NotTo(HaveOccurred()) + Expect(count).To(Equal(0)) + }) + }) + + Describe("MissingHeaders", func() { + var tendBlockNumber int64 + var startingBlockNumber int64 + var endingBlockNumber int64 + var outOfRangeBlockNumber int64 + + BeforeEach(func() { + tendBlockNumber = rand.Int63() + startingBlockNumber = tendBlockNumber - 1 + endingBlockNumber = tendBlockNumber + 1 + outOfRangeBlockNumber = tendBlockNumber + 2 + }) + + It("returns headers for which there isn't an associated flip_kick record", func() { + var headerIds []int64 + + for _, number := range []int64{startingBlockNumber, tendBlockNumber, endingBlockNumber, outOfRangeBlockNumber} { + headerId, err := headerRepository.CreateOrUpdateHeader(core.Header{BlockNumber: number}) + Expect(err).NotTo(HaveOccurred()) + headerIds = append(headerIds, headerId) + } + + err = tendRepository.Create(headerIds[1], test_data.TendModel) + Expect(err).NotTo(HaveOccurred()) + + headers, err := tendRepository.MissingHeaders(startingBlockNumber, endingBlockNumber) + Expect(err).NotTo(HaveOccurred()) + Expect(len(headers)).To(Equal(2)) + Expect(headers[0].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber))) + Expect(headers[1].BlockNumber).To(Or(Equal(startingBlockNumber), Equal(endingBlockNumber))) + }) + + It("only returns missing headers for the current node", func() { + var headerIds []int64 + node2 := core.Node{} + db2 := test_config.NewTestDB(node2) + headerRepository2 := repositories.NewHeaderRepository(db2) + tendRepository2 := tend.NewTendRepository(db2) + + for _, number := range []int64{startingBlockNumber, tendBlockNumber, endingBlockNumber} { + headerId, err := headerRepository.CreateOrUpdateHeader(core.Header{BlockNumber: number}) + Expect(err).NotTo(HaveOccurred()) + headerIds = append(headerIds, headerId) + + headerRepository2.CreateOrUpdateHeader(core.Header{BlockNumber: number}) + Expect(err).NotTo(HaveOccurred()) + } + + err = tendRepository.Create(headerIds[1], test_data.TendModel) + Expect(err).NotTo(HaveOccurred()) + + node1MissingHeaders, err := tendRepository.MissingHeaders(startingBlockNumber, endingBlockNumber) + Expect(err).NotTo(HaveOccurred()) + Expect(len(node1MissingHeaders)).To(Equal(2)) + + node2MissingHeaders, err := tendRepository2.MissingHeaders(startingBlockNumber, endingBlockNumber) + Expect(err).NotTo(HaveOccurred()) + Expect(len(node2MissingHeaders)).To(Equal(3)) + }) + }) +}) diff --git a/pkg/transformers/tend/tend_suite_test.go b/pkg/transformers/tend/tend_suite_test.go new file mode 100644 index 00000000..77b4096f --- /dev/null +++ b/pkg/transformers/tend/tend_suite_test.go @@ -0,0 +1,19 @@ +package tend_test + +import ( + "io/ioutil" + "log" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestTend(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Tend Suite") +} + +var _ = BeforeSuite(func() { + log.SetOutput(ioutil.Discard) +}) diff --git a/pkg/transformers/tend/transformer.go b/pkg/transformers/tend/transformer.go new file mode 100644 index 00000000..90a6858d --- /dev/null +++ b/pkg/transformers/tend/transformer.go @@ -0,0 +1,85 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "log" + + "github.com/ethereum/go-ethereum/common" + + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres" + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" +) + +type TendTransformer struct { + Repository Repository + Fetcher shared.LogFetcher + Converter Converter + Config shared.TransformerConfig +} + +type TendTransformerInitializer struct { + Config shared.TransformerConfig +} + +func (i TendTransformerInitializer) NewTendTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer { + fetcher := shared.NewFetcher(blockChain) + repository := NewTendRepository(db) + transformer := TendTransformer{ + Fetcher: fetcher, + Repository: repository, + Converter: TendConverter{}, + Config: i.Config, + } + + return transformer +} + +func (t TendTransformer) Execute() error { + config := t.Config + topics := [][]common.Hash{{common.HexToHash(shared.TendSignature)}} + + missingHeaders, err := t.Repository.MissingHeaders(config.StartingBlockNumber, config.EndingBlockNumber) + if err != nil { + log.Println("Error fetching missing headers:", err) + return err + } + + for _, header := range missingHeaders { + ethLogs, err := t.Fetcher.FetchLogs(config.ContractAddresses, topics, header.BlockNumber) + if err != nil { + log.Println("Error fetching matching logs:", err) + return err + } + + for _, ethLog := range ethLogs { + entity, err := t.Converter.ToEntity(config.ContractAddresses, config.ContractAbi, ethLog) + model, err := t.Converter.ToModel(entity) + if err != nil { + log.Println("Error converting logs:", err) + return err + } + + err = t.Repository.Create(header.Id, model) + if err != nil { + log.Println("Error persisting tend record:", err) + return err + } + } + } + + return nil +} diff --git a/pkg/transformers/tend/transformer_test.go b/pkg/transformers/tend/transformer_test.go new file mode 100644 index 00000000..d019fbb8 --- /dev/null +++ b/pkg/transformers/tend/transformer_test.go @@ -0,0 +1,141 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend_test + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/common" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/fakes" + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" + "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" + "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks" + tend_mocks "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks/tend" +) + +var _ = Describe("Tend Transformer", func() { + var repository tend_mocks.MockTendRepository + var fetcher mocks.MockLogFetcher + var converter tend_mocks.MockTendConverter + var transformer tend.TendTransformer + var blockNumber1 = rand.Int63() + var blockNumber2 = rand.Int63() + + BeforeEach(func() { + repository = tend_mocks.MockTendRepository{} + fetcher = mocks.MockLogFetcher{} + converter = tend_mocks.MockTendConverter{} + + transformer = tend.TendTransformer{ + Repository: &repository, + Fetcher: &fetcher, + Converter: &converter, + Config: tend.TendConfig, + } + }) + + It("gets missing headers for blocks in the configured range", func() { + err := transformer.Execute() + + Expect(err).NotTo(HaveOccurred()) + Expect(repository.PassedStartingBlockNumber).To(Equal(tend.TendConfig.StartingBlockNumber)) + Expect(repository.PassedEndingBlockNumber).To(Equal(tend.TendConfig.EndingBlockNumber)) + }) + + It("returns an error if it fails to get missing headers", func() { + repository.SetMissingHeadersErr(fakes.FakeError) + err := transformer.Execute() + + Expect(err).To(HaveOccurred()) + }) + + It("fetches eth logs for each missing header", func() { + repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1}, {BlockNumber: blockNumber2}}) + expectedTopics := [][]common.Hash{{common.HexToHash(shared.TendSignature)}} + err := transformer.Execute() + + Expect(err).NotTo(HaveOccurred()) + Expect(fetcher.FetchedBlocks).To(Equal([]int64{blockNumber1, blockNumber2})) + Expect(fetcher.FetchedTopics).To(Equal(expectedTopics)) + Expect(fetcher.FetchedContractAddress).To(Equal(test_data.FlipAddress)) + }) + + It("returns an error if fetching logs fails", func() { + repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}}) + fetcher.SetFetcherError(fakes.FakeError) + err := transformer.Execute() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("converts an eth log to an Entity", func() { + repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}}) + fetcher.SetFetchedLogs([]types.Log{test_data.TendLog}) + err := transformer.Execute() + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.ConverterContract).To(Equal(tend.TendConfig.ContractAddresses)) + Expect(converter.ConverterAbi).To(Equal(tend.TendConfig.ContractAbi)) + Expect(converter.LogsToConvert).To(Equal([]types.Log{test_data.TendLog})) + }) + + It("returns an error if converter fails", func() { + repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}}) + fetcher.SetFetchedLogs([]types.Log{test_data.TendLog}) + converter.SetConverterError(fakes.FakeError) + err := transformer.Execute() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) + + It("returns an error if converter fails", func() { + repository.SetMissingHeaders([]core.Header{{BlockNumber: 1}}) + fetcher.SetFetchedLogs([]types.Log{test_data.TendLog}) + err := transformer.Execute() + + Expect(err).NotTo(HaveOccurred()) + Expect(converter.EntitiesToConvert).To(ContainElement(test_data.TendEntity)) + }) + + It("persists the tend record", func() { + headerId := int64(1) + repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1, Id: headerId}}) + fetcher.SetFetchedLogs([]types.Log{test_data.TendLog}) + + err := transformer.Execute() + + Expect(err).NotTo(HaveOccurred()) + Expect(repository.PassedHeaderID).To(Equal(headerId)) + Expect(repository.PassedTendModel).To(Equal(test_data.TendModel)) + }) + + It("returns error if persisting tend record fails", func() { + repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1}}) + fetcher.SetFetchedLogs([]types.Log{test_data.TendLog}) + repository.SetCreateError(fakes.FakeError) + err := transformer.Execute() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fakes.FakeError)) + }) +}) diff --git a/pkg/transformers/test_data/constants.go b/pkg/transformers/test_data/constants.go new file mode 100644 index 00000000..df50b13d --- /dev/null +++ b/pkg/transformers/test_data/constants.go @@ -0,0 +1,27 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package test_data + +var ( + FlipAddress = "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d" + FlipKickTransactionHash = "0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191" + FlipKickData = "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000008cb6176addcca2e1d1ffe21bee464b72ee4cd8d00000000000000000000000038219779a699d67d7e7740b8c8f43d3e2dae218266616b6520696c6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d922894153be9eef7b7218dc565d1d0ce2a09200000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000005b69b8e7000000000000000000000000000000000000000000000000000000005b607e670000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca0000000000000000000000000000000000000000000000000000000000000032" + FlipKickBlockHash = "0x32f8b12023b3a1b4c73f9a46da976931b0355714ada8b8044ebcb2cd295751a9" + FlipKickBlockNumber = int64(10) + TendData = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000003200000000000000000000000064d922894153be9eef7b7218dc565d1d0ce2a0920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005b6db414" + TendTransactionHash = "0xadeddf804e0fef88b6145807df063c538c9942df2725a0458a084900c0fbf5e9" + TendBlockHash = "0xdd6238b841c8cf4d91b05da7540b7f0851176fcc8477cdc4b75c93e28dfe0a88" + TendBlockNumber = int64(11) +) diff --git a/pkg/transformers/test_data/flip_kick.go b/pkg/transformers/test_data/flip_kick.go index 0d9001ac..ce62eaee 100644 --- a/pkg/transformers/test_data/flip_kick.go +++ b/pkg/transformers/test_data/flip_kick.go @@ -15,21 +15,16 @@ package test_data import ( + "encoding/json" + "math/big" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" - "math/big" "github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick" - "time" -) - -var ( - TemporaryFlipBlockNumber = int64(10) - TemporaryFlipAddress = "0x08cb6176addcca2e1d1ffe21bee464b72ee4cd8d" - TemporaryFlipKickBlockHash = "0x32f8b12023b3a1b4c73f9a46da976931b0355714ada8b8044ebcb2cd295751a9" - TemporaryFlipKickData = "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000008cb6176addcca2e1d1ffe21bee464b72ee4cd8d00000000000000000000000038219779a699d67d7e7740b8c8f43d3e2dae218266616b6520696c6b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d922894153be9eef7b7218dc565d1d0ce2a09200000000000000000000000007fa9ef6609ca7921112231f8f195138ebba2977000000000000000000000000000000000000000000000000000000005b69b8e7000000000000000000000000000000000000000000000000000000005b607e670000000000000000000000007340e006f4135ba6970d43bf43d88dcad4e7a8ca0000000000000000000000000000000000000000000000000000000000000032" - TemporaryFlipKickTransaction = "0x6b155a55fd77b751195deeebf7abfd8691ca01ee588817a920f19d5b27f65191" + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" ) var idString = "1" @@ -48,15 +43,17 @@ var era = int64(1533050471) var lad = "0x7340e006f4135ba6970d43bf43d88dcad4e7a8ca" var tabString = "50" var tab, _ = new(big.Int).SetString(tabString, 10) +var rawLogJson, _ = json.Marshal(EthFlipKickLog) +var rawLogString = string(rawLogJson) var EthFlipKickLog = types.Log{ - Address: common.HexToAddress(TemporaryFlipAddress), - Topics: []common.Hash{common.HexToHash(flip_kick.FlipKickSignature)}, - Data: hexutil.MustDecode(TemporaryFlipKickData), - BlockNumber: uint64(TemporaryFlipBlockNumber), - TxHash: common.HexToHash(TemporaryFlipKickTransaction), + Address: common.HexToAddress(FlipAddress), + Topics: []common.Hash{common.HexToHash(shared.FlipKickSignature)}, + Data: hexutil.MustDecode(FlipKickData), + BlockNumber: uint64(FlipKickBlockNumber), + TxHash: common.HexToHash(FlipKickTransactionHash), TxIndex: 0, - BlockHash: common.HexToHash(TemporaryFlipKickBlockHash), + BlockHash: common.HexToHash(FlipKickBlockHash), Index: 0, Removed: false, } @@ -74,6 +71,7 @@ var FlipKickEntity = flip_kick.FlipKickEntity{ Era: big.NewInt(era), Lad: common.HexToAddress(lad), Tab: tab, + Raw: EthFlipKickLog, } var FlipKickModel = flip_kick.FlipKickModel{ @@ -89,6 +87,7 @@ var FlipKickModel = flip_kick.FlipKickModel{ Era: time.Unix(era, 0), Lad: lad, Tab: tabString, + Raw: rawLogString, } type FlipKickDBRow struct { diff --git a/pkg/transformers/test_data/mocks/tend/converter.go b/pkg/transformers/test_data/mocks/tend/converter.go new file mode 100644 index 00000000..89e41e53 --- /dev/null +++ b/pkg/transformers/test_data/mocks/tend/converter.go @@ -0,0 +1,46 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" + "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data" +) + +type MockTendConverter struct { + ConverterContract string + ConverterAbi string + LogsToConvert []types.Log + EntitiesToConvert []tend.TendEntity + ConverterError error +} + +func (c *MockTendConverter) ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (tend.TendEntity, error) { + c.ConverterContract = contractAddress + c.ConverterAbi = contractAbi + c.LogsToConvert = append(c.LogsToConvert, ethLog) + return test_data.TendEntity, c.ConverterError +} + +func (c *MockTendConverter) ToModel(entity tend.TendEntity) (tend.TendModel, error) { + c.EntitiesToConvert = append(c.EntitiesToConvert, entity) + return test_data.TendModel, c.ConverterError +} + +func (c *MockTendConverter) SetConverterError(err error) { + c.ConverterError = err +} diff --git a/pkg/transformers/test_data/mocks/tend/repository.go b/pkg/transformers/test_data/mocks/tend/repository.go new file mode 100644 index 00000000..7c2e691a --- /dev/null +++ b/pkg/transformers/test_data/mocks/tend/repository.go @@ -0,0 +1,54 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package tend + +import ( + "github.com/vulcanize/vulcanizedb/pkg/core" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" +) + +type MockTendRepository struct { + createError error + PassedEndingBlockNumber int64 + PassedHeaderID int64 + PassedStartingBlockNumber int64 + PassedTendModel tend.TendModel + missingHeaders []core.Header + missingHeadersErr error +} + +func (repository *MockTendRepository) Create(headerId int64, tend tend.TendModel) error { + repository.PassedHeaderID = headerId + repository.PassedTendModel = tend + return repository.createError +} + +func (repository *MockTendRepository) SetCreateError(err error) { + repository.createError = err +} + +func (repository *MockTendRepository) SetMissingHeadersErr(err error) { + repository.missingHeadersErr = err +} + +func (repository *MockTendRepository) SetMissingHeaders(headers []core.Header) { + repository.missingHeaders = headers +} + +func (repository *MockTendRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) { + repository.PassedStartingBlockNumber = startingBlockNumber + repository.PassedEndingBlockNumber = endingBlockNumber + return repository.missingHeaders, repository.missingHeadersErr +} diff --git a/pkg/transformers/test_data/tend.go b/pkg/transformers/test_data/tend.go new file mode 100644 index 00000000..40a191a6 --- /dev/null +++ b/pkg/transformers/test_data/tend.go @@ -0,0 +1,72 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package test_data + +import ( + "encoding/json" + "math/big" + "strconv" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + + "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" +) + +var tendLot = big.NewInt(100) +var tendBid = big.NewInt(50) +var tendGuy = common.HexToAddress("0x64d922894153be9eef7b7218dc565d1d0ce2a092") +var tic = new(big.Int).SetBytes([]byte{0}) +var tendEra = big.NewInt(1533916180) +var RawJson, _ = json.Marshal(TendLog) +var rawString = string(RawJson) + +var TendLog = types.Log{ + Address: common.HexToAddress(FlipAddress), + Topics: []common.Hash{common.HexToHash(shared.TendSignature)}, + Data: hexutil.MustDecode(TendData), + BlockNumber: uint64(TendBlockNumber), + TxHash: common.HexToHash(TendTransactionHash), + TxIndex: 1, + BlockHash: common.HexToHash(TendBlockHash), + Index: 0, + Removed: false, +} + +var tendId = int64(1) +var TendEntity = tend.TendEntity{ + Id: big.NewInt(tendId), + Lot: tendLot, + Bid: tendBid, + Guy: tendGuy, + Tic: tic, + Era: tendEra, + TransactionIndex: TendLog.TxIndex, + Raw: TendLog, +} + +var TendModel = tend.TendModel{ + Id: strconv.FormatInt(tendId, 10), + Lot: tendLot.String(), + Bid: tendBid.String(), + Guy: tendGuy[:], + Tic: tic.String(), + Era: time.Unix(tendEra.Int64(), 0), + TransactionIndex: TendLog.TxIndex, + Raw: rawString, +} diff --git a/pkg/transformers/transformers.go b/pkg/transformers/transformers.go index e554c429..ad53de4a 100644 --- a/pkg/transformers/transformers.go +++ b/pkg/transformers/transformers.go @@ -19,6 +19,7 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/transformers/frob" "github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds" "github.com/vulcanize/vulcanizedb/pkg/transformers/shared" + "github.com/vulcanize/vulcanizedb/pkg/transformers/tend" ) func TransformerInitializers() []shared.TransformerInitializer { @@ -28,9 +29,13 @@ func TransformerInitializers() []shared.TransformerInitializer { frobTransformerInitializer := frob.FrobTransformerInitializer{Config: frobConfig} priceFeedConfig := price_feeds.PriceFeedConfig priceFeedTransformerInitializer := price_feeds.PriceFeedTransformerInitializer{Config: priceFeedConfig} + tendConfig := tend.TendConfig + tendTransformerInitializer := tend.TendTransformerInitializer{Config: tendConfig} + return []shared.TransformerInitializer{ flipKickTransformerInitializer.NewFlipKickTransformer, frobTransformerInitializer.NewFrobTransformer, priceFeedTransformerInitializer.NewPriceFeedTransformer, + tendTransformerInitializer.NewTendTransformer, } } diff --git a/pkg/transformers/utilities/utils.go b/pkg/transformers/utilities/utils.go new file mode 100644 index 00000000..6d14caa8 --- /dev/null +++ b/pkg/transformers/utilities/utils.go @@ -0,0 +1,33 @@ +// Copyright 2018 Vulcanize +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utilities + +import "math/big" + +func ConvertNilToZeroTimeValue(value *big.Int) int64 { + if value == nil { + return int64(0) + } else { + return value.Int64() + } +} + +func ConvertNilToEmptyString(value string) string { + if value == "" { + return "" + } else { + return value + } +}