2018-05-05 20:25:54 +00:00
|
|
|
// 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 every_block_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
|
|
. "github.com/onsi/gomega"
|
|
|
|
|
|
|
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
|
|
|
|
"github.com/vulcanize/vulcanizedb/examples/test_helpers"
|
|
|
|
"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/test_config"
|
|
|
|
"math/rand"
|
|
|
|
)
|
|
|
|
|
2018-08-12 20:35:23 +00:00
|
|
|
var _ = Describe("ERC20 Token Supply Repository", func() {
|
2018-05-05 20:25:54 +00:00
|
|
|
var db *postgres.DB
|
|
|
|
var blockId int64
|
|
|
|
var blockNumber int64
|
2018-08-09 16:58:06 +00:00
|
|
|
var repository every_block.ERC20TokenRepository
|
2018-05-05 20:25:54 +00:00
|
|
|
var blockRepository repositories.BlockRepository
|
|
|
|
testAddress := "abc"
|
|
|
|
|
|
|
|
BeforeEach(func() {
|
|
|
|
db = test_helpers.CreateNewDatabase()
|
2018-08-09 16:58:06 +00:00
|
|
|
repository = every_block.ERC20TokenRepository{DB: db}
|
2018-05-05 20:25:54 +00:00
|
|
|
_, err := db.Query(`DELETE FROM token_supply`)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
|
|
|
blockRepository = *repositories.NewBlockRepository(db)
|
|
|
|
blockNumber = rand.Int63()
|
|
|
|
blockId = test_helpers.CreateBlock(blockNumber, blockRepository)
|
|
|
|
})
|
|
|
|
|
|
|
|
Describe("Create", func() {
|
|
|
|
It("creates a token supply record", func() {
|
|
|
|
supply := supplyModel(blockNumber, testAddress, "100")
|
2018-08-09 16:58:06 +00:00
|
|
|
err := repository.CreateSupply(supply)
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
|
|
|
dbResult := test_helpers.TokenSupplyDBRow{}
|
|
|
|
expectedTokenSupply := test_helpers.TokenSupplyDBRow{
|
|
|
|
Supply: int64(100),
|
|
|
|
BlockID: blockId,
|
|
|
|
TokenAddress: testAddress,
|
|
|
|
}
|
|
|
|
|
|
|
|
var count int
|
|
|
|
err = repository.DB.QueryRowx(`SELECT count(*) FROM token_supply`).Scan(&count)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(count).To(Equal(1))
|
|
|
|
|
|
|
|
err = repository.DB.QueryRowx(`SELECT * FROM token_supply`).StructScan(&dbResult)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(dbResult.Supply).To(Equal(expectedTokenSupply.Supply))
|
|
|
|
Expect(dbResult.BlockID).To(Equal(expectedTokenSupply.BlockID))
|
|
|
|
Expect(dbResult.TokenAddress).To(Equal(expectedTokenSupply.TokenAddress))
|
|
|
|
})
|
|
|
|
|
|
|
|
It("returns an error if fetching the block's id from the database fails", func() {
|
|
|
|
errorSupply := supplyModel(-1, "", "")
|
2018-08-09 16:58:06 +00:00
|
|
|
err := repository.CreateSupply(errorSupply)
|
2018-05-05 20:25:54 +00:00
|
|
|
|
|
|
|
Expect(err).To(HaveOccurred())
|
|
|
|
Expect(err.Error()).To(ContainSubstring("sql"))
|
|
|
|
Expect(err.Error()).To(ContainSubstring("block number -1"))
|
|
|
|
})
|
|
|
|
|
|
|
|
It("returns an error if inserting the token_supply fails", func() {
|
|
|
|
errorSupply := supplyModel(blockNumber, "", "")
|
2018-08-09 16:58:06 +00:00
|
|
|
err := repository.CreateSupply(errorSupply)
|
2018-05-05 20:25:54 +00:00
|
|
|
|
|
|
|
Expect(err).To(HaveOccurred())
|
|
|
|
Expect(err.Error()).To(ContainSubstring("pq"))
|
|
|
|
Expect(err.Error()).To(ContainSubstring("token_supply for block number"))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Describe("When there are multiple nodes", func() {
|
|
|
|
var node2DB *postgres.DB
|
|
|
|
var node2BlockRepo *repositories.BlockRepository
|
|
|
|
var node2BlockId int64
|
2018-08-09 16:58:06 +00:00
|
|
|
var node2TokenSupplyRepo every_block.ERC20TokenRepository
|
2018-05-05 20:25:54 +00:00
|
|
|
var tokenSupply every_block.TokenSupply
|
|
|
|
|
|
|
|
BeforeEach(func() {
|
|
|
|
node2DB = createDbForAnotherNode()
|
|
|
|
|
|
|
|
//create another block with the same number on node2
|
|
|
|
node2BlockRepo = repositories.NewBlockRepository(node2DB)
|
|
|
|
node2BlockId = test_helpers.CreateBlock(blockNumber, *node2BlockRepo)
|
|
|
|
|
|
|
|
tokenSupply = supplyModel(blockNumber, "abc", "100")
|
2018-08-09 16:58:06 +00:00
|
|
|
node2TokenSupplyRepo = every_block.ERC20TokenRepository{DB: node2DB}
|
2018-05-05 20:25:54 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
It("only creates token_supply records for the current node (node2)", func() {
|
2018-08-09 16:58:06 +00:00
|
|
|
err := node2TokenSupplyRepo.CreateSupply(tokenSupply)
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
|
|
|
var tokenSupplies []test_helpers.TokenSupplyDBRow
|
|
|
|
err = node2TokenSupplyRepo.DB.Select(&tokenSupplies, `SELECT * FROM token_supply`)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(len(tokenSupplies)).To(Equal(1))
|
|
|
|
Expect(tokenSupplies[0].BlockID).To(Equal(node2BlockId))
|
|
|
|
})
|
|
|
|
|
|
|
|
It("only includes missing block numbers for the current node", func() {
|
|
|
|
//create token_supply on original node
|
2018-08-09 16:58:06 +00:00
|
|
|
err := repository.CreateSupply(tokenSupply)
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
2018-08-09 16:58:06 +00:00
|
|
|
originalNodeMissingBlocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(len(originalNodeMissingBlocks)).To(Equal(0))
|
|
|
|
|
2018-08-09 16:58:06 +00:00
|
|
|
node2MissingBlocks, err := node2TokenSupplyRepo.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(len(node2MissingBlocks)).To(Equal(1))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
Describe("MissingBlocks", func() {
|
|
|
|
It("returns the block numbers for which an associated TokenSupply record hasn't been created", func() {
|
2018-08-12 20:35:23 +00:00
|
|
|
createTokenSupplyFor(repository, blockNumber, testAddress)
|
2018-05-05 20:25:54 +00:00
|
|
|
|
|
|
|
newBlockNumber := blockNumber + 1
|
|
|
|
test_helpers.CreateBlock(newBlockNumber, blockRepository)
|
2018-08-09 16:58:06 +00:00
|
|
|
blocks, err := repository.MissingSupplyBlocks(blockNumber, newBlockNumber, testAddress)
|
2018-05-05 20:25:54 +00:00
|
|
|
|
|
|
|
Expect(blocks).To(ConsistOf(newBlockNumber))
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
})
|
|
|
|
|
|
|
|
It("only returns blocks within the given range", func() {
|
|
|
|
newBlockNumber := blockNumber + 1
|
|
|
|
test_helpers.CreateBlock(newBlockNumber, blockRepository)
|
2018-08-09 16:58:06 +00:00
|
|
|
blocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
2018-05-05 20:25:54 +00:00
|
|
|
|
|
|
|
Expect(blocks).NotTo(ConsistOf(newBlockNumber))
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
})
|
|
|
|
|
|
|
|
It("does not return numbers that already have an associated TokenSupply record", func() {
|
2018-08-12 20:35:23 +00:00
|
|
|
createTokenSupplyFor(repository, blockNumber, testAddress)
|
2018-08-09 16:58:06 +00:00
|
|
|
blocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
2018-05-05 20:25:54 +00:00
|
|
|
|
|
|
|
Expect(blocks).To(BeEmpty())
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
It("deletes the token supply record when the associated block is deleted", func() {
|
2018-08-12 20:35:23 +00:00
|
|
|
err := repository.CreateSupply(every_block.TokenSupply{BlockNumber: blockNumber, TokenAddress: testAddress, Value: "0"})
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
|
|
|
var count int
|
|
|
|
err = repository.DB.QueryRowx(`SELECT count(*) FROM token_supply`).Scan(&count)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(count).To(Equal(1))
|
|
|
|
|
|
|
|
_, err = db.Query(`DELETE FROM blocks`)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
|
|
|
|
err = repository.DB.QueryRowx(`SELECT count(*) FROM token_supply`).Scan(&count)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(count).To(Equal(0))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2018-08-12 20:35:23 +00:00
|
|
|
func supplyModel(blockNumber int64, tokenAddress, supplyValue string) every_block.TokenSupply {
|
2018-05-05 20:25:54 +00:00
|
|
|
return every_block.TokenSupply{
|
|
|
|
Value: supplyValue,
|
|
|
|
TokenAddress: tokenAddress,
|
2018-08-12 20:35:23 +00:00
|
|
|
BlockNumber: blockNumber,
|
2018-05-05 20:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-12 20:35:23 +00:00
|
|
|
func createTokenSupplyFor(repository every_block.ERC20TokenRepository, blockNumber int64, tokenAddress string) {
|
|
|
|
err := repository.CreateSupply(every_block.TokenSupply{
|
Moved fetcher to generic directory (methods have to remain public since it is in seperate package now), added FetchHash method, created ERC20 and generic getters which call the fetcher with specific contract methods (GetTotalSupply, GetBalance, GetAllowance for ERC20 getter, and GetOwner, GetStoppedStatus, GetStringName, GetHashName, GetStringSymbol, GetHashSymbol, and GetDecimals for generic getter). Getter tests cover all but GetBalance and GetAllowance, and also cover all of the Fetcher methods- but with only nil methodArgs. GetAllowance and GetBalance tests are not working against infura and these are the only contract method calls with arguments passed in so I suspect this might be where the issue lies. Have tested GetBalance using previous version of FetchContractData without the variadic input to the Pack method and it fails with the same error so I don’t think it is due to those changes.
2018-08-15 04:17:22 +00:00
|
|
|
BlockNumber: blockNumber,
|
2018-08-12 20:35:23 +00:00
|
|
|
TokenAddress: tokenAddress,
|
Moved fetcher to generic directory (methods have to remain public since it is in seperate package now), added FetchHash method, created ERC20 and generic getters which call the fetcher with specific contract methods (GetTotalSupply, GetBalance, GetAllowance for ERC20 getter, and GetOwner, GetStoppedStatus, GetStringName, GetHashName, GetStringSymbol, GetHashSymbol, and GetDecimals for generic getter). Getter tests cover all but GetBalance and GetAllowance, and also cover all of the Fetcher methods- but with only nil methodArgs. GetAllowance and GetBalance tests are not working against infura and these are the only contract method calls with arguments passed in so I suspect this might be where the issue lies. Have tested GetBalance using previous version of FetchContractData without the variadic input to the Pack method and it fails with the same error so I don’t think it is due to those changes.
2018-08-15 04:17:22 +00:00
|
|
|
Value: "0",
|
2018-08-12 20:35:23 +00:00
|
|
|
})
|
2018-05-05 20:25:54 +00:00
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
}
|
|
|
|
|
|
|
|
func createDbForAnotherNode() *postgres.DB {
|
|
|
|
anotherNode := core.Node{
|
|
|
|
GenesisBlock: "GENESIS",
|
|
|
|
NetworkID: 1,
|
|
|
|
ID: "testNodeId",
|
|
|
|
ClientName: "Geth/v1.7.2-stable-1db4ecdc/darwin-amd64/go1.9",
|
|
|
|
}
|
|
|
|
|
|
|
|
return test_config.NewTestDBWithoutDeletingRecords(anotherNode)
|
|
|
|
}
|