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 package core
import "math/big"
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:"gaslimit"`
GasUsed uint64 `db:"gasused"` GasUsed uint64 `db:"gasused"`
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:"parenthash"`
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"`
MappedUncleRewards map[string]map[string]*big.Int
} }

View File

@ -20,6 +20,7 @@ import (
"database/sql" "database/sql"
"errors" "errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"math/big"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -139,6 +140,13 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err
} }
return 0, postgres.ErrDBInsertFailed(insertBlockErr) 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 { 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 +168,28 @@ func (blockRepository BlockRepository) insertBlock(block core.Block) (int64, err
return blockId, nil 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 { 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)

View File

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

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, 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()) uncleRewards, mappedUncleRewards := CalcUnclesReward(coreBlock, gethBlock.Uncles())
coreBlock.UnclesReward = uncleRewards.String()
coreBlock.MappedUncleRewards = mappedUncleRewards
return coreBlock, nil return coreBlock, nil
} }

View File

@ -17,54 +17,68 @@
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 { // (U_n + 8 - B_n) * R / 8
var unclesReward float64 // 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 { for _, uncle := range uncles {
blockNumber := block.Number staticBlockReward := staticRewardByBlockNumber(block.Number)
staticBlockReward := float64(staticRewardByBlockNumber(blockNumber)) rewardDiv8 := staticBlockReward.Div(staticBlockReward, big.NewInt(8))
unclesReward += (1.0 + float64(uncle.Number.Int64()-block.Number)/8.0) * staticBlockReward 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 { func CalcBlockReward(block core.Block, uncles []*types.Header) *big.Int {
blockNumber := block.Number staticBlockReward := staticRewardByBlockNumber(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 calcTransactionFees(block core.Block) *big.Int {
var transactionFees float64 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 >= 4370000 {
staticBlockReward = 3 staticBlockReward.SetString("3000000000000000000", 10)
} else { } else {
staticBlockReward = 5 staticBlockReward.SetString("5000000000000000000", 10)
} }
return staticBlockReward return staticBlockReward
} }