Add block rewards to db

This commit is contained in:
Matt Krump 2017-12-28 10:06:13 -06:00
parent 3ca4370221
commit 8b024bade9
10 changed files with 149 additions and 121 deletions

View File

@ -0,0 +1,3 @@
ALTER TABLE blocks
DROP COLUMN block_reward,
DROP COLUMN block_uncles_reward;

View File

@ -0,0 +1,3 @@
ALTER TABLE blocks
ADD COLUMN block_reward NUMERIC,
ADD COLUMN block_uncles_reward NUMERIC;

View File

@ -53,7 +53,9 @@ CREATE TABLE blocks (
node_id integer NOT NULL, node_id integer NOT NULL,
is_final boolean, is_final boolean,
block_miner character varying(42), block_miner character varying(42),
block_extra_data character varying block_extra_data character varying,
block_reward numeric,
block_uncles_reward numeric
); );

View File

@ -9,28 +9,26 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("Reading contracts", func() { var _ = Describe("Rewards calculations", func() {
Describe("Block and Uncle rewards", func() { It("calculates a block reward for a real block", func() {
It("calculates a block reward for a real block", func() { config, err := cfg.NewConfig("infura")
config, err := cfg.NewConfig("infura") if err != nil {
if err != nil { log.Fatalln(err)
log.Fatalln(err) }
} blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
blockchain := geth.NewGethBlockchain(config.Client.IPCPath) block := blockchain.GetBlockByNumber(1071819)
block := blockchain.GetBlockByNumber(1071819) Expect(block.Reward).To(Equal(5.31355))
Expect(block.BlockReward).To(Equal(5.31355)) })
})
It("calculates an uncle reward for a real block", func() { It("calculates an uncle reward for a real block", func() {
config, err := cfg.NewConfig("infura") config, err := cfg.NewConfig("infura")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
blockchain := geth.NewGethBlockchain(config.Client.IPCPath) blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
block := blockchain.GetBlockByNumber(1071819) block := blockchain.GetBlockByNumber(1071819)
Expect(block.UncleReward).To(Equal(6.875)) Expect(block.UnclesReward).To(Equal(6.875))
})
}) })
}) })

View File

@ -1,7 +1,7 @@
package core package core
type Block struct { type Block struct {
BlockReward float64 Reward float64
Difficulty int64 Difficulty int64
ExtraData string ExtraData string
GasLimit int64 GasLimit int64
@ -16,5 +16,5 @@ type Block struct {
Time int64 Time int64
Transactions []Transaction Transactions []Transaction
UncleHash string UncleHash string
UncleReward float64 UnclesReward float64
} }

View File

@ -7,24 +7,27 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
func UncleReward(gethBlock *types.Block, client GethClient) float64 { func CalcUnclesReward(gethBlock *types.Block) float64 {
var uncleReward float64 var unclesReward float64
for _, uncle := range gethBlock.Uncles() { for _, uncle := range gethBlock.Uncles() {
staticBlockReward := float64(blockNumberStaticReward(gethBlock)) / float64(8) blockNumber := gethBlock.Number().Int64()
uncleReward += float64(uncle.Number.Int64()-gethBlock.Number().Int64()+int64(8)) * staticBlockReward staticBlockReward := float64(staticRewardByBlockNumber(blockNumber))
unclesReward += (1.0 + float64(uncle.Number.Int64()-gethBlock.Number().Int64())/8.0) * staticBlockReward
} }
return uncleReward return unclesReward
} }
func BlockReward(gethBlock *types.Block, client GethClient) float64 { func CalcBlockReward(gethBlock *types.Block, client GethClient) float64 {
staticBlockReward := blockNumberStaticReward(gethBlock) blockNumber := gethBlock.Number().Int64()
staticBlockReward := staticRewardByBlockNumber(blockNumber)
transactionFees := calcTransactionFees(gethBlock, client) transactionFees := calcTransactionFees(gethBlock, client)
uncleInclusionRewards := uncleInclusionRewards(gethBlock, staticBlockReward) uncleInclusionRewards := calcUncleInclusionRewards(gethBlock)
return transactionFees + uncleInclusionRewards + staticBlockReward return transactionFees + uncleInclusionRewards + staticBlockReward
} }
func uncleInclusionRewards(gethBlock *types.Block, staticBlockReward float64) float64 { func calcUncleInclusionRewards(gethBlock *types.Block) float64 {
var uncleInclusionRewards float64 var uncleInclusionRewards float64
staticBlockReward := staticRewardByBlockNumber(gethBlock.Number().Int64())
for range gethBlock.Uncles() { for range gethBlock.Uncles() {
uncleInclusionRewards += staticBlockReward * 1 / 32 uncleInclusionRewards += staticBlockReward * 1 / 32
} }
@ -43,9 +46,10 @@ func calcTransactionFees(gethBlock *types.Block, client GethClient) float64 {
return transactionFees / params.Ether return transactionFees / params.Ether
} }
func blockNumberStaticReward(gethBlock *types.Block) float64 { func staticRewardByBlockNumber(blockNumber int64) float64 {
var staticBlockReward float64 var staticBlockReward float64
if gethBlock.Number().Int64() > 4269999 { //https://blog.ethereum.org/2017/10/12/byzantium-hf-announcement/
if blockNumber >= 4370000 {
staticBlockReward = 3 staticBlockReward = 3
} else { } else {
staticBlockReward = 5 staticBlockReward = 5

View File

@ -22,24 +22,24 @@ func GethBlockToCoreBlock(gethBlock *types.Block, client GethClient) core.Block
transaction := gethTransToCoreTrans(gethTransaction, &from) transaction := gethTransToCoreTrans(gethTransaction, &from)
transactions = append(transactions, transaction) transactions = append(transactions, transaction)
} }
blockReward := BlockReward(gethBlock, client) blockReward := CalcBlockReward(gethBlock, client)
uncleReward := UncleReward(gethBlock, client) uncleReward := CalcUnclesReward(gethBlock)
return core.Block{ return core.Block{
Difficulty: gethBlock.Difficulty().Int64(), Difficulty: gethBlock.Difficulty().Int64(),
ExtraData: hexutil.Encode(gethBlock.Extra()),
GasLimit: gethBlock.GasLimit().Int64(), GasLimit: gethBlock.GasLimit().Int64(),
GasUsed: gethBlock.GasUsed().Int64(), GasUsed: gethBlock.GasUsed().Int64(),
Hash: gethBlock.Hash().Hex(), Hash: gethBlock.Hash().Hex(),
ExtraData: hexutil.Encode(gethBlock.Extra()), Miner: gethBlock.Coinbase().Hex(),
Nonce: hexutil.Encode(gethBlock.Header().Nonce[:]), Nonce: hexutil.Encode(gethBlock.Header().Nonce[:]),
Number: gethBlock.Number().Int64(), Number: gethBlock.Number().Int64(),
Miner: gethBlock.Coinbase().Hex(),
ParentHash: gethBlock.ParentHash().Hex(), ParentHash: gethBlock.ParentHash().Hex(),
Reward: blockReward,
Size: gethBlock.Size().Int64(), Size: gethBlock.Size().Int64(),
Time: gethBlock.Time().Int64(), Time: gethBlock.Time().Int64(),
Transactions: transactions, Transactions: transactions,
BlockReward: blockReward,
UncleHash: gethBlock.UncleHash().Hex(), UncleHash: gethBlock.UncleHash().Hex(),
UncleReward: uncleReward, UnclesReward: uncleReward,
} }
} }

View File

@ -83,104 +83,110 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
Expect(gethBlock.IsFinal).To(BeFalse()) Expect(gethBlock.IsFinal).To(BeFalse())
}) })
Describe("the block and uncle rewards calculations", func() { Describe("The block and uncle rewards calculations", func() {
It("Calculates block rewards for a block", func() { It("calculates block rewards for a block", func() {
number := int64(1071819) transaction := types.NewTransaction(
uncles := []*types.Header{{Number: big.NewInt(1071817)}, {Number: big.NewInt(1071818)}} uint64(226823),
common.HexToAddress("0x108fedb097c1dcfed441480170144d8e19bb217f"),
nonce := uint64(226823) big.NewInt(1080900090000000000),
to := common.HexToAddress("0x108fedb097c1dcfed441480170144d8e19bb217f") big.NewInt(90000),
amount := big.NewInt(1080900090000000000) big.NewInt(50000000000),
gasLimit := big.NewInt(90000) []byte{},
gasPrice := big.NewInt(50000000000) )
var payload []byte
transaction := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, payload)
transactions := []*types.Transaction{transaction} transactions := []*types.Transaction{transaction}
txHash := transaction.Hash() txHash := transaction.Hash()
receipt := types.Receipt{TxHash: txHash, GasUsed: big.NewInt(21000)} receipt := types.Receipt{TxHash: txHash, GasUsed: big.NewInt(21000)}
receipts := []*types.Receipt{&receipt} receipts := []*types.Receipt{&receipt}
number := int64(1071819)
header := types.Header{ header := types.Header{
Number: big.NewInt(number), Number: big.NewInt(number),
} }
uncles := []*types.Header{{Number: big.NewInt(1071817)}, {Number: big.NewInt(1071818)}}
block := types.NewBlock(&header, transactions, uncles, []*types.Receipt{})
client := NewFakeClient()
client.AddReceipts(receipts)
Expect(geth.CalcBlockReward(block, client)).To(Equal(5.31355))
})
It("calculates the uncles reward for a block", func() {
transaction := types.NewTransaction(
uint64(226823),
common.HexToAddress("0x108fedb097c1dcfed441480170144d8e19bb217f"),
big.NewInt(1080900090000000000),
big.NewInt(90000),
big.NewInt(50000000000),
[]byte{})
transactions := []*types.Transaction{transaction}
receipt := types.Receipt{
TxHash: transaction.Hash(),
GasUsed: big.NewInt(21000),
}
receipts := []*types.Receipt{&receipt}
header := types.Header{
Number: big.NewInt(int64(1071819)),
}
uncles := []*types.Header{
{Number: big.NewInt(1071816)},
{Number: big.NewInt(1071817)},
}
block := types.NewBlock(&header, transactions, uncles, []*types.Receipt{}) block := types.NewBlock(&header, transactions, uncles, []*types.Receipt{})
client := NewFakeClient() client := NewFakeClient()
client.AddReceipts(receipts) client.AddReceipts(receipts)
Expect(geth.BlockReward(block, client)).To(Equal(5.31355)) Expect(geth.CalcUnclesReward(block)).To(Equal(6.875))
}) })
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() {
number := int64(4370055) transactionOne := types.NewTransaction(
var uncles []*types.Header uint64(8072),
common.HexToAddress("0xebd17720aeb7ac5186c5dfa7bafeb0bb14c02551 "),
big.NewInt(0),
big.NewInt(500000),
big.NewInt(42000000000),
[]byte{},
)
nonce := uint64(8072) transactionTwo := types.NewTransaction(uint64(8071),
to := common.HexToAddress("0xebd17720aeb7ac5186c5dfa7bafeb0bb14c02551 ") common.HexToAddress("0x3cdab63d764c8c5048ed5e8f0a4e95534ba7e1ea"),
amount := big.NewInt(0) big.NewInt(0),
gasLimit := big.NewInt(500000) big.NewInt(500000),
gasPrice := big.NewInt(42000000000) big.NewInt(42000000000),
var payload []byte []byte{})
transactionOne := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, payload)
nonce = uint64(8071)
to = common.HexToAddress("0x3cdab63d764c8c5048ed5e8f0a4e95534ba7e1ea")
amount = big.NewInt(0)
gasLimit = big.NewInt(500000)
gasPrice = big.NewInt(42000000000)
transactionTwo := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, payload)
transactions := []*types.Transaction{transactionOne, transactionTwo} transactions := []*types.Transaction{transactionOne, transactionTwo}
txHashOne := transactionOne.Hash() receiptOne := types.Receipt{
receiptOne := types.Receipt{TxHash: txHashOne, GasUsed: big.NewInt(297508)} TxHash: transactionOne.Hash(),
txHashTwo := transactionTwo.Hash() GasUsed: big.NewInt(297508),
receiptTwo := types.Receipt{TxHash: txHashTwo, GasUsed: big.NewInt(297508)} }
receiptTwo := types.Receipt{
TxHash: transactionTwo.Hash(),
GasUsed: big.NewInt(297508),
}
receipts := []*types.Receipt{&receiptOne, &receiptTwo} receipts := []*types.Receipt{&receiptOne, &receiptTwo}
number := int64(4370055)
header := types.Header{ header := types.Header{
Number: big.NewInt(number), Number: big.NewInt(number),
} }
var uncles []*types.Header
block := types.NewBlock(&header, transactions, uncles, receipts) block := types.NewBlock(&header, transactions, uncles, receipts)
client := NewFakeClient() client := NewFakeClient()
client.AddReceipts(receipts) client.AddReceipts(receipts)
Expect(geth.BlockReward(block, client)).To(Equal(3.024990672)) Expect(geth.CalcBlockReward(block, client)).To(Equal(3.024990672))
}) })
It("Calculates uncle rewards for a block", func() {
number := int64(1071819)
uncles := []*types.Header{{Number: big.NewInt(1071816)}, {Number: big.NewInt(1071817)}}
nonce := uint64(226823)
to := common.HexToAddress("0x108fedb097c1dcfed441480170144d8e19bb217f")
amount := big.NewInt(1080900090000000000)
gasLimit := big.NewInt(90000)
gasPrice := big.NewInt(50000000000)
var payload []byte
transaction := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, payload)
transactions := []*types.Transaction{transaction}
txHash := transaction.Hash()
receipt := types.Receipt{TxHash: txHash, GasUsed: big.NewInt(21000)}
receipts := []*types.Receipt{&receipt}
header := types.Header{
Number: big.NewInt(number),
}
block := types.NewBlock(&header, transactions, uncles, []*types.Receipt{})
client := NewFakeClient()
client.AddReceipts(receipts)
Expect(geth.UncleReward(block, client)).To(Equal(6.875))
})
}) })
Describe("the converted transations", func() { Describe("the converted transactions", func() {
It("is empty", func() { It("is empty", func() {
header := types.Header{} header := types.Header{}
block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{}) block := types.NewBlock(&header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{})

View File

@ -200,7 +200,9 @@ func (repository Postgres) FindBlockByNumber(blockNumber int64) (core.Block, err
uncle_hash, uncle_hash,
is_final, is_final,
block_miner, block_miner,
block_extra_data block_extra_data,
block_reward,
block_uncles_reward
FROM blocks FROM blocks
WHERE node_id = $1 AND block_number = $2`, repository.nodeId, blockNumber) WHERE node_id = $1 AND block_number = $2`, repository.nodeId, blockNumber)
savedBlock, err := repository.loadBlock(blockRows) savedBlock, err := repository.loadBlock(blockRows)
@ -258,10 +260,10 @@ func (repository Postgres) insertBlock(block core.Block) error {
tx, _ := repository.Db.BeginTx(context.Background(), nil) tx, _ := repository.Db.BeginTx(context.Background(), nil)
err := tx.QueryRow( err := tx.QueryRow(
`INSERT INTO blocks `INSERT INTO blocks
(node_id, block_number, block_gaslimit, block_gasused, block_time, block_difficulty, block_hash, block_nonce, block_parenthash, block_size, uncle_hash, is_final, block_miner, block_extra_data) (node_id, block_number, block_gaslimit, block_gasused, block_time, block_difficulty, block_hash, block_nonce, block_parenthash, block_size, uncle_hash, is_final, block_miner, block_extra_data, block_reward, block_uncles_reward)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
RETURNING id `, RETURNING id `,
repository.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). repository.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).
Scan(&blockId) Scan(&blockId)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
@ -312,12 +314,14 @@ func (repository Postgres) loadBlock(blockRows *sql.Row) (core.Block, error) {
var blockParentHash string var blockParentHash string
var blockSize int64 var blockSize int64
var blockTime float64 var blockTime float64
var blockReward float64
var difficulty int64 var difficulty int64
var gasLimit float64 var gasLimit float64
var gasUsed float64 var gasUsed float64
var uncleHash string var uncleHash string
var unclesReward float64
var isFinal bool var isFinal bool
err := blockRows.Scan(&blockId, &blockNumber, &gasLimit, &gasUsed, &blockTime, &difficulty, &blockHash, &blockNonce, &blockParentHash, &blockSize, &uncleHash, &isFinal, &blockMiner, &blockExtraData) err := blockRows.Scan(&blockId, &blockNumber, &gasLimit, &gasUsed, &blockTime, &difficulty, &blockHash, &blockNonce, &blockParentHash, &blockSize, &uncleHash, &isFinal, &blockMiner, &blockExtraData, &blockReward, &unclesReward)
if err != nil { if err != nil {
return core.Block{}, err return core.Block{}, err
} }
@ -334,6 +338,7 @@ func (repository Postgres) loadBlock(blockRows *sql.Row) (core.Block, error) {
ORDER BY tx_hash`, blockId) ORDER BY tx_hash`, blockId)
transactions := repository.loadTransactions(transactionRows) transactions := repository.loadTransactions(transactionRows)
return core.Block{ return core.Block{
Reward: blockReward,
Difficulty: difficulty, Difficulty: difficulty,
ExtraData: blockExtraData, ExtraData: blockExtraData,
GasLimit: int64(gasLimit), GasLimit: int64(gasLimit),
@ -348,6 +353,7 @@ func (repository Postgres) loadBlock(blockRows *sql.Row) (core.Block, error) {
Time: int64(blockTime), Time: int64(blockTime),
Transactions: transactions, Transactions: transactions,
UncleHash: uncleHash, UncleHash: uncleHash,
UnclesReward: unclesReward,
}, nil }, nil
} }

View File

@ -67,25 +67,30 @@ func AssertRepositoryBehavior(buildRepository func(node core.Node) repositories.
uncleHash := "x789" uncleHash := "x789"
blockSize := int64(1000) blockSize := int64(1000)
difficulty := int64(10) difficulty := int64(10)
blockReward := float64(5.132)
unclesReward := float64(3.580)
block := core.Block{ block := core.Block{
Difficulty: difficulty, Reward: blockReward,
GasLimit: gasLimit, Difficulty: difficulty,
GasUsed: gasUsed, GasLimit: gasLimit,
Hash: blockHash, GasUsed: gasUsed,
ExtraData: extraData, Hash: blockHash,
Nonce: blockNonce, ExtraData: extraData,
Miner: miner, Nonce: blockNonce,
Number: blockNumber, Miner: miner,
ParentHash: blockParentHash, Number: blockNumber,
Size: blockSize, ParentHash: blockParentHash,
Time: blockTime, Size: blockSize,
UncleHash: uncleHash, Time: blockTime,
UncleHash: uncleHash,
UnclesReward: unclesReward,
} }
repository.CreateOrUpdateBlock(block) repository.CreateOrUpdateBlock(block)
savedBlock, err := repository.FindBlockByNumber(blockNumber) savedBlock, err := repository.FindBlockByNumber(blockNumber)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(savedBlock.Reward).To(Equal(blockReward))
Expect(savedBlock.Difficulty).To(Equal(difficulty)) Expect(savedBlock.Difficulty).To(Equal(difficulty))
Expect(savedBlock.GasLimit).To(Equal(gasLimit)) Expect(savedBlock.GasLimit).To(Equal(gasLimit))
Expect(savedBlock.GasUsed).To(Equal(gasUsed)) Expect(savedBlock.GasUsed).To(Equal(gasUsed))
@ -98,6 +103,7 @@ func AssertRepositoryBehavior(buildRepository func(node core.Node) repositories.
Expect(savedBlock.Size).To(Equal(blockSize)) Expect(savedBlock.Size).To(Equal(blockSize))
Expect(savedBlock.Time).To(Equal(blockTime)) Expect(savedBlock.Time).To(Equal(blockTime))
Expect(savedBlock.UncleHash).To(Equal(uncleHash)) Expect(savedBlock.UncleHash).To(Equal(uncleHash))
Expect(savedBlock.UnclesReward).To(Equal(unclesReward))
}) })
It("does not find a block when searching for a number that does not exist", func() { It("does not find a block when searching for a number that does not exist", func() {