commit
807b7accd6
@ -27,6 +27,9 @@ Vulcanize DB is a set of tools that make it easier for developers to write appli
|
||||
|
||||
* See below for configuring additional environments
|
||||
|
||||
## Create a migration file (up and down)
|
||||
1. ./script/create_migrate create_bite_table
|
||||
|
||||
## Configuration
|
||||
- To use a local Ethereum node, copy `environments/public.toml.example` to
|
||||
`environments/public.toml` and update the `ipcPath` and `levelDbPath`.
|
||||
|
1
db/migrations/1534295713_create_bite_table.down.sql
Normal file
1
db/migrations/1534295713_create_bite_table.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE maker.bite;
|
14
db/migrations/1534295713_create_bite_table.up.sql
Normal file
14
db/migrations/1534295713_create_bite_table.up.sql
Normal file
@ -0,0 +1,14 @@
|
||||
CREATE TABLE maker.bite (
|
||||
id SERIAL PRIMARY KEY,
|
||||
header_id INTEGER NOT NULL REFERENCES headers (id) ON DELETE CASCADE,
|
||||
ilk bytea,
|
||||
lad bytea,
|
||||
ink VARCHAR,
|
||||
art VARCHAR,
|
||||
iArt VARCHAR,
|
||||
tab NUMERIC,
|
||||
flip VARCHAR,
|
||||
tx_idx INTEGER NOT NUll,
|
||||
raw_log JSONB,
|
||||
UNIQUE (header_id, tx_idx)
|
||||
)
|
@ -40,6 +40,45 @@ SET default_tablespace = '';
|
||||
|
||||
SET default_with_oids = false;
|
||||
|
||||
--
|
||||
-- Name: bite; Type: TABLE; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE maker.bite (
|
||||
id integer NOT NULL,
|
||||
header_id integer NOT NULL,
|
||||
ilk bytea,
|
||||
lad bytea,
|
||||
ink character varying,
|
||||
art character varying,
|
||||
iart character varying,
|
||||
tab numeric,
|
||||
flip character varying,
|
||||
tx_idx integer NOT NULL,
|
||||
raw_log jsonb
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bite_id_seq; Type: SEQUENCE; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE maker.bite_id_seq
|
||||
AS integer
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: bite_id_seq; Type: SEQUENCE OWNED BY; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE maker.bite_id_seq OWNED BY maker.bite.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: flip_kick; Type: TABLE; Schema: maker; Owner: -
|
||||
--
|
||||
@ -564,6 +603,13 @@ CREATE VIEW public.watched_event_logs AS
|
||||
WHERE ((((log_filters.topic0)::text = (logs.topic0)::text) OR (log_filters.topic0 IS NULL)) AND (((log_filters.topic1)::text = (logs.topic1)::text) OR (log_filters.topic1 IS NULL)) AND (((log_filters.topic2)::text = (logs.topic2)::text) OR (log_filters.topic2 IS NULL)) AND (((log_filters.topic3)::text = (logs.topic3)::text) OR (log_filters.topic3 IS NULL)));
|
||||
|
||||
|
||||
--
|
||||
-- Name: bite id; Type: DEFAULT; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY maker.bite ALTER COLUMN id SET DEFAULT nextval('maker.bite_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: flip_kick db_id; Type: DEFAULT; Schema: maker; Owner: -
|
||||
--
|
||||
@ -655,6 +701,22 @@ ALTER TABLE ONLY public.transactions ALTER COLUMN id SET DEFAULT nextval('public
|
||||
ALTER TABLE ONLY public.watched_contracts ALTER COLUMN contract_id SET DEFAULT nextval('public.watched_contracts_contract_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bite bite_header_id_tx_idx_key; Type: CONSTRAINT; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY maker.bite
|
||||
ADD CONSTRAINT bite_header_id_tx_idx_key UNIQUE (header_id, tx_idx);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bite bite_pkey; Type: CONSTRAINT; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY maker.bite
|
||||
ADD CONSTRAINT bite_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: flip_kick flip_kick_id_key; Type: CONSTRAINT; Schema: maker; Owner: -
|
||||
--
|
||||
@ -850,6 +912,14 @@ CREATE INDEX tx_from_index ON public.transactions USING btree (tx_from);
|
||||
CREATE INDEX tx_to_index ON public.transactions USING btree (tx_to);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bite bite_header_id_fkey; Type: FK CONSTRAINT; Schema: maker; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY maker.bite
|
||||
ADD CONSTRAINT bite_header_id_fkey FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- Name: flip_kick flip_kick_header_id_fkey; Type: FK CONSTRAINT; Schema: maker; Owner: -
|
||||
--
|
||||
|
27
pkg/transformers/bite/bite_suite_test.go
Normal file
27
pkg/transformers/bite/bite_suite_test.go
Normal file
@ -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 bite_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestBite(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Bite Suite")
|
||||
}
|
29
pkg/transformers/bite/config.go
Normal file
29
pkg/transformers/bite/config.go
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 bite
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
|
||||
)
|
||||
|
||||
var BiteConfig = shared.TransformerConfig{
|
||||
ContractAddresses: "0xe0f0fa6982c59d8aa4ae0134bfe048327bd788cacf758b643ca41f055ffce76c", //this is a temporary address deployed locally
|
||||
ContractAbi: BiteABI,
|
||||
Topics: []string{BiteSignature},
|
||||
StartingBlockNumber: 0,
|
||||
EndingBlockNumber: 100,
|
||||
}
|
22
pkg/transformers/bite/constants.go
Normal file
22
pkg/transformers/bite/constants.go
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 bite
|
||||
|
||||
var (
|
||||
BiteABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"vat\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"vow\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"flips\",\"outputs\":[{\"name\":\"ilk\",\"type\":\"bytes32\"},{\"name\":\"lad\",\"type\":\"bytes32\"},{\"name\":\"ink\",\"type\":\"uint256\"},{\"name\":\"tab\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"nflip\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"live\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"wards\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"ilks\",\"outputs\":[{\"name\":\"flip\",\"type\":\"address\"},{\"name\":\"chop\",\"type\":\"uint256\"},{\"name\":\"lump\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pit\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"vat_\",\"type\":\"address\"},{\"name\":\"pit_\",\"type\":\"address\"},{\"name\":\"vow_\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"ilk\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"lad\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"ink\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"art\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"tab\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"flip\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"iArt\",\"type\":\"uint256\"}],\"name\":\"Bite\",\"type\":\"event\"},{\"anonymous\":true,\"inputs\":[{\"indexed\":true,\"name\":\"sig\",\"type\":\"bytes4\"},{\"indexed\":true,\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"foo\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"bar\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"wad\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"fax\",\"type\":\"bytes\"}],\"name\":\"LogNote\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"name\":\"guy\",\"type\":\"address\"}],\"name\":\"rely\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"guy\",\"type\":\"address\"}],\"name\":\"deny\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"ilk\",\"type\":\"bytes32\"},{\"name\":\"what\",\"type\":\"bytes32\"},{\"name\":\"data\",\"type\":\"uint256\"}],\"name\":\"file\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"ilk\",\"type\":\"bytes32\"},{\"name\":\"what\",\"type\":\"bytes32\"},{\"name\":\"flip\",\"type\":\"address\"}],\"name\":\"file\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"ilk\",\"type\":\"bytes32\"},{\"name\":\"lad\",\"type\":\"bytes32\"}],\"name\":\"bite\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"n\",\"type\":\"uint256\"},{\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"flip\",\"outputs\":[{\"name\":\"id\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
|
||||
BiteSignature = "0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"
|
||||
)
|
84
pkg/transformers/bite/converter.go
Normal file
84
pkg/transformers/bite/converter.go
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 bite
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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) (BiteEntity, error)
|
||||
ToModel(flipKick BiteEntity) (BiteModel, error)
|
||||
}
|
||||
|
||||
type BiteConverter struct{}
|
||||
|
||||
func (BiteConverter) ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (BiteEntity, error) {
|
||||
entity := BiteEntity{}
|
||||
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, "Bite", ethLog)
|
||||
if err != nil {
|
||||
return entity, err
|
||||
}
|
||||
|
||||
entity.Raw = ethLog
|
||||
entity.TransactionIndex = ethLog.TxIndex
|
||||
|
||||
return entity, nil
|
||||
}
|
||||
func (converter BiteConverter) ToModel(entity BiteEntity) (BiteModel, error) {
|
||||
|
||||
id := entity.Id.String()
|
||||
ilk := entity.Ilk[:]
|
||||
lad := entity.Lad[:]
|
||||
ink := entity.Ink.String()
|
||||
art := entity.Art.String()
|
||||
iArt := entity.IArt.String()
|
||||
tab := entity.Tab.String()
|
||||
flip := entity.Flip.String()
|
||||
txIdx := entity.TransactionIndex
|
||||
rawLogJson, err := json.Marshal(entity.Raw)
|
||||
rawLogString := string(rawLogJson)
|
||||
if err != nil {
|
||||
return BiteModel{}, err
|
||||
}
|
||||
|
||||
return BiteModel{
|
||||
Id: utilities.ConvertNilToEmptyString(id),
|
||||
Ilk: ilk,
|
||||
Lad: lad,
|
||||
Ink: utilities.ConvertNilToEmptyString(ink),
|
||||
Art: utilities.ConvertNilToEmptyString(art),
|
||||
IArt: utilities.ConvertNilToEmptyString(iArt),
|
||||
Tab: utilities.ConvertNilToEmptyString(tab),
|
||||
Flip: utilities.ConvertNilToEmptyString(flip),
|
||||
TransactionIndex: txIdx,
|
||||
Raw: rawLogString,
|
||||
}, nil
|
||||
}
|
93
pkg/transformers/bite/converter_test.go
Normal file
93
pkg/transformers/bite/converter_test.go
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 bite_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Bite Converter", func() {
|
||||
var converter = bite.BiteConverter{}
|
||||
|
||||
Describe("ToEntity", func() {
|
||||
It("converts an eth log to a bite entity", func() {
|
||||
entity, err := converter.ToEntity(test_data.TemporaryBiteAddress, bite.BiteABI, test_data.EthBiteLog)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(entity.Ilk).To(Equal(test_data.BiteEntity.Ilk))
|
||||
Expect(entity.Lad).To(Equal(test_data.BiteEntity.Lad))
|
||||
Expect(entity.Ink).To(Equal(test_data.BiteEntity.Ink))
|
||||
Expect(entity.Art).To(Equal(test_data.BiteEntity.Art))
|
||||
Expect(entity.Tab).To(Equal(test_data.BiteEntity.Tab))
|
||||
Expect(entity.Flip).To(Equal(test_data.BiteEntity.Flip))
|
||||
Expect(entity.IArt).To(Equal(test_data.BiteEntity.IArt))
|
||||
Expect(entity.TransactionIndex).To(Equal(test_data.BiteEntity.TransactionIndex))
|
||||
Expect(entity.Raw).To(Equal(test_data.BiteEntity.Raw))
|
||||
})
|
||||
|
||||
It("returns an error if converting log to entity fails", func() {
|
||||
_, err := converter.ToEntity(test_data.TemporaryBiteAddress, "error abi", test_data.EthBiteLog)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("ToModel", func() {
|
||||
var emptyEntity = bite.BiteEntity{}
|
||||
|
||||
BeforeEach(func() {
|
||||
emptyEntity.Id = big.NewInt(1)
|
||||
})
|
||||
|
||||
It("converts an Entity to a Model", func() {
|
||||
model, err := converter.ToModel(test_data.BiteEntity)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(model).To(Equal(test_data.BiteModel))
|
||||
Expect(model.TransactionIndex).To(Equal(test_data.BiteModel.TransactionIndex))
|
||||
})
|
||||
|
||||
It("handles nil values", func() {
|
||||
emptyLog, err := json.Marshal(types.Log{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectedModel := bite.BiteModel{
|
||||
Id: "1",
|
||||
Ilk: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Lad: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Ink: "",
|
||||
Art: "",
|
||||
IArt: "",
|
||||
Tab: "",
|
||||
Flip: "",
|
||||
TransactionIndex: 0,
|
||||
Raw: string(emptyLog),
|
||||
}
|
||||
model, err := converter.ToModel(emptyEntity)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(model).To(Equal(expectedModel))
|
||||
})
|
||||
})
|
||||
})
|
33
pkg/transformers/bite/entity.go
Normal file
33
pkg/transformers/bite/entity.go
Normal file
@ -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 bite
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type BiteEntity struct {
|
||||
Id *big.Int
|
||||
Ilk [32]byte
|
||||
Lad [32]byte
|
||||
Ink *big.Int
|
||||
Art *big.Int
|
||||
Tab *big.Int
|
||||
Flip *big.Int
|
||||
IArt *big.Int
|
||||
TransactionIndex uint
|
||||
Raw types.Log
|
||||
}
|
83
pkg/transformers/bite/integration_test.go
Normal file
83
pkg/transformers/bite/integration_test.go
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 bite_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"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/bite"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
|
||||
"github.com/vulcanize/vulcanizedb/test_config"
|
||||
)
|
||||
|
||||
var _ = Describe("Integration tests", func() {
|
||||
XIt("Fetches bite 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(bite.BiteSignature)
|
||||
topics := [][]common.Hash{{topic0}}
|
||||
|
||||
result, err := realFetcher.FetchLogs(test_data.TemporaryBiteAddress, topics, int64(26))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(len(result) > 0).To(BeTrue())
|
||||
Expect(result[0].Address).To(Equal(common.HexToAddress(test_data.TemporaryBiteAddress)))
|
||||
Expect(result[0].TxHash).To(Equal(test_data.EthBiteLog.TxHash))
|
||||
Expect(result[0].BlockNumber).To(Equal(test_data.EthBiteLog.BlockNumber))
|
||||
Expect(result[0].Topics).To(Equal(test_data.EthBiteLog.Topics))
|
||||
Expect(result[0].Index).To(Equal(test_data.EthBiteLog.Index))
|
||||
})
|
||||
|
||||
It("unpacks an event log", func() {
|
||||
address := common.HexToAddress(test_data.TemporaryBiteAddress)
|
||||
abi, err := geth.ParseAbi(bite.BiteABI)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
contract := bind.NewBoundContract(address, abi, nil, nil, nil)
|
||||
entity := &bite.BiteEntity{}
|
||||
|
||||
var eventLog = test_data.EthBiteLog
|
||||
|
||||
err = contract.UnpackLog(entity, "Bite", eventLog)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
expectedEntity := test_data.BiteEntity
|
||||
Expect(entity.Art).To(Equal(expectedEntity.Art))
|
||||
Expect(entity.Ilk).To(Equal(expectedEntity.Ilk))
|
||||
Expect(entity.Ink).To(Equal(expectedEntity.Ink))
|
||||
})
|
||||
})
|
28
pkg/transformers/bite/model.go
Normal file
28
pkg/transformers/bite/model.go
Normal file
@ -0,0 +1,28 @@
|
||||
// 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 bite
|
||||
|
||||
type BiteModel struct {
|
||||
Id string
|
||||
Ilk []byte
|
||||
Lad []byte
|
||||
Ink string
|
||||
Art string
|
||||
IArt string
|
||||
Tab string
|
||||
Flip string
|
||||
TransactionIndex uint `db:"tx_idx"`
|
||||
Raw string `db:"raw_log"`
|
||||
}
|
49
pkg/transformers/bite/repository.go
Normal file
49
pkg/transformers/bite/repository.go
Normal file
@ -0,0 +1,49 @@
|
||||
package bite
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
Create(headerID int64, model BiteModel) error
|
||||
MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error)
|
||||
}
|
||||
|
||||
type BiteRepository struct {
|
||||
db *postgres.DB
|
||||
}
|
||||
|
||||
func NewBiteRepository(db *postgres.DB) Repository {
|
||||
return BiteRepository{db: db}
|
||||
}
|
||||
|
||||
func (repository BiteRepository) Create(headerID int64, model BiteModel) error {
|
||||
_, err := repository.db.Exec(
|
||||
`INSERT into maker.bite (header_id, id, ilk, lad, ink, art, iart, tab, flip, tx_idx, raw_log)
|
||||
VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
|
||||
headerID, model.Id, model.Ilk, model.Lad, model.Ink, model.Art, model.IArt, model.Tab, model.Flip, model.TransactionIndex, model.Raw,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (repository BiteRepository) MissingHeaders(startingBlockNumber int64, endingBlockNumber int64) ([]core.Header, error) {
|
||||
var result []core.Header
|
||||
err := repository.db.Select(
|
||||
&result,
|
||||
`SELECT headers.id, headers.block_number FROM headers
|
||||
LEFT JOIN maker.bite 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,
|
||||
repository.db.Node.ID,
|
||||
)
|
||||
return result, err
|
||||
}
|
135
pkg/transformers/bite/repository_test.go
Normal file
135
pkg/transformers/bite/repository_test.go
Normal file
@ -0,0 +1,135 @@
|
||||
// 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 bite_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"database/sql"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
|
||||
"github.com/vulcanize/vulcanizedb/test_config"
|
||||
)
|
||||
|
||||
var _ = Describe("Bite repository", func() {
|
||||
Describe("Create", func() {
|
||||
It("persists a bite record", func() {
|
||||
node := core.Node{}
|
||||
db := test_config.NewTestDB(node)
|
||||
test_config.CleanTestDB(db)
|
||||
headerRepository := repositories.NewHeaderRepository(db)
|
||||
headerID, err := headerRepository.CreateOrUpdateHeader(core.Header{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
biteRepository := bite.NewBiteRepository(db)
|
||||
|
||||
err = biteRepository.Create(headerID, test_data.BiteModel)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
var dbBite bite.BiteModel
|
||||
err = db.Get(&dbBite, `SELECT id, ilk, lad, ink, art, tab, flip, tx_idx, raw_log FROM maker.bite WHERE header_id = $1`, headerID)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(dbBite.Id).To(Equal(test_data.BiteModel.Id))
|
||||
Expect(dbBite.Ilk).To(Equal(test_data.BiteModel.Ilk))
|
||||
Expect(dbBite.Lad).To(Equal(test_data.BiteModel.Lad))
|
||||
Expect(dbBite.Art).To(Equal(test_data.BiteModel.Art))
|
||||
Expect(dbBite.Tab).To(Equal(test_data.BiteModel.Tab))
|
||||
Expect(dbBite.Flip).To(Equal(test_data.BiteModel.Flip))
|
||||
Expect(dbBite.TransactionIndex).To(Equal(test_data.BiteModel.TransactionIndex))
|
||||
Expect(dbBite.Raw).To(MatchJSON(test_data.BiteModel.Raw))
|
||||
})
|
||||
|
||||
It("does not duplicate bite events", func() {
|
||||
node := core.Node{}
|
||||
db := test_config.NewTestDB(node)
|
||||
test_config.CleanTestDB(db)
|
||||
headerRepository := repositories.NewHeaderRepository(db)
|
||||
headerID, err := headerRepository.CreateOrUpdateHeader(core.Header{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
biteRepository := bite.NewBiteRepository(db)
|
||||
err = biteRepository.Create(headerID, test_data.BiteModel)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
var anotherBiteModel = bite.BiteModel{
|
||||
Id: "11",
|
||||
Ilk: test_data.BiteModel.Ilk,
|
||||
Lad: test_data.BiteModel.Lad,
|
||||
Ink: test_data.BiteModel.Ink,
|
||||
Art: test_data.BiteModel.Art,
|
||||
Tab: test_data.BiteModel.Tab,
|
||||
Flip: test_data.BiteModel.Flip,
|
||||
IArt: test_data.BiteModel.IArt,
|
||||
TransactionIndex: test_data.BiteModel.TransactionIndex,
|
||||
Raw: test_data.BiteModel.Raw,
|
||||
}
|
||||
|
||||
err = biteRepository.Create(headerID, anotherBiteModel)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("pq: duplicate key value violates unique constraint"))
|
||||
})
|
||||
|
||||
It("removes bite if corresponding header is deleted", func() {
|
||||
node := core.Node{}
|
||||
db := test_config.NewTestDB(node)
|
||||
test_config.CleanTestDB(db)
|
||||
headerRepository := repositories.NewHeaderRepository(db)
|
||||
headerID, err := headerRepository.CreateOrUpdateHeader(core.Header{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
biteRepository := bite.NewBiteRepository(db)
|
||||
err = biteRepository.Create(headerID, test_data.BiteModel)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, err = db.Exec(`DELETE FROM headers WHERE id = $1`, headerID)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
var dbBite bite.BiteModel
|
||||
err = db.Get(&dbBite, `SELECT id, ilk, lad, ink, art, tab, flip, tx_idx, raw_log FROM maker.bite WHERE header_id = $1`, headerID)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(sql.ErrNoRows))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("MissingHeaders", func() {
|
||||
It("returns headers with no associated bite event", func() {
|
||||
node := core.Node{}
|
||||
db := test_config.NewTestDB(node)
|
||||
test_config.CleanTestDB(db)
|
||||
headerRepository := repositories.NewHeaderRepository(db)
|
||||
startingBlockNumber := int64(1)
|
||||
biteBlockNumber := int64(2)
|
||||
endingBlockNumber := int64(3)
|
||||
blockNumbers := []int64{startingBlockNumber, biteBlockNumber, endingBlockNumber, endingBlockNumber + 1}
|
||||
var headerIDs []int64
|
||||
for _, n := range blockNumbers {
|
||||
headerID, err := headerRepository.CreateOrUpdateHeader(core.Header{BlockNumber: n})
|
||||
headerIDs = append(headerIDs, headerID)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
biteRepository := bite.NewBiteRepository(db)
|
||||
err := biteRepository.Create(headerIDs[1], test_data.BiteModel)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
headers, err := biteRepository.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)))
|
||||
})
|
||||
})
|
||||
})
|
88
pkg/transformers/bite/transformer.go
Normal file
88
pkg/transformers/bite/transformer.go
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 bite
|
||||
|
||||
import (
|
||||
"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"
|
||||
"log"
|
||||
)
|
||||
|
||||
type BiteTransformer struct {
|
||||
Repository Repository
|
||||
Fetcher shared.LogFetcher
|
||||
Converter Converter
|
||||
Config shared.TransformerConfig
|
||||
}
|
||||
|
||||
type BiteTransformerInitializer struct {
|
||||
Config shared.TransformerConfig
|
||||
}
|
||||
|
||||
func (i BiteTransformerInitializer) NewBiteTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
|
||||
fetcher := shared.NewFetcher(blockChain)
|
||||
repository := NewBiteRepository(db)
|
||||
transformer := BiteTransformer{
|
||||
Fetcher: fetcher,
|
||||
Repository: repository,
|
||||
Converter: BiteConverter{},
|
||||
Config: i.Config,
|
||||
}
|
||||
|
||||
return transformer
|
||||
}
|
||||
|
||||
func (b BiteTransformer) Execute() error {
|
||||
config := b.Config
|
||||
topics := [][]common.Hash{{common.HexToHash(shared.BiteSignature)}}
|
||||
|
||||
missingHeaders, err := b.Repository.MissingHeaders(config.StartingBlockNumber, config.EndingBlockNumber)
|
||||
if err != nil {
|
||||
log.Println("Error fetching missing headers:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, header := range missingHeaders {
|
||||
ethLogs, err := b.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 := b.Converter.ToEntity(config.ContractAddresses, config.ContractAbi, ethLog)
|
||||
model, err := b.Converter.ToModel(entity)
|
||||
if err != nil {
|
||||
log.Println("Error converting logs:", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.Repository.Create(header.Id, model)
|
||||
if err != nil {
|
||||
log.Println("Error persisting bite record:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (b BiteTransformer) SetConfig(config shared.TransformerConfig) {
|
||||
b.Config = config
|
||||
}
|
144
pkg/transformers/bite/transfromer_test.go
Normal file
144
pkg/transformers/bite/transfromer_test.go
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 bite_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/shared"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks"
|
||||
bite_mocks "github.com/vulcanize/vulcanizedb/pkg/transformers/test_data/mocks/bite"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
var _ = Describe("Bite Transformer", func() {
|
||||
var repository bite_mocks.MockBiteRepository
|
||||
var fetcher mocks.MockLogFetcher
|
||||
var converter bite_mocks.MockBiteConverter
|
||||
var transformer bite.BiteTransformer
|
||||
var blockNumber1 = rand.Int63()
|
||||
var blockNumber2 = rand.Int63()
|
||||
var testConfig shared.TransformerConfig
|
||||
|
||||
BeforeEach(func() {
|
||||
repository = bite_mocks.MockBiteRepository{}
|
||||
fetcher = mocks.MockLogFetcher{}
|
||||
converter = bite_mocks.MockBiteConverter{}
|
||||
|
||||
transformer = bite.BiteTransformer{
|
||||
Repository: &repository,
|
||||
Fetcher: &fetcher,
|
||||
Converter: &converter,
|
||||
Config: bite.BiteConfig,
|
||||
}
|
||||
|
||||
testConfig = shared.TransformerConfig{
|
||||
ContractAddresses: "0x12345",
|
||||
ContractAbi: "test abi",
|
||||
Topics: []string{shared.BiteSignature},
|
||||
StartingBlockNumber: blockNumber1,
|
||||
EndingBlockNumber: blockNumber2,
|
||||
}
|
||||
transformer.SetConfig(testConfig)
|
||||
})
|
||||
|
||||
It("gets missing headers for blocks in the configured range", func() {
|
||||
err := transformer.Execute()
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(repository.PassedStartingBlockNumber).To(Equal(bite.BiteConfig.StartingBlockNumber))
|
||||
Expect(repository.PassedEndingBlockNumber).To(Equal(bite.BiteConfig.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.BiteSignature)}}
|
||||
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(bite.BiteConfig.ContractAddresses))
|
||||
})
|
||||
|
||||
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.EthBiteLog})
|
||||
err := transformer.Execute()
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(converter.ConverterContract).To(Equal(bite.BiteConfig.ContractAddresses))
|
||||
Expect(converter.ConverterAbi).To(Equal(bite.BiteConfig.ContractAbi))
|
||||
Expect(converter.LogsToConvert).To(Equal([]types.Log{test_data.EthBiteLog}))
|
||||
})
|
||||
|
||||
It("returns an error if converter fails", func() {
|
||||
headerId := int64(1)
|
||||
repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1, Id: headerId}})
|
||||
fetcher.SetFetchedLogs([]types.Log{test_data.EthBiteLog})
|
||||
converter.SetConverterError(fakes.FakeError)
|
||||
|
||||
err := transformer.Execute()
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(fakes.FakeError))
|
||||
})
|
||||
|
||||
It("persists the bite record", func() {
|
||||
headerId := int64(1)
|
||||
repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1, Id: headerId}})
|
||||
fetcher.SetFetchedLogs([]types.Log{test_data.EthBiteLog})
|
||||
|
||||
err := transformer.Execute()
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(repository.PassedHeaderID).To(Equal(headerId))
|
||||
Expect(repository.PassedBiteModel).To(Equal(test_data.BiteModel))
|
||||
})
|
||||
|
||||
It("returns error if persisting bite record fails", func() {
|
||||
repository.SetMissingHeaders([]core.Header{{BlockNumber: blockNumber1}})
|
||||
fetcher.SetFetchedLogs([]types.Log{test_data.EthBiteLog})
|
||||
repository.SetCreateError(fakes.FakeError)
|
||||
err := transformer.Execute()
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(fakes.FakeError))
|
||||
})
|
||||
})
|
File diff suppressed because one or more lines are too long
74
pkg/transformers/test_data/bite.go
Normal file
74
pkg/transformers/test_data/bite.go
Normal file
@ -0,0 +1,74 @@
|
||||
package test_data
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"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/bite"
|
||||
"math/big"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
TemporaryBiteAddress = "0x4ac9588a53dc6008058c86eed71a5c91da793a07"
|
||||
TemporaryBiteBlockHash = common.HexToHash("0xd130caaccc9203ca63eb149faeb013aed21f0317ce23489c0486da2f9adcd0eb")
|
||||
TemporaryBiteBlockNumber = int64(26)
|
||||
TemporaryBiteData = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005"
|
||||
TemporaryBiteTransaction = "0x5c698f13940a2153440c6d19660878bc90219d9298fdcf37365aa8d88d40fc42"
|
||||
)
|
||||
|
||||
var (
|
||||
biteInk = big.NewInt(1)
|
||||
biteArt = big.NewInt(2)
|
||||
biteTab = big.NewInt(3)
|
||||
biteFlip = big.NewInt(4)
|
||||
biteIArt = big.NewInt(5)
|
||||
biteRawJson, _ = json.Marshal(EthBiteLog)
|
||||
biteRawString = string(biteRawJson)
|
||||
biteIlk = [32]byte{102, 97, 107, 101, 32, 105, 108, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
biteLad = [32]byte{102, 97, 107, 101, 32, 108, 97, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
biteId = int64(1)
|
||||
)
|
||||
|
||||
var EthBiteLog = types.Log{
|
||||
Address: common.HexToAddress(TemporaryBiteAddress),
|
||||
Topics: []common.Hash{
|
||||
common.HexToHash("0x99b5620489b6ef926d4518936cfec15d305452712b88bd59da2d9c10fb0953e8"),
|
||||
common.HexToHash("0x66616b6520696c6b000000000000000000000000000000000000000000000000"),
|
||||
common.HexToHash("0x66616b65206c6164000000000000000000000000000000000000000000000000"),
|
||||
},
|
||||
Data: hexutil.MustDecode(TemporaryBiteData),
|
||||
BlockNumber: uint64(TemporaryBiteBlockNumber),
|
||||
TxHash: common.HexToHash(TemporaryBiteTransaction),
|
||||
TxIndex: 111,
|
||||
BlockHash: TemporaryBiteBlockHash,
|
||||
Index: 0,
|
||||
Removed: false,
|
||||
}
|
||||
|
||||
var BiteEntity = bite.BiteEntity{
|
||||
Id: big.NewInt(biteId),
|
||||
Ilk: biteIlk,
|
||||
Lad: biteLad,
|
||||
Ink: biteInk,
|
||||
Art: biteArt,
|
||||
Tab: biteTab,
|
||||
Flip: biteFlip,
|
||||
IArt: biteIArt,
|
||||
TransactionIndex: EthBiteLog.TxIndex,
|
||||
Raw: EthBiteLog,
|
||||
}
|
||||
|
||||
var BiteModel = bite.BiteModel{
|
||||
Id: strconv.FormatInt(biteId, 10),
|
||||
Ilk: biteIlk[:],
|
||||
Lad: biteLad[:],
|
||||
Ink: biteInk.String(),
|
||||
Art: biteArt.String(),
|
||||
Tab: biteTab.String(),
|
||||
Flip: biteFlip.String(),
|
||||
IArt: biteIArt.String(),
|
||||
TransactionIndex: EthBiteLog.TxIndex,
|
||||
Raw: biteRawString,
|
||||
}
|
44
pkg/transformers/test_data/mocks/bite/converter.go
Normal file
44
pkg/transformers/test_data/mocks/bite/converter.go
Normal file
@ -0,0 +1,44 @@
|
||||
// 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 bite
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
. "github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/test_data"
|
||||
)
|
||||
|
||||
type MockBiteConverter struct {
|
||||
ConverterContract string
|
||||
ConverterAbi string
|
||||
LogsToConvert []types.Log
|
||||
EntitiesToConvert []BiteEntity
|
||||
ConverterError error
|
||||
}
|
||||
|
||||
func (mbc *MockBiteConverter) ToEntity(contractAddress string, contractAbi string, ethLog types.Log) (BiteEntity, error) {
|
||||
mbc.ConverterContract = contractAddress
|
||||
mbc.ConverterAbi = contractAbi
|
||||
mbc.LogsToConvert = append(mbc.LogsToConvert, ethLog)
|
||||
return test_data.BiteEntity, mbc.ConverterError
|
||||
}
|
||||
|
||||
func (mbc *MockBiteConverter) ToModel(entity BiteEntity) (BiteModel, error) {
|
||||
mbc.EntitiesToConvert = append(mbc.EntitiesToConvert, entity)
|
||||
return test_data.BiteModel, mbc.ConverterError
|
||||
}
|
||||
func (mbc *MockBiteConverter) SetConverterError(err error) {
|
||||
mbc.ConverterError = err
|
||||
}
|
55
pkg/transformers/test_data/mocks/bite/repository.go
Normal file
55
pkg/transformers/test_data/mocks/bite/repository.go
Normal file
@ -0,0 +1,55 @@
|
||||
// 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 bite
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
|
||||
)
|
||||
|
||||
type MockBiteRepository struct {
|
||||
createError error
|
||||
PassedEndingBlockNumber int64
|
||||
PassedBiteModel bite.BiteModel
|
||||
PassedHeaderID int64
|
||||
PassedStartingBlockNumber int64
|
||||
PassedTransactionIndex uint
|
||||
missingHeaders []core.Header
|
||||
missingHeadersErr error
|
||||
}
|
||||
|
||||
func (repository *MockBiteRepository) SetCreateError(err error) {
|
||||
repository.createError = err
|
||||
}
|
||||
|
||||
func (repository *MockBiteRepository) SetMissingHeadersErr(err error) {
|
||||
repository.missingHeadersErr = err
|
||||
}
|
||||
|
||||
func (repository *MockBiteRepository) SetMissingHeaders(headers []core.Header) {
|
||||
repository.missingHeaders = headers
|
||||
}
|
||||
|
||||
func (repository *MockBiteRepository) Create(headerID int64, model bite.BiteModel) error {
|
||||
repository.PassedHeaderID = headerID
|
||||
repository.PassedBiteModel = model
|
||||
return repository.createError
|
||||
}
|
||||
|
||||
func (repository *MockBiteRepository) MissingHeaders(startingBlockNumber, endingBlockNumber int64) ([]core.Header, error) {
|
||||
repository.PassedStartingBlockNumber = startingBlockNumber
|
||||
repository.PassedEndingBlockNumber = endingBlockNumber
|
||||
return repository.missingHeaders, repository.missingHeadersErr
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/bite"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/flip_kick"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/frob"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||
@ -31,8 +32,10 @@ func TransformerInitializers() []shared.TransformerInitializer {
|
||||
priceFeedTransformerInitializer := price_feeds.PriceFeedTransformerInitializer{Config: priceFeedConfig}
|
||||
tendConfig := tend.TendConfig
|
||||
tendTransformerInitializer := tend.TendTransformerInitializer{Config: tendConfig}
|
||||
biteTransformerInitializer := bite.BiteTransformerInitializer{Config: bite.BiteConfig}
|
||||
|
||||
return []shared.TransformerInitializer{
|
||||
biteTransformerInitializer.NewBiteTransformer,
|
||||
flipKickTransformerInitializer.NewFlipKickTransformer,
|
||||
frobTransformerInitializer.NewFrobTransformer,
|
||||
priceFeedTransformerInitializer.NewPriceFeedTransformer,
|
||||
|
Loading…
Reference in New Issue
Block a user