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.

This commit is contained in:
Ian Norden 2018-08-14 23:17:22 -05:00
parent 99e549b3df
commit 9b41000b88
15 changed files with 837 additions and 243 deletions

File diff suppressed because one or more lines are too long

View File

@ -25,7 +25,7 @@ import (
func TestEveryBlock(t *testing.T) { func TestEveryBlock(t *testing.T) {
RegisterFailHandler(Fail) RegisterFailHandler(Fail)
RunSpecs(t, "EveryBlock Suite") RunSpecs(t, "ERC20 EveryBlock Suite")
} }
var _ = BeforeSuite(func() { var _ = BeforeSuite(func() {

View File

@ -1,176 +0,0 @@
// Copyright 2018 Vulcanize
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package every_block_test
import (
"math/big"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/examples/constants"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"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/ethereum/go-ethereum/common"
)
var _ = Describe("ERC20 Fetcher", func() {
blockNumber := int64(5502914)
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.FetchBigInt("totalSupply", testAbi, testContractAddress, blockNumber, nil)
Expect(err).NotTo(HaveOccurred())
expectedResult := big.Int{}
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "totalSupply", nil, &expected, blockNumber)
})
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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realFetcher := every_block.NewFetcher(blockChain)
result, err := realFetcher.FetchBigInt("totalSupply", constants.DaiAbiString, constants.DaiContractAddress, blockNumber, nil)
Expect(err).NotTo(HaveOccurred())
expectedResult := big.Int{}
expectedResult.SetString("27647235749155415536952630", 10)
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorFetcher := every_block.NewFetcher(blockChain)
result, err := errorFetcher.FetchBigInt("totalSupply", "", "", 0, nil)
Expect(result.String()).To(Equal("0"))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("totalSupply"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("stopped", func() {
It("checks whether or not the contract has been stopped", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testFetcher := every_block.NewFetcher(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testFetcher.FetchBool("stopped", testAbi, testContractAddress, blockNumber, nil)
Expect(err).NotTo(HaveOccurred())
var expectedResult bool
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "stopped", nil, &expected, blockNumber)
})
It("fetches dai token's stopped status 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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realFetcher := every_block.NewFetcher(blockChain)
result, err := realFetcher.FetchBool("stopped", constants.DaiAbiString, constants.DaiContractAddress, blockNumber, nil)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(false))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorFetcher := every_block.NewFetcher(blockChain)
result, err := errorFetcher.FetchBool("stopped", "", "", 0, nil)
Expect(result).To(Equal(false))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("stopped"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("owner", func() {
It("checks what the contract's owner address is", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testFetcher := every_block.NewFetcher(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testFetcher.FetchAddress("owner", testAbi, testContractAddress, blockNumber, nil)
Expect(err).NotTo(HaveOccurred())
var expectedResult common.Address
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "owner", nil, &expected, blockNumber)
})
It("fetches dai token's owner address 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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realFetcher := every_block.NewFetcher(blockChain)
result, err := realFetcher.FetchAddress("owner", constants.DaiAbiString, constants.DaiContractAddress, blockNumber, nil)
Expect(err).NotTo(HaveOccurred())
expectedResult := common.HexToAddress("0x0000000000000000000000000000000000000000")
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorFetcher := every_block.NewFetcher(blockChain)
result, err := errorFetcher.FetchAddress("owner", "", "", 0, nil)
expectedResult := new(common.Address)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("owner"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
})

View File

@ -0,0 +1,64 @@
// 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 og 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 Og ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package every_block
import (
"math/big"
"github.com/vulcanize/vulcanizedb/examples/generic"
"github.com/vulcanize/vulcanizedb/pkg/core"
)
// Getter serves as a higher level data fetcher that invokes its underlying Fetcher methods for a given contract method
// Interface definition for a Getter
type ERC20GetterInterface interface {
GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error)
GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error)
GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error)
GetBlockChain() core.BlockChain
}
// Getter struct
type Getter struct {
fetcher generic.Fetcher
}
// Initializes and returns a Getter with the given blockchain
func NewGetter(blockChain core.BlockChain) Getter {
return Getter{
fetcher: generic.Fetcher{
BlockChain: blockChain,
},
}
}
// Public getter methods for calling contract methods
func (g Getter) GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) {
return g.fetcher.FetchBigInt("totalSupply", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
return g.fetcher.FetchBigInt("balanceOf", contractAbi, contractAddress, blockNumber, methodArgs)
}
func (g Getter) GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
return g.fetcher.FetchBigInt("allowance", contractAbi, contractAddress, blockNumber, methodArgs)
}
// Method to retrieve the Getter's blockchain
func (g Getter) GetBlockChain() core.BlockChain {
return g.fetcher.BlockChain
}

View 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 every_block_test
import (
"math/big"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/vulcanize/vulcanizedb/examples/constants"
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"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"
)
var _ = Describe("ERC20 Getter", func() {
blockNumber := int64(5502914)
Describe("totalSupply", func() {
It("gets total supply data from the blockchain with the correct arguments", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetTotalSupply(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := big.Int{}
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "totalSupply", nil, &expected, blockNumber)
})
It("gets 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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetTotalSupply(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := big.Int{}
expectedResult.SetString("27647235749155415536952630", 10)
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetTotalSupply("", "", 0)
Expect(result.String()).To(Equal("0"))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("totalSupply"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
})

View File

@ -192,9 +192,9 @@ func supplyModel(blockNumber int64, tokenAddress, supplyValue string) every_bloc
func createTokenSupplyFor(repository every_block.ERC20TokenRepository, blockNumber int64, tokenAddress string) { func createTokenSupplyFor(repository every_block.ERC20TokenRepository, blockNumber int64, tokenAddress string) {
err := repository.CreateSupply(every_block.TokenSupply{ err := repository.CreateSupply(every_block.TokenSupply{
BlockNumber: blockNumber, BlockNumber: blockNumber,
TokenAddress: tokenAddress, TokenAddress: tokenAddress,
Value: "0", Value: "0",
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }

View File

@ -25,7 +25,7 @@ import (
) )
type Transformer struct { type Transformer struct {
Fetcher ERC20FetcherInterface Getter ERC20GetterInterface
Repository ERC20RepositoryInterface Repository ERC20RepositoryInterface
Config erc20_watcher.ContractConfig Config erc20_watcher.ContractConfig
} }
@ -38,11 +38,11 @@ type TokenSupplyTransformerInitializer struct {
Config erc20_watcher.ContractConfig Config erc20_watcher.ContractConfig
} }
func (i TokenSupplyTransformerInitializer) NewTokenSupplyTransformer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer { func (i TokenSupplyTransformerInitializer) NewTokenSupplyTransformer(db *postgres.DB, blockChain core.BlockChain) shared.Transformer {
fetcher := NewFetcher(blockchain) getter := NewGetter(blockChain)
repository := ERC20TokenRepository{DB: db} repository := ERC20TokenRepository{DB: db}
transformer := Transformer{ transformer := Transformer{
Fetcher: &fetcher, Getter: &getter,
Repository: &repository, Repository: &repository,
Config: i.Config, Config: i.Config,
} }
@ -51,8 +51,8 @@ func (i TokenSupplyTransformerInitializer) NewTokenSupplyTransformer(db *postgre
} }
const ( const (
FetchingBlocksError = "Error fetching missing blocks starting at block number %d: %s" FetchingBlocksError = "Error getting missing blocks starting at block number %d: %s"
FetchingSupplyError = "Error fetching supply for block %d: %s" GetSupplyError = "Error getting supply for block %d: %s"
CreateSupplyError = "Error inserting token_supply for block %d: %s" CreateSupplyError = "Error inserting token_supply for block %d: %s"
) )
@ -74,8 +74,8 @@ func newTransformerError(err error, blockNumber int64, msg string) error {
func (t Transformer) Execute() error { func (t Transformer) Execute() error {
var upperBoundBlock int64 var upperBoundBlock int64
blockchain := t.Fetcher.GetBlockChain() blockChain := t.Getter.GetBlockChain()
lastBlock := blockchain.LastBlock().Int64() lastBlock := blockChain.LastBlock().Int64()
if t.Config.LastBlock == -1 { if t.Config.LastBlock == -1 {
upperBoundBlock = lastBlock upperBoundBlock = lastBlock
@ -93,14 +93,14 @@ func (t Transformer) Execute() error {
} }
// Fetch supply for missing blocks // Fetch supply for missing blocks
log.Printf("Fetching totalSupply for %d blocks", len(blocks)) log.Printf("Gets totalSupply for %d blocks", len(blocks))
// For each block missing total supply, create supply model and feed the missing data into the repository // For each block missing total supply, create supply model and feed the missing data into the repository
for _, blockNumber := range blocks { for _, blockNumber := range blocks {
totalSupply, err := t.Fetcher.FetchBigInt("totalSupply", t.Config.Abi, t.Config.Address, blockNumber, nil) totalSupply, err := t.Getter.GetTotalSupply(t.Config.Abi, t.Config.Address, blockNumber)
if err != nil { if err != nil {
return newTransformerError(err, blockNumber, FetchingSupplyError) return newTransformerError(err, blockNumber, GetSupplyError)
} }
// Create the supply model // Create the supply model
model := createTokenSupplyModel(totalSupply, t.Config.Address, blockNumber) model := createTokenSupplyModel(totalSupply, t.Config.Address, blockNumber)

View File

@ -38,7 +38,7 @@ var testContractConfig = erc20_watcher.ContractConfig{
var config = testContractConfig var config = testContractConfig
var _ = Describe("Everyblock transformer", func() { var _ = Describe("Everyblock transformer", func() {
var fetcher mocks.Fetcher var getter mocks.Getter
var repository mocks.ERC20TokenRepository var repository mocks.ERC20TokenRepository
var transformer every_block.Transformer var transformer every_block.Transformer
var blockChain *fakes.MockBlockChain var blockChain *fakes.MockBlockChain
@ -51,14 +51,14 @@ var _ = Describe("Everyblock transformer", func() {
BeforeEach(func() { BeforeEach(func() {
blockChain = fakes.NewMockBlockChain() blockChain = fakes.NewMockBlockChain()
blockChain.SetLastBlock(&defaultLastBlock) blockChain.SetLastBlock(&defaultLastBlock)
fetcher = mocks.Fetcher{BlockChain: blockChain} getter = mocks.NewGetter(blockChain)
fetcher.SetSupply(initialSupply) getter.Fetcher.SetSupply(initialSupply)
repository = mocks.ERC20TokenRepository{} repository = mocks.ERC20TokenRepository{}
repository.SetMissingSupplyBlocks([]int64{config.FirstBlock}) repository.SetMissingSupplyBlocks([]int64{config.FirstBlock})
//setting the mock repository to return the first block as the missing blocks //setting the mock repository to return the first block as the missing blocks
transformer = every_block.Transformer{ transformer = every_block.Transformer{
Fetcher: &fetcher, Getter: &getter,
Repository: &repository, Repository: &repository,
} }
transformer.SetConfiguration(config) transformer.SetConfiguration(config)
@ -68,10 +68,10 @@ var _ = Describe("Everyblock transformer", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(fetcher.FetchedBlocks)).To(Equal(1)) Expect(len(getter.Fetcher.FetchedBlocks)).To(Equal(1))
Expect(fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock)) Expect(getter.Fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock))
Expect(fetcher.Abi).To(Equal(config.Abi)) Expect(getter.Fetcher.Abi).To(Equal(config.Abi))
Expect(fetcher.ContractAddress).To(Equal(config.Address)) Expect(getter.Fetcher.ContractAddress).To(Equal(config.Address))
Expect(repository.StartingBlock).To(Equal(config.FirstBlock)) Expect(repository.StartingBlock).To(Equal(config.FirstBlock))
Expect(repository.EndingBlock).To(Equal(config.LastBlock)) Expect(repository.EndingBlock).To(Equal(config.LastBlock))
@ -93,10 +93,10 @@ var _ = Describe("Everyblock transformer", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(len(fetcher.FetchedBlocks)).To(Equal(3)) Expect(len(getter.Fetcher.FetchedBlocks)).To(Equal(3))
Expect(fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock, config.FirstBlock+1, config.FirstBlock+2)) Expect(getter.Fetcher.FetchedBlocks).To(ConsistOf(config.FirstBlock, config.FirstBlock+1, config.FirstBlock+2))
Expect(fetcher.Abi).To(Equal(config.Abi)) Expect(getter.Fetcher.Abi).To(Equal(config.Abi))
Expect(fetcher.ContractAddress).To(Equal(config.Address)) Expect(getter.Fetcher.ContractAddress).To(Equal(config.Address))
Expect(len(repository.TotalSuppliesCreated)).To(Equal(3)) Expect(len(repository.TotalSuppliesCreated)).To(Equal(3))
Expect(repository.TotalSuppliesCreated[0].Value).To(Equal(initialSupplyPlusOne)) Expect(repository.TotalSuppliesCreated[0].Value).To(Equal(initialSupplyPlusOne))
@ -110,9 +110,9 @@ var _ = Describe("Everyblock transformer", func() {
err := transformer.Execute() err := transformer.Execute()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(fetcher.FetchedBlocks).To(ConsistOf(testContractConfig.FirstBlock)) Expect(getter.Fetcher.FetchedBlocks).To(ConsistOf(testContractConfig.FirstBlock))
Expect(fetcher.Abi).To(Equal(testContractConfig.Abi)) Expect(getter.Fetcher.Abi).To(Equal(testContractConfig.Abi))
Expect(fetcher.ContractAddress).To(Equal(testContractConfig.Address)) Expect(getter.Fetcher.ContractAddress).To(Equal(testContractConfig.Address))
Expect(repository.StartingBlock).To(Equal(testContractConfig.FirstBlock)) Expect(repository.StartingBlock).To(Equal(testContractConfig.FirstBlock))
Expect(repository.EndingBlock).To(Equal(testContractConfig.LastBlock)) Expect(repository.EndingBlock).To(Equal(testContractConfig.LastBlock))
@ -146,22 +146,22 @@ var _ = Describe("Everyblock transformer", func() {
failureRepository := mocks.FailureRepository{} failureRepository := mocks.FailureRepository{}
failureRepository.SetMissingSupplyBlocksFail(true) failureRepository.SetMissingSupplyBlocksFail(true)
transformer = every_block.Transformer{ transformer = every_block.Transformer{
Fetcher: &fetcher, Getter: &getter,
Repository: &failureRepository, Repository: &failureRepository,
} }
err := transformer.Execute() err := transformer.Execute()
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error())) Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
Expect(err.Error()).To(ContainSubstring("fetching missing blocks")) Expect(err.Error()).To(ContainSubstring("getting missing blocks"))
}) })
It("returns an error if the call to the blockChain fails", func() { It("returns an error if the call to the blockChain fails", func() {
failureBlockchain := fakes.NewMockBlockChain() failureBlockchain := fakes.NewMockBlockChain()
failureBlockchain.SetLastBlock(&defaultLastBlock) failureBlockchain.SetLastBlock(&defaultLastBlock)
failureBlockchain.SetFetchContractDataErr(fakes.FakeError) failureBlockchain.SetFetchContractDataErr(fakes.FakeError)
fetcher := every_block.NewFetcher(failureBlockchain) getter := every_block.NewGetter(failureBlockchain)
transformer = every_block.Transformer{ transformer = every_block.Transformer{
Fetcher: &fetcher, Getter: &getter,
Repository: &repository, Repository: &repository,
} }
err := transformer.Execute() err := transformer.Execute()
@ -176,7 +176,7 @@ var _ = Describe("Everyblock transformer", func() {
failureRepository.SetCreateSupplyFail(true) failureRepository.SetCreateSupplyFail(true)
transformer = every_block.Transformer{ transformer = every_block.Transformer{
Fetcher: &fetcher, Getter: &getter,
Repository: &failureRepository, Repository: &failureRepository,
} }
err := transformer.Execute() err := transformer.Execute()

View 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 every_block_test
import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"io/ioutil"
"log"
)
func TestEveryBlock(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Generic EveryBlock Suite")
}
var _ = BeforeSuite(func() {
log.SetOutput(ioutil.Discard)
})

View 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 every_block
import (
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/examples/generic"
"github.com/vulcanize/vulcanizedb/pkg/core"
"math/big"
)
// Getter serves as a higher level data fetcher that invokes its underlying Fetcher methods for a given contract method
// Interface definition for a Getter
type GenericGetterInterface interface {
GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error)
GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error)
GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error)
GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error)
GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error)
GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error)
GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error)
GetBlockChain() core.BlockChain
}
// Getter struct
type Getter struct {
fetcher generic.Fetcher // Underlying Fetcher
}
// Initializes and returns a Getter with the given blockchain
func NewGetter(blockChain core.BlockChain) Getter {
return Getter{
fetcher: generic.Fetcher{
BlockChain: blockChain,
},
}
}
// Public getter methods for calling contract methods
func (g Getter) GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) {
return g.fetcher.FetchAddress("owner", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) {
return g.fetcher.FetchBool("stopped", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) {
return g.fetcher.FetchString("name", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) {
return g.fetcher.FetchHash("name", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) {
return g.fetcher.FetchString("symbol", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) {
return g.fetcher.FetchHash("symbol", contractAbi, contractAddress, blockNumber, nil)
}
func (g Getter) GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) {
return g.fetcher.FetchBigInt("decimals", contractAbi, contractAddress, blockNumber, nil)
}
// Method to retrieve the Getter's blockchain
func (g Getter) GetBlockChain() core.BlockChain {
return g.fetcher.BlockChain
}

View File

@ -0,0 +1,364 @@
// 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/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/ethereum/go-ethereum/common"
"github.com/vulcanize/vulcanizedb/examples/constants"
"github.com/vulcanize/vulcanizedb/examples/generic/every_block"
"github.com/vulcanize/vulcanizedb/pkg/fakes"
"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"
"math/big"
)
var _ = Describe("every_block Getter", func() {
blockNumber := int64(5502914)
Describe("stopped", func() {
It("checks whether or not the contract has been stopped", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetStoppedStatus(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult bool
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "stopped", nil, &expected, blockNumber)
})
It("gets dai token's stopped status 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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetStoppedStatus(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(false))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetStoppedStatus("", "", 0)
Expect(result).To(Equal(false))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("stopped"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("owner", func() {
It("checks what the contract's owner address is", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetOwner(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult common.Address
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "owner", nil, &expected, blockNumber)
})
It("gets dai token's owner address 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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetOwner(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := common.HexToAddress("0x0000000000000000000000000000000000000000")
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetOwner("", "", 0)
expectedResult := new(common.Address)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("owner"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("hash name", func() {
It("checks the contract's name", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetHashName(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult common.Hash
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "name", nil, &expected, blockNumber)
})
It("gets dai token's name at the given blockheight", func() {
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
rawRpcClient, err := rpc.Dial(infuraIPC)
Expect(err).NotTo(HaveOccurred())
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetHashName(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := common.HexToHash("0x44616920537461626c65636f696e2076312e3000000000000000000000000000")
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetHashName("", "", 0)
expectedResult := new(common.Hash)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("name"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("hash symbol", func() {
It("checks the contract's symbol", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetHashSymbol(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult common.Hash
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "symbol", nil, &expected, blockNumber)
})
It("gets dai token's symbol at the given blockheight", func() {
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
rawRpcClient, err := rpc.Dial(infuraIPC)
Expect(err).NotTo(HaveOccurred())
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetHashSymbol(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := common.HexToHash("0x4441490000000000000000000000000000000000000000000000000000000000")
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetHashSymbol("", "", 0)
expectedResult := new(common.Hash)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("symbol"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("decimals", func() {
It("checks what the token's number of decimals", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetDecimals(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult big.Int
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "decimals", nil, &expected, blockNumber)
})
It("gets dai token's number of decimals 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)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetDecimals(constants.DaiAbiString, constants.DaiContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := big.Int{}
expectedResult.SetString("18", 10)
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetDecimals("", "", 0)
expectedResult := new(big.Int)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("decimals"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("string name", func() {
It("checks the contract's name", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetStringName(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult string
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "name", nil, &expected, blockNumber)
})
It("gets tusd token's name at the given blockheight", func() {
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
rawRpcClient, err := rpc.Dial(infuraIPC)
Expect(err).NotTo(HaveOccurred())
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetStringName(constants.TusdAbiString, constants.TusdContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := "TrueUSD"
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetStringName("", "", 0)
expectedResult := new(string)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("name"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
Describe("string symbol", func() {
It("checks the contract's symbol", func() {
fakeBlockChain := fakes.NewMockBlockChain()
testGetter := every_block.NewGetter(fakeBlockChain)
testAbi := "testAbi"
testContractAddress := "testContractAddress"
_, err := testGetter.GetStringSymbol(testAbi, testContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
var expectedResult string
expected := &expectedResult
fakeBlockChain.AssertFetchContractDataCalledWith(testAbi, testContractAddress, "symbol", nil, &expected, blockNumber)
})
It("gets tusd token's symbol at the given blockheight", func() {
infuraIPC := "https://mainnet.infura.io/v3/b09888c1113640cc9ab42750ce750c05"
rawRpcClient, err := rpc.Dial(infuraIPC)
Expect(err).NotTo(HaveOccurred())
rpcClient := client.NewRpcClient(rawRpcClient, infuraIPC)
ethClient := ethclient.NewClient(rawRpcClient)
blockChainClient := client.NewEthClient(ethClient)
node := node.MakeNode(rpcClient)
transactionConverter := rpc2.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(blockChainClient, node, transactionConverter)
realGetter := every_block.NewGetter(blockChain)
result, err := realGetter.GetStringName(constants.TusdAbiString, constants.TusdContractAddress, blockNumber)
Expect(err).NotTo(HaveOccurred())
expectedResult := "TrueUSD"
Expect(result).To(Equal(expectedResult))
})
It("returns an error if the call to the blockchain fails", func() {
blockChain := fakes.NewMockBlockChain()
blockChain.SetFetchContractDataErr(fakes.FakeError)
errorGetter := every_block.NewGetter(blockChain)
result, err := errorGetter.GetStringSymbol("", "", 0)
expectedResult := new(string)
Expect(result).To(Equal(*expectedResult))
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("symbol"))
Expect(err.Error()).To(ContainSubstring(fakes.FakeError.Error()))
})
})
})

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package every_block package generic
import ( import (
"fmt" "fmt"
@ -23,26 +23,28 @@ import (
"github.com/vulcanize/vulcanizedb/pkg/core" "github.com/vulcanize/vulcanizedb/pkg/core"
) )
// Fetcher serves as the lower level data fetcher that calls the underlying
// blockchain's FetchConctractData method for a given return type
// Interface definition for a Fetcher // Interface definition for a Fetcher
type ERC20FetcherInterface interface { type FetcherInterface interface {
FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (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) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error)
FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error)
GetBlockChain() core.BlockChain FetchString(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (string, error)
FetchHash(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Hash, error)
} }
// Initializes and returns a Fetcher with the given blockchain // Used to create a new Fetcher error for a given error and fetch method
func NewFetcher(blockChain core.BlockChain) Fetcher { func newFetcherError(err error, fetchMethod string) *fetcherError {
return Fetcher{ e := fetcherError{err.Error(), fetchMethod}
BlockChain: blockChain, log.Println(e.Error())
} return &e
} }
// Fetcher struct // Fetcher struct
type Fetcher struct { type Fetcher struct {
BlockChain core.BlockChain BlockChain core.BlockChain // Underyling Blockchain
ContractAbi string
ContractAddress string
} }
// Fetcher error // Fetcher error
@ -56,14 +58,9 @@ func (fe *fetcherError) Error() string {
return fmt.Sprintf("Error fetching %s: %s", fe.fetchMethod, fe.err) 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 // Generic Fetcher methods used by Getters to call contract methods
func newFetcherError(err error, fetchMethod string) *fetcherError {
e := fetcherError{err.Error(), fetchMethod}
log.Println(e.Error())
return &e
}
// Method used to fetch big.Int result from contract // Method used to fetch big.Int value from contract
func (f Fetcher) FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) { func (f Fetcher) FetchBigInt(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
var result = new(big.Int) var result = new(big.Int)
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber) err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
@ -75,7 +72,7 @@ func (f Fetcher) FetchBigInt(method, contractAbi, contractAddress string, blockN
return *result, nil return *result, nil
} }
// Method used to fetch bool result from contract // Method used to fetch bool value from contract
func (f Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) { func (f Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) {
var result = new(bool) var result = new(bool)
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber) err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
@ -87,7 +84,7 @@ func (f Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNum
return *result, nil return *result, nil
} }
// Method used to fetch address result from contract // Method used to fetch address value from contract
func (f Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) { func (f Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) {
var result = new(common.Address) var result = new(common.Address)
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber) err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
@ -99,7 +96,26 @@ func (f Fetcher) FetchAddress(method, contractAbi, contractAddress string, block
return *result, nil return *result, nil
} }
// Getter method for Fetcher's blockchain // Method used to fetch string value from contract
func (f Fetcher) GetBlockChain() core.BlockChain { func (f Fetcher) FetchString(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (string, error) {
return f.BlockChain var result = new(string)
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 hash value from contract
func (f Fetcher) FetchHash(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Hash, error) {
var result = new(common.Hash)
err := f.BlockChain.FetchContractData(contractAbi, contractAddress, method, methodArgs, &result, blockNumber)
if err != nil {
return *result, newFetcherError(err, method)
}
return *result, nil
} }

View File

@ -33,6 +33,12 @@ type Fetcher struct {
supply big.Int supply big.Int
balance map[string]*big.Int balance map[string]*big.Int
allowance map[string]map[string]*big.Int allowance map[string]map[string]*big.Int
owner common.Address
stopped bool
stringName string
hashName common.Hash
stringSymbol string
hashSymbol common.Hash
} }
func (f *Fetcher) SetSupply(supply string) { func (f *Fetcher) SetSupply(supply string) {
@ -58,7 +64,7 @@ func (f *Fetcher) FetchBigInt(method, contractAbi, contractAddress string, block
} }
if method == "balanceOf" { if method == "balanceOf" {
rfl := reflect.ValueOf(methodArgs).Field(0) rfl := reflect.ValueOf(methodArgs[0])
tokenHolderAddr := rfl.Interface().(string) tokenHolderAddr := rfl.Interface().(string)
pnt := f.balance[tokenHolderAddr] pnt := f.balance[tokenHolderAddr]
f.balance[tokenHolderAddr].Add(pnt, accumulator) f.balance[tokenHolderAddr].Add(pnt, accumulator)
@ -67,8 +73,8 @@ func (f *Fetcher) FetchBigInt(method, contractAbi, contractAddress string, block
} }
if method == "allowance" { if method == "allowance" {
rfl1 := reflect.ValueOf(methodArgs).Field(0) rfl1 := reflect.ValueOf(methodArgs[0])
rfl2 := reflect.ValueOf(methodArgs).Field(1) rfl2 := reflect.ValueOf(methodArgs[1])
tokenHolderAddr := rfl1.Interface().(string) tokenHolderAddr := rfl1.Interface().(string)
spenderAddr := rfl2.Interface().(string) spenderAddr := rfl2.Interface().(string)
pnt := f.allowance[tokenHolderAddr][spenderAddr] pnt := f.allowance[tokenHolderAddr][spenderAddr]
@ -82,14 +88,132 @@ func (f *Fetcher) FetchBigInt(method, contractAbi, contractAddress string, block
} }
func (f *Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) { func (f *Fetcher) FetchBool(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (bool, error) {
//TODO: this
return false, nil f.Abi = contractAbi
f.ContractAddress = contractAddress
f.FetchedBlocks = append(f.FetchedBlocks, blockNumber)
b := true
if method == "stopped" {
f.stopped = b
return f.stopped, nil
}
return false, errors.New("invalid method argument")
} }
func (f *Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) { func (f *Fetcher) FetchAddress(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Address, error) {
//TODO: this
var adr common.Address f.Abi = contractAbi
return adr, nil f.ContractAddress = contractAddress
f.FetchedBlocks = append(f.FetchedBlocks, blockNumber)
adr := common.StringToAddress("test_address")
if method == "owner" {
f.owner = adr
return f.owner, nil
}
return common.StringToAddress(""), errors.New("invalid method argument")
}
func (f *Fetcher) FetchString(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (string, error) {
f.Abi = contractAbi
f.ContractAddress = contractAddress
f.FetchedBlocks = append(f.FetchedBlocks, blockNumber)
if method == "name" {
f.stringName = "test_name"
return f.stringName, nil
}
if method == "symbol" {
f.stringSymbol = "test_symbol"
return f.stringSymbol, nil
}
return "", errors.New("invalid method argument")
}
func (f *Fetcher) FetchHash(method, contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (common.Hash, error) {
f.Abi = contractAbi
f.ContractAddress = contractAddress
f.FetchedBlocks = append(f.FetchedBlocks, blockNumber)
if method == "name" {
f.hashName = common.StringToHash("test_name")
return f.hashName, nil
}
if method == "symbol" {
f.hashSymbol = common.StringToHash("test_symbol")
return f.hashSymbol, nil
}
return common.StringToHash(""), errors.New("invalid method argument")
}
type Getter struct {
Fetcher Fetcher
}
func NewGetter(blockChain core.BlockChain) Getter {
return Getter{
Fetcher: Fetcher{
BlockChain: blockChain,
},
}
}
func (g *Getter) GetTotalSupply(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) {
return g.Fetcher.FetchBigInt("totalSupply", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetBalance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
return g.Fetcher.FetchBigInt("balanceOf", contractAbi, contractAddress, blockNumber, methodArgs)
}
func (g *Getter) GetAllowance(contractAbi, contractAddress string, blockNumber int64, methodArgs []interface{}) (big.Int, error) {
return g.Fetcher.FetchBigInt("allowance", contractAbi, contractAddress, blockNumber, methodArgs)
}
func (g *Getter) GetOwner(contractAbi, contractAddress string, blockNumber int64) (common.Address, error) {
return g.Fetcher.FetchAddress("owner", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetStoppedStatus(contractAbi, contractAddress string, blockNumber int64) (bool, error) {
return g.Fetcher.FetchBool("stopped", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetStringName(contractAbi, contractAddress string, blockNumber int64) (string, error) {
return g.Fetcher.FetchString("name", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetHashName(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) {
return g.Fetcher.FetchHash("name", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetStringSymbol(contractAbi, contractAddress string, blockNumber int64) (string, error) {
return g.Fetcher.FetchString("symbol", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetHashSymbol(contractAbi, contractAddress string, blockNumber int64) (common.Hash, error) {
return g.Fetcher.FetchHash("symbol", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetDecimals(contractAbi, contractAddress string, blockNumber int64) (big.Int, error) {
return g.Fetcher.FetchBigInt("decimals", contractAbi, contractAddress, blockNumber, nil)
}
func (g *Getter) GetBlockChain() core.BlockChain {
return g.Fetcher.BlockChain
} }
type ERC20TokenRepository struct { type ERC20TokenRepository struct {

View File

@ -13,7 +13,7 @@ type MockBlockChain struct {
fetchContractDataPassedAbi string fetchContractDataPassedAbi string
fetchContractDataPassedAddress string fetchContractDataPassedAddress string
fetchContractDataPassedMethod string fetchContractDataPassedMethod string
fetchContractDataPassedMethodArgs []interface{} fetchContractDataPassedMethodArgs []interface{}
fetchContractDataPassedResult interface{} fetchContractDataPassedResult interface{}
fetchContractDataPassedBlockNumber int64 fetchContractDataPassedBlockNumber int64
getBlockByNumberErr error getBlockByNumberErr error