keep track of who is receiving uncle rewards

This commit is contained in:
Ian Norden 2019-03-21 14:52:24 -05:00
parent fea4ce0c7a
commit 9030cff2bd
8 changed files with 109 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
package repositories

View File

@ -0,0 +1 @@
package repositories

View File

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

View File

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