adjust block/uncle reward tests and add methods to pkg/geth blockchain and ethclient for direct fetching of eth balances
This commit is contained in:
parent
9030cff2bd
commit
185f4c0e93
@ -0,0 +1,9 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE blocks
|
||||
ALTER COLUMN uncles_reward TYPE NUMERIC USING uncles_reward::NUMERIC,
|
||||
ALTER COLUMN reward TYPE NUMERIC USING reward::NUMERIC;
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE blocks
|
||||
ALTER COLUMN uncles_reward TYPE DOUBLE PRECISION USING uncles_reward::DOUBLE PRECISION,
|
||||
ALTER COLUMN reward TYPE DOUBLE PRECISION USING reward::DOUBLE PRECISION;
|
@ -42,7 +42,7 @@ var _ = Describe("Rewards calculations", func() {
|
||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||
block, err := blockChain.GetBlockByNumber(1071819)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(block.Reward).To(Equal(5.31355))
|
||||
Expect(block.Reward).To(Equal("5313550000000000000"))
|
||||
})
|
||||
|
||||
It("calculates an uncle reward for a real block", func() {
|
||||
@ -56,7 +56,7 @@ var _ = Describe("Rewards calculations", func() {
|
||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||
block, err := blockChain.GetBlockByNumber(1071819)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(block.UnclesReward).To(Equal(6.875))
|
||||
Expect(block.UnclesReward).To(Equal("6875000000000000000"))
|
||||
})
|
||||
|
||||
})
|
||||
|
24
libraries/shared/utilities/utils.go
Normal file
24
libraries/shared/utilities/utils.go
Normal file
@ -0,0 +1,24 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2019 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package utilities
|
||||
|
||||
func NullToZero(str string) string {
|
||||
if str == "" {
|
||||
return "0"
|
||||
}
|
||||
return str
|
||||
}
|
@ -26,6 +26,7 @@ import (
|
||||
|
||||
type BlockChain interface {
|
||||
ContractDataFetcher
|
||||
AccountDataFetcher
|
||||
GetBlockByNumber(blockNumber int64) (Block, error)
|
||||
GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error)
|
||||
GetHeaderByNumber(blockNumber int64) (Header, error)
|
||||
@ -39,3 +40,7 @@ type BlockChain interface {
|
||||
type ContractDataFetcher interface {
|
||||
FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error
|
||||
}
|
||||
|
||||
type AccountDataFetcher interface {
|
||||
GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error)
|
||||
}
|
||||
|
@ -32,4 +32,5 @@ type EthClient interface {
|
||||
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
||||
TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error)
|
||||
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
||||
BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)
|
||||
}
|
||||
|
@ -19,11 +19,12 @@ package repositories
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"math/big"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/libraries/shared/utilities"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||
@ -131,7 +132,23 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err
|
||||
(eth_node_id, number, gaslimit, gasused, time, difficulty, hash, nonce, parenthash, size, uncle_hash, is_final, miner, extra_data, reward, uncles_reward, eth_node_fingerprint)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||
RETURNING id `,
|
||||
blockRepository.database.NodeID, block.Number, block.GasLimit, block.GasUsed, block.Time, block.Difficulty, block.Hash, block.Nonce, block.ParentHash, block.Size, block.UncleHash, block.IsFinal, block.Miner, block.ExtraData, block.Reward, block.UnclesReward, blockRepository.database.Node.ID).
|
||||
blockRepository.database.NodeID,
|
||||
block.Number,
|
||||
block.GasLimit,
|
||||
block.GasUsed,
|
||||
block.Time,
|
||||
block.Difficulty,
|
||||
block.Hash,
|
||||
block.Nonce,
|
||||
block.ParentHash,
|
||||
block.Size,
|
||||
block.UncleHash,
|
||||
block.IsFinal,
|
||||
block.Miner,
|
||||
block.ExtraData,
|
||||
utilities.NullToZero(block.Reward),
|
||||
utilities.NullToZero(block.UnclesReward),
|
||||
blockRepository.database.Node.ID).
|
||||
Scan(&blockId)
|
||||
if insertBlockErr != nil {
|
||||
rollbackErr := tx.Rollback()
|
||||
@ -186,7 +203,7 @@ func (blockRepository BlockRepository) createUncleReward(tx *sqlx.Tx, blockId in
|
||||
(block_id, block_hash, uncle_hash, uncle_reward, miner_address)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id`,
|
||||
blockId, blockHash, miner, uncleHash, amount)
|
||||
blockId, blockHash, miner, uncleHash, utilities.NullToZero(amount))
|
||||
return err
|
||||
}
|
||||
|
||||
@ -216,7 +233,7 @@ func (blockRepository BlockRepository) createTransaction(tx *sqlx.Tx, blockId in
|
||||
(block_id, gaslimit, gasprice, hash, input_data, nonce, raw, tx_from, tx_index, tx_to, "value")
|
||||
VALUES ($1, $2::NUMERIC, $3::NUMERIC, $4, $5, $6::NUMERIC, $7, $8, $9::NUMERIC, $10, $11::NUMERIC)
|
||||
RETURNING id`, blockId, transaction.GasLimit, transaction.GasPrice, transaction.Hash, transaction.Data,
|
||||
transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To, transaction.Value)
|
||||
transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To, nullStringToZero(transaction.Value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -45,6 +45,10 @@ type MockBlockChain struct {
|
||||
lastBlock *big.Int
|
||||
node core.Node
|
||||
Transactions []core.TransactionModel
|
||||
passedAccountAddress common.Address
|
||||
passedBlockNumer *big.Int
|
||||
passedAccountBalance *big.Int
|
||||
getAccountBalanceErr error
|
||||
}
|
||||
|
||||
func NewMockBlockChain() *MockBlockChain {
|
||||
@ -141,3 +145,17 @@ func (chain *MockBlockChain) AssertFetchContractDataCalledWith(abiJSON string, a
|
||||
func (blockChain *MockBlockChain) AssertGetEthLogsWithCustomQueryCalledWith(query ethereum.FilterQuery) {
|
||||
Expect(blockChain.logQuery).To(Equal(query))
|
||||
}
|
||||
|
||||
func (blockChain *MockBlockChain) SetGetAccountBalanceErr(err error) {
|
||||
blockChain.getAccountBalanceErr = err
|
||||
}
|
||||
|
||||
func (blockChain *MockBlockChain) SetGetAccountBalance(balance *big.Int) {
|
||||
blockChain.passedAccountBalance = balance
|
||||
}
|
||||
|
||||
func (blockChain *MockBlockChain) GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||
blockChain.passedAccountAddress = address
|
||||
blockChain.passedBlockNumer = blockNumber
|
||||
return blockChain.passedAccountBalance, blockChain.getAccountBalanceErr
|
||||
}
|
||||
|
@ -54,6 +54,11 @@ type MockEthClient struct {
|
||||
passedMethod string
|
||||
transactionSenderErr error
|
||||
transactionReceiptErr error
|
||||
passedAddress common.Address
|
||||
passedBlockNumber *big.Int
|
||||
passedBalance *big.Int
|
||||
balanceAtErr error
|
||||
passedbalanceAtContext context.Context
|
||||
}
|
||||
|
||||
func NewMockEthClient() *MockEthClient {
|
||||
@ -208,3 +213,24 @@ func (client *MockEthClient) AssertFilterLogsCalledWith(ctx context.Context, q e
|
||||
func (client *MockEthClient) AssertBatchCalledWith(method string) {
|
||||
Expect(client.passedMethod).To(Equal(method))
|
||||
}
|
||||
|
||||
func (client *MockEthClient) SetBalanceAtErr(err error) {
|
||||
client.balanceAtErr = err
|
||||
}
|
||||
|
||||
func (client *MockEthClient) SetBalanceAt(balance *big.Int) {
|
||||
client.passedBalance = balance
|
||||
}
|
||||
|
||||
func (client *MockEthClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||
client.passedbalanceAtContext = ctx
|
||||
client.passedAddress = account
|
||||
client.passedBlockNumber = blockNumber
|
||||
return client.passedBalance, client.balanceAtErr
|
||||
}
|
||||
|
||||
func (client *MockEthClient) AssertBalanceAtCalled(ctx context.Context, account common.Address, blockNumber *big.Int) {
|
||||
Expect(client.passedbalanceAtContext).To(Equal(ctx))
|
||||
Expect(client.passedAddress).To(Equal(account))
|
||||
Expect(client.passedBlockNumber).To(Equal(blockNumber))
|
||||
}
|
||||
|
@ -265,3 +265,7 @@ func (blockChain *BlockChain) getPOWHeaders(blockNumbers []int64) (headers []cor
|
||||
|
||||
return headers, err
|
||||
}
|
||||
|
||||
func (blockChain *BlockChain) GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||
return blockChain.ethClient.BalanceAt(context.Background(), address, blockNumber)
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package geth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
@ -244,4 +245,28 @@ var _ = Describe("Geth blockchain", func() {
|
||||
Expect(result).To(Equal(big.NewInt(blockNumber)))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("getting an account balance", func() {
|
||||
It("fetches the balance for a given account address at a given block height", func() {
|
||||
balance := big.NewInt(100000)
|
||||
mockClient.SetBalanceAt(balance)
|
||||
|
||||
result, err := blockChain.GetAccountBalance(common.HexToAddress("0x40"), big.NewInt(100))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
mockClient.AssertBalanceAtCalled(context.Background(), common.HexToAddress("0x40"), big.NewInt(100))
|
||||
Expect(result).To(Equal(balance))
|
||||
})
|
||||
|
||||
It("fails if the client returns an error", func() {
|
||||
balance := big.NewInt(100000)
|
||||
mockClient.SetBalanceAt(balance)
|
||||
setErr := errors.New("testError")
|
||||
mockClient.SetBalanceAtErr(setErr)
|
||||
|
||||
_, err := blockChain.GetAccountBalance(common.HexToAddress("0x40"), big.NewInt(100))
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(Equal(setErr))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -56,3 +56,7 @@ func (client EthClient) TransactionSender(ctx context.Context, tx *types.Transac
|
||||
func (client EthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||
return client.client.TransactionReceipt(ctx, txHash)
|
||||
}
|
||||
|
||||
func (client EthClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||
return client.client.BalanceAt(ctx, account, blockNumber)
|
||||
}
|
||||
|
@ -17,10 +17,13 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/vulcanize/vulcanizedb/libraries/shared/utilities"
|
||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BlockConverter struct {
|
||||
@ -54,7 +57,7 @@ func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error)
|
||||
}
|
||||
coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()).String()
|
||||
uncleRewards, mappedUncleRewards := CalcUnclesReward(coreBlock, gethBlock.Uncles())
|
||||
coreBlock.UnclesReward = uncleRewards.String()
|
||||
coreBlock.UnclesReward = utilities.NullToZero(uncleRewards.String())
|
||||
coreBlock.MappedUncleRewards = mappedUncleRewards
|
||||
return coreBlock, nil
|
||||
}
|
||||
|
@ -114,9 +114,13 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(vulcCommon.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(5.31355))
|
||||
|
||||
expectedBlockReward := new(big.Int)
|
||||
expectedBlockReward.SetString("5313550000000000000", 10)
|
||||
|
||||
blockReward := vulcCommon.CalcBlockReward(coreBlock, block.Uncles())
|
||||
Expect(blockReward.String()).To(Equal(expectedBlockReward.String()))
|
||||
})
|
||||
|
||||
It("calculates the uncles reward for a block", func() {
|
||||
@ -151,9 +155,19 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(vulcCommon.CalcUnclesReward(coreBlock, block.Uncles())).To(Equal(6.875))
|
||||
|
||||
expectedTotalReward := new(big.Int)
|
||||
expectedTotalReward.SetString("6875000000000000000", 10)
|
||||
totalReward, mappedRewards := vulcCommon.CalcUnclesReward(coreBlock, block.Uncles())
|
||||
Expect(totalReward.String()).To(Equal(expectedTotalReward.String()))
|
||||
|
||||
Expect(len(mappedRewards)).To(Equal(1))
|
||||
Expect(len(mappedRewards["0x0000000000000000000000000000000000000000"])).To(Equal(2))
|
||||
Expect(mappedRewards["0x0000000000000000000000000000000000000000"]["0xb629de4014b6e30cf9555ee833f1806fa0d8b8516fde194405f9c98c2deb8772"].String()).
|
||||
To(Equal(big.NewInt(3125000000000000000).String()))
|
||||
Expect(mappedRewards["0x0000000000000000000000000000000000000000"]["0x673f5231e4888a951e0bc8a25b5774b982e6e9e258362c21affaff6e02dd5a2b"].String()).
|
||||
To(Equal(big.NewInt(3750000000000000000).String()))
|
||||
})
|
||||
|
||||
It("decreases the static block reward from 5 to 3 for blocks after block 4,269,999", func() {
|
||||
@ -200,9 +214,12 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||
|
||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(vulcCommon.CalcBlockReward(coreBlock, block.Uncles())).To(Equal(3.024990672))
|
||||
|
||||
expectedRewards := new(big.Int)
|
||||
expectedRewards.SetString("3024990672000000000", 10)
|
||||
rewards := vulcCommon.CalcBlockReward(coreBlock, block.Uncles())
|
||||
Expect(rewards.String()).To(Equal(expectedRewards.String()))
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -37,6 +37,12 @@ func CalcUnclesReward(block core.Block, uncles []*types.Header) (*big.Int, map[s
|
||||
uncleBlockPlus8MinusMainBlock := uncleBlockPlus8.Sub(uncleBlockPlus8, mainBlock)
|
||||
thisUncleReward := rewardDiv8.Mul(rewardDiv8, uncleBlockPlus8MinusMainBlock)
|
||||
uncleRewards = uncleRewards.Add(uncleRewards, thisUncleReward)
|
||||
if mappedUncleRewards[uncle.Coinbase.Hex()] == nil {
|
||||
mappedUncleRewards[uncle.Coinbase.Hex()] = make(map[string]*big.Int)
|
||||
}
|
||||
if mappedUncleRewards[uncle.Coinbase.Hex()][uncle.Hash().Hex()] == nil {
|
||||
mappedUncleRewards[uncle.Coinbase.Hex()][uncle.Hash().Hex()] = new(big.Int)
|
||||
}
|
||||
mappedUncleRewards[uncle.Coinbase.Hex()][uncle.Hash().Hex()].Add(mappedUncleRewards[uncle.Coinbase.Hex()][uncle.Hash().Hex()], thisUncleReward)
|
||||
}
|
||||
return uncleRewards, mappedUncleRewards
|
||||
|
Loading…
Reference in New Issue
Block a user