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:
Ian Norden 2018-08-09 11:58:06 -05:00
parent 93960e7c4e
commit ccd21f73c9
12 changed files with 313 additions and 96 deletions

View File

@ -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
}

View File

@ -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()))
})
})
})
})

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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())
}

View File

@ -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)

View File

@ -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,

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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))

View File

@ -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)
}