Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
Expand Down Expand Up @@ -922,6 +923,10 @@ func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.Matche
panic("not supported")
}

func (fb *filterBackend) Config() *ethconfig.Config {
panic("not supported")
}

func (fb *filterBackend) ChainConfig() *params.ChainConfig {
panic("not supported")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/geth/consolecmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

const (
ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 geth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
)

Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ var (
utils.OverrideCancun,
utils.OverrideVerkle,
utils.EnablePersonal,
utils.SupplyDeltaFlag,
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,
utils.TxPoolJournalFlag,
Expand Down
45 changes: 45 additions & 0 deletions cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/pruner"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/supply"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/flags"
Expand Down Expand Up @@ -150,6 +151,18 @@ as the backend data source, making this command a lot faster.

The argument is interpreted as block number or hash. If none is provided, the latest
block is used.
`,
},
{
Name: "crawl-supply",
Usage: "Calculate the ether supply at a specific block",
Action: crawlSupply,
Category: "MISCELLANEOUS COMMANDS",
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
Description: `
geth snapshot crawl-supply
will traverse the whole state from the given root and accumulate all the ether
balances to calculate the total supply.
`,
},
},
Expand Down Expand Up @@ -605,3 +618,35 @@ func checkAccount(ctx *cli.Context) error {
log.Info("Checked the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start)))
return nil
}

func crawlSupply(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

chaindb := utils.MakeChainDatabase(ctx, stack, true)
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
return errors.New("no head block")
}
if ctx.NArg() > 1 {
log.Error("Too many arguments given")
return errors.New("too many arguments")
}
snapConfig := snapshot.Config{
CacheSize: 256,
Recovery: false,
NoBuild: false,
AsyncBuild: false,
}
snaptree, err := snapshot.New(snapConfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root())
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
return err
}
if _, err = supply.Supply(headBlock.Header(), snaptree); err != nil {
log.Error("Failed to calculate current supply", "err", err)
return err
}
return nil
}
7 changes: 7 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,10 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: metrics.DefaultConfig.InfluxDBOrganization,
Category: flags.MetricsCategory,
}
SupplyDeltaFlag = &cli.BoolFlag{
Name: "supplydelta",
Usage: "Track Ether supply deltas (don't use in production)",
}
)

var (
Expand Down Expand Up @@ -1724,6 +1728,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.EthDiscoveryURLs = SplitAndTrim(urls)
}
}
if ctx.IsSet(SupplyDeltaFlag.Name) {
cfg.EnableSupplyDeltaRecording = ctx.Bool(SupplyDeltaFlag.Name)
}
// Override any default configs for hard coded networks.
switch {
case ctx.Bool(MainnetFlag.Name):
Expand Down
23 changes: 16 additions & 7 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
// Finalize implements consensus.Engine, accumulating the block and uncle rewards.
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, withdrawals []*types.Withdrawal) {
// Accumulate any block and uncle rewards
accumulateRewards(chain.Config(), state, header, uncles)
applyRewards(chain.Config(), state, header, uncles)
}

// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
Expand Down Expand Up @@ -543,10 +543,19 @@ var (
big32 = big.NewInt(32)
)

// AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
// applyRewards credits the coinbase of the given block with the mining reward.
func applyRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
f := func(h *types.Header, amt *big.Int) {
state.AddBalance(h.Coinbase, amt)
}
AccumulateRewards(config, header, uncles, f, f)
}

// AccumulateRewards is a generic function that allows the caller to decide how
// to apply rewards. The total reward consists of the static block reward and
// rewards for included uncles. The coinbase of each uncle block is also
// rewarded.
func AccumulateRewards(config *params.ChainConfig, header *types.Header, uncles []*types.Header, accUncleReward, accTotalReward func(*types.Header, *big.Int)) {
// Select the correct block reward based on chain progression
blockReward := FrontierBlockReward
if config.IsByzantium(header.Number) {
Expand All @@ -563,10 +572,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, big8)
state.AddBalance(uncle.Coinbase, r)
accUncleReward(uncle, r)

r.Div(blockReward, big32)
reward.Add(reward, r)
}
state.AddBalance(header.Coinbase, reward)
accTotalReward(header, reward)
}
31 changes: 31 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/supply"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
Expand Down Expand Up @@ -1392,6 +1393,36 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
}
bc.triedb.Dereference(root)
}
// If Ether supply delta tracking is enabled, do it before emitting events
if bc.vmConfig.EnableSupplyDeltaRecording {
// Note, this code path is opt-in for data analysis nodes, so speed
// is not really relevant, simplicity and containment much more so.
parent := rawdb.ReadHeader(bc.db, block.ParentHash(), block.NumberU64()-1)
if parent == nil {
log.Error("Failed to retrieve parent for supply delta", "err", err)
} else {
start := time.Now()

supplyDelta, err := supply.Delta(parent, block.Header(), bc.stateCache.TrieDB())
if err != nil {
log.Error("Failed to record Ether supply delta", "err", err)
} else {
rawdb.WriteSupplyDelta(bc.db, block.NumberU64(), block.Hash(), supplyDelta)
}

// Calculate the block coinbaseReward based on chain rules and progression.
rewards, withdrawals := supply.Issuance(block, bc.chainConfig)
burn := supply.Burn(block.Header())

// Calculate the difference between the "calculated" and "crawled" supply delta.
diff := new(big.Int).Set(supplyDelta)
diff.Sub(diff, rewards)
diff.Sub(diff, withdrawals)
diff.Add(diff, burn)

log.Info("Calculated supply delta for block", "number", block.Number(), "hash", block.Hash(), "supplydelta", supplyDelta, "rewards", rewards, "burn", burn, "withdrawals", withdrawals, "diff", diff, "elapsed", time.Since(start))
}
}
return nil
}

Expand Down
79 changes: 79 additions & 0 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/supply"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -4341,3 +4342,81 @@ func TestEIP3651(t *testing.T) {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
}

func TestDelta(t *testing.T) {
var (
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
engine = beacon.NewFaker()

// A sender who makes transactions, has some funds
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
funds = big.NewInt(params.Ether)
gspec = &Genesis{
Config: params.AllEthashProtocolChanges,
Alloc: GenesisAlloc{
addr1: {Balance: funds},
// The address 0xAAAA self-destructs
aa: {
Code: []byte{
byte(vm.ADDRESS),
byte(vm.SELFDESTRUCT),
},
Nonce: 0,
Balance: big.NewInt(41),
},
},
}
)

gspec.Config.TerminalTotalDifficulty = common.Big0
gspec.Config.TerminalTotalDifficultyPassed = true
gspec.Config.ShanghaiTime = u64(0)
signer := types.LatestSigner(gspec.Config)

db, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})

// One transaction to 0xAAAA
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 0,
To: &aa,
Value: common.Big1,
Gas: 50000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key1)

b.AddTx(tx)
b.AddWithdrawal(&types.Withdrawal{Amount: 1337})
})

var (
parent = gspec.ToBlock().Header()
block = blocks[0]
)

got, err := supply.Delta(parent, block.Header(), trie.NewDatabase(db))
if err != nil {
t.Fatalf("failed to calculate delta: %v", err)
}

// Calculate delta, w/o self-destructs
rewards, withdrawals := supply.Issuance(block, gspec.Config)
burn := supply.Burn(block.Header())

want := new(big.Int)
want.Add(want, rewards)
want.Add(want, withdrawals)
want.Sub(want, burn)

// Now account for self-destructed amount.
want.Sub(want, big.NewInt(42))

if want.Cmp(got) != 0 {
t.Fatalf("incorrect delta calculated: want %d, got %d", want, got)
}
}
36 changes: 36 additions & 0 deletions core/rawdb/accessors_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package rawdb

import (
"encoding/json"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -187,3 +188,38 @@ func WriteTransitionStatus(db ethdb.KeyValueWriter, data []byte) {
log.Crit("Failed to store the eth2 transition status", "err", err)
}
}

// ReadSupplyDelta retrieves the amount of Ether (in Wei) issued (or burnt) in a
// specific block. If unavailable for the specific block (non full synced node),
// nil will be returned.
func ReadSupplyDelta(db ethdb.KeyValueReader, number uint64, hash common.Hash) *big.Int {
blob, _ := db.Get(supplyDeltaKey(number, hash))
if len(blob) < 2 {
return nil
}
// Since negative big ints can't be encoded to bytes directly, use a dirty
// hack to store the negativift flag in the first byte (0 == positive,
// 1 == negative)
supplyDelta := new(big.Int).SetBytes(blob[1:])
if blob[0] == 1 {
supplyDelta.Neg(supplyDelta)
}
return supplyDelta
}

// WriteSupplyDelta stores the amount of Ether (in wei) issued (or burnt) in a
// specific block.
func WriteSupplyDelta(db ethdb.KeyValueWriter, number uint64, hash common.Hash, supplyDelta *big.Int) {
// Since negative big ints can't be encoded to bytes directly, use a dirty
// hack to store the negativift flag in the first byte (0 == positive,
// 1 == negative)
blob := []byte{0}
if supplyDelta.Sign() < 0 {
blob[0] = 1
}
blob = append(blob, supplyDelta.Bytes()...)

if err := db.Put(supplyDeltaKey(number, hash), blob); err != nil {
log.Crit("Failed to store block supply delta", "err", err)
}
}
Loading