(VDB-298) Consume Pit contract storage diffs
- Continuously parse storage diffs CSV data to read Pit contract state - Convert ilks in database to raw bytes32 value for use in generating storage keys dynamically - Persist storage diffs with block number and hash for validation
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package maker
|
||||
|
||||
import "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
|
||||
type IMakerStorageRepository interface {
|
||||
GetIlks() ([]string, error)
|
||||
SetDB(db *postgres.DB)
|
||||
}
|
||||
|
||||
type MakerStorageRepository struct {
|
||||
db *postgres.DB
|
||||
}
|
||||
|
||||
func (repository *MakerStorageRepository) SetDB(db *postgres.DB) {
|
||||
repository.db = db
|
||||
}
|
||||
|
||||
func (repository MakerStorageRepository) GetIlks() ([]string, error) {
|
||||
var ilks []string
|
||||
err := repository.db.Select(&ilks, `SELECT DISTINCT ilk FROM maker.vat_init`)
|
||||
return ilks, err
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package maker_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/maker"
|
||||
"github.com/vulcanize/vulcanizedb/test_config"
|
||||
)
|
||||
|
||||
var _ = Describe("Maker storage repository", func() {
|
||||
It("fetches unique ilks from vat init events", func() {
|
||||
db := test_config.NewTestDB(test_config.NewTestNode())
|
||||
test_config.CleanTestDB(db)
|
||||
insertVatInit("ilk1", 1, db)
|
||||
insertVatInit("ilk2", 2, db)
|
||||
insertVatInit("ilk2", 3, db)
|
||||
repository := maker.MakerStorageRepository{}
|
||||
repository.SetDB(db)
|
||||
|
||||
ilks, err := repository.GetIlks()
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(ilks)).To(Equal(2))
|
||||
Expect(ilks).To(ConsistOf("ilk1", "ilk2"))
|
||||
})
|
||||
})
|
||||
|
||||
func insertVatInit(ilk string, blockNumber int64, db *postgres.DB) {
|
||||
headerRepository := repositories.NewHeaderRepository(db)
|
||||
headerID, err := headerRepository.CreateOrUpdateHeader(fakes.GetFakeHeader(blockNumber))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, execErr := db.Exec(
|
||||
`INSERT INTO maker.vat_init (header_id, ilk, log_idx, tx_idx, raw_log)
|
||||
VALUES($1, $2, $3, $4, $5)`,
|
||||
headerID, ilk, 0, 0, "[]",
|
||||
)
|
||||
Expect(execErr).NotTo(HaveOccurred())
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package maker_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestMaker(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Maker Suite")
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pit
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/maker"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const (
|
||||
IlkLine = "line"
|
||||
IlkSpot = "spot"
|
||||
PitDrip = "drip"
|
||||
PitLine = "Line"
|
||||
PitLive = "live"
|
||||
PitVat = "vat"
|
||||
)
|
||||
|
||||
var (
|
||||
// storage key and value metadata for "drip" on the Pit contract
|
||||
DripKey = common.HexToHash(storage_diffs.IndexFive)
|
||||
DripMetadata = shared.StorageValueMetadata{
|
||||
Name: PitDrip,
|
||||
Key: "",
|
||||
Type: shared.Address,
|
||||
}
|
||||
|
||||
IlkSpotIndex = storage_diffs.IndexOne
|
||||
|
||||
// storage key and value metadata for "Spot" on the Pit contract
|
||||
LineKey = common.HexToHash(storage_diffs.IndexThree)
|
||||
LineMetadata = shared.StorageValueMetadata{
|
||||
Name: PitLine,
|
||||
Key: "",
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
|
||||
// storage key and value metadata for "live" on the Pit contract
|
||||
LiveKey = common.HexToHash(storage_diffs.IndexTwo)
|
||||
LiveMetadata = shared.StorageValueMetadata{
|
||||
Name: PitLive,
|
||||
Key: "",
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
|
||||
// storage key and value metadata for "vat" on the Pit contract
|
||||
VatKey = common.HexToHash(storage_diffs.IndexFour)
|
||||
VatMetadata = shared.StorageValueMetadata{
|
||||
Name: PitVat,
|
||||
Key: "",
|
||||
Type: shared.Address,
|
||||
}
|
||||
)
|
||||
|
||||
type PitMappings struct {
|
||||
StorageRepository maker.IMakerStorageRepository
|
||||
mappings map[common.Hash]shared.StorageValueMetadata
|
||||
}
|
||||
|
||||
func (mappings *PitMappings) SetDB(db *postgres.DB) {
|
||||
mappings.StorageRepository.SetDB(db)
|
||||
}
|
||||
|
||||
func (mappings *PitMappings) Lookup(key common.Hash) (shared.StorageValueMetadata, error) {
|
||||
metadata, ok := mappings.mappings[key]
|
||||
if !ok {
|
||||
err := mappings.loadMappings()
|
||||
if err != nil {
|
||||
return metadata, err
|
||||
}
|
||||
metadata, ok = mappings.mappings[key]
|
||||
if !ok {
|
||||
return metadata, shared.ErrStorageKeyNotFound{Key: key.Hex()}
|
||||
}
|
||||
}
|
||||
return metadata, nil
|
||||
}
|
||||
|
||||
func (mappings *PitMappings) loadMappings() error {
|
||||
mappings.mappings = getStaticMappings()
|
||||
ilks, err := mappings.StorageRepository.GetIlks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ilk := range ilks {
|
||||
mappings.mappings[getSpotKey(ilk)] = getSpotMetadata(ilk)
|
||||
mappings.mappings[getLineKey(ilk)] = getLineMetadata(ilk)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStaticMappings() map[common.Hash]shared.StorageValueMetadata {
|
||||
mappings := make(map[common.Hash]shared.StorageValueMetadata)
|
||||
mappings[DripKey] = DripMetadata
|
||||
mappings[LineKey] = LineMetadata
|
||||
mappings[LiveKey] = LiveMetadata
|
||||
mappings[VatKey] = VatMetadata
|
||||
return mappings
|
||||
}
|
||||
|
||||
func getSpotKey(ilk string) common.Hash {
|
||||
keyBytes := common.FromHex("0x" + ilk + IlkSpotIndex)
|
||||
encoded := crypto.Keccak256(keyBytes)
|
||||
return common.BytesToHash(encoded)
|
||||
}
|
||||
|
||||
func getSpotMetadata(ilk string) shared.StorageValueMetadata {
|
||||
return shared.StorageValueMetadata{
|
||||
Name: IlkSpot,
|
||||
Key: ilk,
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
}
|
||||
|
||||
func getLineKey(ilk string) common.Hash {
|
||||
spotMappingAsInt := big.NewInt(0).SetBytes(getSpotKey(ilk).Bytes())
|
||||
incrementedByOne := big.NewInt(0).Add(spotMappingAsInt, big.NewInt(1))
|
||||
return common.BytesToHash(incrementedByOne.Bytes())
|
||||
}
|
||||
|
||||
func getLineMetadata(ilk string) shared.StorageValueMetadata {
|
||||
return shared.StorageValueMetadata{
|
||||
Name: IlkLine,
|
||||
Key: ilk,
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package pit_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/maker/pit"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/maker/test_helpers"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var _ = Describe("Pit storage mappings", func() {
|
||||
Describe("looking up static keys", func() {
|
||||
It("returns value metadata if key exists", func() {
|
||||
storageRepository := &test_helpers.MockMakerStorageRepository{}
|
||||
mappings := pit.PitMappings{StorageRepository: storageRepository}
|
||||
|
||||
Expect(mappings.Lookup(pit.DripKey)).To(Equal(pit.DripMetadata))
|
||||
Expect(mappings.Lookup(pit.LineKey)).To(Equal(pit.LineMetadata))
|
||||
Expect(mappings.Lookup(pit.LiveKey)).To(Equal(pit.LiveMetadata))
|
||||
Expect(mappings.Lookup(pit.VatKey)).To(Equal(pit.VatMetadata))
|
||||
})
|
||||
|
||||
It("returns error if key does not exist", func() {
|
||||
mappings := pit.PitMappings{StorageRepository: &test_helpers.MockMakerStorageRepository{}}
|
||||
|
||||
_, err := mappings.Lookup(common.HexToHash(fakes.FakeHash.Hex()))
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(shared.ErrStorageKeyNotFound{Key: fakes.FakeHash.Hex()}))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("looking up dynamic keys", func() {
|
||||
It("refreshes mappings from repository if key not found", func() {
|
||||
storageRepository := &test_helpers.MockMakerStorageRepository{}
|
||||
mappings := pit.PitMappings{StorageRepository: storageRepository}
|
||||
|
||||
mappings.Lookup(fakes.FakeHash)
|
||||
|
||||
Expect(storageRepository.GetIlksCalled).To(BeTrue())
|
||||
})
|
||||
|
||||
It("returns value metadata for spot when ilk in the DB", func() {
|
||||
storageRepository := &test_helpers.MockMakerStorageRepository{}
|
||||
fakeIlk := "fakeIlk"
|
||||
storageRepository.SetIlks([]string{fakeIlk})
|
||||
mappings := pit.PitMappings{StorageRepository: storageRepository}
|
||||
ilkSpotKey := common.BytesToHash(crypto.Keccak256(common.FromHex("0x" + fakeIlk + pit.IlkSpotIndex)))
|
||||
expectedMetadata := shared.StorageValueMetadata{
|
||||
Name: pit.IlkSpot,
|
||||
Key: fakeIlk,
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
|
||||
Expect(mappings.Lookup(ilkSpotKey)).To(Equal(expectedMetadata))
|
||||
})
|
||||
|
||||
It("returns value metadata for line when ilk in the DB", func() {
|
||||
storageRepository := &test_helpers.MockMakerStorageRepository{}
|
||||
fakeIlk := "fakeIlk"
|
||||
storageRepository.SetIlks([]string{fakeIlk})
|
||||
mappings := pit.PitMappings{StorageRepository: storageRepository}
|
||||
ilkSpotKeyBytes := crypto.Keccak256(common.FromHex("0x" + fakeIlk + pit.IlkSpotIndex))
|
||||
ilkSpotAsInt := big.NewInt(0).SetBytes(ilkSpotKeyBytes)
|
||||
incrementedIlkSpot := big.NewInt(0).Add(ilkSpotAsInt, big.NewInt(1))
|
||||
ilkLineKey := common.BytesToHash(incrementedIlkSpot.Bytes())
|
||||
expectedMetadata := shared.StorageValueMetadata{
|
||||
Name: pit.IlkLine,
|
||||
Key: fakeIlk,
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
|
||||
Expect(mappings.Lookup(ilkLineKey)).To(Equal(expectedMetadata))
|
||||
})
|
||||
|
||||
It("returns error if key not found", func() {
|
||||
storageRepository := &test_helpers.MockMakerStorageRepository{}
|
||||
mappings := pit.PitMappings{StorageRepository: storageRepository}
|
||||
|
||||
_, err := mappings.Lookup(fakes.FakeHash)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(shared.ErrStorageKeyNotFound{Key: fakes.FakeHash.Hex()}))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
package pit_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestPit(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Pit Suite")
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pit
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
)
|
||||
|
||||
type PitStorageRepository struct {
|
||||
db *postgres.DB
|
||||
}
|
||||
|
||||
func (repository *PitStorageRepository) SetDB(db *postgres.DB) {
|
||||
repository.db = db
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) Create(blockNumber int, blockHash string, metadata shared.StorageValueMetadata, value interface{}) error {
|
||||
switch metadata.Name {
|
||||
case IlkLine:
|
||||
return repository.insertIlkLine(blockNumber, blockHash, metadata.Key, value.(string))
|
||||
case IlkSpot:
|
||||
return repository.insertIlkSpot(blockNumber, blockHash, metadata.Key, value.(string))
|
||||
case PitDrip:
|
||||
return repository.insertPitDrip(blockNumber, blockHash, value.(string))
|
||||
case PitLine:
|
||||
return repository.insertPitLine(blockNumber, blockHash, value.(string))
|
||||
case PitLive:
|
||||
return repository.insertPitLive(blockNumber, blockHash, value.(string))
|
||||
case PitVat:
|
||||
return repository.insertPitVat(blockNumber, blockHash, value.(string))
|
||||
default:
|
||||
panic("unrecognized storage metadata name")
|
||||
}
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) insertIlkLine(blockNumber int, blockHash string, ilk string, line string) error {
|
||||
_, err := repository.db.Exec(`INSERT INTO maker.pit_ilk_line (block_number, block_hash, ilk, line) VALUES ($1, $2, $3, $4)`, blockNumber, blockHash, ilk, line)
|
||||
return err
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) insertIlkSpot(blockNumber int, blockHash string, ilk string, spot string) error {
|
||||
_, err := repository.db.Exec(`INSERT INTO maker.pit_ilk_spot (block_number, block_hash, ilk, spot) VALUES ($1, $2, $3, $4)`, blockNumber, blockHash, ilk, spot)
|
||||
return err
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) insertPitDrip(blockNumber int, blockHash string, drip string) error {
|
||||
_, err := repository.db.Exec(`INSERT INTO maker.pit_drip (block_number, block_hash, drip) VALUES ($1, $2, $3)`, blockNumber, blockHash, drip)
|
||||
return err
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) insertPitLine(blockNumber int, blockHash string, line string) error {
|
||||
_, err := repository.db.Exec(`INSERT INTO maker.pit_line (block_number, block_hash, line) VALUES ($1, $2, $3)`, blockNumber, blockHash, line)
|
||||
return err
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) insertPitLive(blockNumber int, blockHash string, live string) error {
|
||||
_, err := repository.db.Exec(`INSERT INTO maker.pit_live (block_number, block_hash, live) VALUES ($1, $2, $3)`, blockNumber, blockHash, live)
|
||||
return err
|
||||
}
|
||||
|
||||
func (repository PitStorageRepository) insertPitVat(blockNumber int, blockHash string, vat string) error {
|
||||
_, err := repository.db.Exec(`INSERT INTO maker.pit_vat (block_number, block_hash, vat) VALUES ($1, $2, $3)`, blockNumber, blockHash, vat)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pit_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/maker/pit"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
"github.com/vulcanize/vulcanizedb/test_config"
|
||||
)
|
||||
|
||||
var _ = Describe("Pit storage repository", func() {
|
||||
var (
|
||||
blockNumber int
|
||||
blockHash string
|
||||
db *postgres.DB
|
||||
err error
|
||||
repo pit.PitStorageRepository
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
blockNumber = 123
|
||||
blockHash = "expected_block_hash"
|
||||
db = test_config.NewTestDB(test_config.NewTestNode())
|
||||
test_config.CleanTestDB(db)
|
||||
repo = pit.PitStorageRepository{}
|
||||
repo.SetDB(db)
|
||||
})
|
||||
|
||||
It("persists an ilk line", func() {
|
||||
expectedIlk := "fake_ilk"
|
||||
expectedLine := "12345"
|
||||
ilkLineMetadata := shared.StorageValueMetadata{
|
||||
Name: pit.IlkLine,
|
||||
Key: expectedIlk,
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
err = repo.Create(blockNumber, blockHash, ilkLineMetadata, expectedLine)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
type IlkLine struct {
|
||||
BlockMetadata
|
||||
Ilk string
|
||||
Line string
|
||||
}
|
||||
var result IlkLine
|
||||
err = db.Get(&result, `SELECT block_number, block_hash, ilk, line FROM maker.pit_ilk_line`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.BlockNumber).To(Equal(blockNumber))
|
||||
Expect(result.BlockHash).To(Equal(blockHash))
|
||||
Expect(result.Ilk).To(Equal(expectedIlk))
|
||||
Expect(result.Line).To(Equal(expectedLine))
|
||||
})
|
||||
|
||||
It("persists an ilk spot", func() {
|
||||
expectedIlk := "fake_ilk"
|
||||
expectedSpot := "12345"
|
||||
ilkSpotMetadata := shared.StorageValueMetadata{
|
||||
Name: pit.IlkSpot,
|
||||
Key: expectedIlk,
|
||||
Type: shared.Uint256,
|
||||
}
|
||||
err = repo.Create(blockNumber, blockHash, ilkSpotMetadata, expectedSpot)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
type IlkSpot struct {
|
||||
BlockMetadata
|
||||
Ilk string
|
||||
Spot string
|
||||
}
|
||||
var result IlkSpot
|
||||
err = db.Get(&result, `SELECT block_number, block_hash, ilk, spot FROM maker.pit_ilk_spot`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.BlockNumber).To(Equal(blockNumber))
|
||||
Expect(result.BlockHash).To(Equal(blockHash))
|
||||
Expect(result.Ilk).To(Equal(expectedIlk))
|
||||
Expect(result.Spot).To(Equal(expectedSpot))
|
||||
})
|
||||
|
||||
It("persists a pit drip", func() {
|
||||
expectedDrip := "0x0123456789abcdef0123"
|
||||
|
||||
err = repo.Create(blockNumber, blockHash, pit.DripMetadata, expectedDrip)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
type PitDrip struct {
|
||||
BlockMetadata
|
||||
Drip string
|
||||
}
|
||||
var result PitDrip
|
||||
err = db.Get(&result, `SELECT block_number, block_hash, drip FROM maker.pit_drip`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.BlockNumber).To(Equal(blockNumber))
|
||||
Expect(result.BlockHash).To(Equal(blockHash))
|
||||
Expect(result.Drip).To(Equal(expectedDrip))
|
||||
})
|
||||
|
||||
It("persists a pit line", func() {
|
||||
expectedLine := "12345"
|
||||
|
||||
err = repo.Create(blockNumber, blockHash, pit.LineMetadata, expectedLine)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
type PitLine struct {
|
||||
BlockMetadata
|
||||
Line string
|
||||
}
|
||||
var result PitLine
|
||||
err = db.Get(&result, `SELECT block_number, block_hash, line FROM maker.pit_line`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.BlockNumber).To(Equal(blockNumber))
|
||||
Expect(result.BlockHash).To(Equal(blockHash))
|
||||
Expect(result.Line).To(Equal(expectedLine))
|
||||
})
|
||||
|
||||
It("persists a pit live", func() {
|
||||
expectedLive := "12345"
|
||||
|
||||
err = repo.Create(blockNumber, blockHash, pit.LiveMetadata, expectedLive)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
type PitLive struct {
|
||||
BlockMetadata
|
||||
Live string
|
||||
}
|
||||
var result PitLive
|
||||
err = db.Get(&result, `SELECT block_number, block_hash, live FROM maker.pit_live`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.BlockNumber).To(Equal(blockNumber))
|
||||
Expect(result.BlockHash).To(Equal(blockHash))
|
||||
Expect(result.Live).To(Equal(expectedLive))
|
||||
})
|
||||
|
||||
It("persists a pit vat", func() {
|
||||
expectedVat := "0x0123456789abcdef0123"
|
||||
|
||||
err = repo.Create(blockNumber, blockHash, pit.VatMetadata, expectedVat)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
type PitVat struct {
|
||||
BlockMetadata
|
||||
Vat string
|
||||
}
|
||||
var result PitVat
|
||||
err = db.Get(&result, `SELECT block_number, block_hash, vat FROM maker.pit_vat`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.BlockNumber).To(Equal(blockNumber))
|
||||
Expect(result.BlockHash).To(Equal(blockHash))
|
||||
Expect(result.Vat).To(Equal(expectedVat))
|
||||
})
|
||||
})
|
||||
|
||||
type BlockMetadata struct {
|
||||
BlockNumber int `db:"block_number"`
|
||||
BlockHash string `db:"block_hash"`
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package test_helpers
|
||||
|
||||
import "github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
|
||||
type MockMakerStorageRepository struct {
|
||||
GetIlksCalled bool
|
||||
ilks []string
|
||||
}
|
||||
|
||||
func (repository *MockMakerStorageRepository) GetIlks() ([]string, error) {
|
||||
repository.GetIlksCalled = true
|
||||
return repository.ilks, nil
|
||||
}
|
||||
|
||||
func (repository *MockMakerStorageRepository) SetDB(db *postgres.DB) {}
|
||||
|
||||
func (repository *MockMakerStorageRepository) SetIlks(ilks []string) {
|
||||
repository.ilks = ilks
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package storage_diffs
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
)
|
||||
|
||||
type Mappings interface {
|
||||
Lookup(key common.Hash) (shared.StorageValueMetadata, error)
|
||||
SetDB(db *postgres.DB)
|
||||
}
|
||||
|
||||
const (
|
||||
IndexZero = "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
IndexOne = "0000000000000000000000000000000000000000000000000000000000000001"
|
||||
IndexTwo = "0000000000000000000000000000000000000000000000000000000000000002"
|
||||
IndexThree = "0000000000000000000000000000000000000000000000000000000000000003"
|
||||
IndexFour = "0000000000000000000000000000000000000000000000000000000000000004"
|
||||
IndexFive = "0000000000000000000000000000000000000000000000000000000000000005"
|
||||
IndexSix = "0000000000000000000000000000000000000000000000000000000000000006"
|
||||
IndexSeven = "0000000000000000000000000000000000000000000000000000000000000007"
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package storage_diffs
|
||||
|
||||
import (
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
Create(blockNumber int, blockHash string, metadata shared.StorageValueMetadata, value interface{}) error
|
||||
SetDB(db *postgres.DB)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func Decode(row StorageDiffRow, metadata StorageValueMetadata) (interface{}, error) {
|
||||
switch metadata.Type {
|
||||
case Uint256:
|
||||
return decodeUint256(row.StorageValue.Bytes()), nil
|
||||
case Address:
|
||||
return decodeAddress(row.StorageValue.Bytes()), nil
|
||||
default:
|
||||
return nil, ErrTypeNotFound{}
|
||||
}
|
||||
}
|
||||
|
||||
func decodeUint256(raw []byte) string {
|
||||
n := big.NewInt(0).SetBytes(raw)
|
||||
return n.String()
|
||||
}
|
||||
|
||||
func decodeAddress(raw []byte) string {
|
||||
return common.BytesToAddress(raw).Hex()
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var _ = Describe("Storage decoder", func() {
|
||||
It("decodes uint256", func() {
|
||||
fakeInt := common.HexToHash("0000000000000000000000000000000000000000000000000000000000000539")
|
||||
row := shared.StorageDiffRow{StorageValue: fakeInt}
|
||||
metadata := shared.StorageValueMetadata{Type: shared.Uint256}
|
||||
|
||||
result, err := shared.Decode(row, metadata)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result).To(Equal(big.NewInt(0).SetBytes(fakeInt.Bytes()).String()))
|
||||
})
|
||||
|
||||
It("decodes address", func() {
|
||||
fakeAddress := common.HexToAddress("0x12345")
|
||||
row := shared.StorageDiffRow{StorageValue: fakeAddress.Hash()}
|
||||
metadata := shared.StorageValueMetadata{Type: shared.Address}
|
||||
|
||||
result, err := shared.Decode(row, metadata)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result).To(Equal(fakeAddress.Hex()))
|
||||
})
|
||||
|
||||
It("returns error if attempting to decode unknown type", func() {
|
||||
metadata := shared.StorageValueMetadata{Type: 100}
|
||||
|
||||
_, err := shared.Decode(shared.StorageDiffRow{}, metadata)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(shared.ErrTypeNotFound{}))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared
|
||||
|
||||
import "fmt"
|
||||
|
||||
type ErrContractNotFound struct {
|
||||
Contract string
|
||||
}
|
||||
|
||||
func (e ErrContractNotFound) Error() string {
|
||||
return fmt.Sprintf("transformer not found for contract: %s", e.Contract)
|
||||
}
|
||||
|
||||
type ErrHeaderMismatch struct {
|
||||
BlockHeight int
|
||||
DbHash string
|
||||
DiffHash string
|
||||
}
|
||||
|
||||
func (e ErrHeaderMismatch) Error() string {
|
||||
return fmt.Sprintf("header hash in row does not match db at height %d - row: %s, db: %s", e.BlockHeight, e.DbHash, e.DiffHash)
|
||||
}
|
||||
|
||||
type ErrRowMalformed struct {
|
||||
Length int
|
||||
}
|
||||
|
||||
func (e ErrRowMalformed) Error() string {
|
||||
return fmt.Sprintf("storage row malformed: length %d, expected %d", e.Length, ExpectedRowLength)
|
||||
}
|
||||
|
||||
type ErrStorageKeyNotFound struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func (e ErrStorageKeyNotFound) Error() string {
|
||||
return fmt.Sprintf("unknown storage key: %s", e.Key)
|
||||
}
|
||||
|
||||
type ErrTypeNotFound struct {
|
||||
Type int
|
||||
}
|
||||
|
||||
func (e ErrTypeNotFound) Error() string {
|
||||
return fmt.Sprintf("no decoder for type: %d", e.Type)
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const ExpectedRowLength = 5
|
||||
|
||||
type StorageDiffRow struct {
|
||||
Contract common.Address
|
||||
BlockHash common.Hash
|
||||
BlockHeight int
|
||||
StorageKey common.Hash
|
||||
StorageValue common.Hash
|
||||
}
|
||||
|
||||
func FromStrings(csvRow []string) (StorageDiffRow, error) {
|
||||
if len(csvRow) != ExpectedRowLength {
|
||||
return StorageDiffRow{}, ErrRowMalformed{Length: len(csvRow)}
|
||||
}
|
||||
height, err := strconv.Atoi(csvRow[2])
|
||||
if err != nil {
|
||||
return StorageDiffRow{}, err
|
||||
}
|
||||
return StorageDiffRow{
|
||||
Contract: common.HexToAddress(csvRow[0]),
|
||||
BlockHash: common.HexToHash(csvRow[1]),
|
||||
BlockHeight: height,
|
||||
StorageKey: common.HexToHash(csvRow[3]),
|
||||
StorageValue: common.HexToHash(csvRow[4]),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/storage_diffs/shared"
|
||||
)
|
||||
|
||||
var _ = Describe("Storage row parsing", func() {
|
||||
It("converts an array of strings to a row struct", func() {
|
||||
contract := "0x123"
|
||||
blockHash := "0x456"
|
||||
blockHeight := "789"
|
||||
storageKey := "0x987"
|
||||
storageValue := "0x654"
|
||||
data := []string{contract, blockHash, blockHeight, storageKey, storageValue}
|
||||
|
||||
result, err := shared.FromStrings(data)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(result.Contract).To(Equal(common.HexToAddress(contract)))
|
||||
Expect(result.BlockHash).To(Equal(common.HexToHash(blockHash)))
|
||||
Expect(result.BlockHeight).To(Equal(789))
|
||||
Expect(result.StorageKey).To(Equal(common.HexToHash(storageKey)))
|
||||
Expect(result.StorageValue).To(Equal(common.HexToHash(storageValue)))
|
||||
})
|
||||
|
||||
It("returns an error if row is missing data", func() {
|
||||
_, err := shared.FromStrings([]string{"0x123"})
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(shared.ErrRowMalformed{Length: 1}))
|
||||
})
|
||||
|
||||
It("returns error if block height malformed", func() {
|
||||
_, err := shared.FromStrings([]string{"", "", "", "", ""})
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestShared(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Shared Suite")
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2018 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared
|
||||
|
||||
type ValueType int
|
||||
|
||||
const (
|
||||
Uint256 ValueType = iota
|
||||
Bytes32
|
||||
Address
|
||||
)
|
||||
|
||||
type StorageValueMetadata struct {
|
||||
Name string
|
||||
Key string
|
||||
Type ValueType
|
||||
}
|
||||
Reference in New Issue
Block a user