Skip to content

Instantly share code, notes, and snippets.

@innomon
Created December 28, 2018 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save innomon/bab61ca573c6ceb6283206aa11f74891 to your computer and use it in GitHub Desktop.
Save innomon/bab61ca573c6ceb6283206aa11f74891 to your computer and use it in GitHub Desktop.
Please verify my assumption on Ethereum POA (clique) gas burning is correct?

POA Gas burn : code walk

I prepared this gist to confirm from the community if my assumption on Ethereum POA (clique) gas burning is correct?

From what I groked today in the ethereum go code, it appears that the gas used during the contract execution is burned, that is debited from the contract transaction submitter’s account but not credited to anyone.

Please see the code snippets below:

code base groked: geth 'release/1.8'

go-ethereum/core/blockchain.go

L:1069 Bockchain InsertChain calls Blockchain.Process at L:1200

Process then calls ApplyTransaction which in-turn calls ApplyMessage()

Function ApplyMessage calls TransitionDb(), which deducts gass from the executor address and credits to the coinbase address.

coinbase is set to all zero during init of clique, so gas is deducted and burned but not recycled. (TODO re-verify) see:

 consensus/clique/clique.go
L:517 func (c *Clique) Prepare(chain consensus.ChainReader, header *types.Header) error

L:519 header.Coinbase = common.Address{}

go-ethereum/core/state_processor.go
L:49
// Process processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb and applying any rewards to both
// the processor (coinbase) and any included uncles.
//
// Process returns the receipts and logs accumulated during the process and
// returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error.
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) {

L:71 calls ApplyTransaction which in-turn calls ApplyMessage()

go-ethereum/consensus/ethash/consensus.go

Ethash uses mining workers…​see below:

go-ethereum/miner/worker.go

L:402 func (w *worker) mainLoop()

worker mainloop function uses channel select pattern to call commitTransaction function.

L:691
func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) {
	snap := w.current.state.Snapshot()

	receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig())
go-ethereum/core/chain_makers.go
Chain Makers is only used for test & sim.
L:77
// AddTx adds a transaction to the generated block. If no coinbase has
// been set, the block's coinbase is set to the zero address.
//
// AddTx panics if the transaction cannot be executed. In addition to
// the protocol-imposed limitations (gas limit, etc.), there are some
// further limitations on the content of transactions that can be
// added. Notably, contract code relying on the BLOCKHASH instruction
// will panic during execution.
func (b *BlockGen) AddTx(tx *types.Transaction) {
	b.AddTxWithChain(nil, tx)
}
L:86
// AddTxWithChain adds a transaction to the generated block. If no coinbase has
// been set, the block's coinbase is set to the zero address.
//
// AddTxWithChain panics if the transaction cannot be executed. In addition to
// the protocol-imposed limitations (gas limit, etc.), there are some
// further limitations on the content of transactions that can be
// added. If contract code relies on the BLOCKHASH instruction,
// the block in chain will be returned.
func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {

L:99 receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
go-ethereum/consensus/ethash/consensus.go
func (ethash *Ethash) Finalize(...

L:569 accumulateRewards(chain.Config(), state, header, uncles)

L:605: func accumulateRewards(…​)

// 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.
core/state_processor.go

L:88 ApplyTransaction calls ApplyMessage()

internal/ethapi/api.go

L:686 func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, timeout time.Duration) ([]byte, uint64, bool, error) {

L:741 res, gas, failed, err := core.ApplyMessage(evm, msg, gp)

L:748
// Call executes the given transaction on the state for the given block number.
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
	result, _, _, err := s.doCall(ctx, args, blockNr, 5*time.Second)
	return (hexutil.Bytes)(result), err
}
go-ethereum/core/state_transition.go

L:123 func (st *StateTransition) useGas(amount uint64)

L:124

// ApplyMessage computes the new state by applying the given message
// against the old state within the environment.
//
// ApplyMessage returns the bytes returned by any EVM execution (if it took place),
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) {
	return NewStateTransition(evm, msg, gp).TransitionDb()
}

L:152 func (st *StateTransition) buyGas() error

L:183 func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error)

// TransitionDb will transition the state by applying the current message and
// returning the result including the used gas. It returns an error if failed.
// An error indicates a consensus issue.

L:224 st.refundGas() st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))

core/state/statedb.go

L:328 func (self *StateDB) SubBalance(addr common.Address, amount *big.Int)

@TbLtzk
Copy link

TbLtzk commented Jun 24, 2021

I know, it's 3 years later, now, but I was wondering the very same thing: Does Clique burn transaction fees? From mere observation it seems so. Did you ever get any feedback on this?

@innomon
Copy link
Author

innomon commented Jun 25, 2021

:) time flies! yes, I had concluded it burns the gas. But as you said, its been 3 years since. I assume, you too are trying to run a POA/POS sidechain with EVM support. I suggest you to consider using eitheir COSMOS SDK with Etheremint app or COSMWASM or Substrate SDK with EVM pallet.

This was you can be a part of COSMOS/Polkadot ecosystem. And, not left fending on your own.

Best of luck, and happy to help.

@TbLtzk
Copy link

TbLtzk commented Jul 1, 2021

Thx for your help. Your guess is partly correct: we are building an EVM compatible blockchain and tweaked clique to a permissionless dPoS consensus. If that sounds interesting to you, you'll find our material on https://q.org/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment