From 9030cff2bd809dd8c3b91eef0f9a4110c247c3ed Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Thu, 21 Mar 2019 14:52:24 -0500 Subject: [PATCH 1/5] keep track of who is receiving uncle rewards --- .../00045_create_uncle_rewards_table.sql | 15 +++++ pkg/core/block.go | 35 ++++++----- .../postgres/repositories/block_repository.go | 30 ++++++++++ .../repositories/block_repository_test.go | 4 +- .../postgres/repositories/uncle_rewards.go | 1 + .../repositories/uncle_rewards_test.go | 1 + pkg/geth/converters/common/block_converter.go | 6 +- pkg/geth/converters/common/block_rewards.go | 60 ++++++++++++------- 8 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 db/migrations/00045_create_uncle_rewards_table.sql create mode 100644 pkg/datastore/postgres/repositories/uncle_rewards.go create mode 100644 pkg/datastore/postgres/repositories/uncle_rewards_test.go diff --git a/db/migrations/00045_create_uncle_rewards_table.sql b/db/migrations/00045_create_uncle_rewards_table.sql new file mode 100644 index 00000000..4c40561f --- /dev/null +++ b/db/migrations/00045_create_uncle_rewards_table.sql @@ -0,0 +1,15 @@ +-- +goose Up +CREATE TABLE public.uncle_rewards ( + id SERIAL PRIMARY KEY, + block_id INTEGER, + block_hash VARCHAR(66) NOT NULL, + uncle_hash VARCHAR(66) NOT NULL, + uncle_reward NUMERIC NOT NULL, + miner_address VARCHAR(66) NOT NULL, + CONSTRAINT block_id_fk FOREIGN KEY (block_id) + REFERENCES blocks (id) + ON DELETE CASCADE +); + +-- +goose Down +DROP TABLE public.uncle_rewards; diff --git a/pkg/core/block.go b/pkg/core/block.go index 279b8baf..e7546f19 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -16,21 +16,24 @@ package core +import "math/big" + type Block struct { - Reward float64 `db:"reward"` - Difficulty int64 `db:"difficulty"` - ExtraData string `db:"extra_data"` - GasLimit uint64 `db:"gaslimit"` - GasUsed uint64 `db:"gasused"` - Hash string `db:"hash"` - IsFinal bool `db:"is_final"` - Miner string `db:"miner"` - Nonce string `db:"nonce"` - Number int64 `db:"number"` - ParentHash string `db:"parenthash"` - Size string `db:"size"` - Time int64 `db:"time"` - Transactions []TransactionModel - UncleHash string `db:"uncle_hash"` - UnclesReward float64 `db:"uncles_reward"` + Reward string `db:"reward"` + Difficulty int64 `db:"difficulty"` + ExtraData string `db:"extra_data"` + GasLimit uint64 `db:"gaslimit"` + GasUsed uint64 `db:"gasused"` + Hash string `db:"hash"` + IsFinal bool `db:"is_final"` + Miner string `db:"miner"` + Nonce string `db:"nonce"` + Number int64 `db:"number"` + ParentHash string `db:"parenthash"` + Size string `db:"size"` + Time int64 `db:"time"` + Transactions []TransactionModel + UncleHash string `db:"uncle_hash"` + UnclesReward string `db:"uncles_reward"` + MappedUncleRewards map[string]map[string]*big.Int } diff --git a/pkg/datastore/postgres/repositories/block_repository.go b/pkg/datastore/postgres/repositories/block_repository.go index cdbed4a9..9fe2c0df 100644 --- a/pkg/datastore/postgres/repositories/block_repository.go +++ b/pkg/datastore/postgres/repositories/block_repository.go @@ -20,6 +20,7 @@ import ( "database/sql" "errors" log "github.com/sirupsen/logrus" + "math/big" "github.com/jmoiron/sqlx" @@ -139,6 +140,13 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err } return 0, postgres.ErrDBInsertFailed(insertBlockErr) } + if len(block.MappedUncleRewards) > 0 { + insertUncleErr := blockRepository.createUncleRewards(tx, blockId, block.Hash, block.MappedUncleRewards) + if insertUncleErr != nil { + tx.Rollback() + return 0, postgres.ErrDBInsertFailed(insertUncleErr) + } + } if len(block.Transactions) > 0 { insertTxErr := blockRepository.createTransactions(tx, blockId, block.Transactions) if insertTxErr != nil { @@ -160,6 +168,28 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err return blockId, nil } +func (blockRepository BlockRepository) createUncleRewards(tx *sqlx.Tx, blockId int64, blockHash string, mappedUncleRewards map[string]map[string]*big.Int) error { + for miner, uncleRewards := range mappedUncleRewards { + for uncleHash, reward := range uncleRewards { + err := blockRepository.createUncleReward(tx, blockId, blockHash, miner, uncleHash, reward.String()) + if err != nil { + return err + } + } + } + return nil +} + +func (blockRepository BlockRepository) createUncleReward(tx *sqlx.Tx, blockId int64, blockHash, miner, uncleHash, amount string) error { + _, err := tx.Exec( + `INSERT INTO uncle_rewards + (block_id, block_hash, uncle_hash, uncle_reward, miner_address) + VALUES ($1, $2, $3, $4, $5) + RETURNING id`, + blockId, blockHash, miner, uncleHash, amount) + return err +} + func (blockRepository BlockRepository) createTransactions(tx *sqlx.Tx, blockId int64, transactions []core.TransactionModel) error { for _, transaction := range transactions { err := blockRepository.createTransaction(tx, blockId, transaction) diff --git a/pkg/datastore/postgres/repositories/block_repository_test.go b/pkg/datastore/postgres/repositories/block_repository_test.go index 64b40fcb..fb126d00 100644 --- a/pkg/datastore/postgres/repositories/block_repository_test.go +++ b/pkg/datastore/postgres/repositories/block_repository_test.go @@ -84,8 +84,8 @@ var _ = Describe("Saving blocks", func() { uncleHash := "x789" blockSize := string("1000") difficulty := int64(10) - blockReward := float64(5.132) - unclesReward := float64(3.580) + blockReward := "5132000000000000000" + unclesReward := "3580000000000000000" block := core.Block{ Reward: blockReward, Difficulty: difficulty, diff --git a/pkg/datastore/postgres/repositories/uncle_rewards.go b/pkg/datastore/postgres/repositories/uncle_rewards.go new file mode 100644 index 00000000..3f43206c --- /dev/null +++ b/pkg/datastore/postgres/repositories/uncle_rewards.go @@ -0,0 +1 @@ +package repositories diff --git a/pkg/datastore/postgres/repositories/uncle_rewards_test.go b/pkg/datastore/postgres/repositories/uncle_rewards_test.go new file mode 100644 index 00000000..3f43206c --- /dev/null +++ b/pkg/datastore/postgres/repositories/uncle_rewards_test.go @@ -0,0 +1 @@ +package repositories diff --git a/pkg/geth/converters/common/block_converter.go b/pkg/geth/converters/common/block_converter.go index c12d095b..5b36c271 100644 --- a/pkg/geth/converters/common/block_converter.go +++ b/pkg/geth/converters/common/block_converter.go @@ -52,7 +52,9 @@ func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error) Transactions: transactions, UncleHash: gethBlock.UncleHash().Hex(), } - coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()) - coreBlock.UnclesReward = CalcUnclesReward(coreBlock, gethBlock.Uncles()) + coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()).String() + uncleRewards, mappedUncleRewards := CalcUnclesReward(coreBlock, gethBlock.Uncles()) + coreBlock.UnclesReward = uncleRewards.String() + coreBlock.MappedUncleRewards = mappedUncleRewards return coreBlock, nil } diff --git a/pkg/geth/converters/common/block_rewards.go b/pkg/geth/converters/common/block_rewards.go index fcf1a2c7..57f8df28 100644 --- a/pkg/geth/converters/common/block_rewards.go +++ b/pkg/geth/converters/common/block_rewards.go @@ -17,54 +17,68 @@ package common import ( + "math/big" + "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/params" "github.com/vulcanize/vulcanizedb/pkg/core" ) -func CalcUnclesReward(block core.Block, uncles []*types.Header) float64 { - var unclesReward float64 +// (U_n + 8 - B_n) * R / 8 +// Returns a map of miner addresses to a map of the uncles they mined (hashes) to the rewards received for that uncle +func CalcUnclesReward(block core.Block, uncles []*types.Header) (*big.Int, map[string]map[string]*big.Int) { + uncleRewards := new(big.Int) + mappedUncleRewards := make(map[string]map[string]*big.Int) for _, uncle := range uncles { - blockNumber := block.Number - staticBlockReward := float64(staticRewardByBlockNumber(blockNumber)) - unclesReward += (1.0 + float64(uncle.Number.Int64()-block.Number)/8.0) * staticBlockReward + staticBlockReward := staticRewardByBlockNumber(block.Number) + rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8)) + uncleBlock := big.NewInt(uncle.Number.Int64()) + uncleBlockPlus8 := uncleBlock.Add(uncleBlock, big.NewInt(8)) + mainBlock := big.NewInt(block.Number) + uncleBlockPlus8MinusMainBlock := uncleBlockPlus8.Sub(uncleBlockPlus8, mainBlock) + thisUncleReward := rewardDiv8.Mul(rewardDiv8, uncleBlockPlus8MinusMainBlock) + uncleRewards = uncleRewards.Add(uncleRewards, thisUncleReward) + mappedUncleRewards[uncle.Coinbase.Hex()][uncle.Hash().Hex()].Add(mappedUncleRewards[uncle.Coinbase.Hex()][uncle.Hash().Hex()], thisUncleReward) } - return unclesReward + return uncleRewards, mappedUncleRewards } -func CalcBlockReward(block core.Block, uncles []*types.Header) float64 { - blockNumber := block.Number - staticBlockReward := staticRewardByBlockNumber(blockNumber) +func CalcBlockReward(block core.Block, uncles []*types.Header) *big.Int { + staticBlockReward := staticRewardByBlockNumber(block.Number) transactionFees := calcTransactionFees(block) uncleInclusionRewards := calcUncleInclusionRewards(block, uncles) - return transactionFees + uncleInclusionRewards + staticBlockReward + tmp := transactionFees.Add(transactionFees, uncleInclusionRewards) + return tmp.Add(tmp, staticBlockReward) } -func calcTransactionFees(block core.Block) float64 { - var transactionFees float64 +func calcTransactionFees(block core.Block) *big.Int { + transactionFees := new(big.Int) for _, transaction := range block.Transactions { receipt := transaction.Receipt - transactionFees += float64(uint64(transaction.GasPrice) * receipt.GasUsed) + gasPrice := big.NewInt(transaction.GasPrice) + gasUsed := big.NewInt(int64(receipt.GasUsed)) + transactionFee := gasPrice.Mul(gasPrice, gasUsed) + transactionFees = transactionFees.Add(transactionFees, transactionFee) } - return transactionFees / params.Ether + return transactionFees } -func calcUncleInclusionRewards(block core.Block, uncles []*types.Header) float64 { - var uncleInclusionRewards float64 - staticBlockReward := staticRewardByBlockNumber(block.Number) +func calcUncleInclusionRewards(block core.Block, uncles []*types.Header) *big.Int { + uncleInclusionRewards := new(big.Int) for range uncles { - uncleInclusionRewards += staticBlockReward * 1 / 32 + staticBlockReward := staticRewardByBlockNumber(block.Number) + staticBlockReward.Div(staticBlockReward, big.NewInt(32)) + uncleInclusionRewards.Add(uncleInclusionRewards, staticBlockReward) } return uncleInclusionRewards } -func staticRewardByBlockNumber(blockNumber int64) float64 { - var staticBlockReward float64 +func staticRewardByBlockNumber(blockNumber int64) *big.Int { + staticBlockReward := new(big.Int) //https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/ if blockNumber >= 4370000 { - staticBlockReward = 3 + staticBlockReward.SetString("3000000000000000000", 10) } else { - staticBlockReward = 5 + staticBlockReward.SetString("5000000000000000000", 10) } return staticBlockReward } From 185f4c0e93db24dc0ffa91e7ad843170724e060a Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Thu, 21 Mar 2019 22:43:06 -0500 Subject: [PATCH 2/5] adjust block/uncle reward tests and add methods to pkg/geth blockchain and ethclient for direct fetching of eth balances --- ...46_update_block_and_uncle_reward_types.sql | 9 ++++++ integration_test/block_rewards_test.go | 4 +-- libraries/shared/utilities/utils.go | 24 +++++++++++++++ pkg/core/blockchain.go | 5 ++++ pkg/core/eth_client.go | 1 + .../postgres/repositories/block_repository.go | 25 +++++++++++++--- pkg/fakes/mock_blockchain.go | 18 ++++++++++++ pkg/fakes/mock_eth_client.go | 26 +++++++++++++++++ pkg/geth/blockchain.go | 4 +++ pkg/geth/blockchain_test.go | 25 ++++++++++++++++ pkg/geth/client/eth_client.go | 4 +++ pkg/geth/converters/common/block_converter.go | 7 +++-- .../converters/common/block_converter_test.go | 29 +++++++++++++++---- pkg/geth/converters/common/block_rewards.go | 6 ++++ 14 files changed, 173 insertions(+), 14 deletions(-) create mode 100644 db/migrations/00046_update_block_and_uncle_reward_types.sql create mode 100644 libraries/shared/utilities/utils.go diff --git a/db/migrations/00046_update_block_and_uncle_reward_types.sql b/db/migrations/00046_update_block_and_uncle_reward_types.sql new file mode 100644 index 00000000..8bca0604 --- /dev/null +++ b/db/migrations/00046_update_block_and_uncle_reward_types.sql @@ -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; diff --git a/integration_test/block_rewards_test.go b/integration_test/block_rewards_test.go index 2cee003d..7e66f374 100644 --- a/integration_test/block_rewards_test.go +++ b/integration_test/block_rewards_test.go @@ -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")) }) }) diff --git a/libraries/shared/utilities/utils.go b/libraries/shared/utilities/utils.go new file mode 100644 index 00000000..02fc104e --- /dev/null +++ b/libraries/shared/utilities/utils.go @@ -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 . + +package utilities + +func NullToZero(str string) string { + if str == "" { + return "0" + } + return str +} diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index fb43c655..be2fe9eb 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -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) +} diff --git a/pkg/core/eth_client.go b/pkg/core/eth_client.go index 183d224b..d2aa2779 100644 --- a/pkg/core/eth_client.go +++ b/pkg/core/eth_client.go @@ -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) } diff --git a/pkg/datastore/postgres/repositories/block_repository.go b/pkg/datastore/postgres/repositories/block_repository.go index 9fe2c0df..3bda7771 100644 --- a/pkg/datastore/postgres/repositories/block_repository.go +++ b/pkg/datastore/postgres/repositories/block_repository.go @@ -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 } diff --git a/pkg/fakes/mock_blockchain.go b/pkg/fakes/mock_blockchain.go index 1f337781..7083b1ac 100644 --- a/pkg/fakes/mock_blockchain.go +++ b/pkg/fakes/mock_blockchain.go @@ -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 +} diff --git a/pkg/fakes/mock_eth_client.go b/pkg/fakes/mock_eth_client.go index 224ae4d5..033232d5 100644 --- a/pkg/fakes/mock_eth_client.go +++ b/pkg/fakes/mock_eth_client.go @@ -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)) +} diff --git a/pkg/geth/blockchain.go b/pkg/geth/blockchain.go index 6a16a917..a2b641c7 100644 --- a/pkg/geth/blockchain.go +++ b/pkg/geth/blockchain.go @@ -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) +} diff --git a/pkg/geth/blockchain_test.go b/pkg/geth/blockchain_test.go index 292e2cd5..d70eda92 100644 --- a/pkg/geth/blockchain_test.go +++ b/pkg/geth/blockchain_test.go @@ -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)) + }) + }) }) diff --git a/pkg/geth/client/eth_client.go b/pkg/geth/client/eth_client.go index 0b335ee6..fca30d39 100644 --- a/pkg/geth/client/eth_client.go +++ b/pkg/geth/client/eth_client.go @@ -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) +} diff --git a/pkg/geth/converters/common/block_converter.go b/pkg/geth/converters/common/block_converter.go index 5b36c271..8a503e57 100644 --- a/pkg/geth/converters/common/block_converter.go +++ b/pkg/geth/converters/common/block_converter.go @@ -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 } diff --git a/pkg/geth/converters/common/block_converter_test.go b/pkg/geth/converters/common/block_converter_test.go index c98d7d3e..7bdf7751 100644 --- a/pkg/geth/converters/common/block_converter_test.go +++ b/pkg/geth/converters/common/block_converter_test.go @@ -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())) }) }) diff --git a/pkg/geth/converters/common/block_rewards.go b/pkg/geth/converters/common/block_rewards.go index 57f8df28..6326323c 100644 --- a/pkg/geth/converters/common/block_rewards.go +++ b/pkg/geth/converters/common/block_rewards.go @@ -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 From fd407825c173d331bdddc1ad516752f448221812 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Wed, 27 Mar 2019 12:41:15 -0500 Subject: [PATCH 3/5] review fixes --- .../postgres/repositories/block_repository.go | 10 +++++----- pkg/datastore/postgres/repositories/uncle_rewards.go | 1 - .../postgres/repositories/uncle_rewards_test.go | 1 - pkg/geth/converters/common/block_rewards.go | 3 +++ 4 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 pkg/datastore/postgres/repositories/uncle_rewards.go delete mode 100644 pkg/datastore/postgres/repositories/uncle_rewards_test.go diff --git a/pkg/datastore/postgres/repositories/block_repository.go b/pkg/datastore/postgres/repositories/block_repository.go index 3bda7771..16e4c5b4 100644 --- a/pkg/datastore/postgres/repositories/block_repository.go +++ b/pkg/datastore/postgres/repositories/block_repository.go @@ -186,9 +186,9 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err } func (blockRepository BlockRepository) createUncleRewards(tx *sqlx.Tx, blockId int64, blockHash string, mappedUncleRewards map[string]map[string]*big.Int) error { - for miner, uncleRewards := range mappedUncleRewards { + for minerAddr, uncleRewards := range mappedUncleRewards { for uncleHash, reward := range uncleRewards { - err := blockRepository.createUncleReward(tx, blockId, blockHash, miner, uncleHash, reward.String()) + err := blockRepository.createUncleReward(tx, blockId, blockHash, minerAddr, uncleHash, reward.String()) if err != nil { return err } @@ -197,13 +197,13 @@ func (blockRepository BlockRepository) createUncleRewards(tx *sqlx.Tx, blockId i return nil } -func (blockRepository BlockRepository) createUncleReward(tx *sqlx.Tx, blockId int64, blockHash, miner, uncleHash, amount string) error { +func (blockRepository BlockRepository) createUncleReward(tx *sqlx.Tx, blockId int64, blockHash, minerAddr, uncleHash, amount string) error { _, err := tx.Exec( `INSERT INTO uncle_rewards - (block_id, block_hash, uncle_hash, uncle_reward, miner_address) + (block_id, block_hash, miner_address, uncle_hash, uncle_reward) VALUES ($1, $2, $3, $4, $5) RETURNING id`, - blockId, blockHash, miner, uncleHash, utilities.NullToZero(amount)) + blockId, blockHash, minerAddr, uncleHash, utilities.NullToZero(amount)) return err } diff --git a/pkg/datastore/postgres/repositories/uncle_rewards.go b/pkg/datastore/postgres/repositories/uncle_rewards.go deleted file mode 100644 index 3f43206c..00000000 --- a/pkg/datastore/postgres/repositories/uncle_rewards.go +++ /dev/null @@ -1 +0,0 @@ -package repositories diff --git a/pkg/datastore/postgres/repositories/uncle_rewards_test.go b/pkg/datastore/postgres/repositories/uncle_rewards_test.go deleted file mode 100644 index 3f43206c..00000000 --- a/pkg/datastore/postgres/repositories/uncle_rewards_test.go +++ /dev/null @@ -1 +0,0 @@ -package repositories diff --git a/pkg/geth/converters/common/block_rewards.go b/pkg/geth/converters/common/block_rewards.go index 6326323c..fb388910 100644 --- a/pkg/geth/converters/common/block_rewards.go +++ b/pkg/geth/converters/common/block_rewards.go @@ -24,6 +24,9 @@ import ( ) // (U_n + 8 - B_n) * R / 8 +// https://github.com/ethereum/go-ethereum/issues/1591 +// https://ethereum.stackexchange.com/questions/27172/different-uncles-reward +// https://github.com/ethereum/homestead-guide/issues/399 // Returns a map of miner addresses to a map of the uncles they mined (hashes) to the rewards received for that uncle func CalcUnclesReward(block core.Block, uncles []*types.Header) (*big.Int, map[string]map[string]*big.Int) { uncleRewards := new(big.Int) From 197f98c93d4ec9e5932e33dff10bf8246c43954c Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Tue, 2 Apr 2019 13:30:15 -0500 Subject: [PATCH 4/5] going ahead and indexing the entire uncle blocks (one of the issues open on public); finish tests --- db/migrations/00026_create_uncles_table.sql | 20 ++++++ ...7_update_block_and_uncle_reward_types.sql} | 0 .../00045_create_uncle_rewards_table.sql | 15 ----- pkg/core/block.go | 36 +++++----- pkg/core/uncle.go | 27 ++++++++ .../postgres/repositories/block_repository.go | 30 ++++----- .../repositories/block_repository_test.go | 66 +++++++++++++++++++ pkg/fakes/data.go | 13 +++- pkg/geth/converters/common/block_converter.go | 42 ++++++++++-- .../converters/common/block_converter_test.go | 15 +++-- pkg/geth/converters/common/block_rewards.go | 28 -------- 11 files changed, 201 insertions(+), 91 deletions(-) create mode 100644 db/migrations/00026_create_uncles_table.sql rename db/migrations/{00046_update_block_and_uncle_reward_types.sql => 00027_update_block_and_uncle_reward_types.sql} (100%) delete mode 100644 db/migrations/00045_create_uncle_rewards_table.sql create mode 100644 pkg/core/uncle.go diff --git a/db/migrations/00026_create_uncles_table.sql b/db/migrations/00026_create_uncles_table.sql new file mode 100644 index 00000000..524c1f4b --- /dev/null +++ b/db/migrations/00026_create_uncles_table.sql @@ -0,0 +1,20 @@ +-- +goose Up +CREATE TABLE public.uncles ( + id SERIAL PRIMARY KEY, + hash VARCHAR(66) NOT NULL, + block_id INTEGER NOT NULL REFERENCES blocks (id) ON DELETE CASCADE, + block_hash VARCHAR(66) NOT NULL, + reward NUMERIC NOT NULL, + miner VARCHAR(42) NOT NULL, + raw JSONB, + block_timestamp NUMERIC, + eth_node_id INTEGER, + eth_node_fingerprint VARCHAR(128), + CONSTRAINT eth_nodes_fk FOREIGN KEY (eth_node_id) + REFERENCES eth_nodes (id) + ON DELETE CASCADE, + UNIQUE (block_id, hash) +); + +-- +goose Down +DROP TABLE public.uncles; diff --git a/db/migrations/00046_update_block_and_uncle_reward_types.sql b/db/migrations/00027_update_block_and_uncle_reward_types.sql similarity index 100% rename from db/migrations/00046_update_block_and_uncle_reward_types.sql rename to db/migrations/00027_update_block_and_uncle_reward_types.sql diff --git a/db/migrations/00045_create_uncle_rewards_table.sql b/db/migrations/00045_create_uncle_rewards_table.sql deleted file mode 100644 index 4c40561f..00000000 --- a/db/migrations/00045_create_uncle_rewards_table.sql +++ /dev/null @@ -1,15 +0,0 @@ --- +goose Up -CREATE TABLE public.uncle_rewards ( - id SERIAL PRIMARY KEY, - block_id INTEGER, - block_hash VARCHAR(66) NOT NULL, - uncle_hash VARCHAR(66) NOT NULL, - uncle_reward NUMERIC NOT NULL, - miner_address VARCHAR(66) NOT NULL, - CONSTRAINT block_id_fk FOREIGN KEY (block_id) - REFERENCES blocks (id) - ON DELETE CASCADE -); - --- +goose Down -DROP TABLE public.uncle_rewards; diff --git a/pkg/core/block.go b/pkg/core/block.go index e7546f19..f878df98 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -16,24 +16,22 @@ package core -import "math/big" - type Block struct { - Reward string `db:"reward"` - Difficulty int64 `db:"difficulty"` - ExtraData string `db:"extra_data"` - GasLimit uint64 `db:"gaslimit"` - GasUsed uint64 `db:"gasused"` - Hash string `db:"hash"` - IsFinal bool `db:"is_final"` - Miner string `db:"miner"` - Nonce string `db:"nonce"` - Number int64 `db:"number"` - ParentHash string `db:"parenthash"` - Size string `db:"size"` - Time int64 `db:"time"` - Transactions []TransactionModel - UncleHash string `db:"uncle_hash"` - UnclesReward string `db:"uncles_reward"` - MappedUncleRewards map[string]map[string]*big.Int + Reward string `db:"reward"` + Difficulty int64 `db:"difficulty"` + ExtraData string `db:"extra_data"` + GasLimit uint64 `db:"gaslimit"` + GasUsed uint64 `db:"gasused"` + Hash string `db:"hash"` + IsFinal bool `db:"is_final"` + Miner string `db:"miner"` + Nonce string `db:"nonce"` + Number int64 `db:"number"` + ParentHash string `db:"parenthash"` + Size string `db:"size"` + Time int64 `db:"time"` + Transactions []TransactionModel + UncleHash string `db:"uncle_hash"` + UnclesReward string `db:"uncles_reward"` + Uncles []Uncle } diff --git a/pkg/core/uncle.go b/pkg/core/uncle.go new file mode 100644 index 00000000..018d5924 --- /dev/null +++ b/pkg/core/uncle.go @@ -0,0 +1,27 @@ +// 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 . + +package core + +type Uncle struct { + Id int64 + Miner string + BlockHash string `db:"block_hash"` + Reward string + Hash string + Timestamp string `db:"block_timestamp"` + Raw []byte +} diff --git a/pkg/datastore/postgres/repositories/block_repository.go b/pkg/datastore/postgres/repositories/block_repository.go index 16e4c5b4..80affa11 100644 --- a/pkg/datastore/postgres/repositories/block_repository.go +++ b/pkg/datastore/postgres/repositories/block_repository.go @@ -19,12 +19,10 @@ package repositories import ( "database/sql" "errors" - "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" @@ -157,8 +155,8 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err } return 0, postgres.ErrDBInsertFailed(insertBlockErr) } - if len(block.MappedUncleRewards) > 0 { - insertUncleErr := blockRepository.createUncleRewards(tx, blockId, block.Hash, block.MappedUncleRewards) + if len(block.Uncles) > 0 { + insertUncleErr := blockRepository.createUncles(tx, blockId, block.Hash, block.Uncles) if insertUncleErr != nil { tx.Rollback() return 0, postgres.ErrDBInsertFailed(insertUncleErr) @@ -185,25 +183,23 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err return blockId, nil } -func (blockRepository BlockRepository) createUncleRewards(tx *sqlx.Tx, blockId int64, blockHash string, mappedUncleRewards map[string]map[string]*big.Int) error { - for minerAddr, uncleRewards := range mappedUncleRewards { - for uncleHash, reward := range uncleRewards { - err := blockRepository.createUncleReward(tx, blockId, blockHash, minerAddr, uncleHash, reward.String()) - if err != nil { - return err - } +func (blockRepository BlockRepository) createUncles(tx *sqlx.Tx, blockId int64, blockHash string, uncles []core.Uncle) error { + for _, uncle := range uncles { + err := blockRepository.createUncle(tx, blockId, uncle) + if err != nil { + return err } } return nil } -func (blockRepository BlockRepository) createUncleReward(tx *sqlx.Tx, blockId int64, blockHash, minerAddr, uncleHash, amount string) error { +func (blockRepository BlockRepository) createUncle(tx *sqlx.Tx, blockId int64, uncle core.Uncle) error { _, err := tx.Exec( - `INSERT INTO uncle_rewards - (block_id, block_hash, miner_address, uncle_hash, uncle_reward) - VALUES ($1, $2, $3, $4, $5) + `INSERT INTO uncles + (hash, block_id, block_hash, reward, miner, raw, block_timestamp, eth_node_id, eth_node_fingerprint) + VALUES ($1, $2, $3, $4, $5, $6, $7::NUMERIC, $8, $9) RETURNING id`, - blockId, blockHash, minerAddr, uncleHash, utilities.NullToZero(amount)) + uncle.Hash, blockId, uncle.BlockHash, utilities.NullToZero(uncle.Reward), uncle.Miner, uncle.Raw, uncle.Timestamp, blockRepository.database.NodeID, blockRepository.database.Node.ID) return err } diff --git a/pkg/datastore/postgres/repositories/block_repository_test.go b/pkg/datastore/postgres/repositories/block_repository_test.go index fb126d00..2d355667 100644 --- a/pkg/datastore/postgres/repositories/block_repository_test.go +++ b/pkg/datastore/postgres/repositories/block_repository_test.go @@ -158,6 +158,72 @@ var _ = Describe("Saving blocks", func() { Expect(len(savedBlock.Transactions)).To(Equal(2)) }) + It("saves one uncle associated to the block", func() { + block := core.Block{ + Hash: fakes.FakeHash.String(), + Number: 123, + Transactions: []core.TransactionModel{fakes.FakeTransaction}, + Uncles: []core.Uncle{fakes.GetFakeUncle(common.BytesToHash([]byte{1, 2, 3}).String(), "100000")}, + UnclesReward: "156250000000000000", + } + + id, insertErr := blockRepository.CreateOrUpdateBlock(block) + + Expect(insertErr).NotTo(HaveOccurred()) + savedBlock, getErr := blockRepository.GetBlock(123) + Expect(getErr).NotTo(HaveOccurred()) + Expect(len(savedBlock.Transactions)).To(Equal(1)) + Expect(savedBlock.UnclesReward).To(Equal(big.NewInt(0).Div(big.NewInt(5000000000000000000), big.NewInt(32)).String())) + + var uncleModel core.Uncle + err := db.Get(&uncleModel, `SELECT hash, block_hash, reward, miner, raw, block_timestamp FROM uncles + WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{1, 2, 3}).Hex()) + Expect(err).ToNot(HaveOccurred()) + Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{1, 2, 3}).Hex())) + Expect(uncleModel.Reward).To(Equal("100000")) + Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) + Expect(uncleModel.Timestamp).To(Equal("111111111")) + }) + + It("saves one uncle associated to the block", func() { + block := core.Block{ + Hash: fakes.FakeHash.String(), + Number: 123, + Transactions: []core.TransactionModel{fakes.FakeTransaction}, + Uncles: []core.Uncle{ + fakes.GetFakeUncle(common.BytesToHash([]byte{1, 2, 3}).String(), "100000"), + fakes.GetFakeUncle(common.BytesToHash([]byte{3, 2, 1}).String(), "90000")}, + UnclesReward: "312500000000000000", + } + + id, insertErr := blockRepository.CreateOrUpdateBlock(block) + + Expect(insertErr).NotTo(HaveOccurred()) + savedBlock, getErr := blockRepository.GetBlock(123) + Expect(getErr).NotTo(HaveOccurred()) + Expect(len(savedBlock.Transactions)).To(Equal(1)) + b := new(big.Int) + b.SetString("10000000000000000000", 10) + Expect(savedBlock.UnclesReward).To(Equal(big.NewInt(0).Div(b, big.NewInt(32)).String())) + + var uncleModel core.Uncle + err := db.Get(&uncleModel, `SELECT hash, block_hash, reward, miner, raw, block_timestamp FROM uncles + WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{1, 2, 3}).Hex()) + Expect(err).ToNot(HaveOccurred()) + Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{1, 2, 3}).Hex())) + Expect(uncleModel.Reward).To(Equal("100000")) + Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) + Expect(uncleModel.Timestamp).To(Equal("111111111")) + + err = db.Get(&uncleModel, `SELECT hash, block_hash, reward, miner, raw, block_timestamp FROM uncles + WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{3, 2, 1}).Hex()) + Expect(err).ToNot(HaveOccurred()) + Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{3, 2, 1}).Hex())) + Expect(uncleModel.Reward).To(Equal("90000")) + Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) + Expect(uncleModel.Timestamp).To(Equal("111111111")) + }) + It(`replaces blocks and transactions associated to the block when a more new block is in conflict (same block number + nodeid)`, func() { blockOne := core.Block{ diff --git a/pkg/fakes/data.go b/pkg/fakes/data.go index f8549a0a..6d2829fa 100644 --- a/pkg/fakes/data.go +++ b/pkg/fakes/data.go @@ -73,7 +73,7 @@ func GetFakeTransaction(hash string, receipt core.Receipt) core.TransactionModel var raw bytes.Buffer err := gethTransaction.EncodeRLP(&raw) if err != nil { - panic("failed to marshal transaction creating test fake") + panic("failed to marshal transaction while creating test fake") } return core.TransactionModel{ Data: []byte{}, @@ -89,3 +89,14 @@ func GetFakeTransaction(hash string, receipt core.Receipt) core.TransactionModel Value: "0", } } + +func GetFakeUncle(hash, reward string) core.Uncle { + return core.Uncle{ + Miner: FakeAddress.String(), + Hash: hash, + BlockHash: FakeHash.String(), + Reward: reward, + Raw: rawFakeHeader, + Timestamp: strconv.FormatInt(fakeTimestamp, 10), + } +} diff --git a/pkg/geth/converters/common/block_converter.go b/pkg/geth/converters/common/block_converter.go index 8a503e57..e53d18a2 100644 --- a/pkg/geth/converters/common/block_converter.go +++ b/pkg/geth/converters/common/block_converter.go @@ -17,12 +17,13 @@ package common import ( + "encoding/json" + "math/big" "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" ) @@ -56,8 +57,41 @@ func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error) UncleHash: gethBlock.UncleHash().Hex(), } coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()).String() - uncleRewards, mappedUncleRewards := CalcUnclesReward(coreBlock, gethBlock.Uncles()) - coreBlock.UnclesReward = utilities.NullToZero(uncleRewards.String()) - coreBlock.MappedUncleRewards = mappedUncleRewards + totalUncleReward, uncles := bc.ToCoreUncle(coreBlock, gethBlock.Uncles()) + + coreBlock.UnclesReward = totalUncleReward.String() + coreBlock.Uncles = uncles return coreBlock, nil } + +// Rewards for the miners of uncles is calculated as (U_n + 8 - B_n) * R / 8 +// Where U_n is the uncle block number, B_n is the parent block number and R is the static block reward at B_n +// https://github.com/ethereum/go-ethereum/issues/1591 +// https://ethereum.stackexchange.com/questions/27172/different-uncles-reward +// https://github.com/ethereum/homestead-guide/issues/399 +// Returns the total uncle reward and the individual processed uncles +func (bc BlockConverter) ToCoreUncle(block core.Block, uncles []*types.Header) (*big.Int, []core.Uncle) { + totalUncleRewards := new(big.Int) + coreUncles := make([]core.Uncle, 0, len(uncles)) + for _, uncle := range uncles { + staticBlockReward := staticRewardByBlockNumber(block.Number) + rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8)) + mainBlock := big.NewInt(block.Number) + uncleBlock := big.NewInt(uncle.Number.Int64()) + uncleBlockPlus8 := uncleBlock.Add(uncleBlock, big.NewInt(8)) + uncleBlockPlus8MinusMainBlock := uncleBlockPlus8.Sub(uncleBlockPlus8, mainBlock) + thisUncleReward := rewardDiv8.Mul(rewardDiv8, uncleBlockPlus8MinusMainBlock) + raw, _ := json.Marshal(uncle) + coreUncle := core.Uncle{ + Miner: uncle.Coinbase.Hex(), + BlockHash: block.Hash, + Hash: uncle.Hash().Hex(), + Raw: raw, + Reward: thisUncleReward.String(), + Timestamp: uncle.Time.String(), + } + coreUncles = append(coreUncles, coreUncle) + totalUncleRewards.Add(totalUncleRewards, thisUncleReward) + } + return totalUncleRewards, coreUncles +} diff --git a/pkg/geth/converters/common/block_converter_test.go b/pkg/geth/converters/common/block_converter_test.go index 7bdf7751..9ecef611 100644 --- a/pkg/geth/converters/common/block_converter_test.go +++ b/pkg/geth/converters/common/block_converter_test.go @@ -159,15 +159,16 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() { expectedTotalReward := new(big.Int) expectedTotalReward.SetString("6875000000000000000", 10) - totalReward, mappedRewards := vulcCommon.CalcUnclesReward(coreBlock, block.Uncles()) + totalReward, coreUncles := blockConverter.ToCoreUncle(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())) + Expect(len(coreUncles)).To(Equal(2)) + Expect(coreUncles[0].Reward).To(Equal("3125000000000000000")) + Expect(coreUncles[0].Miner).To(Equal("0x0000000000000000000000000000000000000000")) + Expect(coreUncles[0].Hash).To(Equal("0xb629de4014b6e30cf9555ee833f1806fa0d8b8516fde194405f9c98c2deb8772")) + Expect(coreUncles[1].Reward).To(Equal("3750000000000000000")) + Expect(coreUncles[1].Miner).To(Equal("0x0000000000000000000000000000000000000000")) + Expect(coreUncles[1].Hash).To(Equal("0x673f5231e4888a951e0bc8a25b5774b982e6e9e258362c21affaff6e02dd5a2b")) }) It("decreases the static block reward from 5 to 3 for blocks after block 4,269,999", func() { diff --git a/pkg/geth/converters/common/block_rewards.go b/pkg/geth/converters/common/block_rewards.go index fb388910..ce26cadc 100644 --- a/pkg/geth/converters/common/block_rewards.go +++ b/pkg/geth/converters/common/block_rewards.go @@ -23,34 +23,6 @@ import ( "github.com/vulcanize/vulcanizedb/pkg/core" ) -// (U_n + 8 - B_n) * R / 8 -// https://github.com/ethereum/go-ethereum/issues/1591 -// https://ethereum.stackexchange.com/questions/27172/different-uncles-reward -// https://github.com/ethereum/homestead-guide/issues/399 -// Returns a map of miner addresses to a map of the uncles they mined (hashes) to the rewards received for that uncle -func CalcUnclesReward(block core.Block, uncles []*types.Header) (*big.Int, map[string]map[string]*big.Int) { - uncleRewards := new(big.Int) - mappedUncleRewards := make(map[string]map[string]*big.Int) - for _, uncle := range uncles { - staticBlockReward := staticRewardByBlockNumber(block.Number) - rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8)) - uncleBlock := big.NewInt(uncle.Number.Int64()) - uncleBlockPlus8 := uncleBlock.Add(uncleBlock, big.NewInt(8)) - mainBlock := big.NewInt(block.Number) - 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 -} - func CalcBlockReward(block core.Block, uncles []*types.Header) *big.Int { staticBlockReward := staticRewardByBlockNumber(block.Number) transactionFees := calcTransactionFees(block) From 5dcf534b2cd9d4031168fdd19933767ea41eb353 Mon Sep 17 00:00:00 2001 From: Ian Norden Date: Thu, 4 Apr 2019 15:21:39 -0500 Subject: [PATCH 5/5] review fixes --- db/migrations/00001_create_blocks_table.sql | 10 +++++----- ...02_create_full_sync_transactions_table.sql | 4 ++-- db/migrations/00022_create_headers_table.sql | 7 ++----- ...5_create_light_sync_transactions_table.sql | 4 ++-- db/migrations/00026_create_uncles_table.sql | 6 +----- ...27_update_block_and_uncle_reward_types.sql | 9 --------- pkg/core/block.go | 6 +++--- pkg/core/transaction.go | 4 ++-- pkg/core/uncle.go | 1 - .../postgres/repositories/block_repository.go | 20 +++++++++---------- .../repositories/block_repository_test.go | 8 ++++---- .../repositories/contract_repository.go | 4 ++-- .../repositories/header_repository.go | 2 +- .../repositories/header_repository_test.go | 4 ++-- pkg/fakes/data.go | 1 - pkg/fakes/mock_blockchain.go | 10 +++------- pkg/geth/converters/common/block_converter.go | 9 +-------- pkg/geth/converters/common/block_rewards.go | 14 ++++++++++++- 18 files changed, 53 insertions(+), 70 deletions(-) delete mode 100644 db/migrations/00027_update_block_and_uncle_reward_types.sql diff --git a/db/migrations/00001_create_blocks_table.sql b/db/migrations/00001_create_blocks_table.sql index 9f787381..c11cf1de 100644 --- a/db/migrations/00001_create_blocks_table.sql +++ b/db/migrations/00001_create_blocks_table.sql @@ -3,15 +3,15 @@ CREATE TABLE public.blocks ( id SERIAL PRIMARY KEY, difficulty BIGINT, extra_data VARCHAR, - gaslimit BIGINT, - gasused BIGINT, + gas_limit BIGINT, + gas_used BIGINT, hash VARCHAR(66), miner VARCHAR(42), nonce VARCHAR(20), "number" BIGINT, - parenthash VARCHAR(66), - reward DOUBLE PRECISION, - uncles_reward DOUBLE PRECISION, + parent_hash VARCHAR(66), + reward NUMERIC, + uncles_reward NUMERIC, "size" VARCHAR, "time" BIGINT, is_final BOOLEAN, diff --git a/db/migrations/00002_create_full_sync_transactions_table.sql b/db/migrations/00002_create_full_sync_transactions_table.sql index dc42a7c7..72548c95 100644 --- a/db/migrations/00002_create_full_sync_transactions_table.sql +++ b/db/migrations/00002_create_full_sync_transactions_table.sql @@ -2,8 +2,8 @@ CREATE TABLE full_sync_transactions ( id SERIAL PRIMARY KEY, block_id INTEGER NOT NULL REFERENCES blocks(id) ON DELETE CASCADE, - gaslimit NUMERIC, - gasprice NUMERIC, + gas_limit NUMERIC, + gas_price NUMERIC, hash VARCHAR(66), input_data BYTEA, nonce NUMERIC, diff --git a/db/migrations/00022_create_headers_table.sql b/db/migrations/00022_create_headers_table.sql index 1867044f..925c202b 100644 --- a/db/migrations/00022_create_headers_table.sql +++ b/db/migrations/00022_create_headers_table.sql @@ -5,11 +5,8 @@ CREATE TABLE public.headers ( block_number BIGINT, raw JSONB, block_timestamp NUMERIC, - eth_node_id INTEGER, - eth_node_fingerprint VARCHAR(128), - CONSTRAINT eth_nodes_fk FOREIGN KEY (eth_node_id) - REFERENCES eth_nodes (id) - ON DELETE CASCADE + eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE, + eth_node_fingerprint VARCHAR(128) ); -- Index is removed when table is diff --git a/db/migrations/00025_create_light_sync_transactions_table.sql b/db/migrations/00025_create_light_sync_transactions_table.sql index 6773c1e3..ab37c996 100644 --- a/db/migrations/00025_create_light_sync_transactions_table.sql +++ b/db/migrations/00025_create_light_sync_transactions_table.sql @@ -3,8 +3,8 @@ CREATE TABLE light_sync_transactions ( id SERIAL PRIMARY KEY, header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE, hash TEXT, - gaslimit NUMERIC, - gasprice NUMERIC, + gas_limit NUMERIC, + gas_price NUMERIC, input_data BYTEA, nonce NUMERIC, raw BYTEA, diff --git a/db/migrations/00026_create_uncles_table.sql b/db/migrations/00026_create_uncles_table.sql index 524c1f4b..9ec0ffa7 100644 --- a/db/migrations/00026_create_uncles_table.sql +++ b/db/migrations/00026_create_uncles_table.sql @@ -3,16 +3,12 @@ CREATE TABLE public.uncles ( id SERIAL PRIMARY KEY, hash VARCHAR(66) NOT NULL, block_id INTEGER NOT NULL REFERENCES blocks (id) ON DELETE CASCADE, - block_hash VARCHAR(66) NOT NULL, reward NUMERIC NOT NULL, miner VARCHAR(42) NOT NULL, raw JSONB, block_timestamp NUMERIC, - eth_node_id INTEGER, + eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE, eth_node_fingerprint VARCHAR(128), - CONSTRAINT eth_nodes_fk FOREIGN KEY (eth_node_id) - REFERENCES eth_nodes (id) - ON DELETE CASCADE, UNIQUE (block_id, hash) ); diff --git a/db/migrations/00027_update_block_and_uncle_reward_types.sql b/db/migrations/00027_update_block_and_uncle_reward_types.sql deleted file mode 100644 index 8bca0604..00000000 --- a/db/migrations/00027_update_block_and_uncle_reward_types.sql +++ /dev/null @@ -1,9 +0,0 @@ --- +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; diff --git a/pkg/core/block.go b/pkg/core/block.go index f878df98..e877f80d 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -20,14 +20,14 @@ type Block struct { Reward string `db:"reward"` Difficulty int64 `db:"difficulty"` ExtraData string `db:"extra_data"` - GasLimit uint64 `db:"gaslimit"` - GasUsed uint64 `db:"gasused"` + GasLimit uint64 `db:"gas_limit"` + GasUsed uint64 `db:"gas_used"` Hash string `db:"hash"` IsFinal bool `db:"is_final"` Miner string `db:"miner"` Nonce string `db:"nonce"` Number int64 `db:"number"` - ParentHash string `db:"parenthash"` + ParentHash string `db:"parent_hash"` Size string `db:"size"` Time int64 `db:"time"` Transactions []TransactionModel diff --git a/pkg/core/transaction.go b/pkg/core/transaction.go index c5198cf7..92d18edc 100644 --- a/pkg/core/transaction.go +++ b/pkg/core/transaction.go @@ -19,8 +19,8 @@ package core type TransactionModel struct { Data []byte `db:"input_data"` From string `db:"tx_from"` - GasLimit uint64 - GasPrice int64 + GasLimit uint64 `db:"gas_limit"` + GasPrice int64 `db:"gas_price"` Hash string Nonce uint64 Raw []byte diff --git a/pkg/core/uncle.go b/pkg/core/uncle.go index 018d5924..dfece8e7 100644 --- a/pkg/core/uncle.go +++ b/pkg/core/uncle.go @@ -19,7 +19,6 @@ package core type Uncle struct { Id int64 Miner string - BlockHash string `db:"block_hash"` Reward string Hash string Timestamp string `db:"block_timestamp"` diff --git a/pkg/datastore/postgres/repositories/block_repository.go b/pkg/datastore/postgres/repositories/block_repository.go index 80affa11..82fd0960 100644 --- a/pkg/datastore/postgres/repositories/block_repository.go +++ b/pkg/datastore/postgres/repositories/block_repository.go @@ -90,13 +90,13 @@ func (blockRepository BlockRepository) GetBlock(blockNumber int64) (core.Block, blockRows := blockRepository.database.QueryRowx( `SELECT id, number, - gaslimit, - gasused, + gas_limit, + gas_used, time, difficulty, hash, nonce, - parenthash, + parent_hash, size, uncle_hash, is_final, @@ -127,7 +127,7 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err } insertBlockErr := tx.QueryRow( `INSERT INTO blocks - (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) + (eth_node_id, number, gas_limit, gas_used, time, difficulty, hash, nonce, parent_hash, 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, @@ -196,10 +196,10 @@ func (blockRepository BlockRepository) createUncles(tx *sqlx.Tx, blockId int64, func (blockRepository BlockRepository) createUncle(tx *sqlx.Tx, blockId int64, uncle core.Uncle) error { _, err := tx.Exec( `INSERT INTO uncles - (hash, block_id, block_hash, reward, miner, raw, block_timestamp, eth_node_id, eth_node_fingerprint) - VALUES ($1, $2, $3, $4, $5, $6, $7::NUMERIC, $8, $9) + (hash, block_id, reward, miner, raw, block_timestamp, eth_node_id, eth_node_fingerprint) + VALUES ($1, $2, $3, $4, $5, $6, $7::NUMERIC, $8) RETURNING id`, - uncle.Hash, blockId, uncle.BlockHash, utilities.NullToZero(uncle.Reward), uncle.Miner, uncle.Raw, uncle.Timestamp, blockRepository.database.NodeID, blockRepository.database.Node.ID) + uncle.Hash, blockId, utilities.NullToZero(uncle.Reward), uncle.Miner, uncle.Raw, uncle.Timestamp, blockRepository.database.NodeID, blockRepository.database.Node.ID) return err } @@ -226,7 +226,7 @@ func nullStringToZero(s string) string { func (blockRepository BlockRepository) createTransaction(tx *sqlx.Tx, blockId int64, transaction core.TransactionModel) error { _, err := tx.Exec( `INSERT INTO full_sync_transactions - (block_id, gaslimit, gasprice, hash, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") + (block_id, gas_limit, gas_price, 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, nullStringToZero(transaction.Value)) @@ -325,8 +325,8 @@ func (blockRepository BlockRepository) loadBlock(blockRows *sqlx.Row) (core.Bloc } transactionRows, err := blockRepository.database.Queryx(` SELECT hash, - gaslimit, - gasprice, + gas_limit, + gas_price, input_data, nonce, raw, diff --git a/pkg/datastore/postgres/repositories/block_repository_test.go b/pkg/datastore/postgres/repositories/block_repository_test.go index 2d355667..39d2c9df 100644 --- a/pkg/datastore/postgres/repositories/block_repository_test.go +++ b/pkg/datastore/postgres/repositories/block_repository_test.go @@ -176,7 +176,7 @@ var _ = Describe("Saving blocks", func() { Expect(savedBlock.UnclesReward).To(Equal(big.NewInt(0).Div(big.NewInt(5000000000000000000), big.NewInt(32)).String())) var uncleModel core.Uncle - err := db.Get(&uncleModel, `SELECT hash, block_hash, reward, miner, raw, block_timestamp FROM uncles + err := db.Get(&uncleModel, `SELECT hash, reward, miner, raw, block_timestamp FROM uncles WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{1, 2, 3}).Hex()) Expect(err).ToNot(HaveOccurred()) Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{1, 2, 3}).Hex())) @@ -185,7 +185,7 @@ var _ = Describe("Saving blocks", func() { Expect(uncleModel.Timestamp).To(Equal("111111111")) }) - It("saves one uncle associated to the block", func() { + It("saves two uncles associated to the block", func() { block := core.Block{ Hash: fakes.FakeHash.String(), Number: 123, @@ -207,7 +207,7 @@ var _ = Describe("Saving blocks", func() { Expect(savedBlock.UnclesReward).To(Equal(big.NewInt(0).Div(b, big.NewInt(32)).String())) var uncleModel core.Uncle - err := db.Get(&uncleModel, `SELECT hash, block_hash, reward, miner, raw, block_timestamp FROM uncles + err := db.Get(&uncleModel, `SELECT hash, reward, miner, raw, block_timestamp FROM uncles WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{1, 2, 3}).Hex()) Expect(err).ToNot(HaveOccurred()) Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{1, 2, 3}).Hex())) @@ -215,7 +215,7 @@ var _ = Describe("Saving blocks", func() { Expect(uncleModel.Miner).To(Equal(fakes.FakeAddress.Hex())) Expect(uncleModel.Timestamp).To(Equal("111111111")) - err = db.Get(&uncleModel, `SELECT hash, block_hash, reward, miner, raw, block_timestamp FROM uncles + err = db.Get(&uncleModel, `SELECT hash, reward, miner, raw, block_timestamp FROM uncles WHERE block_id = $1 AND hash = $2`, id, common.BytesToHash([]byte{3, 2, 1}).Hex()) Expect(err).ToNot(HaveOccurred()) Expect(uncleModel.Hash).To(Equal(common.BytesToHash([]byte{3, 2, 1}).Hex())) diff --git a/pkg/datastore/postgres/repositories/contract_repository.go b/pkg/datastore/postgres/repositories/contract_repository.go index fc68f510..d198ecae 100644 --- a/pkg/datastore/postgres/repositories/contract_repository.go +++ b/pkg/datastore/postgres/repositories/contract_repository.go @@ -82,8 +82,8 @@ func (contractRepository ContractRepository) addTransactions(contract core.Contr nonce, tx_to, tx_from, - gaslimit, - gasprice, + gas_limit, + gas_price, value, input_data FROM full_sync_transactions diff --git a/pkg/datastore/postgres/repositories/header_repository.go b/pkg/datastore/postgres/repositories/header_repository.go index 6ee990f8..52b32c9d 100644 --- a/pkg/datastore/postgres/repositories/header_repository.go +++ b/pkg/datastore/postgres/repositories/header_repository.go @@ -52,7 +52,7 @@ func (repository HeaderRepository) CreateOrUpdateHeader(header core.Header) (int func (repository HeaderRepository) CreateTransactions(headerID int64, transactions []core.TransactionModel) error { for _, transaction := range transactions { _, err := repository.database.Exec(`INSERT INTO public.light_sync_transactions - (header_id, hash, gaslimit, gasprice, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") + (header_id, hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value") VALUES ($1, $2, $3::NUMERIC, $4::NUMERIC, $5, $6::NUMERIC, $7, $8, $9::NUMERIC, $10, $11::NUMERIC) ON CONFLICT DO NOTHING`, headerID, transaction.Hash, transaction.GasLimit, transaction.GasPrice, transaction.Data, transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To, diff --git a/pkg/datastore/postgres/repositories/header_repository_test.go b/pkg/datastore/postgres/repositories/header_repository_test.go index a22f6131..ce861857 100644 --- a/pkg/datastore/postgres/repositories/header_repository_test.go +++ b/pkg/datastore/postgres/repositories/header_repository_test.go @@ -226,7 +226,7 @@ var _ = Describe("Block header repository", func() { It("adds transactions", func() { var dbTransactions []core.TransactionModel err = db.Select(&dbTransactions, - `SELECT hash, gaslimit, gasprice, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" + `SELECT hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" FROM public.light_sync_transactions WHERE header_id = $1`, headerID) Expect(err).NotTo(HaveOccurred()) Expect(dbTransactions).To(ConsistOf(transactions)) @@ -238,7 +238,7 @@ var _ = Describe("Block header repository", func() { var dbTransactions []core.TransactionModel err = db.Select(&dbTransactions, - `SELECT hash, gaslimit, gasprice, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" + `SELECT hash, gas_limit, gas_price, input_data, nonce, raw, tx_from, tx_index, tx_to, "value" FROM public.light_sync_transactions WHERE header_id = $1`, headerID) Expect(err).NotTo(HaveOccurred()) Expect(len(dbTransactions)).To(Equal(2)) diff --git a/pkg/fakes/data.go b/pkg/fakes/data.go index 6d2829fa..8b8b45a7 100644 --- a/pkg/fakes/data.go +++ b/pkg/fakes/data.go @@ -94,7 +94,6 @@ func GetFakeUncle(hash, reward string) core.Uncle { return core.Uncle{ Miner: FakeAddress.String(), Hash: hash, - BlockHash: FakeHash.String(), Reward: reward, Raw: rawFakeHeader, Timestamp: strconv.FormatInt(fakeTimestamp, 10), diff --git a/pkg/fakes/mock_blockchain.go b/pkg/fakes/mock_blockchain.go index 7083b1ac..d09a91b3 100644 --- a/pkg/fakes/mock_blockchain.go +++ b/pkg/fakes/mock_blockchain.go @@ -45,9 +45,7 @@ type MockBlockChain struct { lastBlock *big.Int node core.Node Transactions []core.TransactionModel - passedAccountAddress common.Address - passedBlockNumer *big.Int - passedAccountBalance *big.Int + accountBalanceReturnValue *big.Int getAccountBalanceErr error } @@ -151,11 +149,9 @@ func (blockChain *MockBlockChain) SetGetAccountBalanceErr(err error) { } func (blockChain *MockBlockChain) SetGetAccountBalance(balance *big.Int) { - blockChain.passedAccountBalance = balance + blockChain.accountBalanceReturnValue = 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 + return blockChain.accountBalanceReturnValue, blockChain.getAccountBalanceErr } diff --git a/pkg/geth/converters/common/block_converter.go b/pkg/geth/converters/common/block_converter.go index e53d18a2..b813223d 100644 --- a/pkg/geth/converters/common/block_converter.go +++ b/pkg/geth/converters/common/block_converter.go @@ -74,17 +74,10 @@ func (bc BlockConverter) ToCoreUncle(block core.Block, uncles []*types.Header) ( totalUncleRewards := new(big.Int) coreUncles := make([]core.Uncle, 0, len(uncles)) for _, uncle := range uncles { - staticBlockReward := staticRewardByBlockNumber(block.Number) - rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8)) - mainBlock := big.NewInt(block.Number) - uncleBlock := big.NewInt(uncle.Number.Int64()) - uncleBlockPlus8 := uncleBlock.Add(uncleBlock, big.NewInt(8)) - uncleBlockPlus8MinusMainBlock := uncleBlockPlus8.Sub(uncleBlockPlus8, mainBlock) - thisUncleReward := rewardDiv8.Mul(rewardDiv8, uncleBlockPlus8MinusMainBlock) + thisUncleReward := calcUncleMinerReward(block.Number, uncle.Number.Int64()) raw, _ := json.Marshal(uncle) coreUncle := core.Uncle{ Miner: uncle.Coinbase.Hex(), - BlockHash: block.Hash, Hash: uncle.Hash().Hex(), Raw: raw, Reward: thisUncleReward.String(), diff --git a/pkg/geth/converters/common/block_rewards.go b/pkg/geth/converters/common/block_rewards.go index ce26cadc..c0f6aae6 100644 --- a/pkg/geth/converters/common/block_rewards.go +++ b/pkg/geth/converters/common/block_rewards.go @@ -31,6 +31,16 @@ func CalcBlockReward(block core.Block, uncles []*types.Header) *big.Int { return tmp.Add(tmp, staticBlockReward) } +func calcUncleMinerReward(blockNumber, uncleBlockNumber int64) *big.Int { + staticBlockReward := staticRewardByBlockNumber(blockNumber) + rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8)) + mainBlock := big.NewInt(blockNumber) + uncleBlock := big.NewInt(uncleBlockNumber) + uncleBlockPlus8 := uncleBlock.Add(uncleBlock, big.NewInt(8)) + uncleBlockPlus8MinusMainBlock := uncleBlockPlus8.Sub(uncleBlockPlus8, mainBlock) + return rewardDiv8.Mul(rewardDiv8, uncleBlockPlus8MinusMainBlock) +} + func calcTransactionFees(block core.Block) *big.Int { transactionFees := new(big.Int) for _, transaction := range block.Transactions { @@ -56,7 +66,9 @@ func calcUncleInclusionRewards(block core.Block, uncles []*types.Header) *big.In func staticRewardByBlockNumber(blockNumber int64) *big.Int { staticBlockReward := new(big.Int) //https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/ - if blockNumber >= 4370000 { + if blockNumber >= 7280000 { + staticBlockReward.SetString("2000000000000000000", 10) + } else if blockNumber >= 4370000 { staticBlockReward.SetString("3000000000000000000", 10) } else { staticBlockReward.SetString("5000000000000000000", 10)