Merge pull request #47 from vulcanize/track_uncle_rewards
Track uncle rewards + direct balance polling
This commit is contained in:
commit
04ad7b7696
@ -3,15 +3,15 @@ CREATE TABLE public.blocks (
|
|||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
difficulty BIGINT,
|
difficulty BIGINT,
|
||||||
extra_data VARCHAR,
|
extra_data VARCHAR,
|
||||||
gaslimit BIGINT,
|
gas_limit BIGINT,
|
||||||
gasused BIGINT,
|
gas_used BIGINT,
|
||||||
hash VARCHAR(66),
|
hash VARCHAR(66),
|
||||||
miner VARCHAR(42),
|
miner VARCHAR(42),
|
||||||
nonce VARCHAR(20),
|
nonce VARCHAR(20),
|
||||||
"number" BIGINT,
|
"number" BIGINT,
|
||||||
parenthash VARCHAR(66),
|
parent_hash VARCHAR(66),
|
||||||
reward DOUBLE PRECISION,
|
reward NUMERIC,
|
||||||
uncles_reward DOUBLE PRECISION,
|
uncles_reward NUMERIC,
|
||||||
"size" VARCHAR,
|
"size" VARCHAR,
|
||||||
"time" BIGINT,
|
"time" BIGINT,
|
||||||
is_final BOOLEAN,
|
is_final BOOLEAN,
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
CREATE TABLE full_sync_transactions (
|
CREATE TABLE full_sync_transactions (
|
||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
block_id INTEGER NOT NULL REFERENCES blocks(id) ON DELETE CASCADE,
|
block_id INTEGER NOT NULL REFERENCES blocks(id) ON DELETE CASCADE,
|
||||||
gaslimit NUMERIC,
|
gas_limit NUMERIC,
|
||||||
gasprice NUMERIC,
|
gas_price NUMERIC,
|
||||||
hash VARCHAR(66),
|
hash VARCHAR(66),
|
||||||
input_data BYTEA,
|
input_data BYTEA,
|
||||||
nonce NUMERIC,
|
nonce NUMERIC,
|
||||||
|
@ -5,11 +5,8 @@ CREATE TABLE public.headers (
|
|||||||
block_number BIGINT,
|
block_number BIGINT,
|
||||||
raw JSONB,
|
raw JSONB,
|
||||||
block_timestamp NUMERIC,
|
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),
|
eth_node_fingerprint VARCHAR(128)
|
||||||
CONSTRAINT eth_nodes_fk FOREIGN KEY (eth_node_id)
|
|
||||||
REFERENCES eth_nodes (id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Index is removed when table is
|
-- Index is removed when table is
|
||||||
|
@ -3,8 +3,8 @@ CREATE TABLE light_sync_transactions (
|
|||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE,
|
header_id INTEGER NOT NULL REFERENCES headers(id) ON DELETE CASCADE,
|
||||||
hash TEXT,
|
hash TEXT,
|
||||||
gaslimit NUMERIC,
|
gas_limit NUMERIC,
|
||||||
gasprice NUMERIC,
|
gas_price NUMERIC,
|
||||||
input_data BYTEA,
|
input_data BYTEA,
|
||||||
nonce NUMERIC,
|
nonce NUMERIC,
|
||||||
raw BYTEA,
|
raw BYTEA,
|
||||||
|
16
db/migrations/00026_create_uncles_table.sql
Normal file
16
db/migrations/00026_create_uncles_table.sql
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
-- +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,
|
||||||
|
reward NUMERIC NOT NULL,
|
||||||
|
miner VARCHAR(42) NOT NULL,
|
||||||
|
raw JSONB,
|
||||||
|
block_timestamp NUMERIC,
|
||||||
|
eth_node_id INTEGER NOT NULL REFERENCES eth_nodes (id) ON DELETE CASCADE,
|
||||||
|
eth_node_fingerprint VARCHAR(128),
|
||||||
|
UNIQUE (block_id, hash)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE public.uncles;
|
@ -42,7 +42,7 @@ var _ = Describe("Rewards calculations", func() {
|
|||||||
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
block, err := blockChain.GetBlockByNumber(1071819)
|
block, err := blockChain.GetBlockByNumber(1071819)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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() {
|
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)
|
blockChain := geth.NewBlockChain(blockChainClient, rpcClient, node, transactionConverter)
|
||||||
block, err := blockChain.GetBlockByNumber(1071819)
|
block, err := blockChain.GetBlockByNumber(1071819)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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
|
||||||
|
}
|
@ -17,20 +17,21 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
type Block struct {
|
type Block struct {
|
||||||
Reward float64 `db:"reward"`
|
Reward string `db:"reward"`
|
||||||
Difficulty int64 `db:"difficulty"`
|
Difficulty int64 `db:"difficulty"`
|
||||||
ExtraData string `db:"extra_data"`
|
ExtraData string `db:"extra_data"`
|
||||||
GasLimit uint64 `db:"gaslimit"`
|
GasLimit uint64 `db:"gas_limit"`
|
||||||
GasUsed uint64 `db:"gasused"`
|
GasUsed uint64 `db:"gas_used"`
|
||||||
Hash string `db:"hash"`
|
Hash string `db:"hash"`
|
||||||
IsFinal bool `db:"is_final"`
|
IsFinal bool `db:"is_final"`
|
||||||
Miner string `db:"miner"`
|
Miner string `db:"miner"`
|
||||||
Nonce string `db:"nonce"`
|
Nonce string `db:"nonce"`
|
||||||
Number int64 `db:"number"`
|
Number int64 `db:"number"`
|
||||||
ParentHash string `db:"parenthash"`
|
ParentHash string `db:"parent_hash"`
|
||||||
Size string `db:"size"`
|
Size string `db:"size"`
|
||||||
Time int64 `db:"time"`
|
Time int64 `db:"time"`
|
||||||
Transactions []TransactionModel
|
Transactions []TransactionModel
|
||||||
UncleHash string `db:"uncle_hash"`
|
UncleHash string `db:"uncle_hash"`
|
||||||
UnclesReward float64 `db:"uncles_reward"`
|
UnclesReward string `db:"uncles_reward"`
|
||||||
|
Uncles []Uncle
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
type BlockChain interface {
|
type BlockChain interface {
|
||||||
ContractDataFetcher
|
ContractDataFetcher
|
||||||
|
AccountDataFetcher
|
||||||
GetBlockByNumber(blockNumber int64) (Block, error)
|
GetBlockByNumber(blockNumber int64) (Block, error)
|
||||||
GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error)
|
GetEthLogsWithCustomQuery(query ethereum.FilterQuery) ([]types.Log, error)
|
||||||
GetHeaderByNumber(blockNumber int64) (Header, error)
|
GetHeaderByNumber(blockNumber int64) (Header, error)
|
||||||
@ -39,3 +40,7 @@ type BlockChain interface {
|
|||||||
type ContractDataFetcher interface {
|
type ContractDataFetcher interface {
|
||||||
FetchContractData(abiJSON string, address string, method string, methodArgs []interface{}, result interface{}, blockNumber int64) error
|
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)
|
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)
|
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)
|
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
||||||
|
BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error)
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ package core
|
|||||||
type TransactionModel struct {
|
type TransactionModel struct {
|
||||||
Data []byte `db:"input_data"`
|
Data []byte `db:"input_data"`
|
||||||
From string `db:"tx_from"`
|
From string `db:"tx_from"`
|
||||||
GasLimit uint64
|
GasLimit uint64 `db:"gas_limit"`
|
||||||
GasPrice int64
|
GasPrice int64 `db:"gas_price"`
|
||||||
Hash string
|
Hash string
|
||||||
Nonce uint64
|
Nonce uint64
|
||||||
Raw []byte
|
Raw []byte
|
||||||
|
26
pkg/core/uncle.go
Normal file
26
pkg/core/uncle.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// 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 core
|
||||||
|
|
||||||
|
type Uncle struct {
|
||||||
|
Id int64
|
||||||
|
Miner string
|
||||||
|
Reward string
|
||||||
|
Hash string
|
||||||
|
Timestamp string `db:"block_timestamp"`
|
||||||
|
Raw []byte
|
||||||
|
}
|
@ -19,9 +19,9 @@ package repositories
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"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/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
@ -90,13 +90,13 @@ func (blockRepository BlockRepository) GetBlock(blockNumber int64) (core.Block,
|
|||||||
blockRows := blockRepository.database.QueryRowx(
|
blockRows := blockRepository.database.QueryRowx(
|
||||||
`SELECT id,
|
`SELECT id,
|
||||||
number,
|
number,
|
||||||
gaslimit,
|
gas_limit,
|
||||||
gasused,
|
gas_used,
|
||||||
time,
|
time,
|
||||||
difficulty,
|
difficulty,
|
||||||
hash,
|
hash,
|
||||||
nonce,
|
nonce,
|
||||||
parenthash,
|
parent_hash,
|
||||||
size,
|
size,
|
||||||
uncle_hash,
|
uncle_hash,
|
||||||
is_final,
|
is_final,
|
||||||
@ -127,10 +127,26 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err
|
|||||||
}
|
}
|
||||||
insertBlockErr := tx.QueryRow(
|
insertBlockErr := tx.QueryRow(
|
||||||
`INSERT INTO blocks
|
`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)
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||||
RETURNING id `,
|
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)
|
Scan(&blockId)
|
||||||
if insertBlockErr != nil {
|
if insertBlockErr != nil {
|
||||||
rollbackErr := tx.Rollback()
|
rollbackErr := tx.Rollback()
|
||||||
@ -139,6 +155,13 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err
|
|||||||
}
|
}
|
||||||
return 0, postgres.ErrDBInsertFailed(insertBlockErr)
|
return 0, postgres.ErrDBInsertFailed(insertBlockErr)
|
||||||
}
|
}
|
||||||
|
if len(block.Uncles) > 0 {
|
||||||
|
insertUncleErr := blockRepository.createUncles(tx, blockId, block.Hash, block.Uncles)
|
||||||
|
if insertUncleErr != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return 0, postgres.ErrDBInsertFailed(insertUncleErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(block.Transactions) > 0 {
|
if len(block.Transactions) > 0 {
|
||||||
insertTxErr := blockRepository.createTransactions(tx, blockId, block.Transactions)
|
insertTxErr := blockRepository.createTransactions(tx, blockId, block.Transactions)
|
||||||
if insertTxErr != nil {
|
if insertTxErr != nil {
|
||||||
@ -160,6 +183,26 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err
|
|||||||
return blockId, nil
|
return blockId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) createUncle(tx *sqlx.Tx, blockId int64, uncle core.Uncle) error {
|
||||||
|
_, err := tx.Exec(
|
||||||
|
`INSERT INTO uncles
|
||||||
|
(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, utilities.NullToZero(uncle.Reward), uncle.Miner, uncle.Raw, uncle.Timestamp, blockRepository.database.NodeID, blockRepository.database.Node.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (blockRepository BlockRepository) createTransactions(tx *sqlx.Tx, blockId int64, transactions []core.TransactionModel) error {
|
func (blockRepository BlockRepository) createTransactions(tx *sqlx.Tx, blockId int64, transactions []core.TransactionModel) error {
|
||||||
for _, transaction := range transactions {
|
for _, transaction := range transactions {
|
||||||
err := blockRepository.createTransaction(tx, blockId, transaction)
|
err := blockRepository.createTransaction(tx, blockId, transaction)
|
||||||
@ -183,10 +226,10 @@ func nullStringToZero(s string) string {
|
|||||||
func (blockRepository BlockRepository) createTransaction(tx *sqlx.Tx, blockId int64, transaction core.TransactionModel) error {
|
func (blockRepository BlockRepository) createTransaction(tx *sqlx.Tx, blockId int64, transaction core.TransactionModel) error {
|
||||||
_, err := tx.Exec(
|
_, err := tx.Exec(
|
||||||
`INSERT INTO full_sync_transactions
|
`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)
|
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,
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -282,8 +325,8 @@ func (blockRepository BlockRepository) loadBlock(blockRows *sqlx.Row) (core.Bloc
|
|||||||
}
|
}
|
||||||
transactionRows, err := blockRepository.database.Queryx(`
|
transactionRows, err := blockRepository.database.Queryx(`
|
||||||
SELECT hash,
|
SELECT hash,
|
||||||
gaslimit,
|
gas_limit,
|
||||||
gasprice,
|
gas_price,
|
||||||
input_data,
|
input_data,
|
||||||
nonce,
|
nonce,
|
||||||
raw,
|
raw,
|
||||||
|
@ -84,8 +84,8 @@ var _ = Describe("Saving blocks", func() {
|
|||||||
uncleHash := "x789"
|
uncleHash := "x789"
|
||||||
blockSize := string("1000")
|
blockSize := string("1000")
|
||||||
difficulty := int64(10)
|
difficulty := int64(10)
|
||||||
blockReward := float64(5.132)
|
blockReward := "5132000000000000000"
|
||||||
unclesReward := float64(3.580)
|
unclesReward := "3580000000000000000"
|
||||||
block := core.Block{
|
block := core.Block{
|
||||||
Reward: blockReward,
|
Reward: blockReward,
|
||||||
Difficulty: difficulty,
|
Difficulty: difficulty,
|
||||||
@ -158,6 +158,72 @@ var _ = Describe("Saving blocks", func() {
|
|||||||
Expect(len(savedBlock.Transactions)).To(Equal(2))
|
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, 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 two uncles 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, 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, 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
|
It(`replaces blocks and transactions associated to the block
|
||||||
when a more new block is in conflict (same block number + nodeid)`, func() {
|
when a more new block is in conflict (same block number + nodeid)`, func() {
|
||||||
blockOne := core.Block{
|
blockOne := core.Block{
|
||||||
|
@ -82,8 +82,8 @@ func (contractRepository ContractRepository) addTransactions(contract core.Contr
|
|||||||
nonce,
|
nonce,
|
||||||
tx_to,
|
tx_to,
|
||||||
tx_from,
|
tx_from,
|
||||||
gaslimit,
|
gas_limit,
|
||||||
gasprice,
|
gas_price,
|
||||||
value,
|
value,
|
||||||
input_data
|
input_data
|
||||||
FROM full_sync_transactions
|
FROM full_sync_transactions
|
||||||
|
@ -52,7 +52,7 @@ func (repository HeaderRepository) CreateOrUpdateHeader(header core.Header) (int
|
|||||||
func (repository HeaderRepository) CreateTransactions(headerID int64, transactions []core.TransactionModel) error {
|
func (repository HeaderRepository) CreateTransactions(headerID int64, transactions []core.TransactionModel) error {
|
||||||
for _, transaction := range transactions {
|
for _, transaction := range transactions {
|
||||||
_, err := repository.database.Exec(`INSERT INTO public.light_sync_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)
|
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,
|
ON CONFLICT DO NOTHING`, headerID, transaction.Hash, transaction.GasLimit, transaction.GasPrice,
|
||||||
transaction.Data, transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To,
|
transaction.Data, transaction.Nonce, transaction.Raw, transaction.From, transaction.TxIndex, transaction.To,
|
||||||
|
@ -226,7 +226,7 @@ var _ = Describe("Block header repository", func() {
|
|||||||
It("adds transactions", func() {
|
It("adds transactions", func() {
|
||||||
var dbTransactions []core.TransactionModel
|
var dbTransactions []core.TransactionModel
|
||||||
err = db.Select(&dbTransactions,
|
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)
|
FROM public.light_sync_transactions WHERE header_id = $1`, headerID)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(dbTransactions).To(ConsistOf(transactions))
|
Expect(dbTransactions).To(ConsistOf(transactions))
|
||||||
@ -238,7 +238,7 @@ var _ = Describe("Block header repository", func() {
|
|||||||
|
|
||||||
var dbTransactions []core.TransactionModel
|
var dbTransactions []core.TransactionModel
|
||||||
err = db.Select(&dbTransactions,
|
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)
|
FROM public.light_sync_transactions WHERE header_id = $1`, headerID)
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(len(dbTransactions)).To(Equal(2))
|
Expect(len(dbTransactions)).To(Equal(2))
|
||||||
|
@ -73,7 +73,7 @@ func GetFakeTransaction(hash string, receipt core.Receipt) core.TransactionModel
|
|||||||
var raw bytes.Buffer
|
var raw bytes.Buffer
|
||||||
err := gethTransaction.EncodeRLP(&raw)
|
err := gethTransaction.EncodeRLP(&raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("failed to marshal transaction creating test fake")
|
panic("failed to marshal transaction while creating test fake")
|
||||||
}
|
}
|
||||||
return core.TransactionModel{
|
return core.TransactionModel{
|
||||||
Data: []byte{},
|
Data: []byte{},
|
||||||
@ -89,3 +89,13 @@ func GetFakeTransaction(hash string, receipt core.Receipt) core.TransactionModel
|
|||||||
Value: "0",
|
Value: "0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetFakeUncle(hash, reward string) core.Uncle {
|
||||||
|
return core.Uncle{
|
||||||
|
Miner: FakeAddress.String(),
|
||||||
|
Hash: hash,
|
||||||
|
Reward: reward,
|
||||||
|
Raw: rawFakeHeader,
|
||||||
|
Timestamp: strconv.FormatInt(fakeTimestamp, 10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -45,6 +45,8 @@ type MockBlockChain struct {
|
|||||||
lastBlock *big.Int
|
lastBlock *big.Int
|
||||||
node core.Node
|
node core.Node
|
||||||
Transactions []core.TransactionModel
|
Transactions []core.TransactionModel
|
||||||
|
accountBalanceReturnValue *big.Int
|
||||||
|
getAccountBalanceErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMockBlockChain() *MockBlockChain {
|
func NewMockBlockChain() *MockBlockChain {
|
||||||
@ -141,3 +143,15 @@ func (chain *MockBlockChain) AssertFetchContractDataCalledWith(abiJSON string, a
|
|||||||
func (blockChain *MockBlockChain) AssertGetEthLogsWithCustomQueryCalledWith(query ethereum.FilterQuery) {
|
func (blockChain *MockBlockChain) AssertGetEthLogsWithCustomQueryCalledWith(query ethereum.FilterQuery) {
|
||||||
Expect(blockChain.logQuery).To(Equal(query))
|
Expect(blockChain.logQuery).To(Equal(query))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (blockChain *MockBlockChain) SetGetAccountBalanceErr(err error) {
|
||||||
|
blockChain.getAccountBalanceErr = err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (blockChain *MockBlockChain) SetGetAccountBalance(balance *big.Int) {
|
||||||
|
blockChain.accountBalanceReturnValue = balance
|
||||||
|
}
|
||||||
|
|
||||||
|
func (blockChain *MockBlockChain) GetAccountBalance(address common.Address, blockNumber *big.Int) (*big.Int, error) {
|
||||||
|
return blockChain.accountBalanceReturnValue, blockChain.getAccountBalanceErr
|
||||||
|
}
|
||||||
|
@ -54,6 +54,11 @@ type MockEthClient struct {
|
|||||||
passedMethod string
|
passedMethod string
|
||||||
transactionSenderErr error
|
transactionSenderErr error
|
||||||
transactionReceiptErr error
|
transactionReceiptErr error
|
||||||
|
passedAddress common.Address
|
||||||
|
passedBlockNumber *big.Int
|
||||||
|
passedBalance *big.Int
|
||||||
|
balanceAtErr error
|
||||||
|
passedbalanceAtContext context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMockEthClient() *MockEthClient {
|
func NewMockEthClient() *MockEthClient {
|
||||||
@ -208,3 +213,24 @@ func (client *MockEthClient) AssertFilterLogsCalledWith(ctx context.Context, q e
|
|||||||
func (client *MockEthClient) AssertBatchCalledWith(method string) {
|
func (client *MockEthClient) AssertBatchCalledWith(method string) {
|
||||||
Expect(client.passedMethod).To(Equal(method))
|
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
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
@ -244,4 +245,28 @@ var _ = Describe("Geth blockchain", func() {
|
|||||||
Expect(result).To(Equal(big.NewInt(blockNumber)))
|
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) {
|
func (client EthClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||||
return client.client.TransactionReceipt(ctx, txHash)
|
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,14 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlockConverter struct {
|
type BlockConverter struct {
|
||||||
@ -52,7 +56,35 @@ func (bc BlockConverter) ToCoreBlock(gethBlock *types.Block) (core.Block, error)
|
|||||||
Transactions: transactions,
|
Transactions: transactions,
|
||||||
UncleHash: gethBlock.UncleHash().Hex(),
|
UncleHash: gethBlock.UncleHash().Hex(),
|
||||||
}
|
}
|
||||||
coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles())
|
coreBlock.Reward = CalcBlockReward(coreBlock, gethBlock.Uncles()).String()
|
||||||
coreBlock.UnclesReward = CalcUnclesReward(coreBlock, gethBlock.Uncles())
|
totalUncleReward, uncles := bc.ToCoreUncle(coreBlock, gethBlock.Uncles())
|
||||||
|
|
||||||
|
coreBlock.UnclesReward = totalUncleReward.String()
|
||||||
|
coreBlock.Uncles = uncles
|
||||||
return coreBlock, nil
|
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 {
|
||||||
|
thisUncleReward := calcUncleMinerReward(block.Number, uncle.Number.Int64())
|
||||||
|
raw, _ := json.Marshal(uncle)
|
||||||
|
coreUncle := core.Uncle{
|
||||||
|
Miner: uncle.Coinbase.Hex(),
|
||||||
|
Hash: uncle.Hash().Hex(),
|
||||||
|
Raw: raw,
|
||||||
|
Reward: thisUncleReward.String(),
|
||||||
|
Timestamp: uncle.Time.String(),
|
||||||
|
}
|
||||||
|
coreUncles = append(coreUncles, coreUncle)
|
||||||
|
totalUncleRewards.Add(totalUncleRewards, thisUncleReward)
|
||||||
|
}
|
||||||
|
return totalUncleRewards, coreUncles
|
||||||
|
}
|
||||||
|
@ -114,9 +114,13 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
|||||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||||
|
|
||||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||||
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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() {
|
It("calculates the uncles reward for a block", func() {
|
||||||
@ -151,9 +155,20 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
|||||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||||
|
|
||||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||||
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(vulcCommon.CalcUnclesReward(coreBlock, block.Uncles())).To(Equal(6.875))
|
|
||||||
|
expectedTotalReward := new(big.Int)
|
||||||
|
expectedTotalReward.SetString("6875000000000000000", 10)
|
||||||
|
totalReward, coreUncles := blockConverter.ToCoreUncle(coreBlock, block.Uncles())
|
||||||
|
Expect(totalReward.String()).To(Equal(expectedTotalReward.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() {
|
It("decreases the static block reward from 5 to 3 for blocks after block 4,269,999", func() {
|
||||||
@ -200,9 +215,12 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
|
|||||||
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
blockConverter := vulcCommon.NewBlockConverter(transactionConverter)
|
||||||
|
|
||||||
coreBlock, err := blockConverter.ToCoreBlock(block)
|
coreBlock, err := blockConverter.ToCoreBlock(block)
|
||||||
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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()))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -17,54 +17,61 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CalcUnclesReward(block core.Block, uncles []*types.Header) float64 {
|
func CalcBlockReward(block core.Block, uncles []*types.Header) *big.Int {
|
||||||
var unclesReward float64
|
staticBlockReward := staticRewardByBlockNumber(block.Number)
|
||||||
for _, uncle := range uncles {
|
|
||||||
blockNumber := block.Number
|
|
||||||
staticBlockReward := float64(staticRewardByBlockNumber(blockNumber))
|
|
||||||
unclesReward += (1.0 + float64(uncle.Number.Int64()-block.Number)/8.0) * staticBlockReward
|
|
||||||
}
|
|
||||||
return unclesReward
|
|
||||||
}
|
|
||||||
|
|
||||||
func CalcBlockReward(block core.Block, uncles []*types.Header) float64 {
|
|
||||||
blockNumber := block.Number
|
|
||||||
staticBlockReward := staticRewardByBlockNumber(blockNumber)
|
|
||||||
transactionFees := calcTransactionFees(block)
|
transactionFees := calcTransactionFees(block)
|
||||||
uncleInclusionRewards := calcUncleInclusionRewards(block, uncles)
|
uncleInclusionRewards := calcUncleInclusionRewards(block, uncles)
|
||||||
return transactionFees + uncleInclusionRewards + staticBlockReward
|
tmp := transactionFees.Add(transactionFees, uncleInclusionRewards)
|
||||||
|
return tmp.Add(tmp, staticBlockReward)
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcTransactionFees(block core.Block) float64 {
|
func calcUncleMinerReward(blockNumber, uncleBlockNumber int64) *big.Int {
|
||||||
var transactionFees float64
|
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 {
|
for _, transaction := range block.Transactions {
|
||||||
receipt := transaction.Receipt
|
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 {
|
func calcUncleInclusionRewards(block core.Block, uncles []*types.Header) *big.Int {
|
||||||
var uncleInclusionRewards float64
|
uncleInclusionRewards := new(big.Int)
|
||||||
staticBlockReward := staticRewardByBlockNumber(block.Number)
|
|
||||||
for range uncles {
|
for range uncles {
|
||||||
uncleInclusionRewards += staticBlockReward * 1 / 32
|
staticBlockReward := staticRewardByBlockNumber(block.Number)
|
||||||
|
staticBlockReward.Div(staticBlockReward, big.NewInt(32))
|
||||||
|
uncleInclusionRewards.Add(uncleInclusionRewards, staticBlockReward)
|
||||||
}
|
}
|
||||||
return uncleInclusionRewards
|
return uncleInclusionRewards
|
||||||
}
|
}
|
||||||
|
|
||||||
func staticRewardByBlockNumber(blockNumber int64) float64 {
|
func staticRewardByBlockNumber(blockNumber int64) *big.Int {
|
||||||
var staticBlockReward float64
|
staticBlockReward := new(big.Int)
|
||||||
//https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/
|
//https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/
|
||||||
if blockNumber >= 4370000 {
|
if blockNumber >= 7280000 {
|
||||||
staticBlockReward = 3
|
staticBlockReward.SetString("2000000000000000000", 10)
|
||||||
|
} else if blockNumber >= 4370000 {
|
||||||
|
staticBlockReward.SetString("3000000000000000000", 10)
|
||||||
} else {
|
} else {
|
||||||
staticBlockReward = 5
|
staticBlockReward.SetString("5000000000000000000", 10)
|
||||||
}
|
}
|
||||||
return staticBlockReward
|
return staticBlockReward
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user