adjusted FetchContractData to work with variable number of contract method arguments, changed fetcher's FetchSupply method to more general FetchBigInt method and added FetchBool and FetchAddress methods
This commit is contained in:
parent
93960e7c4e
commit
ccd21f73c9
@ -19,45 +19,54 @@ import (
|
||||
"log"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
)
|
||||
|
||||
// Interface definition for a Fetcher
|
||||
type ERC20FetcherInterface interface {
|
||||
FetchSupplyOf(contractAbi string, contractAddress string, blockNumber int64) (big.Int, error)
|
||||
FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error)
|
||||
FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error)
|
||||
FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error)
|
||||
GetBlockChain() core.BlockChain
|
||||
}
|
||||
|
||||
func NewFetcher(blockchain core.BlockChain) Fetcher {
|
||||
// Initializes and returns a Fetcher with the given blockchain
|
||||
func NewFetcher(blockChain core.BlockChain) Fetcher {
|
||||
return Fetcher{
|
||||
Blockchain: blockchain,
|
||||
BlockChain: blockChain,
|
||||
}
|
||||
}
|
||||
|
||||
// Fetcher struct
|
||||
type Fetcher struct {
|
||||
Blockchain core.BlockChain
|
||||
BlockChain core.BlockChain
|
||||
ContractAbi string
|
||||
ContractAddress string
|
||||
}
|
||||
|
||||
// Fetcher error
|
||||
type fetcherError struct {
|
||||
err string
|
||||
fetchMethod string
|
||||
}
|
||||
|
||||
// Fetcher error method
|
||||
func (fe *fetcherError) Error() string {
|
||||
return fmt.Sprintf("Error fetching %s: %s", fe.fetchMethod, fe.err)
|
||||
}
|
||||
|
||||
// Used to create a new Fetcher error for a given error and fetch method
|
||||
func newFetcherError(err error, fetchMethod string) *fetcherError {
|
||||
e := fetcherError{err.Error(), fetchMethod}
|
||||
log.Println(e.Error())
|
||||
return &e
|
||||
}
|
||||
|
||||
func (f Fetcher) FetchSupplyOf(contractAbi string, contractAddress string, blockNumber int64) (big.Int, error) {
|
||||
method := "totalSupply"
|
||||
// Method used to fetch big.Int result from contract
|
||||
func (f Fetcher) FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
|
||||
var result = new(big.Int)
|
||||
err := f.Blockchain.FetchContractData(contractAbi, contractAddress, method, nil, &result, blockNumber)
|
||||
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
|
||||
|
||||
if err != nil {
|
||||
return *result, newFetcherError(err, method)
|
||||
@ -66,6 +75,31 @@ func (f Fetcher) FetchSupplyOf(contractAbi string, contractAddress string, block
|
||||
return *result, nil
|
||||
}
|
||||
|
||||
func (f Fetcher) GetBlockChain() core.BlockChain {
|
||||
return f.Blockchain
|
||||
// Method used to fetch bool result from contract
|
||||
func (f Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) {
|
||||
var result = new(bool)
|
||||
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
|
||||
|
||||
if err != nil {
|
||||
return *result, newFetcherError(err, method)
|
||||
}
|
||||
|
||||
return *result, nil
|
||||
}
|
||||
|
||||
// Method used to fetch address result from contract
|
||||
func (f Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) {
|
||||
var result = new(common.Address)
|
||||
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
|
||||
|
||||
if err != nil {
|
||||
return *result, newFetcherError(err, method)
|
||||
}
|
||||
|
||||
return *result, nil
|
||||
}
|
||||
|
||||
// Getter method for Fetcher's blockchain
|
||||
func (f Fetcher) GetBlockChain() core.BlockChain {
|
||||
return f.BlockChain
|
||||
}
|
||||
|
@ -34,22 +34,23 @@ import (
|
||||
var _ = Describe("ERC20 Fetcher", func() {
|
||||
blockNumber := int64(5502914)
|
||||
|
||||
Describe("FetchSupplyOf", func() {
|
||||
It("fetches data from the blockchain with the correct arguments", func() {
|
||||
fakeBlockchain := fakes.NewMockBlockChain()
|
||||
testFetcher := every_block.NewFetcher(fakeBlockchain)
|
||||
Describe("totalSupply", func() {
|
||||
It("fetches total supply data from the blockchain with the correct arguments", func() {
|
||||
fakeBlockChain := fakes.NewMockBlockChain()
|
||||
testFetcher := every_block.NewFetcher(fakeBlockChain)
|
||||
testAbi := "testAbi"
|
||||
testContractAddress := "testContractAddress"
|
||||
_, err := testFetcher.FetchSupplyOf(testAbi, testContractAddress, blockNumber)
|
||||
|
||||
_, err := testFetcher.FetchBigInt("totalSupply", testAbi, testContractAddress, blockNumber, nil)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectedResult := big.Int{}
|
||||
expected := &expectedResult
|
||||
fakeBlockchain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "totalSupply", nil, &expected, blockNumber)
|
||||
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "totalSupply", nil, &expected, blockNumber)
|
||||
})
|
||||
|
||||
It("fetches a token's total supply at the given block height", func() {
|
||||
infuraIPC := "https://mainnet.infura.io/J5Vd2fRtGsw0zZ0Ov3BL"
|
||||
It("fetches dai token's total supply at the given block height", func() {
|
||||
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
|
||||
rawRpcClient, err := rpc.Dial(infuraIPC)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
|
||||
@ -59,7 +60,7 @@ var _ = Describe("ERC20 Fetcher", func() {
|
||||
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
|
||||
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
|
||||
realFetcher := every_block.NewFetcher(blockChain)
|
||||
result, err := realFetcher.FetchSupplyOf(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
|
||||
result, err := realFetcher.FetchBigInt("totalSupply", constants.DaiAbiString, constants.DaiContractAddress, blockNumber, nil)
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expectedResult := big.Int{}
|
||||
@ -71,7 +72,7 @@ var _ = Describe("ERC20 Fetcher", func() {
|
||||
blockChain := fakes.NewMockBlockChain()
|
||||
blockChain.SetFetchContractDataErr(fakes.FakeError)
|
||||
errorFetcher := every_block.NewFetcher(blockChain)
|
||||
result, err := errorFetcher.FetchSupplyOf("", "", 0)
|
||||
result, err := errorFetcher.FetchBigInt("totalSupply", "", "", 0, nil)
|
||||
|
||||
Expect(result.String()).To(Equal("0"))
|
||||
Expect(err).To(HaveOccurred())
|
||||
@ -79,4 +80,4 @@ var _ = Describe("ERC20 Fetcher", func() {
|
||||
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -14,8 +14,26 @@
|
||||
|
||||
package every_block
|
||||
|
||||
// Struct to hold token supply data
|
||||
type TokenSupply struct {
|
||||
Value string
|
||||
TokenAddress string
|
||||
BlockNumber int64
|
||||
}
|
||||
|
||||
// Struct to hold token holder address balance data
|
||||
type TokenBalance struct {
|
||||
Value string
|
||||
TokenAddress string
|
||||
BlockNumber int64
|
||||
TokenHolderAddress string
|
||||
}
|
||||
|
||||
// Struct to hold token allowance data
|
||||
type TokenAllowance struct {
|
||||
Value string
|
||||
TokenAddress string
|
||||
BlockNumber int64
|
||||
TokenHolderAddress string
|
||||
TokenSpenderAddress string
|
||||
}
|
||||
|
@ -20,38 +20,46 @@ import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Interface definition for a generic ERC20 token repository
|
||||
type ERC20RepositoryInterface interface {
|
||||
Create(supply TokenSupply) error
|
||||
MissingBlocks(startingBlock int64, highestBlock int64) ([]int64, error)
|
||||
CreateSupply(supply TokenSupply) error
|
||||
MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error)
|
||||
}
|
||||
|
||||
type TokenSupplyRepository struct {
|
||||
// Generic ERC20 token Repo struct
|
||||
type ERC20TokenRepository struct {
|
||||
*postgres.DB
|
||||
}
|
||||
|
||||
// Repo error
|
||||
type repositoryError struct {
|
||||
err string
|
||||
msg string
|
||||
blockNumber int64
|
||||
}
|
||||
|
||||
// Repo error method
|
||||
func (re *repositoryError) Error() string {
|
||||
return fmt.Sprintf(re.msg, re.blockNumber, re.err)
|
||||
}
|
||||
|
||||
// Used to create a new Repo error for a given error and fetch method
|
||||
func newRepositoryError(err error, msg string, blockNumber int64) error {
|
||||
e := repositoryError{err.Error(), msg, blockNumber}
|
||||
log.Println(e.Error())
|
||||
return &e
|
||||
}
|
||||
|
||||
// Constant error definitions
|
||||
const (
|
||||
GetBlockError = "Error fetching block number %d: %s"
|
||||
InsertTokenSupplyError = "Error inserting token_supply for block number %d: %s"
|
||||
MissingBlockError = "Error finding missing token_supply records starting at block %d: %s"
|
||||
)
|
||||
|
||||
func (tsp *TokenSupplyRepository) Create(supply TokenSupply) error {
|
||||
// Supply methods
|
||||
// This method inserts the supply for a given token contract address at a given block height into the token_supply table
|
||||
func (tsp *ERC20TokenRepository) CreateSupply(supply TokenSupply) error {
|
||||
var blockId int
|
||||
err := tsp.DB.Get(&blockId, `SELECT id FROM blocks WHERE number = $1 AND eth_node_id = $2`, supply.BlockNumber, tsp.NodeID)
|
||||
if err != nil {
|
||||
@ -68,7 +76,8 @@ func (tsp *TokenSupplyRepository) Create(supply TokenSupply) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tsp *TokenSupplyRepository) MissingBlocks(startingBlock int64, highestBlock int64) ([]int64, error) {
|
||||
// This method returns an array of blocks that are missing a token_supply entry for a given tokenAddress
|
||||
func (tsp *ERC20TokenRepository) MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) {
|
||||
blockNumbers := make([]int64, 0)
|
||||
|
||||
err := tsp.DB.Select(
|
||||
@ -88,4 +97,4 @@ func (tsp *TokenSupplyRepository) MissingBlocks(startingBlock int64, highestBloc
|
||||
return []int64{}, newRepositoryError(err, MissingBlockError, startingBlock)
|
||||
}
|
||||
return blockNumbers, err
|
||||
}
|
||||
}
|
@ -31,13 +31,13 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
var db *postgres.DB
|
||||
var blockId int64
|
||||
var blockNumber int64
|
||||
var repository every_block.TokenSupplyRepository
|
||||
var repository every_block.ERC20TokenRepository
|
||||
var blockRepository repositories.BlockRepository
|
||||
testAddress := "abc"
|
||||
|
||||
BeforeEach(func() {
|
||||
db = test_helpers.CreateNewDatabase()
|
||||
repository = every_block.TokenSupplyRepository{DB: db}
|
||||
repository = every_block.ERC20TokenRepository{DB: db}
|
||||
_, err := db.Query(`DELETE FROM token_supply`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@ -49,7 +49,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
Describe("Create", func() {
|
||||
It("creates a token supply record", func() {
|
||||
supply := supplyModel(blockNumber, testAddress, "100")
|
||||
err := repository.Create(supply)
|
||||
err := repository.CreateSupply(supply)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
dbResult := test_helpers.TokenSupplyDBRow{}
|
||||
@ -73,7 +73,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
|
||||
It("returns an error if fetching the block's id from the database fails", func() {
|
||||
errorSupply := supplyModel(-1, "", "")
|
||||
err := repository.Create(errorSupply)
|
||||
err := repository.CreateSupply(errorSupply)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql"))
|
||||
@ -82,7 +82,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
|
||||
It("returns an error if inserting the token_supply fails", func() {
|
||||
errorSupply := supplyModel(blockNumber, "", "")
|
||||
err := repository.Create(errorSupply)
|
||||
err := repository.CreateSupply(errorSupply)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("pq"))
|
||||
@ -94,7 +94,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
var node2DB *postgres.DB
|
||||
var node2BlockRepo *repositories.BlockRepository
|
||||
var node2BlockId int64
|
||||
var node2TokenSupplyRepo every_block.TokenSupplyRepository
|
||||
var node2TokenSupplyRepo every_block.ERC20TokenRepository
|
||||
var tokenSupply every_block.TokenSupply
|
||||
|
||||
BeforeEach(func() {
|
||||
@ -105,11 +105,11 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
node2BlockId = test_helpers.CreateBlock(blockNumber, *node2BlockRepo)
|
||||
|
||||
tokenSupply = supplyModel(blockNumber, "abc", "100")
|
||||
node2TokenSupplyRepo = every_block.TokenSupplyRepository{DB: node2DB}
|
||||
node2TokenSupplyRepo = every_block.ERC20TokenRepository{DB: node2DB}
|
||||
})
|
||||
|
||||
It("only creates token_supply records for the current node (node2)", func() {
|
||||
err := node2TokenSupplyRepo.Create(tokenSupply)
|
||||
err := node2TokenSupplyRepo.CreateSupply(tokenSupply)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
var tokenSupplies []test_helpers.TokenSupplyDBRow
|
||||
@ -121,14 +121,14 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
|
||||
It("only includes missing block numbers for the current node", func() {
|
||||
//create token_supply on original node
|
||||
err := repository.Create(tokenSupply)
|
||||
err := repository.CreateSupply(tokenSupply)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
originalNodeMissingBlocks, err := repository.MissingBlocks(blockNumber, blockNumber)
|
||||
originalNodeMissingBlocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(originalNodeMissingBlocks)).To(Equal(0))
|
||||
|
||||
node2MissingBlocks, err := node2TokenSupplyRepo.MissingBlocks(blockNumber, blockNumber)
|
||||
node2MissingBlocks, err := node2TokenSupplyRepo.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(len(node2MissingBlocks)).To(Equal(1))
|
||||
})
|
||||
@ -140,7 +140,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
|
||||
newBlockNumber := blockNumber + 1
|
||||
test_helpers.CreateBlock(newBlockNumber, blockRepository)
|
||||
blocks, err := repository.MissingBlocks(blockNumber, newBlockNumber)
|
||||
blocks, err := repository.MissingSupplyBlocks(blockNumber, newBlockNumber, testAddress)
|
||||
|
||||
Expect(blocks).To(ConsistOf(newBlockNumber))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@ -149,7 +149,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
It("only returns blocks within the given range", func() {
|
||||
newBlockNumber := blockNumber + 1
|
||||
test_helpers.CreateBlock(newBlockNumber, blockRepository)
|
||||
blocks, err := repository.MissingBlocks(blockNumber, blockNumber)
|
||||
blocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
||||
|
||||
Expect(blocks).NotTo(ConsistOf(newBlockNumber))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@ -157,7 +157,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
|
||||
It("does not return numbers that already have an associated TokenSupply record", func() {
|
||||
createTokenSupplyFor(repository, blockNumber)
|
||||
blocks, err := repository.MissingBlocks(blockNumber, blockNumber)
|
||||
blocks, err := repository.MissingSupplyBlocks(blockNumber, blockNumber, testAddress)
|
||||
|
||||
Expect(blocks).To(BeEmpty())
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@ -165,7 +165,7 @@ var _ = Describe("ERC20 Token Repository", func() {
|
||||
})
|
||||
|
||||
It("deletes the token supply record when the associated block is deleted", func() {
|
||||
err := repository.Create(every_block.TokenSupply{BlockNumber: blockNumber, Value: "0"})
|
||||
err := repository.CreateSupply(every_block.TokenSupply{BlockNumber: blockNumber, Value: "0"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
var count int
|
||||
@ -190,8 +190,8 @@ func supplyModel(blockNumber int64, tokenAddress string, supplyValue string) eve
|
||||
}
|
||||
}
|
||||
|
||||
func createTokenSupplyFor(repository every_block.TokenSupplyRepository, blockNumber int64) {
|
||||
err := repository.Create(every_block.TokenSupply{BlockNumber: blockNumber, Value: "0"})
|
||||
func createTokenSupplyFor(repository every_block.ERC20TokenRepository, blockNumber int64) {
|
||||
err := repository.CreateSupply(every_block.TokenSupply{BlockNumber: blockNumber, Value: "0"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ type TokenSupplyTransformerInitializer struct {
|
||||
|
||||
func (i TokenSupplyTransformerInitializer) NewTokenSupplyTransformer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer {
|
||||
fetcher := NewFetcher(blockchain)
|
||||
repository := TokenSupplyRepository{DB: db}
|
||||
repository := ERC20TokenRepository{DB: db}
|
||||
transformer := Transformer{
|
||||
Fetcher: &fetcher,
|
||||
Repository: &repository,
|
||||
@ -83,21 +83,29 @@ func (t Transformer) Execute() error {
|
||||
upperBoundBlock = t.Config.LastBlock
|
||||
}
|
||||
|
||||
blocks, err := t.Repository.MissingBlocks(t.Config.FirstBlock, upperBoundBlock)
|
||||
// Supply transformations:
|
||||
|
||||
// Fetch missing supply blocks
|
||||
blocks, err := t.Repository.MissingSupplyBlocks(t.Config.FirstBlock, upperBoundBlock, t.Config.Address)
|
||||
|
||||
if err != nil {
|
||||
return newTransformerError(err, t.Config.FirstBlock, FetchingBlocksError)
|
||||
}
|
||||
|
||||
// Fetch supply for missing blocks
|
||||
log.Printf("Fetching totalSupply for %d blocks", len(blocks))
|
||||
|
||||
// For each block missing total supply, create supply model and feed the missing data into the repository
|
||||
for _, blockNumber := range blocks {
|
||||
totalSupply, err := t.Fetcher.FetchSupplyOf(t.Config.Abi, t.Config.Address, blockNumber)
|
||||
totalSupply, err := t.Fetcher.FetchBigInt("totalSupply", t.Config.Abi, t.Config.Address, blockNumber, nil)
|
||||
|
||||
if err != nil {
|
||||
return newTransformerError(err, blockNumber, FetchingSupplyError)
|
||||
}
|
||||
// Create the supply model
|
||||
model := createTokenSupplyModel(totalSupply, t.Config.Address, blockNumber)
|
||||
err = t.Repository.Create(model)
|
||||
// Feed it into the repository
|
||||
err = t.Repository.CreateSupply(model)
|
||||
|
||||
if err != nil {
|
||||
return newTransformerError(err, blockNumber, CreateSupplyError)
|
||||
|
@ -39,7 +39,7 @@ var config = testContractConfig
|
||||
|
||||
var _ = Describe("Everyblock transformer", func() {
|
||||
var fetcher mocks.Fetcher
|
||||
var repository mocks.TotalSupplyRepository
|
||||
var repository mocks.ERC20TokenRepository
|
||||
var transformer every_block.Transformer
|
||||
var blockChain *fakes.MockBlockChain
|
||||
var initialSupply = "27647235749155415536952630"
|
||||
@ -53,8 +53,8 @@ var _ = Describe("Everyblock transformer", func() {
|
||||
blockChain.SetLastBlock(&defaultLastBlock)
|
||||
fetcher = mocks.Fetcher{BlockChain: blockChain}
|
||||
fetcher.SetSupply(initialSupply)
|
||||
repository = mocks.TotalSupplyRepository{}
|
||||
repository.SetMissingBlocks([]int64{config.FirstBlock})
|
||||
repository = mocks.ERC20TokenRepository{}
|
||||
repository.SetMissingSupplyBlocks([]int64{config.FirstBlock})
|
||||
//setting the mock repository to return the first block as the missing blocks
|
||||
|
||||
transformer = every_block.Transformer{
|
||||
@ -89,8 +89,9 @@ var _ = Describe("Everyblock transformer", func() {
|
||||
config.FirstBlock + 1,
|
||||
config.FirstBlock + 2,
|
||||
}
|
||||
repository.SetMissingBlocks(missingBlocks)
|
||||
transformer.Execute()
|
||||
repository.SetMissingSupplyBlocks(missingBlocks)
|
||||
err := transformer.Execute()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
Expect(len(fetcher.FetchedBlocks)).To(Equal(3))
|
||||
Expect(fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock, config.FirstBlock+1, config.FirstBlock+2))
|
||||
@ -104,7 +105,7 @@ var _ = Describe("Everyblock transformer", func() {
|
||||
})
|
||||
|
||||
It("uses the set contract configuration", func() {
|
||||
repository.SetMissingBlocks([]int64{testContractConfig.FirstBlock})
|
||||
repository.SetMissingSupplyBlocks([]int64{testContractConfig.FirstBlock})
|
||||
transformer.SetConfiguration(testContractConfig)
|
||||
err := transformer.Execute()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@ -143,7 +144,7 @@ var _ = Describe("Everyblock transformer", func() {
|
||||
|
||||
It("returns an error if the call to get missing blocks fails", func() {
|
||||
failureRepository := mocks.FailureRepository{}
|
||||
failureRepository.SetMissingBlocksFail(true)
|
||||
failureRepository.SetMissingSupplyBlocksFail(true)
|
||||
transformer = every_block.Transformer{
|
||||
Fetcher: &fetcher,
|
||||
Repository: &failureRepository,
|
||||
@ -171,8 +172,8 @@ var _ = Describe("Everyblock transformer", func() {
|
||||
|
||||
It("returns an error if the call to save the token_supply fails", func() {
|
||||
failureRepository := mocks.FailureRepository{}
|
||||
failureRepository.SetMissingBlocks([]int64{config.FirstBlock})
|
||||
failureRepository.SetCreateFail(true)
|
||||
failureRepository.SetMissingSupplyBlocks([]int64{config.FirstBlock})
|
||||
failureRepository.SetCreateSupplyFail(true)
|
||||
|
||||
transformer = every_block.Transformer{
|
||||
Fetcher: &fetcher,
|
||||
|
@ -15,11 +15,14 @@
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Fetcher struct {
|
||||
@ -28,6 +31,8 @@ type Fetcher struct {
|
||||
FetchedBlocks []int64
|
||||
BlockChain core.BlockChain
|
||||
supply big.Int
|
||||
balance map[string]*big.Int
|
||||
allowance map[string]map[string]*big.Int
|
||||
}
|
||||
|
||||
func (f *Fetcher) SetSupply(supply string) {
|
||||
@ -38,69 +43,203 @@ func (f Fetcher) GetBlockChain() core.BlockChain {
|
||||
return f.BlockChain
|
||||
}
|
||||
|
||||
func (f *Fetcher) FetchSupplyOf(contractAbi string, contractAddress string, blockNumber int64) (big.Int, error) {
|
||||
func (f *Fetcher) FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
|
||||
|
||||
f.Abi = contractAbi
|
||||
f.ContractAddress = contractAddress
|
||||
f.FetchedBlocks = append(f.FetchedBlocks, blockNumber)
|
||||
|
||||
accumulator := big.NewInt(1)
|
||||
f.supply.Add(&f.supply, accumulator)
|
||||
|
||||
return f.supply, nil
|
||||
if method == "totalSupply" {
|
||||
f.supply.Add(&f.supply, accumulator)
|
||||
|
||||
return f.supply, nil
|
||||
}
|
||||
|
||||
if method == "balanceOf" {
|
||||
rfl := reflect.ValueOf(methodArgs).Field(0)
|
||||
tokenHolderAddr := rfl.Interface().(string)
|
||||
pnt := f.balance[tokenHolderAddr]
|
||||
f.balance[tokenHolderAddr].Add(pnt, accumulator)
|
||||
|
||||
return *f.balance[tokenHolderAddr], nil
|
||||
}
|
||||
|
||||
if method == "allowance" {
|
||||
rfl1 := reflect.ValueOf(methodArgs).Field(0)
|
||||
rfl2 := reflect.ValueOf(methodArgs).Field(1)
|
||||
tokenHolderAddr := rfl1.Interface().(string)
|
||||
spenderAddr := rfl2.Interface().(string)
|
||||
pnt := f.allowance[tokenHolderAddr][spenderAddr]
|
||||
f.allowance[tokenHolderAddr][spenderAddr].Add(pnt, accumulator)
|
||||
|
||||
return *f.allowance[tokenHolderAddr][spenderAddr], nil
|
||||
}
|
||||
|
||||
return *big.NewInt(0), errors.New("invalid method argument")
|
||||
|
||||
}
|
||||
|
||||
type TotalSupplyRepository struct {
|
||||
TotalSuppliesCreated []every_block.TokenSupply
|
||||
MissingBlockNumbers []int64
|
||||
StartingBlock int64
|
||||
EndingBlock int64
|
||||
func (f *Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) {
|
||||
//TODO: this
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (fr *TotalSupplyRepository) Create(supply every_block.TokenSupply) error {
|
||||
func (f *Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) {
|
||||
//TODO: this
|
||||
var adr common.Address
|
||||
return adr, nil
|
||||
}
|
||||
|
||||
type ERC20TokenRepository struct {
|
||||
TotalSuppliesCreated []every_block.TokenSupply
|
||||
MissingSupplyBlockNumbers []int64
|
||||
TotalBalancesCreated []every_block.TokenBalance
|
||||
MissingBalanceBlockNumbers []int64
|
||||
TotalAllowancesCreated []every_block.TokenAllowance
|
||||
MissingAllowanceBlockNumbers []int64
|
||||
StartingBlock int64
|
||||
EndingBlock int64
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) CreateSupply(supply every_block.TokenSupply) error {
|
||||
fr.TotalSuppliesCreated = append(fr.TotalSuppliesCreated, supply)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *TotalSupplyRepository) MissingBlocks(startingBlock int64, highestBlock int64) ([]int64, error) {
|
||||
fr.StartingBlock = startingBlock
|
||||
fr.EndingBlock = highestBlock
|
||||
return fr.MissingBlockNumbers, nil
|
||||
func (fr *ERC20TokenRepository) CreateBalance(balance every_block.TokenBalance) error {
|
||||
fr.TotalBalancesCreated = append(fr.TotalBalancesCreated, balance)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *TotalSupplyRepository) SetMissingBlocks(missingBlocks []int64) {
|
||||
fr.MissingBlockNumbers = missingBlocks
|
||||
func (fr *ERC20TokenRepository) CreateAllowance(allowance every_block.TokenAllowance) error {
|
||||
fr.TotalAllowancesCreated = append(fr.TotalAllowancesCreated, allowance)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) {
|
||||
fr.StartingBlock = startingBlock
|
||||
fr.EndingBlock = highestBlock
|
||||
return fr.MissingSupplyBlockNumbers, nil
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) MissingBalanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress string) ([]int64, error) {
|
||||
fr.StartingBlock = startingBlock
|
||||
fr.EndingBlock = highestBlock
|
||||
return fr.MissingBalanceBlockNumbers, nil
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) MissingAllowanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress, spenderAddress string) ([]int64, error) {
|
||||
fr.StartingBlock = startingBlock
|
||||
fr.EndingBlock = highestBlock
|
||||
return fr.MissingAllowanceBlockNumbers, nil
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) SetMissingSupplyBlocks(missingBlocks []int64) {
|
||||
fr.MissingSupplyBlockNumbers = missingBlocks
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) SetMissingBalanceBlocks(missingBlocks []int64) {
|
||||
fr.MissingBalanceBlockNumbers = missingBlocks
|
||||
}
|
||||
|
||||
func (fr *ERC20TokenRepository) SetMissingAllowanceBlocks(missingBlocks []int64) {
|
||||
fr.MissingAllowanceBlockNumbers = missingBlocks
|
||||
}
|
||||
|
||||
type FailureRepository struct {
|
||||
createFail bool
|
||||
missingBlocksFail bool
|
||||
missingBlocksNumbers []int64
|
||||
createSupplyFail bool
|
||||
createBalanceFail bool
|
||||
createAllowanceFail bool
|
||||
missingSupplyBlocksFail bool
|
||||
missingBalanceBlocksFail bool
|
||||
missingAllowanceBlocksFail bool
|
||||
missingSupplyBlocksNumbers []int64
|
||||
missingBalanceBlocksNumbers []int64
|
||||
missingAllowanceBlocksNumbers []int64
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) Create(supply every_block.TokenSupply) error {
|
||||
if fr.createFail {
|
||||
func (fr *FailureRepository) CreateSupply(supply every_block.TokenSupply) error {
|
||||
if fr.createSupplyFail {
|
||||
return fakes.FakeError
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) MissingBlocks(startingBlock int64, highestBlock int64) ([]int64, error) {
|
||||
if fr.missingBlocksFail {
|
||||
return []int64{}, fakes.FakeError
|
||||
func (fr *FailureRepository) CreateBalance(balance every_block.TokenBalance) error {
|
||||
if fr.createBalanceFail {
|
||||
return fakes.FakeError
|
||||
} else {
|
||||
return fr.missingBlocksNumbers, nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetCreateFail(fail bool) {
|
||||
fr.createFail = fail
|
||||
func (fr *FailureRepository) CreateAllowance(allowance every_block.TokenAllowance) error {
|
||||
if fr.createAllowanceFail {
|
||||
return fakes.FakeError
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingBlocksFail(fail bool) {
|
||||
fr.missingBlocksFail = fail
|
||||
func (fr *FailureRepository) MissingSupplyBlocks(startingBlock, highestBlock int64, tokenAddress string) ([]int64, error) {
|
||||
if fr.missingSupplyBlocksFail {
|
||||
return []int64{}, fakes.FakeError
|
||||
} else {
|
||||
return fr.missingSupplyBlocksNumbers, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingBlocks(missingBlocks []int64) {
|
||||
fr.missingBlocksNumbers = missingBlocks
|
||||
func (fr *FailureRepository) MissingBalanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress string) ([]int64, error) {
|
||||
if fr.missingBalanceBlocksFail {
|
||||
return []int64{}, fakes.FakeError
|
||||
} else {
|
||||
return fr.missingBalanceBlocksNumbers, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) MissingAllowanceBlocks(startingBlock, highestBlock int64, tokenAddress, holderAddress, spenderAddress string) ([]int64, error) {
|
||||
if fr.missingAllowanceBlocksFail {
|
||||
return []int64{}, fakes.FakeError
|
||||
} else {
|
||||
return fr.missingAllowanceBlocksNumbers, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetCreateSupplyFail(fail bool) {
|
||||
fr.createSupplyFail = fail
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetCreateBalanceFail(fail bool) {
|
||||
fr.createBalanceFail = fail
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetCreateAllowanceFail(fail bool) {
|
||||
fr.createAllowanceFail = fail
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingSupplyBlocksFail(fail bool) {
|
||||
fr.missingSupplyBlocksFail = fail
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingBalanceBlocksFail(fail bool) {
|
||||
fr.missingBalanceBlocksFail = fail
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingAllowanceBlocksFail(fail bool) {
|
||||
fr.missingAllowanceBlocksFail = fail
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingSupplyBlocks(missingBlocks []int64) {
|
||||
fr.missingSupplyBlocksNumbers = missingBlocks
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingBalanceBlocks(missingBlocks []int64) {
|
||||
fr.missingBalanceBlocksNumbers = missingBlocks
|
||||
}
|
||||
|
||||
func (fr *FailureRepository) SetMissingAllowanceBlocks(missingBlocks []int64) {
|
||||
fr.missingAllowanceBlocksNumbers = missingBlocks
|
||||
}
|
||||
|
@ -80,8 +80,15 @@ var _ = Describe("Reading contracts", func() {
|
||||
|
||||
contract := testing.SampleContract()
|
||||
var balance = new(big.Int)
|
||||
args := common.HexToHash("0xd26114cd6ee289accf82350c8d8487fedb8a0c07")
|
||||
err = blockChain.FetchContractData(contract.Abi, "0xd26114cd6ee289accf82350c8d8487fedb8a0c07", "balanceOf", args, &balance, 5167471)
|
||||
|
||||
arg := common.HexToHash("0xd26114cd6ee289accf82350c8d8487fedb8a0c07")
|
||||
hashArgs := []common.Hash{arg}
|
||||
balanceOfArgs := make([]interface{}, len(hashArgs))
|
||||
for i, s := range hashArgs {
|
||||
balanceOfArgs[i] = s
|
||||
}
|
||||
|
||||
err = blockChain.FetchContractData(contract.Abi, "0xd26114cd6ee289accf82350c8d8487fedb8a0c07", "balanceOf", balanceOfArgs, &balance, 5167471)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
expected := new(big.Int)
|
||||
expected.SetString("10897295492887612977137", 10)
|
||||
|
@ -12,5 +12,5 @@ type BlockChain interface {
|
||||
}
|
||||
|
||||
type ContractDataFetcher interface {
|
||||
FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error
|
||||
FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ type MockBlockChain struct {
|
||||
fetchContractDataPassedAbi string
|
||||
fetchContractDataPassedAddress string
|
||||
fetchContractDataPassedMethod string
|
||||
fetchContractDataPassedMethodArg interface{}
|
||||
fetchContractDataPassedMethodArgs []interface{}
|
||||
fetchContractDataPassedResult interface{}
|
||||
fetchContractDataPassedBlockNumber int64
|
||||
getBlockByNumberErr error
|
||||
@ -43,11 +43,11 @@ func (blockChain *MockBlockChain) GetHeaderByNumber(blockNumber int64) (core.Hea
|
||||
return core.Header{BlockNumber: blockNumber}, nil
|
||||
}
|
||||
|
||||
func (blockChain *MockBlockChain) FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error {
|
||||
func (blockChain *MockBlockChain) FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error {
|
||||
blockChain.fetchContractDataPassedAbi = abiJSON
|
||||
blockChain.fetchContractDataPassedAddress = address
|
||||
blockChain.fetchContractDataPassedMethod = method
|
||||
blockChain.fetchContractDataPassedMethodArg = methodArg
|
||||
blockChain.fetchContractDataPassedMethodArgs = methodArgs
|
||||
blockChain.fetchContractDataPassedResult = result
|
||||
blockChain.fetchContractDataPassedBlockNumber = blockNumber
|
||||
return blockChain.fetchContractDataErr
|
||||
@ -74,7 +74,7 @@ func (blockChain *MockBlockChain) GetBlockByNumber(blockNumber int64) (core.Bloc
|
||||
}
|
||||
|
||||
// TODO: handle methodArg being nil (can't match nil to nil in Gomega)
|
||||
func (blockChain *MockBlockChain) AssertFetchContractDataCalledWith(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) {
|
||||
func (blockChain *MockBlockChain) AssertFetchContractDataCalledWith(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) {
|
||||
Expect(blockChain.fetchContractDataPassedAbi).To(Equal(abiJSON))
|
||||
Expect(blockChain.fetchContractDataPassedAddress).To(Equal(address))
|
||||
Expect(blockChain.fetchContractDataPassedMethod).To(Equal(method))
|
||||
|
@ -14,14 +14,14 @@ var (
|
||||
ErrInvalidStateAttribute = errors.New("invalid state attribute")
|
||||
)
|
||||
|
||||
func (blockChain *BlockChain) FetchContractData(abiJSON string, address string, method string, methodArg interface{}, result interface{}, blockNumber int64) error {
|
||||
func (blockChain *BlockChain) FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error {
|
||||
parsed, err := ParseAbi(abiJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var input []byte
|
||||
if methodArg != nil {
|
||||
input, err = parsed.Pack(method, methodArg)
|
||||
if methodArgs != nil {
|
||||
input, err = parsed.Pack(method, methodArgs...)
|
||||
} else {
|
||||
input, err = parsed.Pack(method)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user