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

eth/tracers/live: run supply tests off of generated artifacts #30451

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
28 changes: 15 additions & 13 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa
if params.BeaconRoot != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root"))
}
switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) {
switch api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) {
case forks.Paris:
if params.Withdrawals != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai"))
Expand All @@ -238,7 +238,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
if params.BeaconRoot == nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root"))
}
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Cancun &&
api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Prague {
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads"))
}
}
Expand Down Expand Up @@ -270,7 +271,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV2(update engine.Forkchoice
if params.BeaconRoot != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("unexpected beacon root"))
}
switch api.eth.BlockChain().Config().LatestFork(params.Timestamp) {
switch api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) {
case forks.Paris:
if params.Withdrawals != nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("withdrawals before shanghai"))
Expand All @@ -296,7 +297,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice
if params.BeaconRoot == nil {
return engine.STATUS_INVALID, engine.InvalidPayloadAttributes.With(errors.New("missing beacon root"))
}
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun && api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Cancun &&
api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Prague {
return engine.STATUS_INVALID, engine.UnsupportedFork.With(errors.New("forkchoiceUpdatedV3 must only be called for cancun payloads"))
}
}
Expand Down Expand Up @@ -568,7 +570,7 @@ func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.Payl
if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun"))
}
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) == forks.Shanghai {
if params.Withdrawals == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
}
Expand Down Expand Up @@ -605,7 +607,7 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun"))
}

if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Cancun {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV3 must only be called for cancun payloads"))
}
return api.newPayload(params, versionedHashes, beaconRoot, nil, false)
Expand Down Expand Up @@ -633,7 +635,7 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil executionRequests post-prague"))
}

if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Prague {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadV4 must only be called for prague payloads"))
}
requests := convertRequests(executionRequests)
Expand All @@ -655,7 +657,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV2(params engine.ExecutableData) (
if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun"))
}
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) == forks.Shanghai {
if params.Withdrawals == nil {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
}
Expand Down Expand Up @@ -693,7 +695,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV3(params engine.ExecutableData, v
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun"))
}

if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Cancun {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV3 must only be called for cancun payloads"))
}
return api.newPayload(params, versionedHashes, beaconRoot, nil, true)
Expand Down Expand Up @@ -722,7 +724,7 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, v
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil executionRequests post-prague"))
}

if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Prague {
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("newPayloadWithWitnessV4 must only be called for prague payloads"))
}
requests := convertRequests(executionRequests)
Expand All @@ -744,7 +746,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV2(params engine.ExecutableData,
if api.eth.BlockChain().Config().IsCancun(api.eth.BlockChain().Config().LondonBlock, params.Timestamp) {
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("can't use newPayloadV2 post-cancun"))
}
if api.eth.BlockChain().Config().LatestFork(params.Timestamp) == forks.Shanghai {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) == forks.Shanghai {
if params.Withdrawals == nil {
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil withdrawals post-shanghai"))
}
Expand Down Expand Up @@ -782,7 +784,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV3(params engine.ExecutableData,
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil beaconRoot post-cancun"))
}

if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Cancun {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Cancun {
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("executeStatelessPayloadV3 must only be called for cancun payloads"))
}
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, nil, opaqueWitness)
Expand Down Expand Up @@ -811,7 +813,7 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData,
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(errors.New("nil executionRequests post-prague"))
}

if api.eth.BlockChain().Config().LatestFork(params.Timestamp) != forks.Prague {
if api.eth.BlockChain().Config().LatestPostLondonFork(params.Timestamp) != forks.Prague {
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.UnsupportedFork.With(errors.New("executeStatelessPayloadV4 must only be called for prague payloads"))
}
requests := convertRequests(executionRequests)
Expand Down
132 changes: 132 additions & 0 deletions eth/tracers/live/supply_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package live

import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"testing"

"github.com/ethereum/go-ethereum/tests"
)

type blockTest struct {
bt *tests.BlockTest
Expected []supplyInfo `json:"expected"`
}

func (bt *blockTest) UnmarshalJSON(data []byte) error {
tmp := make(map[string]json.RawMessage)
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
if err := json.Unmarshal(tmp["expected"], &bt.Expected); err != nil {
return err
}
if err := json.Unmarshal(data, &bt.bt); err != nil {
return err
}
return nil
}

// The tests have been filled using the executable at
// eth/tracers/live/tests/supply_filler.go.
func TestSupplyTracerBlockchain(t *testing.T) {
dirPath := filepath.Join("testdata", "supply")
files, err := os.ReadDir(dirPath)
if err != nil {
t.Fatalf("failed to retrieve tracer test suite: %v", err)
}
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".json") {
continue
}
var testcases map[string]*blockTest
var blob []byte
// Tracer test found, read if from disk
if blob, err = os.ReadFile(filepath.Join(dirPath, file.Name())); err != nil {
t.Fatalf("failed to read testcase: %v", err)
}
if err := json.Unmarshal(blob, &testcases); err != nil {
t.Fatalf("failed to parse testcase %s: %v", file.Name(), err)
}
for testname, blockTest := range testcases {
t.Run(fmt.Sprintf("%s/%s", file.Name(), testname),
func(t *testing.T) { runBlockTest(t, blockTest) })
}
}
}

func runBlockTest(t *testing.T, test *blockTest) {
t.Parallel()

traceOutputPath := filepath.ToSlash(t.TempDir())
traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl")
// Load supply tracer
tracer, err := newSupplyTracer(json.RawMessage(fmt.Sprintf(`{"path":"%s"}`, traceOutputPath)))
if err != nil {
t.Fatalf("failed to create tracer: %v", err)
}
if err := test.bt.Run(false, "path", false, tracer, nil); err != nil {
t.Errorf("failed to run test: %v\n", err)
}
// Check and compare the results
file, err := os.OpenFile(traceOutputFilename, os.O_RDONLY, 0666)
if err != nil {
t.Fatalf("failed to open output file: %v", err)
}
defer file.Close()

var (
output []supplyInfo
scanner = bufio.NewScanner(file)
)
for scanner.Scan() {
var info supplyInfo
if err := json.Unmarshal(scanner.Bytes(), &info); err != nil {
t.Fatalf("failed to unmarshal result: %v", err)
}
output = append(output, info)
}
if len(output) != len(test.Expected) {
fmt.Printf("output: %v\n", output)
t.Fatalf("expected %d supply infos, got %d", len(test.Expected), len(output))
}
for i, expected := range test.Expected {
compareAsJSON(t, expected, output[i])
}
}

func compareAsJSON(t *testing.T, expected interface{}, actual interface{}) {
want, err := json.Marshal(expected)
if err != nil {
t.Fatalf("failed to marshal expected value to JSON: %v", err)
}
have, err := json.Marshal(actual)
if err != nil {
t.Fatalf("failed to marshal actual value to JSON: %v", err)
}
if !bytes.Equal(want, have) {
t.Fatalf("incorrect supply info:\nhave: %s\nwant: %s", string(have), string(want))
}
}
87 changes: 87 additions & 0 deletions eth/tracers/live/testdata/supply/eip1559_burn.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"eip1559_burn_grayGlacier": {
"blocks": [
{
"BlockHeader": {
"BaseFeePerGas": "0x342770c0",
"BlobGasUsed": null,
"Bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"Coinbase": "0x0100000000000000000000000000000000000000",
"Difficulty": "0x20000",
"ExcessBlobGas": null,
"ExtraData": "0x",
"GasLimit": "0x47e7c4",
"GasUsed": "0x5208",
"Hash": "0x7891c11e0cc121c578c62c4b42622b909f4ded1a66fea03336c303e6bc8d6f88",
"MixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"Nonce": "0x0000000000000000",
"Number": "0x1",
"ParentBeaconBlockRoot": null,
"ParentHash": "0xc4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7",
"ReceiptTrie": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
"StateRoot": "0x208dc296c4dc37b673a99aed4837174a2ed7f5380ad802d5aed0295e6795241d",
"Timestamp": "0xa",
"TransactionsTrie": "0x4ff793bd96fb3d8d186476e59a5118de9f1813b3f22bd8a64875a535422ac62f",
"UncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"WithdrawalsRoot": null
},
"ExpectException": "",
"Rlp": "0xf9026cf901faa0c4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940100000000000000000000000000000000000000a0208dc296c4dc37b673a99aed4837174a2ed7f5380ad802d5aed0295e6795241da04ff793bd96fb3d8d186476e59a5118de9f1813b3f22bd8a64875a535422ac62fa0f78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efab901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000018347e7c48252080a80a0000000000000000000000000000000000000000000000000000000000000000088000000000000000084342770c0f86cb86a02f86701800285012a05f20082520894000000000000000000000000000000000000aaaa8080c001a083b46f9cdfcb2c087934d9ae79eedeaa53df39b73c58b7cba5c77d69039bdc64a05af6144d3123f5b9850f9c40fc4b8ce02bf4782f6d6bca3f88e553689d66480bc0",
"UncleHeaders": null
}
],
"expected": [
{
"issuance": {
"genesisAlloc": "0xde0b6b3a7640000"
},
"blockNumber": 0,
"hash": "0xc4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"issuance": {
"reward": "0x1bc16d674ec80000"
},
"burn": {
"1559": "0x10b643590600"
},
"blockNumber": 1,
"hash": "0x7891c11e0cc121c578c62c4b42622b909f4ded1a66fea03336c303e6bc8d6f88",
"parentHash": "0xc4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7"
}
],
"genesisBlockHeader": {
"BaseFeePerGas": "0x3b9aca00",
"BlobGasUsed": null,
"Bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"Coinbase": "0x0000000000000000000000000000000000000000",
"Difficulty": "0x20000",
"ExcessBlobGas": null,
"ExtraData": "0x",
"GasLimit": "0x47e7c4",
"GasUsed": "0x0",
"Hash": "0xc4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7",
"MixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"Nonce": "0x0000000000000000",
"Number": "0x0",
"ParentBeaconBlockRoot": null,
"ParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"ReceiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"StateRoot": "0x9f88be00eee1114edfd9372f52560aab3980a142efe8b5b39a09644075084275",
"Timestamp": "0x0",
"TransactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"UncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
"WithdrawalsRoot": null
},
"lastblockhash": "7891c11e0cc121c578c62c4b42622b909f4ded1a66fea03336c303e6bc8d6f88",
"network": "GrayGlacier",
"postState": {},
"pre": {
"0x71562b71999873db5b286df957af199ec94617f7": {
"balance": "0xde0b6b3a7640000"
}
},
"sealEngine": ""
}
}
Loading