Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Push tracing of Parlia system transactions so that live tracers can properly traces those state changes #2772

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

maoueh
Copy link
Contributor

@maoueh maoueh commented Nov 26, 2024

Description

See #2768 for context and details.

This introduced OnSystemTxStart/OnSystemTxEnd and renamed OnSystemTxEnd to OnSystemTxFixIntrinsicGas (so OnSystemTxEnd can be re-used for other purposes).

The Parlia engine is now tracing it's system transaction properly which was not the case before.

Rationale

This PR ensure that system transactions are properly tested when using live tracers.

Changes

Consensus engine is now receiving a tracer *tracing.Hooks that Parlia engine then uses when needing to apply system transactions.

@zzzckck zzzckck changed the base branch from merge_geth_v1.13.15_v1.14.11 to develop November 27, 2024 03:12
txs *[]*types.Transaction, receipts *[]*types.Receipt,
receivedTxs *[]*types.Transaction, usedGas *uint64, mining bool,
vmConfig vm.Config,
) (receipt *types.Receipt, applyErr error) {
Copy link
Contributor

@zlacfzy zlacfzy Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seem don't need receipt in context, maybe can just use applyTransaction?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's for the defer to pass it down to OnTxEnd(receipt) at https://github.com/bnb-chain/bsc/pull/2772/files/a69186357e1be7043932f26dd621cadb22342c13#diff-7c199a2e5208a5ff8460e89bc19a9f9734312a8a4b15052d9d3e7e65c74aaa06R2022.

I initially modified applyTransaction but felt it was bad to change all call site to right away ignore so I created a second version.

But I could implemented differently maybe that would be less confusing:

func applyTransaction(...) error {
  // Used by OnTxEnd via a defer to properly pass the final receipt.
  var tracingReceipt *types.Receipt
...

I usually prefer to use Go native return capabilities which works even if receipt is not set explicitly but only return.

Let me know the team preference here, we can also keep the current code and I can document the function to explain receipt usage.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maoueh I would prefer the second one: create the receipt variable at the beginning

func applyTransaction(...) error {
  // Used by OnTxEnd via a defer to properly pass the final receipt.
  var tracingReceipt *types.Receipt
...

Comment on lines 1847 to 1852
// FIXME Those need some balance change reason, in our current Firehose implementation we had put
// firehose.BalanceChangeReason("reward_transfaction_fee"), this would map to
// `tracing.BalanceIncreaseRewardTransactionFee` in the new tracing API, is that accurate enough here?
// I would be fine adding a new more specific reason if needed.
state.SetBalance(consensus.SystemAddress, common.U2560, tracing.BalanceIncreaseRewardTransactionFee)
state.AddBalance(coinbase, balance, tracing.BalanceIncreaseRewardTransactionFee)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zlacfzy @zzzckck I would like to have BSC's team input on those balance change reasons.

For SetBalance, I'm not sure BalanceIncreaseRewardTransactionFee would be the best choice. There is BalanceChangeTransfer that would be possible, however I find this would breaks the symmetry for transfers where usually there is 2 in a row, one for the recipient and the other.

Maybe we should introduce BalanceChangeBSCDistributeReward or two, one for each leg:

  • BalanceDecreaseBSCDistributeReward
  • BalanceIncreaseBSCDistributeReward

Copy link
Collaborator

@zzzckck zzzckck Nov 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maoueh I think BalanceIncreaseRewardTransactionFee is not accurate. I would prefer to introduce the two new reason for BSC, but I am afraid of forward compatible issue, how about:

BalanceDecreaseBSCDistributeReward BalanceChangeReason = 1000
BalanceIncreaseBSCDistributeReward BalanceChangeReason = 1001

Another solution would be just leave it to unspecified: BalanceChangeUnspecified

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer indeed to add 2 new reasons, makes tracing system aware of important balance changes. Don't think Unspecified is good here.

but I am afraid of forward compatible issue

Indeed, that's always a possibility, even more that the BalanceChangeReason is a byte today leading to just 255 values.

But having managed multiple Geth forks over the last 3 years, I can tell you that new balance change reasons is very rare. I think it will be just fine. I've put BSC starting at 210 for now, let me know how it feels.

@zzzckck
Copy link
Collaborator

zzzckck commented Dec 2, 2024

@maoueh basically, I am ok with this PR, we can merge it and create a new PR to address my 2 comments:

1.create the receipt variable at the beginning.
2.BalanceIncreaseRewardTransactionFee to BalanceChangeUnspecified

Copy link

@Joj501 Joj501 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve change

@maoueh
Copy link
Contributor Author

maoueh commented Dec 2, 2024

@zzzckck @Joj501 I adjusted the PR

@maoueh maoueh force-pushed the fix/geth-1.14-bsc-system-trx-tracing branch from 7890af0 to fe10268 Compare December 2, 2024 18:47
zlacfzy
zlacfzy previously approved these changes Dec 5, 2024
consensus/parlia/parlia.go Outdated Show resolved Hide resolved
miner/worker.go Show resolved Hide resolved
core/tracing/hooks.go Show resolved Hide resolved
@maoueh maoueh force-pushed the fix/geth-1.14-bsc-system-trx-tracing branch from fe10268 to b68c0c9 Compare December 5, 2024 20:44
if vmConfig.Tracer.OnSystemTxStart != nil {
vmConfig.Tracer.OnSystemTxStart()
}
if tracer.OnTxStart != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OnTxStart may need to be called first, then it can use the right env.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry not sure I fully understand the comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the onTxStart need be called before OnSystemTxStart.

if tracer := vmConfig.Tracer; tracer != nil {
		if tracer.OnTxStart != nil {
			tracer.OnTxStart(vmenv.GetVMContext(), expectedTx, msg.From())
		}
		if vmConfig.Tracer.OnSystemTxStart != nil {
			vmConfig.Tracer.OnSystemTxStart()
		}
...
}

Because the EVM env only transfers in OnTxStart, so it is better to call first. Do I understand correctly?

func (l *jsonLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
	l.env = env
}
func (l *jsonLogger) OnSystemTxStart() {
	l.encoder.Encode(l.env.Coinbase, "trigger system tx")
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the OnSystemTxStart acting as a marker. Usually you track the overall state of execution, so I would see an implementation like this:

type Tracer struct {
    (... implement Hooks)
    
    inSystemTrx bool
}

func (t *Tracer) OnSystemTrxStart() { t.inSystemTrx = true }
func (t *Tracer) OnTrxStart() { <track trx normally> }
func (t *Tracer) OnTrxEnd() { if (t.inSystemTrx) { // In sytsem } else { // In normal }  }
func (t *Tracer) OnSystemTrxEnd() { t.inSystemTrx = false }

In that setup, the system trx start must be called first.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but the defer order is wrong, may

if vmConfig.Tracer.OnSystemTxEnd != nil {
	defer func() {
		vmConfig.Tracer.OnSystemTxEnd()
	}()
}
if tracer.OnTxEnd != nil {
	defer func() {
		tracer.OnTxEnd(tracingReceipt, applyErr)
	}()
}

It will run as you expect:

func (t *Tracer) OnSystemTrxStart() { t.inSystemTrx = true }
func (t *Tracer) OnTrStart() { <track trx normally> }
func (t *Tracer) OnTxEnd() { if (t.inSystemTrx) { // In sytsem } else { // In normal }  }
func (t *Tracer) OnSystemTrxEnd() { t.inSystemTrx = false }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are so right, good catch, thanks!

Is there Go tests in the project that exercices the parlia consensus engine and test system transactions that I could tweak to ensure the system tracing is fully covered?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can refer newTestParliaHandlerAfterCancun in eth/handler_test.go:256, there are some integrated testings with parlia. It may help you.

context := core.NewEVMBlockContext(header, chainContext, nil)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, vm.TxContext{Origin: msg.From(), GasPrice: big.NewInt(0)}, state, p.chainConfig, vmConfig)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one change the code logic, the vmConfig was empty before, but now it will use the vmConfig passed from uplayer.

vmenv := vm.NewEVM(context, vm.TxContext{Origin: msg.From(), GasPrice: big.NewInt(0)}, state, chainConfig, vm.Config{})

Should be careful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true.

I can pass the tracer around instead of a pre-built vm.Config instance and I could change back to vm.Config{Tracer: tracer}. Would you prefer that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

@zzzckck zzzckck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will hold this PR for the moment, as there would be 2nd round of code sync, which could have conflict.

Push tracing of Parlia system transactions so that live tracers can properly traces
those state changes.
@maoueh maoueh force-pushed the fix/geth-1.14-bsc-system-trx-tracing branch from e4a1b02 to e03c20d Compare December 17, 2024 19:52
@maoueh
Copy link
Contributor Author

maoueh commented Dec 17, 2024

Ok I rebased on latest develop and added unit tests, I would have liked to actually test at a higher level, probably using Blockchain directly of StateProcessor.

But at least the current tests shows overall correct behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants