make filler an executable module

This commit is contained in:
Sina Mahmoodi 2024-09-17 18:50:21 +02:00 committed by Martin Holst Swende
parent a4e0549d3f
commit f6f916a1b2
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
5 changed files with 265 additions and 143 deletions

View file

@ -2,6 +2,7 @@ package live
import ( import (
"bufio" "bufio"
"bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@ -10,8 +11,31 @@ import (
"strings" "strings"
"testing" "testing"
"unicode" "unicode"
"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/tracetest/supply_filler.go.
func TestSupplyTracerBlockchain(t *testing.T) { func TestSupplyTracerBlockchain(t *testing.T) {
dirPath := "supply" dirPath := "supply"
files, err := os.ReadDir(filepath.Join("testdata", dirPath)) files, err := os.ReadDir(filepath.Join("testdata", dirPath))
@ -23,7 +47,7 @@ func TestSupplyTracerBlockchain(t *testing.T) {
continue continue
} }
file := file // capture range variable file := file // capture range variable
var testcases map[string]*BlockTest var testcases map[string]*blockTest
var blob []byte var blob []byte
// Call tracer test found, read if from disk // Call tracer test found, read if from disk
if blob, err = os.ReadFile(filepath.Join("testdata", dirPath, file.Name())); err != nil { if blob, err = os.ReadFile(filepath.Join("testdata", dirPath, file.Name())); err != nil {
@ -85,3 +109,17 @@ func camel(str string) string {
} }
return strings.Join(pieces, "") return strings.Join(pieces, "")
} }
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:\nexpected:\n%s\ngot:\n%s", string(want), string(have))
}
}

View file

@ -1,51 +0,0 @@
package live
import (
"encoding/json"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/tests"
)
type BlockTest struct {
bt *tests.BlockTest
Expected []supplyInfo `json:"expected"`
}
func btFromChain(db ethdb.Database, chain *core.BlockChain, post *types.GenesisAlloc) (*BlockTest, error) {
bt, err := tests.FromChain(db, chain, post)
if err != nil {
return nil, err
}
return &BlockTest{bt: &bt}, nil
}
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
}
func (bt *BlockTest) MarshalJSON() ([]byte, error) {
enc, err := json.Marshal(bt.bt)
if err != nil {
return nil, err
}
// Insert the expected supply info
result := make(map[string]any)
if err := json.Unmarshal(enc, &result); err != nil {
return nil, err
}
result["expected"] = bt.Expected
return json.Marshal(result)
}

View file

@ -1,17 +1,5 @@
{ {
"omitted_fields_cancun": { "omitted_fields_cancun": {
"expected": [
{
"blockNumber": 0,
"hash": "0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"blockNumber": 1,
"hash": "0xe430cdf604a88b9d713d4f89fd100ddddf38c1cc6b049e3d5df563c7bfd320fc",
"parentHash": "0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"
}
],
"blocks": [ "blocks": [
{ {
"BlockHeader": { "BlockHeader": {
@ -42,6 +30,18 @@
"UncleHeaders": null "UncleHeaders": null
} }
], ],
"expected": [
{
"blockNumber": 0,
"hash": "0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"blockNumber": 1,
"hash": "0xe430cdf604a88b9d713d4f89fd100ddddf38c1cc6b049e3d5df563c7bfd320fc",
"parentHash": "0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"
}
],
"genesisBlockHeader": { "genesisBlockHeader": {
"BaseFeePerGas": "0x3b9aca00", "BaseFeePerGas": "0x3b9aca00",
"BlobGasUsed": "0x0", "BlobGasUsed": "0x0",

View file

@ -1,4 +1,4 @@
// Copyright 2021 The go-ethereum Authors // Copyright 2024 The go-ethereum Authors
// This file is part of the go-ethereum library. // This file is part of the go-ethereum library.
// //
// The go-ethereum library is free software: you can redistribute it and/or modify // The go-ethereum library is free software: you can redistribute it and/or modify
@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License // 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/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package live package main
import ( import (
"bufio" "bufio"
@ -25,9 +25,9 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
@ -38,11 +38,80 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/tests"
_ "github.com/ethereum/go-ethereum/eth/tracers/live"
) )
type supplyInfoIssuance struct {
GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
Reward *hexutil.Big `json:"reward,omitempty"`
Withdrawals *hexutil.Big `json:"withdrawals,omitempty"`
}
type supplyInfoBurn struct {
EIP1559 *hexutil.Big `json:"1559,omitempty"`
Blob *hexutil.Big `json:"blob,omitempty"`
Misc *hexutil.Big `json:"misc,omitempty"`
}
type supplyInfo struct {
Issuance *supplyInfoIssuance `json:"issuance,omitempty"`
Burn *supplyInfoBurn `json:"burn,omitempty"`
// Block info
Number uint64 `json:"blockNumber"`
Hash common.Hash `json:"hash"`
ParentHash common.Hash `json:"parentHash"`
}
func main() {
// Takes a path where the filled tests will be written.
if len(os.Args) < 2 {
fmt.Println("Please provide a path as a command-line argument")
os.Exit(1)
}
path, err := filepath.Abs(os.Args[1])
if err != nil {
fmt.Printf("Error resolving path: %v\n", err)
os.Exit(1)
}
// Create all directories in the path if they don't exist
if err := os.MkdirAll(path, 0755); err != nil {
fmt.Printf("failed to create directory: %v\n", err)
os.Exit(1)
}
if err := fillSupplyOmittedFields(path); err != nil {
fmt.Printf("fillSupplyOmittedFields failed: %v\n", err)
os.Exit(1)
}
if err := fillSupplyGenesisAlloc(path); err != nil {
fmt.Printf("fillSupplyGenesisAlloc failed: %v\n", err)
os.Exit(1)
}
if err := fillSupplyEip1559Burn(path); err != nil {
fmt.Printf("fillSupplyEip1559Burn failed: %v\n")
os.Exit(1)
}
if err := fillSupplyWithdrawals(path); err != nil {
fmt.Printf("fillSupplyWithdrawals failed: %v\n", err)
os.Exit(1)
}
if err := fillSupplySelfdestruct(path); err != nil {
fmt.Printf("fillSupplySelfdestruct failed: %v\n", err)
os.Exit(1)
}
if err := fillSupplySelfdestructItselfAndRevert(path); err != nil {
fmt.Printf("fillSupplySelfdestructItselfAndRevert failed: %v\n", err)
os.Exit(1)
}
}
func emptyBlockGenerationFunc(b *core.BlockGen) {} func emptyBlockGenerationFunc(b *core.BlockGen) {}
func TestSupplyOmittedFields(t *testing.T) { func fillSupplyOmittedFields(path string) error {
var ( var (
config = *params.MergedTestChainConfig config = *params.MergedTestChainConfig
gspec = &core.Genesis{ gspec = &core.Genesis{
@ -59,18 +128,22 @@ func TestSupplyOmittedFields(t *testing.T) {
}} }}
) )
gspec.Config.TerminalTotalDifficulty = big.NewInt(0) gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
out, db, chain, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) { out, db, chain, err := testSupplyTracer(gspec, func(b *core.BlockGen) {
b.SetPoS() b.SetPoS()
}) })
if err != nil { if err != nil {
t.Fatalf("failed to test supply tracer: %v", err) return fmt.Errorf("failed to test supply tracer: %v", err)
} }
if err := compareAsJSON(expected, out); err != nil {
compareAsJSON(t, expected, out) return err
writeArtifact(t, "omitted_fields_cancun", db, chain, expected, nil) }
if err := writeArtifact(filepath.Join(path, "omitted_fields.json"), "omitted_fields_cancun", db, chain, expected, nil); err != nil {
return err
}
return nil
} }
func TestSupplyGenesisAlloc(t *testing.T) { func fillSupplyGenesisAlloc(path string) error {
var ( var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
@ -88,14 +161,14 @@ func TestSupplyGenesisAlloc(t *testing.T) {
} }
expected = []supplyInfo{{ expected = []supplyInfo{{
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
GenesisAlloc: new(big.Int).Mul(common.Big2, big.NewInt(params.Ether)), GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
}, },
Number: 0, Number: 0,
Hash: common.HexToHash("0xbcc9466e9fc6a8b56f4b29ca353a421ff8b51a0c1a58ca4743b427605b08f2ca"), Hash: common.HexToHash("0xbcc9466e9fc6a8b56f4b29ca353a421ff8b51a0c1a58ca4743b427605b08f2ca"),
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}, { }, {
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
Reward: new(big.Int).Mul(common.Big2, big.NewInt(params.Ether)), Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
}, },
Number: 1, Number: 1,
Hash: common.HexToHash("0x37bb7e9b45f4fb7b311abb5f815e3e00d3382d83a2c39b9b0bd22b717566cd04"), Hash: common.HexToHash("0x37bb7e9b45f4fb7b311abb5f815e3e00d3382d83a2c39b9b0bd22b717566cd04"),
@ -103,15 +176,20 @@ func TestSupplyGenesisAlloc(t *testing.T) {
}} }}
) )
out, db, chain, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) out, db, chain, err := testSupplyTracer(gspec, emptyBlockGenerationFunc)
if err != nil { if err != nil {
t.Fatalf("failed to test supply tracer: %v", err) return fmt.Errorf("failed to test supply tracer: %v", err)
} }
compareAsJSON(t, expected, out) if err := compareAsJSON(expected, out); err != nil {
writeArtifact(t, "genesis_alloc_grayGlacier", db, chain, expected, nil) return err
}
if err := writeArtifact(filepath.Join(path, "genesis_alloc.json"), "genesis_alloc_grayGlacier", db, chain, expected, nil); err != nil {
return err
}
return nil
} }
func TestSupplyEip1559Burn(t *testing.T) { func fillSupplyEip1559Burn(path string) error {
var ( var (
config = *params.AllEthashProtocolChanges config = *params.AllEthashProtocolChanges
@ -147,9 +225,9 @@ func TestSupplyEip1559Burn(t *testing.T) {
b.AddTx(tx) b.AddTx(tx)
} }
out, db, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc) out, db, chain, err := testSupplyTracer(gspec, eip1559BlockGenerationFunc)
if err != nil { if err != nil {
t.Fatalf("failed to test supply tracer: %v", err) return fmt.Errorf("failed to test supply tracer: %v", err)
} }
var ( var (
head = chain.CurrentBlock() head = chain.CurrentBlock()
@ -157,28 +235,33 @@ func TestSupplyEip1559Burn(t *testing.T) {
burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee) burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee)
expected = []supplyInfo{{ expected = []supplyInfo{{
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
GenesisAlloc: eth1, GenesisAlloc: (*hexutil.Big)(eth1),
}, },
Number: 0, Number: 0,
Hash: common.HexToHash("0xc4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7"), Hash: common.HexToHash("0xc4265421181cafc43e4b97ae4f21530e37e00320f219a13311482c9c552bcdc7"),
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}, { }, {
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
Reward: reward, Reward: (*hexutil.Big)(reward),
}, },
Burn: &supplyInfoBurn{ Burn: &supplyInfoBurn{
EIP1559: burn, EIP1559: (*hexutil.Big)(burn),
}, },
Number: 1, Number: 1,
Hash: head.Hash(), Hash: head.Hash(),
ParentHash: head.ParentHash, ParentHash: head.ParentHash,
}} }}
) )
compareAsJSON(t, expected, out) if err := compareAsJSON(expected, out); err != nil {
writeArtifact(t, "eip1559_burn_grayGlacier", db, chain, expected, nil) return err
}
if err := writeArtifact(filepath.Join(path, "eip1559_burn.json"), "eip1559_burn_grayGlacier", db, chain, expected, nil); err != nil {
return err
}
return nil
} }
func TestSupplyWithdrawals(t *testing.T) { func fillSupplyWithdrawals(path string) error {
var ( var (
config = *params.MergedTestChainConfig config = *params.MergedTestChainConfig
gspec = &core.Genesis{ gspec = &core.Genesis{
@ -196,9 +279,9 @@ func TestSupplyWithdrawals(t *testing.T) {
}) })
} }
out, db, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc) out, db, chain, err := testSupplyTracer(gspec, withdrawalsBlockGenerationFunc)
if err != nil { if err != nil {
t.Fatalf("failed to test supply tracer: %v", err) return fmt.Errorf("failed to test supply tracer: %v", err)
} }
var ( var (
@ -209,15 +292,20 @@ func TestSupplyWithdrawals(t *testing.T) {
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}, { }, {
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
Withdrawals: big.NewInt(1337000000000), Withdrawals: (*hexutil.Big)(big.NewInt(1337000000000)),
}, },
Number: 1, Number: 1,
Hash: head.Hash(), Hash: head.Hash(),
ParentHash: head.ParentHash, ParentHash: head.ParentHash,
}} }}
) )
compareAsJSON(t, expected, out) if err := compareAsJSON(expected, out); err != nil {
writeArtifact(t, "withdrawals_cancun", db, chain, expected, nil) return err
}
if err := writeArtifact(filepath.Join(path, "withdrawals.json"), "withdrawals_cancun", db, chain, expected, nil); err != nil {
return err
}
return nil
} }
// Tests fund retrieval after contract's selfdestruct. // Tests fund retrieval after contract's selfdestruct.
@ -225,7 +313,7 @@ func TestSupplyWithdrawals(t *testing.T) {
// after the selfdestruct opcode executes from Contract A. // after the selfdestruct opcode executes from Contract A.
// Because Contract B is removed only at the end of the transaction // Because Contract B is removed only at the end of the transaction
// the ether sent in between is burnt before Cancun hard fork. // the ether sent in between is burnt before Cancun hard fork.
func TestSupplySelfdestruct(t *testing.T) { func fillSupplySelfdestruct(path string) error {
var ( var (
config = *params.TestChainConfig config = *params.TestChainConfig
@ -274,9 +362,9 @@ func TestSupplySelfdestruct(t *testing.T) {
) )
// 1. Test pre Cancun // 1. Test pre Cancun
preCancunOutput, preCancunDB, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) preCancunOutput, preCancunDB, preCancunChain, err := testSupplyTracer(gspec, testBlockGenerationFunc)
if err != nil { if err != nil {
t.Fatalf("Pre-cancun failed to test supply tracer: %v", err) return fmt.Errorf("failed to test supply tracer: %v", err)
} }
// Check balance at state: // Check balance at state:
@ -285,13 +373,13 @@ func TestSupplySelfdestruct(t *testing.T) {
// 3. B has 0 ether // 3. B has 0 ether
statedb, _ := preCancunChain.State() statedb, _ := preCancunChain.State()
if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 {
t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", dad, got, exp) return fmt.Errorf("Pre-cancun address \"%v\" balance, got %v exp %v\n", dad, got, exp)
} }
if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 {
t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", aa, got, exp) return fmt.Errorf("Pre-cancun address \"%v\" balance, got %v exp %v\n", aa, got, exp)
} }
if got, exp := statedb.GetBalance(bb), big.NewInt(0); got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(bb), big.NewInt(0); got.CmpBig(exp) != 0 {
t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", bb, got, exp) return fmt.Errorf("Pre-cancun address \"%v\" balance, got %v exp %v\n", bb, got, exp)
} }
var ( var (
@ -299,18 +387,18 @@ func TestSupplySelfdestruct(t *testing.T) {
// Check live trace output // Check live trace output
expected = []supplyInfo{{ expected = []supplyInfo{{
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
GenesisAlloc: new(big.Int).Mul(big.NewInt(2), big.NewInt(params.Ether)), GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(2), big.NewInt(params.Ether))),
}, },
Number: 0, Number: 0,
Hash: common.HexToHash("0xdd9fbe877f0b43987d2f0cda0df176b7939be14f33eb5137f16e6eddf4562706"), Hash: common.HexToHash("0xdd9fbe877f0b43987d2f0cda0df176b7939be14f33eb5137f16e6eddf4562706"),
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}, { }, {
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
Reward: new(big.Int).Mul(big.NewInt(2), big.NewInt(params.Ether)), Reward: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(2), big.NewInt(params.Ether))),
}, },
Burn: &supplyInfoBurn{ Burn: &supplyInfoBurn{
EIP1559: big.NewInt(55289500000000), EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)),
Misc: big.NewInt(5000000000), Misc: (*hexutil.Big)(big.NewInt(5000000000)),
}, },
Number: 1, Number: 1,
Hash: head.Hash(), Hash: head.Hash(),
@ -323,10 +411,12 @@ func TestSupplySelfdestruct(t *testing.T) {
} }
) )
compareAsJSON(t, expected, preCancunOutput) if err := compareAsJSON(expected, preCancunOutput); err != nil {
return err
}
preCancunTest, err := btFromChain(preCancunDB, preCancunChain, post) preCancunTest, err := btFromChain(preCancunDB, preCancunChain, post)
if err != nil { if err != nil {
t.Fatalf("failed to fill tests from chain: %v", err) return fmt.Errorf("failed to fill tests from chain: %v", err)
} }
preCancunTest.Expected = expected preCancunTest.Expected = expected
@ -341,9 +431,9 @@ func TestSupplySelfdestruct(t *testing.T) {
b.SetPoS() b.SetPoS()
testBlockGenerationFunc(b) testBlockGenerationFunc(b)
} }
postCancunOutput, postCancunDB, postCancunChain, err := testSupplyTracer(t, gspec, posTestBlockGenerationFunc) postCancunOutput, postCancunDB, postCancunChain, err := testSupplyTracer(gspec, posTestBlockGenerationFunc)
if err != nil { if err != nil {
t.Fatalf("Post-cancun failed to test supply tracer: %v", err) return fmt.Errorf("Post-cancun failed to test supply tracer: %v", err)
} }
// Check balance at state: // Check balance at state:
@ -352,27 +442,27 @@ func TestSupplySelfdestruct(t *testing.T) {
// 3. B has 5 gwei // 3. B has 5 gwei
statedb, _ = postCancunChain.State() statedb, _ = postCancunChain.State()
if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 {
t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", dad, got, exp) return fmt.Errorf("Post-shanghai address \"%v\" balance, got %v exp %v\n", dad, got, exp)
} }
if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 {
t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", aa, got, exp) return fmt.Errorf("Post-shanghai address \"%v\" balance, got %v exp %v\n", aa, got, exp)
} }
if got, exp := statedb.GetBalance(bb), gwei5; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(bb), gwei5; got.CmpBig(exp) != 0 {
t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", bb, got, exp) return fmt.Errorf("Post-shanghai address \"%v\" balance, got %v exp %v\n", bb, got, exp)
} }
// Check live trace output // Check live trace output
head = postCancunChain.CurrentBlock() head = postCancunChain.CurrentBlock()
expected = []supplyInfo{{ expected = []supplyInfo{{
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
GenesisAlloc: new(big.Int).Mul(big.NewInt(2), big.NewInt(params.Ether)), GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(2), big.NewInt(params.Ether))),
}, },
Number: 0, Number: 0,
Hash: common.HexToHash("0x16d2bb0b366d3963bf2d8d75cb4b3bc0f233047c948fa746cbd38ac82bf9cfe9"), Hash: common.HexToHash("0x16d2bb0b366d3963bf2d8d75cb4b3bc0f233047c948fa746cbd38ac82bf9cfe9"),
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}, { }, {
Burn: &supplyInfoBurn{ Burn: &supplyInfoBurn{
EIP1559: big.NewInt(55289500000000), EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)),
}, },
Number: 1, Number: 1,
Hash: head.Hash(), Hash: head.Hash(),
@ -384,13 +474,18 @@ func TestSupplySelfdestruct(t *testing.T) {
bb: {Balance: gwei5, Code: gspec.Alloc[bb].Code}, bb: {Balance: gwei5, Code: gspec.Alloc[bb].Code},
} }
compareAsJSON(t, expected, postCancunOutput) if err := compareAsJSON(expected, postCancunOutput); err != nil {
return err
}
postCancunTest, err := btFromChain(postCancunDB, postCancunChain, post) postCancunTest, err := btFromChain(postCancunDB, postCancunChain, post)
if err != nil { if err != nil {
t.Fatalf("failed to fill tests from chain: %v", err) return fmt.Errorf("failed to fill tests from chain: %v", err)
} }
postCancunTest.Expected = expected postCancunTest.Expected = expected
writeBTs(t, map[string]*BlockTest{"selfdestruct_grayGlacier": preCancunTest, "selfdestruct_cancun": postCancunTest}) if err := writeBTs(filepath.Join(path, "selfdestruct.json"), map[string]*blockTest{"selfdestruct_grayGlacier": preCancunTest, "selfdestruct_cancun": postCancunTest}); err != nil {
return err
}
return nil
} }
// Tests selfdestructing contract to send its balance to itself (burn). // Tests selfdestructing contract to send its balance to itself (burn).
@ -400,7 +495,7 @@ func TestSupplySelfdestruct(t *testing.T) {
// - Contract C selfdestructs and sends the eth1 to itself. // - Contract C selfdestructs and sends the eth1 to itself.
// - Contract D calls C and reverts (Burn amount of C // - Contract D calls C and reverts (Burn amount of C
// has to be reverted as well). // has to be reverted as well).
func TestSupplySelfdestructItselfAndRevert(t *testing.T) { func fillSupplySelfdestructItselfAndRevert(path string) error {
var ( var (
config = *params.TestChainConfig config = *params.TestChainConfig
@ -492,9 +587,9 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) {
b.AddTx(tx) b.AddTx(tx)
} }
output, db, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) output, db, chain, err := testSupplyTracer(gspec, testBlockGenerationFunc)
if err != nil { if err != nil {
t.Fatalf("failed to test supply tracer: %v", err) return fmt.Errorf("failed to test supply tracer: %v", err)
} }
// Check balance at state: // Check balance at state:
@ -504,50 +599,61 @@ func TestSupplySelfdestructItselfAndRevert(t *testing.T) {
// 4. D has 1 ether, reverted // 4. D has 1 ether, reverted
statedb, _ := chain.State() statedb, _ := chain.State()
if got, exp := statedb.GetBalance(aa), common.Big0; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(aa), common.Big0; got.CmpBig(exp) != 0 {
t.Fatalf("address \"%v\" balance, got %v exp %v\n", aa, got, exp) return fmt.Errorf("address \"%v\" balance, got %v exp %v\n", aa, got, exp)
} }
if got, exp := statedb.GetBalance(bb), common.Big0; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(bb), common.Big0; got.CmpBig(exp) != 0 {
t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) return fmt.Errorf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
} }
if got, exp := statedb.GetBalance(cc), eth1; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(cc), eth1; got.CmpBig(exp) != 0 {
t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) return fmt.Errorf("address \"%v\" balance, got %v exp %v\n", cc, got, exp)
} }
if got, exp := statedb.GetBalance(dd), eth2; got.CmpBig(exp) != 0 { if got, exp := statedb.GetBalance(dd), eth2; got.CmpBig(exp) != 0 {
t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) return fmt.Errorf("address \"%v\" balance, got %v exp %v\n", dd, got, exp)
} }
// Check live trace output // Check live trace output
block := chain.GetBlockByNumber(1) block := chain.GetBlockByNumber(1)
expected := []supplyInfo{{ expected := []supplyInfo{{
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
GenesisAlloc: new(big.Int).Mul(big.NewInt(9), big.NewInt(params.Ether)), GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(9), big.NewInt(params.Ether))),
}, },
Number: 0, Number: 0,
Hash: common.HexToHash("0xaf41e72f748de317965454508c749f7e14dc4fe444cd07bca4c981c7e952364d"), Hash: common.HexToHash("0xaf41e72f748de317965454508c749f7e14dc4fe444cd07bca4c981c7e952364d"),
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
}, { }, {
Burn: &supplyInfoBurn{ Burn: &supplyInfoBurn{
EIP1559: new(big.Int).Mul(block.BaseFee(), big.NewInt(int64(block.GasUsed()))), EIP1559: (*hexutil.Big)(new(big.Int).Mul(block.BaseFee(), big.NewInt(int64(block.GasUsed())))),
Misc: eth5, // 5ETH burned from contract B Misc: (*hexutil.Big)(eth5), // 5ETH burned from contract B
}, },
Issuance: &supplyInfoIssuance{ Issuance: &supplyInfoIssuance{
Reward: eth2, Reward: (*hexutil.Big)(eth2),
}, },
Number: 1, Number: 1,
Hash: block.Hash(), Hash: block.Hash(),
ParentHash: block.ParentHash(), ParentHash: block.ParentHash(),
}} }}
compareAsJSON(t, expected, output) if err := compareAsJSON(expected, output); err != nil {
writeArtifact(t, "selfdestruct_itself_and_revert_grayGlacier", db, chain, expected, nil) return err
}
if err := writeArtifact(filepath.Join(path, "selfdestruct_itself_and_revert.json"), "selfdestruct_itself_and_revert_grayGlacier", db, chain, expected, nil); err != nil {
return err
}
return nil
} }
func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, ethdb.Database, *core.BlockChain, error) { func testSupplyTracer(genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, ethdb.Database, *core.BlockChain, error) {
var ( var (
engine = beacon.New(ethash.NewFaker()) engine = beacon.New(ethash.NewFaker())
) )
traceOutputPath := filepath.ToSlash(t.TempDir()) tempDir, err := os.MkdirTemp("", "supply-filler-")
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to generate directory for tracer outputs: %v", err)
}
defer os.RemoveAll(tempDir) // Clean up
traceOutputPath := filepath.ToSlash(tempDir)
traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl") traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl")
// Load supply tracer // Load supply tracer
@ -596,34 +702,64 @@ func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockG
return output, db, chain, nil return output, db, chain, nil
} }
func compareAsJSON(t *testing.T, expected interface{}, actual interface{}) { func compareAsJSON(expected interface{}, actual interface{}) error {
t.Helper()
want, err := json.Marshal(expected) want, err := json.Marshal(expected)
if err != nil { if err != nil {
t.Fatalf("failed to marshal expected value to JSON: %v", err) return fmt.Errorf("failed to marshal expected value to JSON: %v", err)
} }
have, err := json.Marshal(actual) have, err := json.Marshal(actual)
if err != nil { if err != nil {
t.Fatalf("failed to marshal actual value to JSON: %v", err) return fmt.Errorf("failed to marshal actual value to JSON: %v", err)
} }
if !bytes.Equal(want, have) { if !bytes.Equal(want, have) {
t.Fatalf("incorrect supply info:\nwant %s\nhave %s", string(want), string(have)) return fmt.Errorf("incorrect supply info:\nwant %s\nhave %s", string(want), string(have))
} }
return nil
} }
func writeArtifact(t *testing.T, name string, db ethdb.Database, chain *core.BlockChain, expected []supplyInfo, post *types.GenesisAlloc) { func writeArtifact(path, name string, db ethdb.Database, chain *core.BlockChain, expected []supplyInfo, post *types.GenesisAlloc) error {
bt, err := btFromChain(db, chain, post) bt, err := btFromChain(db, chain, post)
if err != nil { if err != nil {
t.Fatalf("failed to fill tests from chain: %v", err) return fmt.Errorf("failed to fill tests from chain: %v", err)
} }
bt.Expected = expected bt.Expected = expected
writeBTs(t, map[string]*BlockTest{name: bt}) return writeBTs(path, map[string]*blockTest{name: bt})
} }
func writeBTs(t *testing.T, tests map[string]*BlockTest) { type blockTest struct {
bt *tests.BlockTest
Expected []supplyInfo `json:"expected"`
}
func writeBTs(path string, tests map[string]*blockTest) error {
enc, err := json.MarshalIndent(&tests, "", " ") enc, err := json.MarshalIndent(&tests, "", " ")
if err != nil { if err != nil {
t.Fatalf("failed to marshal tests: %v", err) return fmt.Errorf("failed to marshal tests: %v", err)
} }
t.Logf("Tests: %s", enc) if err := os.WriteFile(path, enc, 0644); err != nil {
return fmt.Errorf("failed to write test to file: %v", err)
}
return nil
}
func btFromChain(db ethdb.Database, chain *core.BlockChain, post *types.GenesisAlloc) (*blockTest, error) {
bt, err := tests.FromChain(db, chain, post)
if err != nil {
return nil, err
}
return &blockTest{bt: &bt}, nil
}
func (bt *blockTest) MarshalJSON() ([]byte, error) {
enc, err := json.Marshal(bt.bt)
if err != nil {
return nil, err
}
// Insert the expected supply info
result := make(map[string]any)
if err := json.Unmarshal(enc, &result); err != nil {
return nil, err
}
result["expected"] = bt.Expected
return json.Marshal(result)
} }

View file

@ -72,7 +72,6 @@ func FromChain(db ethdb.Database, chain *core.BlockChain, post *types.GenesisAll
) )
for i := 1; i <= int(head.Number.Uint64()); i++ { for i := 1; i <= int(head.Number.Uint64()); i++ {
block := chain.GetBlockByNumber(uint64(i)) block := chain.GetBlockByNumber(uint64(i))
fmt.Printf("block: %v\n", block)
if block == nil { if block == nil {
return bt, fmt.Errorf("block %d not found", i) return bt, fmt.Errorf("block %d not found", i)
} }