Add Block + Uncle Rewards calculation

This commit is contained in:
Matt Krump 2017-12-27 17:51:17 -06:00
parent cb4e745464
commit 3ca4370221
5 changed files with 221 additions and 4 deletions

View File

@ -0,0 +1,36 @@
package integration
import (
"log"
cfg "github.com/8thlight/vulcanizedb/pkg/config"
"github.com/8thlight/vulcanizedb/pkg/geth"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Reading contracts", func() {
Describe("Block and Uncle rewards", func() {
It("calculates a block reward for a real block", func() {
config, err := cfg.NewConfig("infura")
if err != nil {
log.Fatalln(err)
}
blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
block := blockchain.GetBlockByNumber(1071819)
Expect(block.BlockReward).To(Equal(5.31355))
})
It("calculates an uncle reward for a real block", func() {
config, err := cfg.NewConfig("infura")
if err != nil {
log.Fatalln(err)
}
blockchain := geth.NewGethBlockchain(config.Client.IPCPath)
block := blockchain.GetBlockByNumber(1071819)
Expect(block.UncleReward).To(Equal(6.875))
})
})
})

View File

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

View File

@ -0,0 +1,54 @@
package geth
import (
"context"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
func UncleReward(gethBlock *types.Block, client GethClient) float64 {
var uncleReward float64
for _, uncle := range gethBlock.Uncles() {
staticBlockReward := float64(blockNumberStaticReward(gethBlock)) / float64(8)
uncleReward += float64(uncle.Number.Int64()-gethBlock.Number().Int64()+int64(8)) * staticBlockReward
}
return uncleReward
}
func BlockReward(gethBlock *types.Block, client GethClient) float64 {
staticBlockReward := blockNumberStaticReward(gethBlock)
transactionFees := calcTransactionFees(gethBlock, client)
uncleInclusionRewards := uncleInclusionRewards(gethBlock, staticBlockReward)
return transactionFees + uncleInclusionRewards + staticBlockReward
}
func uncleInclusionRewards(gethBlock *types.Block, staticBlockReward float64) float64 {
var uncleInclusionRewards float64
for range gethBlock.Uncles() {
uncleInclusionRewards += staticBlockReward * 1 / 32
}
return uncleInclusionRewards
}
func calcTransactionFees(gethBlock *types.Block, client GethClient) float64 {
var transactionFees float64
for _, transaction := range gethBlock.Transactions() {
receipt, err := client.TransactionReceipt(context.Background(), transaction.Hash())
if err != nil {
continue
}
transactionFees += float64(transaction.GasPrice().Int64() * receipt.GasUsed.Int64())
}
return transactionFees / params.Ether
}
func blockNumberStaticReward(gethBlock *types.Block) float64 {
var staticBlockReward float64
if gethBlock.Number().Int64() > 4269999 {
staticBlockReward = 3
} else {
staticBlockReward = 5
}
return staticBlockReward
}

View File

@ -12,6 +12,7 @@ import (
type GethClient interface { type GethClient interface {
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)
} }
func GethBlockToCoreBlock(gethBlock *types.Block, client GethClient) core.Block { func GethBlockToCoreBlock(gethBlock *types.Block, client GethClient) core.Block {
@ -21,6 +22,8 @@ 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)
uncleReward := UncleReward(gethBlock, client)
return core.Block{ return core.Block{
Difficulty: gethBlock.Difficulty().Int64(), Difficulty: gethBlock.Difficulty().Int64(),
GasLimit: gethBlock.GasLimit().Int64(), GasLimit: gethBlock.GasLimit().Int64(),
@ -34,7 +37,9 @@ func GethBlockToCoreBlock(gethBlock *types.Block, client GethClient) core.Block
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,
} }
} }

View File

@ -13,7 +13,28 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
type FakeGethClient struct{} type FakeGethClient struct {
receipts map[string]*types.Receipt
}
func NewFakeClient() *FakeGethClient {
return &FakeGethClient{
receipts: make(map[string]*types.Receipt),
}
}
func (client *FakeGethClient) AddReceipts(receipts []*types.Receipt) {
for _, receipt := range receipts {
client.receipts[receipt.TxHash.Hex()] = receipt
}
}
func (client *FakeGethClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
if gasUsed, ok := client.receipts[txHash.Hex()]; ok {
return gasUsed, nil
}
return &types.Receipt{GasUsed: big.NewInt(0)}, nil
}
func (client *FakeGethClient) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { func (client *FakeGethClient) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
return common.HexToAddress("0x123"), nil return common.HexToAddress("0x123"), nil
@ -62,6 +83,103 @@ 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() {
It("Calculates block rewards for a block", func() {
number := int64(1071819)
uncles := []*types.Header{{Number: big.NewInt(1071817)}, {Number: big.NewInt(1071818)}}
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.BlockReward(block, client)).To(Equal(5.31355))
})
It("decreases the static block reward from 5 to 3 for blocks after block 4,269,999", func() {
number := int64(4370055)
var uncles []*types.Header
nonce := uint64(8072)
to := common.HexToAddress("0xebd17720aeb7ac5186c5dfa7bafeb0bb14c02551 ")
amount := big.NewInt(0)
gasLimit := big.NewInt(500000)
gasPrice := big.NewInt(42000000000)
var payload []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}
txHashOne := transactionOne.Hash()
receiptOne := types.Receipt{TxHash: txHashOne, GasUsed: big.NewInt(297508)}
txHashTwo := transactionTwo.Hash()
receiptTwo := types.Receipt{TxHash: txHashTwo, GasUsed: big.NewInt(297508)}
receipts := []*types.Receipt{&receiptOne, &receiptTwo}
header := types.Header{
Number: big.NewInt(number),
}
block := types.NewBlock(&header, transactions, uncles, receipts)
client := NewFakeClient()
client.AddReceipts(receipts)
Expect(geth.BlockReward(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 transations", func() {
It("is empty", func() { It("is empty", func() {
header := types.Header{} header := types.Header{}
@ -72,7 +190,7 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
Expect(len(coreBlock.Transactions)).To(Equal(0)) Expect(len(coreBlock.Transactions)).To(Equal(0))
}) })
It("converts a single transations", func() { It("converts a single transaction", func() {
nonce := uint64(10000) nonce := uint64(10000)
header := types.Header{} header := types.Header{}
to := common.Address{1} to := common.Address{1}
@ -82,7 +200,9 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
payload := []byte("1234") payload := []byte("1234")
gethTransaction := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, payload) gethTransaction := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, payload)
client := &FakeGethClient{}
client := NewFakeClient()
gethBlock := types.NewBlock(&header, []*types.Transaction{gethTransaction}, []*types.Header{}, []*types.Receipt{}) gethBlock := types.NewBlock(&header, []*types.Transaction{gethTransaction}, []*types.Header{}, []*types.Receipt{})
coreBlock := geth.GethBlockToCoreBlock(gethBlock, client) coreBlock := geth.GethBlockToCoreBlock(gethBlock, client)
@ -100,8 +220,8 @@ var _ = Describe("Conversion of GethBlock to core.Block", func() {
It("has an empty to field when transaction creates a new contract", func() { It("has an empty to field when transaction creates a new contract", func() {
gethTransaction := types.NewContractCreation(uint64(10000), big.NewInt(10), big.NewInt(5000), big.NewInt(3), []byte("1234")) gethTransaction := types.NewContractCreation(uint64(10000), big.NewInt(10), big.NewInt(5000), big.NewInt(3), []byte("1234"))
gethBlock := types.NewBlock(&types.Header{}, []*types.Transaction{gethTransaction}, []*types.Header{}, []*types.Receipt{}) gethBlock := types.NewBlock(&types.Header{}, []*types.Transaction{gethTransaction}, []*types.Header{}, []*types.Receipt{})
client := &FakeGethClient{}
client := NewFakeClient()
coreBlock := geth.GethBlockToCoreBlock(gethBlock, client) coreBlock := geth.GethBlockToCoreBlock(gethBlock, client)
coreTransaction := coreBlock.Transactions[0] coreTransaction := coreBlock.Transactions[0]