Merge remote-tracking branch 'upstream/master' into vm-mempool

This commit is contained in:
lmittmann 2024-08-07 12:04:53 +02:00
commit b98528258a
88 changed files with 708 additions and 665 deletions

View file

@ -64,10 +64,6 @@ issues:
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
- path: core/vm/contracts.go - path: core/vm/contracts.go
text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.' text: 'SA1019: "golang.org/x/crypto/ripemd160" is deprecated: RIPEMD-160 is a legacy hash and should not be used for new applications.'
- path: accounts/usbwallet/trezor.go
text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.'
- path: accounts/usbwallet/trezor/
text: 'SA1019: "github.com/golang/protobuf/proto" is deprecated: Use the "google.golang.org/protobuf/proto" package instead.'
exclude: exclude:
- 'SA1019: event.TypeMux is deprecated: use Feed' - 'SA1019: event.TypeMux is deprecated: use Feed'
- 'SA1019: strings.Title is deprecated' - 'SA1019: strings.Title is deprecated'

View file

@ -42,7 +42,7 @@ clean:
devtools: devtools:
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
env GOBIN= go install github.com/fjl/gencodec@latest env GOBIN= go install github.com/fjl/gencodec@latest
env GOBIN= go install github.com/golang/protobuf/protoc-gen-go@latest env GOBIN= go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
env GOBIN= go install ./cmd/abigen env GOBIN= go install ./cmd/abigen
@type "solc" 2> /dev/null || echo 'Please install solc' @type "solc" 2> /dev/null || echo 'Please install solc'
@type "protoc" 2> /dev/null || echo 'Please install protoc' @type "protoc" 2> /dev/null || echo 'Please install protoc'

View file

@ -171,5 +171,5 @@ i4O1UeWKs9owWttan9+PI47ozBSKOTxmMqLSQ0f56Np9FJsV0ilGxRKfjhzJ4KniOMUBA7mP
epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx
PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano= PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano=
=arte =arte
-----END PGP PUBLIC KEY BLOCK------ -----END PGP PUBLIC KEY BLOCK-----
``` ```

View file

@ -59,11 +59,12 @@ type TransactOpts struct {
Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state)
Signer SignerFn // Method to use for signing the transaction (mandatory) Signer SignerFn // Method to use for signing the transaction (mandatory)
Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds) Value *big.Int // Funds to transfer along the transaction (nil = 0 = no funds)
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle) GasFeeCap *big.Int // Gas fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle) GasTipCap *big.Int // Gas priority fee cap to use for the 1559 transaction execution (nil = gas price oracle)
GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate)
AccessList types.AccessList // Access list to set for the transaction execution (nil = no access list)
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
@ -300,20 +301,21 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add
return nil, err return nil, err
} }
baseTx := &types.DynamicFeeTx{ baseTx := &types.DynamicFeeTx{
To: contract, To: contract,
Nonce: nonce, Nonce: nonce,
GasFeeCap: gasFeeCap, GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap, GasTipCap: gasTipCap,
Gas: gasLimit, Gas: gasLimit,
Value: value, Value: value,
Data: input, Data: input,
AccessList: opts.AccessList,
} }
return types.NewTx(baseTx), nil return types.NewTx(baseTx), nil
} }
func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) {
if opts.GasFeeCap != nil || opts.GasTipCap != nil { if opts.GasFeeCap != nil || opts.GasTipCap != nil || opts.AccessList != nil {
return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas or accessList specified but london is not active yet")
} }
// Normalize value // Normalize value
value := opts.Value value := opts.Value

View file

@ -114,7 +114,7 @@ func TestWatchNewFile(t *testing.T) {
func TestWatchNoDir(t *testing.T) { func TestWatchNoDir(t *testing.T) {
t.Parallel() t.Parallel()
// Create ks but not the directory that it watches. // Create ks but not the directory that it watches.
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int())) dir := filepath.Join(t.TempDir(), fmt.Sprintf("eth-keystore-watchnodir-test-%d-%d", os.Getpid(), rand.Int()))
ks := NewKeyStore(dir, LightScryptN, LightScryptP) ks := NewKeyStore(dir, LightScryptN, LightScryptP)
list := ks.Accounts() list := ks.Accounts()
if len(list) > 0 { if len(list) > 0 {
@ -126,7 +126,6 @@ func TestWatchNoDir(t *testing.T) {
} }
// Create the directory and copy a key file into it. // Create the directory and copy a key file into it.
os.MkdirAll(dir, 0700) os.MkdirAll(dir, 0700)
defer os.RemoveAll(dir)
file := filepath.Join(dir, "aaa") file := filepath.Join(dir, "aaa")
if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil { if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/golang/protobuf/proto" "google.golang.org/protobuf/proto"
) )
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In // ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In

View file

@ -39,8 +39,8 @@
// - Download the latest protoc https://github.com/protocolbuffers/protobuf/releases // - Download the latest protoc https://github.com/protocolbuffers/protobuf/releases
// - Build with the usual `./configure && make` and ensure it's on your $PATH // - Build with the usual `./configure && make` and ensure it's on your $PATH
// - Delete all the .proto and .pb.go files, pull in fresh ones from Trezor // - Delete all the .proto and .pb.go files, pull in fresh ones from Trezor
// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go` // - Grab the latest Go plugin `go get -u google.golang.org/protobuf/cmd/protoc-gen-go`
// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...` // - Vendor in the latest Go plugin `govendor fetch google.golang.org/protobuf/...`
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto //go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
@ -50,7 +50,7 @@ package trezor
import ( import (
"reflect" "reflect"
"github.com/golang/protobuf/proto" "google.golang.org/protobuf/proto"
) )
// Type returns the protocol buffer type number of a specific message. If the // Type returns the protocol buffer type number of a specific message. If the

View file

@ -48,7 +48,7 @@ func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) {
case "capella": case "capella":
obj = new(capella.BeaconBlock) obj = new(capella.BeaconBlock)
default: default:
return nil, fmt.Errorf("unsupported fork: " + forkName) return nil, fmt.Errorf("unsupported fork: %s", forkName)
} }
if err := json.Unmarshal(data, obj); err != nil { if err := json.Unmarshal(data, obj); err != nil {
return nil, err return nil, err

View file

@ -46,7 +46,7 @@ func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, er
case "deneb": case "deneb":
obj = new(deneb.ExecutionPayloadHeader) obj = new(deneb.ExecutionPayloadHeader)
default: default:
return nil, fmt.Errorf("unsupported fork: " + forkName) return nil, fmt.Errorf("unsupported fork: %s", forkName)
} }
if err := json.Unmarshal(data, obj); err != nil { if err := json.Unmarshal(data, obj); err != nil {
return nil, err return nil, err

View file

@ -22,6 +22,6 @@ package tools
import ( import (
// Tool imports for go:generate. // Tool imports for go:generate.
_ "github.com/fjl/gencodec" _ "github.com/fjl/gencodec"
_ "github.com/golang/protobuf/protoc-gen-go"
_ "golang.org/x/tools/cmd/stringer" _ "golang.org/x/tools/cmd/stringer"
_ "google.golang.org/protobuf/cmd/protoc-gen-go"
) )

View file

@ -27,9 +27,8 @@ import (
// TestImportRaw tests clef --importraw // TestImportRaw tests clef --importraw
func TestImportRaw(t *testing.T) { func TestImportRaw(t *testing.T) {
t.Parallel() t.Parallel()
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
t.Cleanup(func() { os.Remove(keyPath) })
t.Run("happy-path", func(t *testing.T) { t.Run("happy-path", func(t *testing.T) {
t.Parallel() t.Parallel()
@ -68,9 +67,8 @@ func TestImportRaw(t *testing.T) {
// TestListAccounts tests clef --list-accounts // TestListAccounts tests clef --list-accounts
func TestListAccounts(t *testing.T) { func TestListAccounts(t *testing.T) {
t.Parallel() t.Parallel()
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
t.Cleanup(func() { os.Remove(keyPath) })
t.Run("no-accounts", func(t *testing.T) { t.Run("no-accounts", func(t *testing.T) {
t.Parallel() t.Parallel()
@ -97,9 +95,8 @@ func TestListAccounts(t *testing.T) {
// TestListWallets tests clef --list-wallets // TestListWallets tests clef --list-wallets
func TestListWallets(t *testing.T) { func TestListWallets(t *testing.T) {
t.Parallel() t.Parallel()
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name())) keyPath := filepath.Join(t.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777) os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
t.Cleanup(func() { os.Remove(keyPath) })
t.Run("no-accounts", func(t *testing.T) { t.Run("no-accounts", func(t *testing.T) {
t.Parallel() t.Parallel()

View file

@ -34,12 +34,12 @@ import (
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
) )
func makeJWTSecret() (string, [32]byte, error) { func makeJWTSecret(t *testing.T) (string, [32]byte, error) {
var secret [32]byte var secret [32]byte
if _, err := crand.Read(secret[:]); err != nil { if _, err := crand.Read(secret[:]); err != nil {
return "", secret, fmt.Errorf("failed to create jwt secret: %v", err) return "", secret, fmt.Errorf("failed to create jwt secret: %v", err)
} }
jwtPath := filepath.Join(os.TempDir(), "jwt_secret") jwtPath := filepath.Join(t.TempDir(), "jwt_secret")
if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil { if err := os.WriteFile(jwtPath, []byte(hexutil.Encode(secret[:])), 0600); err != nil {
return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err) return "", secret, fmt.Errorf("failed to prepare jwt secret file: %v", err)
} }
@ -47,7 +47,7 @@ func makeJWTSecret() (string, [32]byte, error) {
} }
func TestEthSuite(t *testing.T) { func TestEthSuite(t *testing.T) {
jwtPath, secret, err := makeJWTSecret() jwtPath, secret, err := makeJWTSecret(t)
if err != nil { if err != nil {
t.Fatalf("could not make jwt secret: %v", err) t.Fatalf("could not make jwt secret: %v", err)
} }
@ -75,7 +75,7 @@ func TestEthSuite(t *testing.T) {
} }
func TestSnapSuite(t *testing.T) { func TestSnapSuite(t *testing.T) {
jwtPath, secret, err := makeJWTSecret() jwtPath, secret, err := makeJWTSecret(t)
if err != nil { if err != nil {
t.Fatalf("could not make jwt secret: %v", err) t.Fatalf("could not make jwt secret: %v", err)
} }

View file

@ -79,7 +79,7 @@ func rlpxPing(ctx *cli.Context) error {
n := getNodeArg(ctx) n := getNodeArg(ctx)
tcpEndpoint, ok := n.TCPEndpoint() tcpEndpoint, ok := n.TCPEndpoint()
if !ok { if !ok {
return fmt.Errorf("node has no TCP endpoint") return errors.New("node has no TCP endpoint")
} }
fd, err := net.Dial("tcp", tcpEndpoint.String()) fd, err := net.Dial("tcp", tcpEndpoint.String())
if err != nil { if err != nil {

View file

@ -162,7 +162,6 @@ func runCmd(ctx *cli.Context) error {
if ctx.String(SenderFlag.Name) != "" { if ctx.String(SenderFlag.Name) != "" {
sender = common.HexToAddress(ctx.String(SenderFlag.Name)) sender = common.HexToAddress(ctx.String(SenderFlag.Name))
} }
statedb.CreateAccount(sender)
if ctx.String(ReceiverFlag.Name) != "" { if ctx.String(ReceiverFlag.Name) != "" {
receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name)) receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name))

View file

@ -248,7 +248,8 @@ func removeDB(ctx *cli.Context) error {
// Delete state data // Delete state data
statePaths := []string{ statePaths := []string{
rootDir, rootDir,
filepath.Join(ancientDir, rawdb.StateFreezerName), filepath.Join(ancientDir, rawdb.MerkleStateFreezerName),
filepath.Join(ancientDir, rawdb.VerkleStateFreezerName),
} }
confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name) confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)

View file

@ -28,8 +28,7 @@ import (
// TestExport does a basic test of "geth export", exporting the test-genesis. // TestExport does a basic test of "geth export", exporting the test-genesis.
func TestExport(t *testing.T) { func TestExport(t *testing.T) {
t.Parallel() t.Parallel()
outfile := fmt.Sprintf("%v/testExport.out", os.TempDir()) outfile := fmt.Sprintf("%v/testExport.out", t.TempDir())
defer os.Remove(outfile)
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile) geth := runGeth(t, "--datadir", initGeth(t), "export", outfile)
geth.WaitExit() geth.WaitExit()
if have, want := geth.ExitStatus(), 0; have != want { if have, want := geth.ExitStatus(), 0; have != want {

View file

@ -201,9 +201,8 @@ func TestFileOut(t *testing.T) {
var ( var (
have, want []byte have, want []byte
err error err error
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63()) path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
) )
t.Cleanup(func() { os.Remove(path) })
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil { if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "logtest"); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -222,9 +221,8 @@ func TestRotatingFileOut(t *testing.T) {
var ( var (
have, want []byte have, want []byte
err error err error
path = fmt.Sprintf("%s/test_file_out-%d", os.TempDir(), rand.Int63()) path = fmt.Sprintf("%s/test_file_out-%d", t.TempDir(), rand.Int63())
) )
t.Cleanup(func() { os.Remove(path) })
if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil { if want, err = runSelf(fmt.Sprintf("--log.file=%s", path), "--log.rotate", "logtest"); err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -360,8 +360,6 @@ func geth(ctx *cli.Context) error {
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner. // miner.
func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) { func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
debug.Memsize.Add("node", stack)
// Start up the node itself // Start up the node itself
utils.StartNode(ctx, stack, isConsole) utils.StartNode(ctx, stack, isConsole)

View file

@ -29,18 +29,12 @@ import (
// TestExport does basic sanity checks on the export/import functionality // TestExport does basic sanity checks on the export/import functionality
func TestExport(t *testing.T) { func TestExport(t *testing.T) {
f := fmt.Sprintf("%v/tempdump", os.TempDir()) f := fmt.Sprintf("%v/tempdump", t.TempDir())
defer func() {
os.Remove(f)
}()
testExport(t, f) testExport(t, f)
} }
func TestExportGzip(t *testing.T) { func TestExportGzip(t *testing.T) {
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir()) f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
defer func() {
os.Remove(f)
}()
testExport(t, f) testExport(t, f)
} }
@ -99,20 +93,14 @@ func testExport(t *testing.T, f string) {
// TestDeletionExport tests if the deletion markers can be exported/imported correctly // TestDeletionExport tests if the deletion markers can be exported/imported correctly
func TestDeletionExport(t *testing.T) { func TestDeletionExport(t *testing.T) {
f := fmt.Sprintf("%v/tempdump", os.TempDir()) f := fmt.Sprintf("%v/tempdump", t.TempDir())
defer func() {
os.Remove(f)
}()
testDeletion(t, f) testDeletion(t, f)
} }
// TestDeletionExportGzip tests if the deletion markers can be exported/imported // TestDeletionExportGzip tests if the deletion markers can be exported/imported
// correctly with gz compression. // correctly with gz compression.
func TestDeletionExportGzip(t *testing.T) { func TestDeletionExportGzip(t *testing.T) {
f := fmt.Sprintf("%v/tempdump.gz", os.TempDir()) f := fmt.Sprintf("%v/tempdump.gz", t.TempDir())
defer func() {
os.Remove(f)
}()
testDeletion(t, f) testDeletion(t, f)
} }
@ -171,10 +159,7 @@ func testDeletion(t *testing.T, f string) {
// TestImportFutureFormat tests that we reject unsupported future versions. // TestImportFutureFormat tests that we reject unsupported future versions.
func TestImportFutureFormat(t *testing.T) { func TestImportFutureFormat(t *testing.T) {
t.Parallel() t.Parallel()
f := fmt.Sprintf("%v/tempdump-future", os.TempDir()) f := fmt.Sprintf("%v/tempdump-future", t.TempDir())
defer func() {
os.Remove(f)
}()
fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View file

@ -42,6 +42,7 @@ import (
"github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/common/fdlimit"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
"github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/core/txpool/legacypool"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -291,7 +292,7 @@ var (
} }
BeaconApiHeaderFlag = &cli.StringSliceFlag{ BeaconApiHeaderFlag = &cli.StringSliceFlag{
Name: "beacon.api.header", Name: "beacon.api.header",
Usage: "Pass custom HTTP header fields to the emote beacon node API in \"key:value\" format. This flag can be given multiple times.", Usage: "Pass custom HTTP header fields to the remote beacon node API in \"key:value\" format. This flag can be given multiple times.",
Category: flags.BeaconCategory, Category: flags.BeaconCategory,
} }
BeaconThresholdFlag = &cli.IntFlag{ BeaconThresholdFlag = &cli.IntFlag{
@ -1550,6 +1551,18 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) {
} }
} }
func setBlobPool(ctx *cli.Context, cfg *blobpool.Config) {
if ctx.IsSet(BlobPoolDataDirFlag.Name) {
cfg.Datadir = ctx.String(BlobPoolDataDirFlag.Name)
}
if ctx.IsSet(BlobPoolDataCapFlag.Name) {
cfg.Datacap = ctx.Uint64(BlobPoolDataCapFlag.Name)
}
if ctx.IsSet(BlobPoolPriceBumpFlag.Name) {
cfg.PriceBump = ctx.Uint64(BlobPoolPriceBumpFlag.Name)
}
}
func setMiner(ctx *cli.Context, cfg *miner.Config) { func setMiner(ctx *cli.Context, cfg *miner.Config) {
if ctx.Bool(MiningEnabledFlag.Name) { if ctx.Bool(MiningEnabledFlag.Name) {
log.Warn("The flag --mine is deprecated and will be removed") log.Warn("The flag --mine is deprecated and will be removed")
@ -1651,6 +1664,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
setEtherbase(ctx, cfg) setEtherbase(ctx, cfg)
setGPO(ctx, &cfg.GPO) setGPO(ctx, &cfg.GPO)
setTxPool(ctx, &cfg.TxPool) setTxPool(ctx, &cfg.TxPool)
setBlobPool(ctx, &cfg.BlobPool)
setMiner(ctx, &cfg.Miner) setMiner(ctx, &cfg.Miner)
setRequiredBlocks(ctx, cfg) setRequiredBlocks(ctx, cfg)
setLes(ctx, cfg) setLes(ctx, cfg)

View file

@ -311,7 +311,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
} }
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults}) triedb := triedb.NewDatabase(db, triedb.VerkleDefaults)
block := genesis.MustCommit(db, triedb) block := genesis.MustCommit(db, triedb)
if !bytes.Equal(block.Root().Bytes(), expected) { if !bytes.Equal(block.Root().Bytes(), expected) {
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root()) t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root())
@ -321,8 +321,8 @@ func TestVerkleGenesisCommit(t *testing.T) {
if !triedb.IsVerkle() { if !triedb.IsVerkle() {
t.Fatalf("expected trie to be verkle") t.Fatalf("expected trie to be verkle")
} }
vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix))
if !rawdb.HasAccountTrieNode(db, nil) { if !rawdb.HasAccountTrieNode(vdb, nil) {
t.Fatal("could not find node") t.Fatal("could not find node")
} }
} }

View file

@ -245,7 +245,7 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
// ReadStateScheme reads the state scheme of persistent state, or none // ReadStateScheme reads the state scheme of persistent state, or none
// if the state is not present in database. // if the state is not present in database.
func ReadStateScheme(db ethdb.Reader) string { func ReadStateScheme(db ethdb.Database) string {
// Check if state in path-based scheme is present. // Check if state in path-based scheme is present.
if HasAccountTrieNode(db, nil) { if HasAccountTrieNode(db, nil) {
return PathScheme return PathScheme
@ -255,6 +255,16 @@ func ReadStateScheme(db ethdb.Reader) string {
if id := ReadPersistentStateID(db); id != 0 { if id := ReadPersistentStateID(db); id != 0 {
return PathScheme return PathScheme
} }
// Check if verkle state in path-based scheme is present.
vdb := NewTable(db, string(VerklePrefix))
if HasAccountTrieNode(vdb, nil) {
return PathScheme
}
// The root node of verkle might be deleted during the initial snap sync,
// check the persistent state id then.
if id := ReadPersistentStateID(vdb); id != 0 {
return PathScheme
}
// In a hash-based scheme, the genesis state is consistently stored // In a hash-based scheme, the genesis state is consistently stored
// on the disk. To assess the scheme of the persistent state, it // on the disk. To assess the scheme of the persistent state, it
// suffices to inspect the scheme of the genesis state. // suffices to inspect the scheme of the genesis state.

View file

@ -72,12 +72,13 @@ var stateFreezerNoSnappy = map[string]bool{
// The list of identifiers of ancient stores. // The list of identifiers of ancient stores.
var ( var (
ChainFreezerName = "chain" // the folder name of chain segment ancient store. ChainFreezerName = "chain" // the folder name of chain segment ancient store.
StateFreezerName = "state" // the folder name of reverse diff ancient store. MerkleStateFreezerName = "state" // the folder name of state history ancient store.
VerkleStateFreezerName = "state_verkle" // the folder name of state history ancient store.
) )
// freezers the collections of all builtin freezers. // freezers the collections of all builtin freezers.
var freezers = []string{ChainFreezerName, StateFreezerName} var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName}
// NewStateFreezer initializes the ancient store for state history. // NewStateFreezer initializes the ancient store for state history.
// //
@ -85,9 +86,15 @@ var freezers = []string{ChainFreezerName, StateFreezerName}
// state freezer (e.g. dev mode). // state freezer (e.g. dev mode).
// - if non-empty directory is given, initializes the regular file-based // - if non-empty directory is given, initializes the regular file-based
// state freezer. // state freezer.
func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) { func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) {
if ancientDir == "" { if ancientDir == "" {
return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil
} }
return newResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy) var name string
if verkle {
name = filepath.Join(ancientDir, VerkleStateFreezerName)
} else {
name = filepath.Join(ancientDir, MerkleStateFreezerName)
}
return newResettableFreezer(name, "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
} }

View file

@ -88,12 +88,12 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
} }
infos = append(infos, info) infos = append(infos, info)
case StateFreezerName: case MerkleStateFreezerName, VerkleStateFreezerName:
datadir, err := db.AncientDatadir() datadir, err := db.AncientDatadir()
if err != nil { if err != nil {
return nil, err return nil, err
} }
f, err := NewStateFreezer(datadir, true) f, err := NewStateFreezer(datadir, freezer == VerkleStateFreezerName, true)
if err != nil { if err != nil {
continue // might be possible the state freezer is not existent continue // might be possible the state freezer is not existent
} }
@ -124,7 +124,7 @@ func InspectFreezerTable(ancient string, freezerName string, tableName string, s
switch freezerName { switch freezerName {
case ChainFreezerName: case ChainFreezerName:
path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy
case StateFreezerName: case MerkleStateFreezerName, VerkleStateFreezerName:
path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy
default: default:
return fmt.Errorf("unknown freezer, supported ones: %v", freezers) return fmt.Errorf("unknown freezer, supported ones: %v", freezers)

View file

@ -481,6 +481,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
beaconHeaders stat beaconHeaders stat
cliqueSnaps stat cliqueSnaps stat
// Verkle statistics
verkleTries stat
verkleStateLookups stat
// Les statistic // Les statistic
chtTrieNodes stat chtTrieNodes stat
bloomTrieNodes stat bloomTrieNodes stat
@ -550,6 +554,24 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
bytes.HasPrefix(key, BloomTrieIndexPrefix) || bytes.HasPrefix(key, BloomTrieIndexPrefix) ||
bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub
bloomTrieNodes.Add(size) bloomTrieNodes.Add(size)
// Verkle trie data is detected, determine the sub-category
case bytes.HasPrefix(key, VerklePrefix):
remain := key[len(VerklePrefix):]
switch {
case IsAccountTrieNode(remain):
verkleTries.Add(size)
case bytes.HasPrefix(remain, stateIDPrefix) && len(remain) == len(stateIDPrefix)+common.HashLength:
verkleStateLookups.Add(size)
case bytes.Equal(remain, persistentStateIDKey):
metadata.Add(size)
case bytes.Equal(remain, trieJournalKey):
metadata.Add(size)
case bytes.Equal(remain, snapSyncStatusFlagKey):
metadata.Add(size)
default:
unaccounted.Add(size)
}
default: default:
var accounted bool var accounted bool
for _, meta := range [][]byte{ for _, meta := range [][]byte{
@ -590,6 +612,8 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
{"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()}, {"Key-Value store", "Path trie state lookups", stateLookups.Size(), stateLookups.Count()},
{"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()}, {"Key-Value store", "Path trie account nodes", accountTries.Size(), accountTries.Count()},
{"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()}, {"Key-Value store", "Path trie storage nodes", storageTries.Size(), storageTries.Count()},
{"Key-Value store", "Verkle trie nodes", verkleTries.Size(), verkleTries.Count()},
{"Key-Value store", "Verkle trie state lookups", verkleStateLookups.Size(), verkleStateLookups.Count()},
{"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()}, {"Key-Value store", "Trie preimages", preimages.Size(), preimages.Count()},
{"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()}, {"Key-Value store", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()},
{"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()}, {"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()},

View file

@ -22,10 +22,11 @@ import (
) )
func TestReadWriteFreezerTableMeta(t *testing.T) { func TestReadWriteFreezerTableMeta(t *testing.T) {
f, err := os.CreateTemp(os.TempDir(), "*") f, err := os.CreateTemp(t.TempDir(), "*")
if err != nil { if err != nil {
t.Fatalf("Failed to create file %v", err) t.Fatalf("Failed to create file %v", err)
} }
defer f.Close()
err = writeMetadata(f, newMetadata(100)) err = writeMetadata(f, newMetadata(100))
if err != nil { if err != nil {
t.Fatalf("Failed to write metadata %v", err) t.Fatalf("Failed to write metadata %v", err)
@ -43,10 +44,11 @@ func TestReadWriteFreezerTableMeta(t *testing.T) {
} }
func TestInitializeFreezerTableMeta(t *testing.T) { func TestInitializeFreezerTableMeta(t *testing.T) {
f, err := os.CreateTemp(os.TempDir(), "*") f, err := os.CreateTemp(t.TempDir(), "*")
if err != nil { if err != nil {
t.Fatalf("Failed to create file %v", err) t.Fatalf("Failed to create file %v", err)
} }
defer f.Close()
meta, err := loadMetadata(f, uint64(100)) meta, err := loadMetadata(f, uint64(100))
if err != nil { if err != nil {
t.Fatalf("Failed to read metadata %v", err) t.Fatalf("Failed to read metadata %v", err)

View file

@ -117,6 +117,13 @@ var (
TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node
stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id stateIDPrefix = []byte("L") // stateIDPrefix + state root -> state id
// VerklePrefix is the database prefix for Verkle trie data, which includes:
// (a) Trie nodes
// (b) In-memory trie node journal
// (c) Persistent state ID
// (d) State ID lookups, etc.
VerklePrefix = []byte("v")
PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage PreimagePrefix = []byte("secure-key-") // PreimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db configPrefix = []byte("ethereum-config-") // config prefix for the db
genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db

View file

@ -200,13 +200,6 @@ func (t *table) NewBatchWithSize(size int) ethdb.Batch {
return &tableBatch{t.db.NewBatchWithSize(size), t.prefix} return &tableBatch{t.db.NewBatchWithSize(size), t.prefix}
} }
// NewSnapshot creates a database snapshot based on the current state.
// The created snapshot will not be affected by all following mutations
// happened on the database.
func (t *table) NewSnapshot() (ethdb.Snapshot, error) {
return t.db.NewSnapshot()
}
// tableBatch is a wrapper around a database batch that prefixes each key access // tableBatch is a wrapper around a database batch that prefixes each key access
// with a pre-configured string. // with a pre-configured string.
type tableBatch struct { type tableBatch struct {

View file

@ -27,10 +27,4 @@ var (
storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil)
accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil) accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil)
storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil) storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil)
slotDeletionMaxCount = metrics.NewRegisteredGauge("state/delete/storage/max/slot", nil)
slotDeletionMaxSize = metrics.NewRegisteredGauge("state/delete/storage/max/size", nil)
slotDeletionTimer = metrics.NewRegisteredResettingTimer("state/delete/storage/timer", nil)
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
) )

View file

@ -471,20 +471,28 @@ func (s *StateDB) SetState(addr common.Address, key, value common.Hash) {
// storage. This function should only be used for debugging and the mutations // storage. This function should only be used for debugging and the mutations
// must be discarded afterwards. // must be discarded afterwards.
func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) { func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) {
// SetStorage needs to wipe existing storage. We achieve this by pretending // SetStorage needs to wipe the existing storage. We achieve this by marking
// that the account self-destructed earlier in this block, by flagging // the account as self-destructed in this block. The effect is that storage
// it in stateObjectsDestruct. The effect of doing so is that storage lookups // lookups will not hit the disk, as it is assumed that the disk data belongs
// will not hit disk, since it is assumed that the disk-data is belonging
// to a previous incarnation of the object. // to a previous incarnation of the object.
// //
// TODO(rjl493456442) this function should only be supported by 'unwritable' // TODO (rjl493456442): This function should only be supported by 'unwritable'
// state and all mutations made should all be discarded afterwards. // state, and all mutations made should be discarded afterward.
if _, ok := s.stateObjectsDestruct[addr]; !ok { obj := s.getStateObject(addr)
s.stateObjectsDestruct[addr] = nil if obj != nil {
if _, ok := s.stateObjectsDestruct[addr]; !ok {
s.stateObjectsDestruct[addr] = obj
}
} }
stateObject := s.getOrNewStateObject(addr) newObj := s.createObject(addr)
for k, v := range storage { for k, v := range storage {
stateObject.SetState(k, v) newObj.SetState(k, v)
}
// Inherit the metadata of original object if it was existent
if obj != nil {
newObj.SetCode(common.BytesToHash(obj.CodeHash()), obj.code)
newObj.SetNonce(obj.Nonce())
newObj.SetBalance(obj.Balance(), tracing.BalanceChangeUnspecified)
} }
} }
@ -860,12 +868,16 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
} }
obj := s.stateObjects[addr] // closure for the task runner below obj := s.stateObjects[addr] // closure for the task runner below
workers.Go(func() error { workers.Go(func() error {
obj.updateRoot() if s.db.TrieDB().IsVerkle() {
obj.updateTrie()
} else {
obj.updateRoot()
// If witness building is enabled and the state object has a trie, // If witness building is enabled and the state object has a trie,
// gather the witnesses for its specific storage trie // gather the witnesses for its specific storage trie
if s.witness != nil && obj.trie != nil { if s.witness != nil && obj.trie != nil {
s.witness.AddState(obj.trie.Witness()) s.witness.AddState(obj.trie.Witness())
}
} }
return nil return nil
}) })
@ -907,9 +919,12 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// Now we're about to start to write changes to the trie. The trie is so far // Now we're about to start to write changes to the trie. The trie is so far
// _untouched_. We can check with the prefetcher, if it can give us a trie // _untouched_. We can check with the prefetcher, if it can give us a trie
// which has the same root, but also has some content loaded into it. // which has the same root, but also has some content loaded into it.
//
// Don't check prefetcher if verkle trie has been used. In the context of verkle,
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
// here could result in losing uncommitted changes from storage.
start = time.Now() start = time.Now()
if s.prefetcher != nil && (s.trie == nil || !s.trie.IsVerkle()) {
if s.prefetcher != nil {
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
log.Error("Failed to retrieve account pre-fetcher trie") log.Error("Failed to retrieve account pre-fetcher trie")
} else { } else {
@ -985,76 +1000,70 @@ func (s *StateDB) clearJournalAndRefund() {
// of a specific account. It leverages the associated state snapshot for fast // of a specific account. It leverages the associated state snapshot for fast
// storage iteration and constructs trie node deletion markers by creating // storage iteration and constructs trie node deletion markers by creating
// stack trie with iterated slots. // stack trie with iterated slots.
func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { func (s *StateDB) fastDeleteStorage(addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{}) iter, err := s.snaps.StorageIterator(s.originalRoot, addrHash, common.Hash{})
if err != nil { if err != nil {
return 0, nil, nil, err return nil, nil, err
} }
defer iter.Release() defer iter.Release()
var ( var (
size common.StorageSize
nodes = trienode.NewNodeSet(addrHash) nodes = trienode.NewNodeSet(addrHash)
slots = make(map[common.Hash][]byte) slots = make(map[common.Hash][]byte)
) )
stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) {
nodes.AddNode(path, trienode.NewDeleted()) nodes.AddNode(path, trienode.NewDeleted())
size += common.StorageSize(len(path))
}) })
for iter.Next() { for iter.Next() {
slot := common.CopyBytes(iter.Slot()) slot := common.CopyBytes(iter.Slot())
if err := iter.Error(); err != nil { // error might occur after Slot function if err := iter.Error(); err != nil { // error might occur after Slot function
return 0, nil, nil, err return nil, nil, err
} }
size += common.StorageSize(common.HashLength + len(slot))
slots[iter.Hash()] = slot slots[iter.Hash()] = slot
if err := stack.Update(iter.Hash().Bytes(), slot); err != nil { if err := stack.Update(iter.Hash().Bytes(), slot); err != nil {
return 0, nil, nil, err return nil, nil, err
} }
} }
if err := iter.Error(); err != nil { // error might occur during iteration if err := iter.Error(); err != nil { // error might occur during iteration
return 0, nil, nil, err return nil, nil, err
} }
if stack.Hash() != root { if stack.Hash() != root {
return 0, nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash()) return nil, nil, fmt.Errorf("snapshot is not matched, exp %x, got %x", root, stack.Hash())
} }
return size, slots, nodes, nil return slots, nodes, nil
} }
// slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage," // slowDeleteStorage serves as a less-efficient alternative to "fastDeleteStorage,"
// employed when the associated state snapshot is not available. It iterates the // employed when the associated state snapshot is not available. It iterates the
// storage slots along with all internal trie nodes via trie directly. // storage slots along with all internal trie nodes via trie directly.
func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (common.StorageSize, map[common.Hash][]byte, *trienode.NodeSet, error) { func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie) tr, err := s.db.OpenStorageTrie(s.originalRoot, addr, root, s.trie)
if err != nil { if err != nil {
return 0, nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err) return nil, nil, fmt.Errorf("failed to open storage trie, err: %w", err)
} }
it, err := tr.NodeIterator(nil) it, err := tr.NodeIterator(nil)
if err != nil { if err != nil {
return 0, nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err) return nil, nil, fmt.Errorf("failed to open storage iterator, err: %w", err)
} }
var ( var (
size common.StorageSize
nodes = trienode.NewNodeSet(addrHash) nodes = trienode.NewNodeSet(addrHash)
slots = make(map[common.Hash][]byte) slots = make(map[common.Hash][]byte)
) )
for it.Next(true) { for it.Next(true) {
if it.Leaf() { if it.Leaf() {
slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob()) slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob())
size += common.StorageSize(common.HashLength + len(it.LeafBlob()))
continue continue
} }
if it.Hash() == (common.Hash{}) { if it.Hash() == (common.Hash{}) {
continue continue
} }
size += common.StorageSize(len(it.Path()))
nodes.AddNode(it.Path(), trienode.NewDeleted()) nodes.AddNode(it.Path(), trienode.NewDeleted())
} }
if err := it.Error(); err != nil { if err := it.Error(); err != nil {
return 0, nil, nil, err return nil, nil, err
} }
return size, slots, nodes, nil return slots, nodes, nil
} }
// deleteStorage is designed to delete the storage trie of a designated account. // deleteStorage is designed to delete the storage trie of a designated account.
@ -1063,9 +1072,7 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r
// efficient approach. // efficient approach.
func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
var ( var (
start = time.Now()
err error err error
size common.StorageSize
slots map[common.Hash][]byte slots map[common.Hash][]byte
nodes *trienode.NodeSet nodes *trienode.NodeSet
) )
@ -1073,24 +1080,14 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
// generated, or it's internally corrupted. Fallback to the slow // generated, or it's internally corrupted. Fallback to the slow
// one just in case. // one just in case.
if s.snap != nil { if s.snap != nil {
size, slots, nodes, err = s.fastDeleteStorage(addrHash, root) slots, nodes, err = s.fastDeleteStorage(addrHash, root)
} }
if s.snap == nil || err != nil { if s.snap == nil || err != nil {
size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root)
} }
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
// Report the metrics
n := int64(len(slots))
slotDeletionMaxCount.UpdateIfGt(int64(len(slots)))
slotDeletionMaxSize.UpdateIfGt(int64(size))
slotDeletionTimer.UpdateSince(start)
slotDeletionCount.Mark(n)
slotDeletionSize.Mark(int64(size))
return slots, nodes, nil return slots, nodes, nil
} }
@ -1169,6 +1166,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
// Finalize any pending changes and merge everything into the tries // Finalize any pending changes and merge everything into the tries
s.IntermediateRoot(deleteEmptyObjects) s.IntermediateRoot(deleteEmptyObjects)
// Short circuit if any error occurs within the IntermediateRoot.
if s.dbErr != nil {
return nil, fmt.Errorf("commit aborted due to database error: %v", s.dbErr)
}
// Commit objects to the trie, measuring the elapsed time // Commit objects to the trie, measuring the elapsed time
var ( var (
accountTrieNodesUpdated int accountTrieNodesUpdated int

View file

@ -2,7 +2,7 @@
All notable changes to the tracing interface will be documented in this file. All notable changes to the tracing interface will be documented in this file.
## [Unreleased] ## [v1.14.3]
There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork. There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork.
@ -77,3 +77,4 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale
[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master [unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master
[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0 [v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0
[v1.14.3]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.3

View file

@ -1116,7 +1116,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
ExistingCost: func(addr common.Address, nonce uint64) *big.Int { ExistingCost: func(addr common.Address, nonce uint64) *big.Int {
next := p.state.GetNonce(addr) next := p.state.GetNonce(addr)
if uint64(len(p.index[addr])) > nonce-next { if uint64(len(p.index[addr])) > nonce-next {
return p.index[addr][int(tx.Nonce()-next)].costCap.ToBig() return p.index[addr][int(nonce-next)].costCap.ToBig()
} }
return nil return nil
}, },
@ -1598,8 +1598,9 @@ func (p *BlobPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool
// Nonce returns the next nonce of an account, with all transactions executable // Nonce returns the next nonce of an account, with all transactions executable
// by the pool already applied on top. // by the pool already applied on top.
func (p *BlobPool) Nonce(addr common.Address) uint64 { func (p *BlobPool) Nonce(addr common.Address) uint64 {
p.lock.RLock() // We need a write lock here, since state.GetNonce might write the cache.
defer p.lock.RUnlock() p.lock.Lock()
defer p.lock.Unlock()
if txs, ok := p.index[addr]; ok { if txs, ok := p.index[addr]; ok {
return txs[len(txs)-1].nonce + 1 return txs[len(txs)-1].nonce + 1

View file

@ -38,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"golang.org/x/exp/maps"
) )
const ( const (
@ -1717,7 +1718,7 @@ func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type accountSet struct { type accountSet struct {
accounts map[common.Address]struct{} accounts map[common.Address]struct{}
signer types.Signer signer types.Signer
cache *[]common.Address cache []common.Address
} }
// newAccountSet creates a new address set with an associated signer for sender // newAccountSet creates a new address set with an associated signer for sender
@ -1765,20 +1766,14 @@ func (as *accountSet) addTx(tx *types.Transaction) {
// reuse. The returned slice should not be changed! // reuse. The returned slice should not be changed!
func (as *accountSet) flatten() []common.Address { func (as *accountSet) flatten() []common.Address {
if as.cache == nil { if as.cache == nil {
accounts := make([]common.Address, 0, len(as.accounts)) as.cache = maps.Keys(as.accounts)
for account := range as.accounts {
accounts = append(accounts, account)
}
as.cache = &accounts
} }
return *as.cache return as.cache
} }
// merge adds all addresses from the 'other' set into 'as'. // merge adds all addresses from the 'other' set into 'as'.
func (as *accountSet) merge(other *accountSet) { func (as *accountSet) merge(other *accountSet) {
for addr := range other.accounts { maps.Copy(as.accounts, other.accounts)
as.accounts[addr] = struct{}{}
}
as.cache = nil as.cache = nil
} }

View file

@ -201,7 +201,7 @@ type ValidationOptionsWithState struct {
// rules without duplicating code and running the risk of missed updates. // rules without duplicating code and running the risk of missed updates.
func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState) error { func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState) error {
// Ensure the transaction adheres to nonce ordering // Ensure the transaction adheres to nonce ordering
from, err := signer.Sender(tx) // already validated (and cached), but cleaner to check from, err := types.Sender(signer, tx) // already validated (and cached), but cleaner to check
if err != nil { if err != nil {
log.Error("Transaction sender recovery failed", "err", err) log.Error("Transaction sender recovery failed", "err", err)
return err return err

View file

@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int {
} }
return new(big.Int).SetUint64((v - 35) / 2) return new(big.Int).SetUint64((v - 35) / 2)
} }
v.Sub(v, big.NewInt(35)) vCopy := new(big.Int).Sub(v, big.NewInt(35))
return v.Rsh(v, 1) return vCopy.Rsh(vCopy, 1)
} }

View file

@ -345,6 +345,41 @@ func TestTransactionCoding(t *testing.T) {
} }
} }
func TestLegacyTransaction_ConsistentV_LargeChainIds(t *testing.T) {
chainId := new(big.Int).SetUint64(13317435930671861669)
txdata := &LegacyTx{
Nonce: 1,
Gas: 1,
GasPrice: big.NewInt(2),
Data: []byte("abcdef"),
}
key, err := crypto.GenerateKey()
if err != nil {
t.Fatalf("could not generate key: %v", err)
}
tx, err := SignNewTx(key, NewEIP2930Signer(chainId), txdata)
if err != nil {
t.Fatalf("could not sign transaction: %v", err)
}
// Make a copy of the initial V value
preV, _, _ := tx.RawSignatureValues()
preV = new(big.Int).Set(preV)
if tx.ChainId().Cmp(chainId) != 0 {
t.Fatalf("wrong chain id: %v", tx.ChainId())
}
v, _, _ := tx.RawSignatureValues()
if v.Cmp(preV) != 0 {
t.Fatalf("wrong v value: %v", v)
}
}
func encodeDecodeJSON(tx *Transaction) (*Transaction, error) { func encodeDecodeJSON(tx *Transaction) (*Transaction, error) {
data, err := json.Marshal(tx) data, err := json.Marshal(tx)
if err != nil { if err != nil {

View file

@ -583,6 +583,86 @@ func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte
return nil, nil return nil, nil
} }
func opSwap1(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap1()
return nil, nil
}
func opSwap2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap2()
return nil, nil
}
func opSwap3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap3()
return nil, nil
}
func opSwap4(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap4()
return nil, nil
}
func opSwap5(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap5()
return nil, nil
}
func opSwap6(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap6()
return nil, nil
}
func opSwap7(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap7()
return nil, nil
}
func opSwap8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap8()
return nil, nil
}
func opSwap9(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap9()
return nil, nil
}
func opSwap10(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap10()
return nil, nil
}
func opSwap11(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap11()
return nil, nil
}
func opSwap12(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap12()
return nil, nil
}
func opSwap13(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap13()
return nil, nil
}
func opSwap14(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap14()
return nil, nil
}
func opSwap15(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap15()
return nil, nil
}
func opSwap16(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap16()
return nil, nil
}
func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly { if interpreter.readOnly {
return nil, ErrWriteProtection return nil, ErrWriteProtection
@ -923,13 +1003,3 @@ func makeDup(size int64) executionFunc {
return nil, nil return nil, nil
} }
} }
// make swap instruction function
func makeSwap(size int64) executionFunc {
// switch n + 1 otherwise n would be swapped with n
size++
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.swap(int(size))
return nil, nil
}
}

View file

@ -892,97 +892,97 @@ func newFrontierInstructionSet() JumpTable {
maxStack: maxDupStack(16), maxStack: maxDupStack(16),
}, },
SWAP1: { SWAP1: {
execute: makeSwap(1), execute: opSwap1,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(2), minStack: minSwapStack(2),
maxStack: maxSwapStack(2), maxStack: maxSwapStack(2),
}, },
SWAP2: { SWAP2: {
execute: makeSwap(2), execute: opSwap2,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(3), minStack: minSwapStack(3),
maxStack: maxSwapStack(3), maxStack: maxSwapStack(3),
}, },
SWAP3: { SWAP3: {
execute: makeSwap(3), execute: opSwap3,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(4), minStack: minSwapStack(4),
maxStack: maxSwapStack(4), maxStack: maxSwapStack(4),
}, },
SWAP4: { SWAP4: {
execute: makeSwap(4), execute: opSwap4,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(5), minStack: minSwapStack(5),
maxStack: maxSwapStack(5), maxStack: maxSwapStack(5),
}, },
SWAP5: { SWAP5: {
execute: makeSwap(5), execute: opSwap5,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(6), minStack: minSwapStack(6),
maxStack: maxSwapStack(6), maxStack: maxSwapStack(6),
}, },
SWAP6: { SWAP6: {
execute: makeSwap(6), execute: opSwap6,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(7), minStack: minSwapStack(7),
maxStack: maxSwapStack(7), maxStack: maxSwapStack(7),
}, },
SWAP7: { SWAP7: {
execute: makeSwap(7), execute: opSwap7,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(8), minStack: minSwapStack(8),
maxStack: maxSwapStack(8), maxStack: maxSwapStack(8),
}, },
SWAP8: { SWAP8: {
execute: makeSwap(8), execute: opSwap8,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(9), minStack: minSwapStack(9),
maxStack: maxSwapStack(9), maxStack: maxSwapStack(9),
}, },
SWAP9: { SWAP9: {
execute: makeSwap(9), execute: opSwap9,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(10), minStack: minSwapStack(10),
maxStack: maxSwapStack(10), maxStack: maxSwapStack(10),
}, },
SWAP10: { SWAP10: {
execute: makeSwap(10), execute: opSwap10,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(11), minStack: minSwapStack(11),
maxStack: maxSwapStack(11), maxStack: maxSwapStack(11),
}, },
SWAP11: { SWAP11: {
execute: makeSwap(11), execute: opSwap11,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(12), minStack: minSwapStack(12),
maxStack: maxSwapStack(12), maxStack: maxSwapStack(12),
}, },
SWAP12: { SWAP12: {
execute: makeSwap(12), execute: opSwap12,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(13), minStack: minSwapStack(13),
maxStack: maxSwapStack(13), maxStack: maxSwapStack(13),
}, },
SWAP13: { SWAP13: {
execute: makeSwap(13), execute: opSwap13,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(14), minStack: minSwapStack(14),
maxStack: maxSwapStack(14), maxStack: maxSwapStack(14),
}, },
SWAP14: { SWAP14: {
execute: makeSwap(14), execute: opSwap14,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(15), minStack: minSwapStack(15),
maxStack: maxSwapStack(15), maxStack: maxSwapStack(15),
}, },
SWAP15: { SWAP15: {
execute: makeSwap(15), execute: opSwap15,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(16), minStack: minSwapStack(16),
maxStack: maxSwapStack(16), maxStack: maxSwapStack(16),
}, },
SWAP16: { SWAP16: {
execute: makeSwap(16), execute: opSwap16,
constantGas: GasFastestStep, constantGas: GasFastestStep,
minStack: minSwapStack(17), minStack: minSwapStack(17),
maxStack: maxSwapStack(17), maxStack: maxSwapStack(17),

View file

@ -40,7 +40,6 @@ import (
// force-load js tracers to trigger registration // force-load js tracers to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js" _ "github.com/ethereum/go-ethereum/eth/tracers/js"
"github.com/holiman/uint256"
) )
func TestDefaults(t *testing.T) { func TestDefaults(t *testing.T) {
@ -215,6 +214,35 @@ func BenchmarkEVM_CREATE2_1200(bench *testing.B) {
benchmarkEVM_Create(bench, "5b5862124f80600080f5600152600056") benchmarkEVM_Create(bench, "5b5862124f80600080f5600152600056")
} }
func BenchmarkEVM_SWAP1(b *testing.B) {
// returns a contract that does n swaps (SWAP1)
swapContract := func(n uint64) []byte {
contract := []byte{
byte(vm.PUSH0), // PUSH0
byte(vm.PUSH0), // PUSH0
}
for i := uint64(0); i < n; i++ {
contract = append(contract, byte(vm.SWAP1))
}
return contract
}
state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
contractAddr := common.BytesToAddress([]byte("contract"))
b.Run("10k", func(b *testing.B) {
contractCode := swapContract(10_000)
state.SetCode(contractAddr, contractCode)
for i := 0; i < b.N; i++ {
_, _, err := Call(contractAddr, []byte{}, &Config{State: state})
if err != nil {
b.Fatal(err)
}
}
})
}
func BenchmarkEVM_RETURN(b *testing.B) { func BenchmarkEVM_RETURN(b *testing.B) {
// returns a contract that returns a zero-byte slice of len size // returns a contract that returns a zero-byte slice of len size
returnContract := func(size uint64) []byte { returnContract := func(size uint64) []byte {
@ -376,11 +404,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
Tracer: tracer.Hooks, Tracer: tracer.Hooks,
} }
} }
var ( destination := common.BytesToAddress([]byte("contract"))
destination = common.BytesToAddress([]byte("contract"))
vmenv = NewEnv(cfg)
sender = vm.AccountRef(cfg.Origin)
)
cfg.State.CreateAccount(destination) cfg.State.CreateAccount(destination)
eoa := common.HexToAddress("E0") eoa := common.HexToAddress("E0")
{ {
@ -400,12 +424,12 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
//cfg.State.CreateAccount(cfg.Origin) //cfg.State.CreateAccount(cfg.Origin)
// set the receiver's (the executing contract) code for execution. // set the receiver's (the executing contract) code for execution.
cfg.State.SetCode(destination, code) cfg.State.SetCode(destination, code)
vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value)) Call(destination, nil, cfg)
b.Run(name, func(b *testing.B) { b.Run(name, func(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value)) Call(destination, nil, cfg)
} }
}) })
} }

View file

@ -30,7 +30,7 @@ var stackPool = sync.Pool{
// Stack is an object for basic stack operations. Items popped to the stack are // Stack is an object for basic stack operations. Items popped to the stack are
// expected to be changed and modified. stack does not take care of adding newly // expected to be changed and modified. stack does not take care of adding newly
// initialised objects. // initialized objects.
type Stack struct { type Stack struct {
data []uint256.Int data []uint256.Int
} }
@ -64,8 +64,53 @@ func (st *Stack) len() int {
return len(st.data) return len(st.data)
} }
func (st *Stack) swap(n int) { func (st *Stack) swap1() {
st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n] st.data[st.len()-2], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-2]
}
func (st *Stack) swap2() {
st.data[st.len()-3], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-3]
}
func (st *Stack) swap3() {
st.data[st.len()-4], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-4]
}
func (st *Stack) swap4() {
st.data[st.len()-5], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-5]
}
func (st *Stack) swap5() {
st.data[st.len()-6], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-6]
}
func (st *Stack) swap6() {
st.data[st.len()-7], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-7]
}
func (st *Stack) swap7() {
st.data[st.len()-8], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-8]
}
func (st *Stack) swap8() {
st.data[st.len()-9], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-9]
}
func (st *Stack) swap9() {
st.data[st.len()-10], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-10]
}
func (st *Stack) swap10() {
st.data[st.len()-11], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-11]
}
func (st *Stack) swap11() {
st.data[st.len()-12], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-12]
}
func (st *Stack) swap12() {
st.data[st.len()-13], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-13]
}
func (st *Stack) swap13() {
st.data[st.len()-14], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-14]
}
func (st *Stack) swap14() {
st.data[st.len()-15], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-15]
}
func (st *Stack) swap15() {
st.data[st.len()-16], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-16]
}
func (st *Stack) swap16() {
st.data[st.len()-17], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-17]
} }
func (st *Stack) dup(n int) { func (st *Stack) dup(n int) {

View file

@ -88,10 +88,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
return nil, errors.New("invalid private key") return nil, errors.New("invalid private key")
} }
defer priv.Zero() defer priv.Zero()
sig, err := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey sig := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey
if err != nil {
return nil, err
}
// Convert to Ethereum signature format with 'recovery id' v at the end. // Convert to Ethereum signature format with 'recovery id' v at the end.
v := sig[0] - 27 v := sig[0] - 27
copy(sig, sig[1:]) copy(sig, sig[1:])

View file

@ -264,11 +264,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
if eth.APIBackend.allowUnprotectedTxs { if eth.APIBackend.allowUnprotectedTxs {
log.Info("Unprotected transactions allowed") log.Info("Unprotected transactions allowed")
} }
gpoParams := config.GPO eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice)
if gpoParams.Default == nil {
gpoParams.Default = config.Miner.GasPrice
}
eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams)
// Setup DNS discovery iterators. // Setup DNS discovery iterators.
dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) dnsclient := dnsdisc.NewClient(dnsdisc.Config{})

View file

@ -546,7 +546,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
bgu = strconv.Itoa(int(*params.BlobGasUsed)) bgu = strconv.Itoa(int(*params.BlobGasUsed))
} }
ebg := "nil" ebg := "nil"
if params.BlobGasUsed != nil { if params.ExcessBlobGas != nil {
ebg = strconv.Itoa(int(*params.ExcessBlobGas)) ebg = strconv.Itoa(int(*params.ExcessBlobGas))
} }
log.Warn("Invalid NewPayload params", log.Warn("Invalid NewPayload params",

View file

@ -302,7 +302,7 @@ func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error {
return errors.New("parent not found") return errors.New("parent not found")
} }
withdrawals := c.withdrawals.gatherPending(10) withdrawals := c.withdrawals.gatherPending(10)
return c.sealBlock(withdrawals, parent.Time+uint64(adjustment)) return c.sealBlock(withdrawals, parent.Time+uint64(adjustment/time.Second))
} }
func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) { func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) {

View file

@ -123,7 +123,8 @@ func (b *beaconBackfiller) resume() {
func (b *beaconBackfiller) setMode(mode SyncMode) { func (b *beaconBackfiller) setMode(mode SyncMode) {
// Update the old sync mode and track if it was changed // Update the old sync mode and track if it was changed
b.lock.Lock() b.lock.Lock()
updated := b.syncMode != mode oldMode := b.syncMode
updated := oldMode != mode
filling := b.filling filling := b.filling
b.syncMode = mode b.syncMode = mode
b.lock.Unlock() b.lock.Unlock()
@ -133,7 +134,7 @@ func (b *beaconBackfiller) setMode(mode SyncMode) {
if !updated || !filling { if !updated || !filling {
return return
} }
log.Error("Downloader sync mode changed mid-run", "old", mode.String(), "new", mode.String()) log.Error("Downloader sync mode changed mid-run", "old", oldMode.String(), "new", mode.String())
b.suspend() b.suspend()
b.resume() b.resume()
} }

View file

@ -59,7 +59,7 @@ func TestFeeHistory(t *testing.T) {
MaxBlockHistory: c.maxBlock, MaxBlockHistory: c.maxBlock,
} }
backend := newTestBackend(t, big.NewInt(16), big.NewInt(28), c.pending) backend := newTestBackend(t, big.NewInt(16), big.NewInt(28), c.pending)
oracle := NewOracle(backend, config) oracle := NewOracle(backend, config, nil)
first, reward, baseFee, ratio, blobBaseFee, blobRatio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent) first, reward, baseFee, ratio, blobBaseFee, blobRatio, err := oracle.FeeHistory(context.Background(), c.count, c.last, c.percent)
backend.teardown() backend.teardown()

View file

@ -45,7 +45,6 @@ type Config struct {
Percentile int Percentile int
MaxHeaderHistory uint64 MaxHeaderHistory uint64
MaxBlockHistory uint64 MaxBlockHistory uint64
Default *big.Int `toml:",omitempty"`
MaxPrice *big.Int `toml:",omitempty"` MaxPrice *big.Int `toml:",omitempty"`
IgnorePrice *big.Int `toml:",omitempty"` IgnorePrice *big.Int `toml:",omitempty"`
} }
@ -79,7 +78,7 @@ type Oracle struct {
// NewOracle returns a new gasprice oracle which can recommend suitable // NewOracle returns a new gasprice oracle which can recommend suitable
// gasprice for newly created transaction. // gasprice for newly created transaction.
func NewOracle(backend OracleBackend, params Config) *Oracle { func NewOracle(backend OracleBackend, params Config, startPrice *big.Int) *Oracle {
blocks := params.Blocks blocks := params.Blocks
if blocks < 1 { if blocks < 1 {
blocks = 1 blocks = 1
@ -115,6 +114,9 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
maxBlockHistory = 1 maxBlockHistory = 1
log.Warn("Sanitizing invalid gasprice oracle max block history", "provided", params.MaxBlockHistory, "updated", maxBlockHistory) log.Warn("Sanitizing invalid gasprice oracle max block history", "provided", params.MaxBlockHistory, "updated", maxBlockHistory)
} }
if startPrice == nil {
startPrice = new(big.Int)
}
cache := lru.NewCache[cacheKey, processedFees](2048) cache := lru.NewCache[cacheKey, processedFees](2048)
headEvent := make(chan core.ChainHeadEvent, 1) headEvent := make(chan core.ChainHeadEvent, 1)
@ -131,7 +133,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
return &Oracle{ return &Oracle{
backend: backend, backend: backend,
lastPrice: params.Default, lastPrice: startPrice,
maxPrice: maxPrice, maxPrice: maxPrice,
ignorePrice: ignorePrice, ignorePrice: ignorePrice,
checkBlocks: blocks, checkBlocks: blocks,

View file

@ -235,7 +235,6 @@ func TestSuggestTipCap(t *testing.T) {
config := Config{ config := Config{
Blocks: 3, Blocks: 3,
Percentile: 60, Percentile: 60,
Default: big.NewInt(params.GWei),
} }
var cases = []struct { var cases = []struct {
fork *big.Int // London fork number fork *big.Int // London fork number
@ -249,7 +248,7 @@ func TestSuggestTipCap(t *testing.T) {
} }
for _, c := range cases { for _, c := range cases {
backend := newTestBackend(t, c.fork, nil, false) backend := newTestBackend(t, c.fork, nil, false)
oracle := NewOracle(backend, config) oracle := NewOracle(backend, config, big.NewInt(params.GWei))
// The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G // The gas price sampled is: 32G, 31G, 30G, 29G, 28G, 27G
got, err := oracle.SuggestTipCap(context.Background()) got, err := oracle.SuggestTipCap(context.Background())

View file

@ -843,7 +843,7 @@ func TestTracingWithOverrides(t *testing.T) {
byte(vm.PUSH1), 00, byte(vm.PUSH1), 00,
byte(vm.RETURN), byte(vm.RETURN),
}), }),
StateDiff: &map[common.Hash]common.Hash{ StateDiff: map[common.Hash]common.Hash{
common.HexToHash("0x03"): common.HexToHash("0x11"), common.HexToHash("0x03"): common.HexToHash("0x11"),
}, },
}, },
@ -898,9 +898,9 @@ func newAccounts(n int) (accounts []Account) {
return accounts return accounts
} }
func newRPCBalance(balance *big.Int) **hexutil.Big { func newRPCBalance(balance *big.Int) *hexutil.Big {
rpcBalance := (*hexutil.Big)(balance) rpcBalance := (*hexutil.Big)(balance)
return &rpcBalance return rpcBalance
} }
func newRPCBytes(bytes []byte) *hexutil.Bytes { func newRPCBytes(bytes []byte) *hexutil.Bytes {
@ -908,7 +908,7 @@ func newRPCBytes(bytes []byte) *hexutil.Bytes {
return &rpcBytes return &rpcBytes
} }
func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash { func newStates(keys []common.Hash, vals []common.Hash) map[common.Hash]common.Hash {
if len(keys) != len(vals) { if len(keys) != len(vals) {
panic("invalid input") panic("invalid input")
} }
@ -916,7 +916,7 @@ func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.H
for i := 0; i < len(keys); i++ { for i := 0; i < len(keys); i++ {
m[keys[i]] = vals[i] m[keys[i]] = vals[i]
} }
return &m return m
} }
func TestTraceChain(t *testing.T) { func TestTraceChain(t *testing.T) {

View file

@ -359,7 +359,7 @@ func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) {
if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil { if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil {
return nil, err return nil, err
} }
if _, ok := version.SetString(ver, 10); !ok { if _, ok := version.SetString(ver, 0); !ok {
return nil, fmt.Errorf("invalid net_version result %q", ver) return nil, fmt.Errorf("invalid net_version result %q", ver)
} }
return version, nil return version, nil

View file

@ -106,7 +106,7 @@ func TestAdjustTime(t *testing.T) {
block2, _ := client.BlockByNumber(context.Background(), nil) block2, _ := client.BlockByNumber(context.Background(), nil)
prevTime := block1.Time() prevTime := block1.Time()
newTime := block2.Time() newTime := block2.Time()
if newTime-prevTime != uint64(time.Minute) { if newTime-prevTime != 60 {
t.Errorf("adjusted time not equal to 60 seconds. prev: %v, new: %v", prevTime, newTime) t.Errorf("adjusted time not equal to 60 seconds. prev: %v, new: %v", prevTime, newTime)
} }
} }

View file

@ -64,7 +64,6 @@ type KeyValueStore interface {
Batcher Batcher
Iteratee Iteratee
Compacter Compacter
Snapshotter
io.Closer io.Closer
} }
@ -199,6 +198,5 @@ type Database interface {
Iteratee Iteratee
Stater Stater
Compacter Compacter
Snapshotter
io.Closer io.Closer
} }

View file

@ -318,69 +318,6 @@ func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) {
} }
}) })
t.Run("Snapshot", func(t *testing.T) {
db := New()
defer db.Close()
initial := map[string]string{
"k1": "v1", "k2": "v2", "k3": "", "k4": "",
}
for k, v := range initial {
db.Put([]byte(k), []byte(v))
}
snapshot, err := db.NewSnapshot()
if err != nil {
t.Fatal(err)
}
for k, v := range initial {
got, err := snapshot.Get([]byte(k))
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(got, []byte(v)) {
t.Fatalf("Unexpected value want: %v, got %v", v, got)
}
}
// Flush more modifications into the database, ensure the snapshot
// isn't affected.
var (
update = map[string]string{"k1": "v1-b", "k3": "v3-b"}
insert = map[string]string{"k5": "v5-b"}
delete = map[string]string{"k2": ""}
)
for k, v := range update {
db.Put([]byte(k), []byte(v))
}
for k, v := range insert {
db.Put([]byte(k), []byte(v))
}
for k := range delete {
db.Delete([]byte(k))
}
for k, v := range initial {
got, err := snapshot.Get([]byte(k))
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(got, []byte(v)) {
t.Fatalf("Unexpected value want: %v, got %v", v, got)
}
}
for k := range insert {
got, err := snapshot.Get([]byte(k))
if err == nil || len(got) != 0 {
t.Fatal("Unexpected value")
}
}
for k := range delete {
got, err := snapshot.Get([]byte(k))
if err != nil || len(got) == 0 {
t.Fatal("Unexpected deletion")
}
}
})
t.Run("OperationsAfterClose", func(t *testing.T) { t.Run("OperationsAfterClose", func(t *testing.T) {
db := New() db := New()
db.Put([]byte("key"), []byte("value")) db.Put([]byte("key"), []byte("value"))

View file

@ -230,19 +230,6 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
return db.db.NewIterator(bytesPrefixRange(prefix, start), nil) return db.db.NewIterator(bytesPrefixRange(prefix, start), nil)
} }
// NewSnapshot creates a database snapshot based on the current state.
// The created snapshot will not be affected by all following mutations
// happened on the database.
// Note don't forget to release the snapshot once it's used up, otherwise
// the stale data will never be cleaned up by the underlying compactor.
func (db *Database) NewSnapshot() (ethdb.Snapshot, error) {
snap, err := db.db.GetSnapshot()
if err != nil {
return nil, err
}
return &snapshot{db: snap}, nil
}
// Stat returns the statistic data of the database. // Stat returns the statistic data of the database.
func (db *Database) Stat() (string, error) { func (db *Database) Stat() (string, error) {
var stats leveldb.DBStats var stats leveldb.DBStats
@ -498,26 +485,3 @@ func bytesPrefixRange(prefix, start []byte) *util.Range {
r.Start = append(r.Start, start...) r.Start = append(r.Start, start...)
return r return r
} }
// snapshot wraps a leveldb snapshot for implementing the Snapshot interface.
type snapshot struct {
db *leveldb.Snapshot
}
// Has retrieves if a key is present in the snapshot backing by a key-value
// data store.
func (snap *snapshot) Has(key []byte) (bool, error) {
return snap.db.Has(key, nil)
}
// Get retrieves the given key if it's present in the snapshot backing by
// key-value data store.
func (snap *snapshot) Get(key []byte) ([]byte, error) {
return snap.db.Get(key, nil)
}
// Release releases associated resources. Release should always succeed and can
// be called multiple times without causing error.
func (snap *snapshot) Release() {
snap.db.Release()
}

View file

@ -35,10 +35,6 @@ var (
// errMemorydbNotFound is returned if a key is requested that is not found in // errMemorydbNotFound is returned if a key is requested that is not found in
// the provided memory database. // the provided memory database.
errMemorydbNotFound = errors.New("not found") errMemorydbNotFound = errors.New("not found")
// errSnapshotReleased is returned if callers want to retrieve data from a
// released snapshot.
errSnapshotReleased = errors.New("snapshot released")
) )
// Database is an ephemeral key-value store. Apart from basic data storage // Database is an ephemeral key-value store. Apart from basic data storage
@ -175,13 +171,6 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
} }
} }
// NewSnapshot creates a database snapshot based on the current state.
// The created snapshot will not be affected by all following mutations
// happened on the database.
func (db *Database) NewSnapshot() (ethdb.Snapshot, error) {
return newSnapshot(db), nil
}
// Stat returns the statistic data of the database. // Stat returns the statistic data of the database.
func (db *Database) Stat() (string, error) { func (db *Database) Stat() (string, error) {
return "", nil return "", nil
@ -332,59 +321,3 @@ func (it *iterator) Value() []byte {
func (it *iterator) Release() { func (it *iterator) Release() {
it.index, it.keys, it.values = -1, nil, nil it.index, it.keys, it.values = -1, nil, nil
} }
// snapshot wraps a batch of key-value entries deep copied from the in-memory
// database for implementing the Snapshot interface.
type snapshot struct {
db map[string][]byte
lock sync.RWMutex
}
// newSnapshot initializes the snapshot with the given database instance.
func newSnapshot(db *Database) *snapshot {
db.lock.RLock()
defer db.lock.RUnlock()
copied := make(map[string][]byte, len(db.db))
for key, val := range db.db {
copied[key] = common.CopyBytes(val)
}
return &snapshot{db: copied}
}
// Has retrieves if a key is present in the snapshot backing by a key-value
// data store.
func (snap *snapshot) Has(key []byte) (bool, error) {
snap.lock.RLock()
defer snap.lock.RUnlock()
if snap.db == nil {
return false, errSnapshotReleased
}
_, ok := snap.db[string(key)]
return ok, nil
}
// Get retrieves the given key if it's present in the snapshot backing by
// key-value data store.
func (snap *snapshot) Get(key []byte) ([]byte, error) {
snap.lock.RLock()
defer snap.lock.RUnlock()
if snap.db == nil {
return nil, errSnapshotReleased
}
if entry, ok := snap.db[string(key)]; ok {
return common.CopyBytes(entry), nil
}
return nil, errMemorydbNotFound
}
// Release releases associated resources. Release should always succeed and can
// be called multiple times without causing error.
func (snap *snapshot) Release() {
snap.lock.Lock()
defer snap.lock.Unlock()
snap.db = nil
}

View file

@ -351,55 +351,6 @@ func (d *Database) NewBatchWithSize(size int) ethdb.Batch {
} }
} }
// snapshot wraps a pebble snapshot for implementing the Snapshot interface.
type snapshot struct {
db *pebble.Snapshot
}
// NewSnapshot creates a database snapshot based on the current state.
// The created snapshot will not be affected by all following mutations
// happened on the database.
// Note don't forget to release the snapshot once it's used up, otherwise
// the stale data will never be cleaned up by the underlying compactor.
func (d *Database) NewSnapshot() (ethdb.Snapshot, error) {
snap := d.db.NewSnapshot()
return &snapshot{db: snap}, nil
}
// Has retrieves if a key is present in the snapshot backing by a key-value
// data store.
func (snap *snapshot) Has(key []byte) (bool, error) {
_, closer, err := snap.db.Get(key)
if err != nil {
if err != pebble.ErrNotFound {
return false, err
} else {
return false, nil
}
}
closer.Close()
return true, nil
}
// Get retrieves the given key if it's present in the snapshot backing by
// key-value data store.
func (snap *snapshot) Get(key []byte) ([]byte, error) {
dat, closer, err := snap.db.Get(key)
if err != nil {
return nil, err
}
ret := make([]byte, len(dat))
copy(ret, dat)
closer.Close()
return ret, nil
}
// Release releases associated resources. Release should always succeed and can
// be called multiple times without causing error.
func (snap *snapshot) Release() {
snap.db.Close()
}
// upperBound returns the upper bound for the given prefix // upperBound returns the upper bound for the given prefix
func upperBound(prefix []byte) (limit []byte) { func upperBound(prefix []byte) (limit []byte) {
for i := len(prefix) - 1; i >= 0; i-- { for i := len(prefix) - 1; i >= 0; i-- {

View file

@ -138,10 +138,6 @@ func (db *Database) Compact(start []byte, limit []byte) error {
return nil return nil
} }
func (db *Database) NewSnapshot() (ethdb.Snapshot, error) {
panic("not supported")
}
func (db *Database) Close() error { func (db *Database) Close() error {
db.remote.Close() db.remote.Close()
return nil return nil

View file

@ -1,41 +0,0 @@
// Copyright 2022 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 ethdb
type Snapshot interface {
// Has retrieves if a key is present in the snapshot backing by a key-value
// data store.
Has(key []byte) (bool, error)
// Get retrieves the given key if it's present in the snapshot backing by
// key-value data store.
Get(key []byte) ([]byte, error)
// Release releases associated resources. Release should always succeed and can
// be called multiple times without causing error.
Release()
}
// Snapshotter wraps the Snapshot method of a backing data store.
type Snapshotter interface {
// NewSnapshot creates a database snapshot based on the current state.
// The created snapshot will not be affected by all following mutations
// happened on the database.
// Note don't forget to release the snapshot once it's used up, otherwise
// the stale data will never be cleaned up by the underlying compactor.
NewSnapshot() (Snapshot, error)
}

7
go.mod
View file

@ -10,7 +10,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/config v1.18.45
github.com/aws/aws-sdk-go-v2/credentials v1.13.43 github.com/aws/aws-sdk-go-v2/credentials v1.13.43
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/btcsuite/btcd/btcec/v2 v2.3.4
github.com/cespare/cp v0.1.0 github.com/cespare/cp v0.1.0
github.com/cloudflare/cloudflare-go v0.79.0 github.com/cloudflare/cloudflare-go v0.79.0
github.com/cockroachdb/pebble v1.1.1 github.com/cockroachdb/pebble v1.1.1
@ -26,12 +26,10 @@ require (
github.com/fatih/color v1.16.0 github.com/fatih/color v1.16.0
github.com/ferranbt/fastssz v0.1.2 github.com/ferranbt/fastssz v0.1.2
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.2
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/protobuf v1.5.4
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/gofuzz v1.2.0 github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
@ -74,7 +72,7 @@ require (
golang.org/x/text v0.14.0 golang.org/x/text v0.14.0
golang.org/x/time v0.5.0 golang.org/x/time v0.5.0
golang.org/x/tools v0.20.0 golang.org/x/tools v0.20.0
google.golang.org/protobuf v1.33.0 google.golang.org/protobuf v1.34.2
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@ -112,6 +110,7 @@ require (
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect

8
go.sum
View file

@ -92,8 +92,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -178,8 +178,6 @@ github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNP
github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@ -842,6 +840,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View file

@ -31,15 +31,12 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/metrics/exp" "github.com/ethereum/go-ethereum/metrics/exp"
"github.com/fjl/memsize/memsizeui"
"github.com/mattn/go-colorable" "github.com/mattn/go-colorable"
"github.com/mattn/go-isatty" "github.com/mattn/go-isatty"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
) )
var Memsize memsizeui.Handler
var ( var (
verbosityFlag = &cli.IntFlag{ verbosityFlag = &cli.IntFlag{
Name: "verbosity", Name: "verbosity",
@ -313,7 +310,6 @@ func StartPProf(address string, withMetrics bool) {
if withMetrics { if withMetrics {
exp.Exp(metrics.DefaultRegistry) exp.Exp(metrics.DefaultRegistry)
} }
http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize))
log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address))
go func() { go func() {
if err := http.ListenAndServe(address, nil); err != nil { if err := http.ListenAndServe(address, nil); err != nil {

View file

@ -968,11 +968,11 @@ func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rp
// if stateDiff is set, all diff will be applied first and then execute the call // if stateDiff is set, all diff will be applied first and then execute the call
// message. // message.
type OverrideAccount struct { type OverrideAccount struct {
Nonce *hexutil.Uint64 `json:"nonce"` Nonce *hexutil.Uint64 `json:"nonce"`
Code *hexutil.Bytes `json:"code"` Code *hexutil.Bytes `json:"code"`
Balance **hexutil.Big `json:"balance"` Balance *hexutil.Big `json:"balance"`
State *map[common.Hash]common.Hash `json:"state"` State map[common.Hash]common.Hash `json:"state"`
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"` StateDiff map[common.Hash]common.Hash `json:"stateDiff"`
} }
// StateOverride is the collection of overridden accounts. // StateOverride is the collection of overridden accounts.
@ -994,7 +994,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error {
} }
// Override account balance. // Override account balance.
if account.Balance != nil { if account.Balance != nil {
u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance)) u256Balance, _ := uint256.FromBig((*big.Int)(account.Balance))
statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified)
} }
if account.State != nil && account.StateDiff != nil { if account.State != nil && account.StateDiff != nil {
@ -1002,11 +1002,11 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error {
} }
// Replace entire state if caller requires. // Replace entire state if caller requires.
if account.State != nil { if account.State != nil {
statedb.SetStorage(addr, *account.State) statedb.SetStorage(addr, account.State)
} }
// Apply state diff into specified accounts. // Apply state diff into specified accounts.
if account.StateDiff != nil { if account.StateDiff != nil {
for key, value := range *account.StateDiff { for key, value := range account.StateDiff {
statedb.SetState(addr, key, value) statedb.SetState(addr, key, value)
} }
} }

View file

@ -781,15 +781,24 @@ func TestEstimateGas(t *testing.T) {
func TestCall(t *testing.T) { func TestCall(t *testing.T) {
t.Parallel() t.Parallel()
// Initialize test accounts // Initialize test accounts
var ( var (
accounts = newAccounts(3) accounts = newAccounts(3)
dad = common.HexToAddress("0x0000000000000000000000000000000000000dad")
genesis = &core.Genesis{ genesis = &core.Genesis{
Config: params.MergedTestChainConfig, Config: params.MergedTestChainConfig,
Alloc: types.GenesisAlloc{ Alloc: types.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)}, accounts[2].addr: {Balance: big.NewInt(params.Ether)},
dad: {
Balance: big.NewInt(params.Ether),
Nonce: 1,
Storage: map[common.Hash]common.Hash{
common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"),
},
},
}, },
} }
genBlocks = 10 genBlocks = 10
@ -904,7 +913,7 @@ func TestCall(t *testing.T) {
overrides: StateOverride{ overrides: StateOverride{
randomAccounts[2].addr: OverrideAccount{ randomAccounts[2].addr: OverrideAccount{
Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"), Code: hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"),
StateDiff: &map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))}, StateDiff: map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))},
}, },
}, },
want: "0x000000000000000000000000000000000000000000000000000000000000007b", want: "0x000000000000000000000000000000000000000000000000000000000000007b",
@ -949,6 +958,32 @@ func TestCall(t *testing.T) {
}, },
want: "0x0122000000000000000000000000000000000000000000000000000000000000", want: "0x0122000000000000000000000000000000000000000000000000000000000000",
}, },
// Clear the entire storage set
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[1].addr,
// Yul:
// object "Test" {
// code {
// let dad := 0x0000000000000000000000000000000000000dad
// if eq(balance(dad), 0) {
// revert(0, 0)
// }
// let slot := sload(0)
// mstore(0, slot)
// return(0, 32)
// }
// }
Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"),
},
overrides: StateOverride{
dad: OverrideAccount{
State: map[common.Hash]common.Hash{},
},
},
want: "0x0000000000000000000000000000000000000000000000000000000000000000",
},
} }
for i, tc := range testSuite { for i, tc := range testSuite {
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
@ -1308,9 +1343,9 @@ func newAccounts(n int) (accounts []account) {
return accounts return accounts
} }
func newRPCBalance(balance *big.Int) **hexutil.Big { func newRPCBalance(balance *big.Int) *hexutil.Big {
rpcBalance := (*hexutil.Big)(balance) rpcBalance := (*hexutil.Big)(balance)
return &rpcBalance return rpcBalance
} }
func hex2Bytes(str string) *hexutil.Bytes { func hex2Bytes(str string) *hexutil.Bytes {

View file

@ -205,8 +205,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error)
// makeEnv creates a new environment for the sealing block. // makeEnv creates a new environment for the sealing block.
func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) { func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address) (*environment, error) {
// Retrieve the parent state to execute on top and start a prefetcher for // Retrieve the parent state to execute on top.
// the miner to speed block sealing up a bit.
state, err := miner.chain.StateAt(parent.Root) state, err := miner.chain.StateAt(parent.Root)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -17,16 +17,10 @@
package discover package discover
import ( import (
"crypto/ecdsa"
"crypto/elliptic"
"errors"
"math/big"
"slices" "slices"
"sort" "sort"
"time" "time"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
) )
@ -48,33 +42,6 @@ type tableNode struct {
isValidatedLive bool // true if existence of node is considered validated right now isValidatedLive bool // true if existence of node is considered validated right now
} }
type encPubkey [64]byte
func encodePubkey(key *ecdsa.PublicKey) encPubkey {
var e encPubkey
math.ReadBits(key.X, e[:len(e)/2])
math.ReadBits(key.Y, e[len(e)/2:])
return e
}
func decodePubkey(curve elliptic.Curve, e []byte) (*ecdsa.PublicKey, error) {
if len(e) != len(encPubkey{}) {
return nil, errors.New("wrong size public key data")
}
p := &ecdsa.PublicKey{Curve: curve, X: new(big.Int), Y: new(big.Int)}
half := len(e) / 2
p.X.SetBytes(e[:half])
p.Y.SetBytes(e[half:])
if !p.Curve.IsOnCurve(p.X, p.Y) {
return nil, errors.New("invalid curve point")
}
return p, nil
}
func (e encPubkey) id() enode.ID {
return enode.ID(crypto.Keccak256Hash(e[:]))
}
func unwrapNodes(ns []*tableNode) []*enode.Node { func unwrapNodes(ns []*tableNode) []*enode.Node {
result := make([]*enode.Node, len(ns)) result := make([]*enode.Node, len(ns))
for i, n := range ns { for i, n := range ns {

View file

@ -77,14 +77,18 @@ func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *tableNode) {
// It returns the next time it should be invoked, which is used in the Table main loop // It returns the next time it should be invoked, which is used in the Table main loop
// to schedule a timer. However, run can be called at any time. // to schedule a timer. However, run can be called at any time.
func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) {
if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { reval := func(list *revalidationList) {
tr.startRequest(tab, n) if list.nextTime <= now {
tr.fast.schedule(now, &tab.rand) if n := list.get(now, &tab.rand, tr.activeReq); n != nil {
} tr.startRequest(tab, n)
if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { }
tr.startRequest(tab, n) // Update nextTime regardless if any requests were started because
tr.slow.schedule(now, &tab.rand) // current value has passed.
list.schedule(now, &tab.rand)
}
} }
reval(&tr.fast)
reval(&tr.slow)
return min(tr.fast.nextTime, tr.slow.nextTime) return min(tr.fast.nextTime, tr.slow.nextTime)
} }
@ -200,7 +204,7 @@ type revalidationList struct {
// get returns a random node from the queue. Nodes in the 'exclude' map are not returned. // get returns a random node from the queue. Nodes in the 'exclude' map are not returned.
func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *tableNode { func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *tableNode {
if now < list.nextTime || len(list.nodes) == 0 { if len(list.nodes) == 0 {
return nil return nil
} }
for i := 0; i < len(list.nodes)*3; i++ { for i := 0; i < len(list.nodes)*3; i++ {

View file

@ -30,6 +30,7 @@ import (
"time" "time"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/discover/v4wire"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
) )
@ -284,7 +285,7 @@ func hexEncPrivkey(h string) *ecdsa.PrivateKey {
} }
// hexEncPubkey decodes h as a public key. // hexEncPubkey decodes h as a public key.
func hexEncPubkey(h string) (ret encPubkey) { func hexEncPubkey(h string) (ret v4wire.Pubkey) {
b, err := hex.DecodeString(h) b, err := hex.DecodeString(h)
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -34,7 +34,7 @@ func TestUDPv4_Lookup(t *testing.T) {
test := newUDPTest(t) test := newUDPTest(t)
// Lookup on empty table returns no nodes. // Lookup on empty table returns no nodes.
targetKey, _ := decodePubkey(crypto.S256(), lookupTestnet.target[:]) targetKey, _ := v4wire.DecodePubkey(crypto.S256(), lookupTestnet.target)
if results := test.udp.LookupPubkey(targetKey); len(results) > 0 { if results := test.udp.LookupPubkey(targetKey); len(results) > 0 {
t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results)
} }
@ -56,7 +56,7 @@ func TestUDPv4_Lookup(t *testing.T) {
results := <-resultC results := <-resultC
t.Logf("results:") t.Logf("results:")
for _, e := range results { for _, e := range results {
t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.target.id(), e.ID()), e.ID().Bytes()) t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.target.ID(), e.ID()), e.ID().Bytes())
} }
if len(results) != bucketSize { if len(results) != bucketSize {
t.Errorf("wrong number of results: got %d, want %d", len(results), bucketSize) t.Errorf("wrong number of results: got %d, want %d", len(results), bucketSize)
@ -142,7 +142,7 @@ func serveTestnet(test *udpTest, testnet *preminedTestnet) {
case *v4wire.Ping: case *v4wire.Ping:
test.packetInFrom(nil, key, to, &v4wire.Pong{Expiration: futureExp, ReplyTok: hash}) test.packetInFrom(nil, key, to, &v4wire.Pong{Expiration: futureExp, ReplyTok: hash})
case *v4wire.Findnode: case *v4wire.Findnode:
dist := enode.LogDist(n.ID(), testnet.target.id()) dist := enode.LogDist(n.ID(), testnet.target.ID())
nodes := testnet.nodesAtDistance(dist - 1) nodes := testnet.nodesAtDistance(dist - 1)
test.packetInFrom(nil, key, to, &v4wire.Neighbors{Expiration: futureExp, Nodes: nodes}) test.packetInFrom(nil, key, to, &v4wire.Neighbors{Expiration: futureExp, Nodes: nodes})
} }
@ -156,12 +156,12 @@ func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node
t.Helper() t.Helper()
t.Logf("results:") t.Logf("results:")
for _, e := range results { for _, e := range results {
t.Logf(" ld=%d, %x", enode.LogDist(tn.target.id(), e.ID()), e.ID().Bytes()) t.Logf(" ld=%d, %x", enode.LogDist(tn.target.ID(), e.ID()), e.ID().Bytes())
} }
if hasDuplicates(results) { if hasDuplicates(results) {
t.Errorf("result set contains duplicate entries") t.Errorf("result set contains duplicate entries")
} }
if !sortedByDistanceTo(tn.target.id(), results) { if !sortedByDistanceTo(tn.target.ID(), results) {
t.Errorf("result set not sorted by distance to target") t.Errorf("result set not sorted by distance to target")
} }
wantNodes := tn.closest(len(results)) wantNodes := tn.closest(len(results))
@ -231,7 +231,7 @@ var lookupTestnet = &preminedTestnet{
} }
type preminedTestnet struct { type preminedTestnet struct {
target encPubkey target v4wire.Pubkey
dists [hashBits + 1][]*ecdsa.PrivateKey dists [hashBits + 1][]*ecdsa.PrivateKey
} }
@ -304,7 +304,7 @@ func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) {
} }
} }
slices.SortFunc(nodes, func(a, b *enode.Node) int { slices.SortFunc(nodes, func(a, b *enode.Node) int {
return enode.DistCmp(tn.target.id(), a.ID(), b.ID()) return enode.DistCmp(tn.target.ID(), a.ID(), b.ID())
}) })
return nodes[:n] return nodes[:n]
} }
@ -319,11 +319,11 @@ func (tn *preminedTestnet) mine() {
tn.dists[i] = nil tn.dists[i] = nil
} }
targetSha := tn.target.id() targetSha := tn.target.ID()
found, need := 0, 40 found, need := 0, 40
for found < need { for found < need {
k := newkey() k := newkey()
ld := enode.LogDist(targetSha, encodePubkey(&k.PublicKey).id()) ld := enode.LogDist(targetSha, v4wire.EncodePubkey(&k.PublicKey).ID())
if len(tn.dists[ld]) < 8 { if len(tn.dists[ld]) < 8 {
tn.dists[ld] = append(tn.dists[ld], k) tn.dists[ld] = append(tn.dists[ld], k)
found++ found++

View file

@ -271,7 +271,7 @@ func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node {
// case and run the bootstrapping logic. // case and run the bootstrapping logic.
<-t.tab.refresh() <-t.tab.refresh()
} }
return t.newLookup(t.closeCtx, encodePubkey(key)).run() return t.newLookup(t.closeCtx, v4wire.EncodePubkey(key)).run()
} }
// RandomNodes is an iterator yielding nodes from a random walk of the DHT. // RandomNodes is an iterator yielding nodes from a random walk of the DHT.
@ -286,24 +286,24 @@ func (t *UDPv4) lookupRandom() []*enode.Node {
// lookupSelf implements transport. // lookupSelf implements transport.
func (t *UDPv4) lookupSelf() []*enode.Node { func (t *UDPv4) lookupSelf() []*enode.Node {
return t.newLookup(t.closeCtx, encodePubkey(&t.priv.PublicKey)).run() pubkey := v4wire.EncodePubkey(&t.priv.PublicKey)
return t.newLookup(t.closeCtx, pubkey).run()
} }
func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup { func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup {
var target encPubkey var target v4wire.Pubkey
crand.Read(target[:]) crand.Read(target[:])
return t.newLookup(ctx, target) return t.newLookup(ctx, target)
} }
func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup { func (t *UDPv4) newLookup(ctx context.Context, targetKey v4wire.Pubkey) *lookup {
target := enode.ID(crypto.Keccak256Hash(targetKey[:])) target := enode.ID(crypto.Keccak256Hash(targetKey[:]))
ekey := v4wire.Pubkey(targetKey)
it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) {
addr, ok := n.UDPEndpoint() addr, ok := n.UDPEndpoint()
if !ok { if !ok {
return nil, errNoUDPEndpoint return nil, errNoUDPEndpoint
} }
return t.findnode(n.ID(), addr, ekey) return t.findnode(n.ID(), addr, targetKey)
}) })
return it return it
} }

View file

@ -314,7 +314,7 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) {
// queue a pending findnode request // queue a pending findnode request
resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1)
go func() { go func() {
rid := encodePubkey(&test.remotekey.PublicKey).id() rid := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID()
ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget)
if err != nil && len(ns) == 0 { if err != nil && len(ns) == 0 {
errc <- err errc <- err
@ -433,7 +433,7 @@ func TestUDPv4_successfulPing(t *testing.T) {
// pong packet. // pong packet.
select { select {
case n := <-added: case n := <-added:
rid := encodePubkey(&test.remotekey.PublicKey).id() rid := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID()
if n.ID() != rid { if n.ID() != rid {
t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid)
} }

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/internal/testlog" "github.com/ethereum/go-ethereum/internal/testlog"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/discover/v4wire"
"github.com/ethereum/go-ethereum/p2p/discover/v5wire" "github.com/ethereum/go-ethereum/p2p/discover/v5wire"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
@ -576,7 +577,7 @@ func TestUDPv5_lookup(t *testing.T) {
test := newUDPV5Test(t) test := newUDPV5Test(t)
// Lookup on empty table returns no nodes. // Lookup on empty table returns no nodes.
if results := test.udp.Lookup(lookupTestnet.target.id()); len(results) > 0 { if results := test.udp.Lookup(lookupTestnet.target.ID()); len(results) > 0 {
t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results)
} }
@ -596,7 +597,7 @@ func TestUDPv5_lookup(t *testing.T) {
// Start the lookup. // Start the lookup.
resultC := make(chan []*enode.Node, 1) resultC := make(chan []*enode.Node, 1)
go func() { go func() {
resultC <- test.udp.Lookup(lookupTestnet.target.id()) resultC <- test.udp.Lookup(lookupTestnet.target.ID())
test.close() test.close()
}() }()
@ -793,7 +794,7 @@ func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr netip.AddrPort,
// getNode ensures the test knows about a node at the given endpoint. // getNode ensures the test knows about a node at the given endpoint.
func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr netip.AddrPort) *enode.LocalNode { func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr netip.AddrPort) *enode.LocalNode {
id := encodePubkey(&key.PublicKey).id() id := v4wire.EncodePubkey(&key.PublicKey).ID()
ln := test.nodesByID[id] ln := test.nodesByID[id]
if ln == nil { if ln == nil {
db, _ := enode.OpenDB("") db, _ := enode.OpenDB("")

View file

@ -177,7 +177,7 @@ func (v IPv4Addr) ENRKey() string { return "ip" }
func (v IPv4Addr) EncodeRLP(w io.Writer) error { func (v IPv4Addr) EncodeRLP(w io.Writer) error {
addr := netip.Addr(v) addr := netip.Addr(v)
if !addr.Is4() { if !addr.Is4() {
return fmt.Errorf("address is not IPv4") return errors.New("address is not IPv4")
} }
enc := rlp.NewEncoderBuffer(w) enc := rlp.NewEncoderBuffer(w)
bytes := addr.As4() bytes := addr.As4()
@ -204,7 +204,7 @@ func (v IPv6Addr) ENRKey() string { return "ip6" }
func (v IPv6Addr) EncodeRLP(w io.Writer) error { func (v IPv6Addr) EncodeRLP(w io.Writer) error {
addr := netip.Addr(v) addr := netip.Addr(v)
if !addr.Is6() { if !addr.Is6() {
return fmt.Errorf("address is not IPv6") return errors.New("address is not IPv6")
} }
enc := rlp.NewEncoderBuffer(w) enc := rlp.NewEncoderBuffer(w)
bytes := addr.As16() bytes := addr.As16()

View file

@ -138,8 +138,10 @@ func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", ne
// These do nothing. // These do nothing.
func (ExtIP) AddMapping(string, int, int, string, time.Duration) (uint16, error) { return 0, nil } func (ExtIP) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) {
func (ExtIP) DeleteMapping(string, int, int) error { return nil } return uint16(extport), nil
}
func (ExtIP) DeleteMapping(string, int, int) error { return nil }
// Any returns a port mapper that tries to discover any supported // Any returns a port mapper that tries to discover any supported
// mechanism on the local network. // mechanism on the local network.

View file

@ -125,7 +125,7 @@ func (srv *Server) portMappingLoop() {
if err != nil { if err != nil {
log.Debug("Couldn't get external IP", "err", err, "interface", srv.NAT) log.Debug("Couldn't get external IP", "err", err, "interface", srv.NAT)
} else if !ip.Equal(lastExtIP) { } else if !ip.Equal(lastExtIP) {
log.Debug("External IP changed", "ip", extip, "interface", srv.NAT) log.Debug("External IP changed", "ip", ip, "interface", srv.NAT)
} else { } else {
continue continue
} }

View file

@ -36,6 +36,7 @@ func TestServerPortMapping(t *testing.T) {
PrivateKey: newkey(), PrivateKey: newkey(),
NoDial: true, NoDial: true,
ListenAddr: ":0", ListenAddr: ":0",
DiscAddr: ":0",
NAT: mockNAT, NAT: mockNAT,
Logger: testlog.Logger(t, log.LvlTrace), Logger: testlog.Logger(t, log.LvlTrace),
clock: clock, clock: clock,

View file

@ -24,44 +24,13 @@ const (
// contains on the server side. // contains on the server side.
BloomBitsBlocks uint64 = 4096 BloomBitsBlocks uint64 = 4096
// BloomBitsBlocksClient is the number of blocks a single bloom bit section vector
// contains on the light client side
BloomBitsBlocksClient uint64 = 32768
// BloomConfirms is the number of confirmation blocks before a bloom section is // BloomConfirms is the number of confirmation blocks before a bloom section is
// considered probably final and its rotated bits are calculated. // considered probably final and its rotated bits are calculated.
BloomConfirms = 256 BloomConfirms = 256
// CHTFrequency is the block frequency for creating CHTs
CHTFrequency = 32768
// BloomTrieFrequency is the block frequency for creating BloomTrie on both
// server/client sides.
BloomTrieFrequency = 32768
// HelperTrieConfirmations is the number of confirmations before a client is expected
// to have the given HelperTrie available.
HelperTrieConfirmations = 2048
// HelperTrieProcessConfirmations is the number of confirmations before a HelperTrie
// is generated
HelperTrieProcessConfirmations = 256
// CheckpointFrequency is the block frequency for creating checkpoint
CheckpointFrequency = 32768
// CheckpointProcessConfirmations is the number before a checkpoint is generated
CheckpointProcessConfirmations = 256
// FullImmutabilityThreshold is the number of blocks after which a chain segment is // FullImmutabilityThreshold is the number of blocks after which a chain segment is
// considered immutable (i.e. soft finality). It is used by the downloader as a // considered immutable (i.e. soft finality). It is used by the downloader as a
// hard limit against deep ancestors, by the blockchain against deep reorgs, by // hard limit against deep ancestors, by the blockchain against deep reorgs, by
// the freezer as the cutoff threshold and by clique as the snapshot trust limit. // the freezer as the cutoff threshold and by clique as the snapshot trust limit.
FullImmutabilityThreshold = 90000 FullImmutabilityThreshold = 90000
// LightImmutabilityThreshold is the number of blocks after which a header chain
// segment is considered immutable for light client(i.e. soft finality). It is used by
// the downloader as a hard limit against deep ancestors, by the blockchain against deep
// reorgs, by the light pruner as the pruning validity guarantee.
LightImmutabilityThreshold = 30000
) )

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 14 // Minor version component of the current release VersionMinor = 14 // Minor version component of the current release
VersionPatch = 7 // Patch version component of the current release VersionPatch = 8 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

View file

@ -18,7 +18,9 @@ package rpc
import ( import (
"context" "context"
"errors"
"io" "io"
"net"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -151,8 +153,8 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) {
reqs, batch, err := codec.readBatch() reqs, batch, err := codec.readBatch()
if err != nil { if err != nil {
if err != io.EOF { if msg := messageForReadError(err); msg != "" {
resp := errorMessage(&invalidMessageError{"parse error"}) resp := errorMessage(&invalidMessageError{msg})
codec.writeJSON(ctx, resp, true) codec.writeJSON(ctx, resp, true)
} }
return return
@ -164,6 +166,20 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) {
} }
} }
func messageForReadError(err error) string {
var netErr net.Error
if errors.As(err, &netErr) {
if netErr.Timeout() {
return "read timeout"
} else {
return "read error"
}
} else if err != io.EOF {
return "parse error"
}
return ""
}
// Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending // Stop stops reading new requests, waits for stopPendingRequestTimeout to allow pending
// requests to finish, then closes all codecs which will cancel pending requests and // requests to finish, then closes all codecs which will cancel pending requests and
// subscriptions. // subscriptions.

View file

@ -267,13 +267,9 @@ func TestNotify(t *testing.T) {
sub: &Subscription{ID: id}, sub: &Subscription{ID: id},
activated: true, activated: true,
} }
msg := &types.Header{ notifier.Notify(id, "hello")
ParentHash: common.HexToHash("0x01"),
Number: big.NewInt(100),
}
notifier.Notify(id, msg)
have := strings.TrimSpace(out.String()) have := strings.TrimSpace(out.String())
want := `{"jsonrpc":"2.0","method":"_subscription","params":{"subscription":"test","result":{"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000001","sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000","miner":"0x0000000000000000000000000000000000000000","stateRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","receiptsRoot":"0x0000000000000000000000000000000000000000000000000000000000000000","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","difficulty":null,"number":"0x64","gasLimit":"0x0","gasUsed":"0x0","timestamp":"0x0","extraData":"0x","mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0000000000000000","baseFeePerGas":null,"withdrawalsRoot":null,"blobGasUsed":null,"excessBlobGas":null,"parentBeaconBlockRoot":null,"hash":"0xe5fb877dde471b45b9742bb4bb4b3d74a761e2fb7cb849a3d2b687eed90fb604"}}}` want := `{"jsonrpc":"2.0","method":"_subscription","params":{"subscription":"test","result":"hello"}}`
if have != want { if have != want {
t.Errorf("have:\n%v\nwant:\n%v\n", have, want) t.Errorf("have:\n%v\nwant:\n%v\n", have, want)
} }

View file

@ -154,12 +154,8 @@ func (c *committer) store(path []byte, n node) node {
return hash return hash
} }
// MerkleResolver the children resolver in merkle-patricia-tree. // ForGatherChildren decodes the provided node and traverses the children inside.
type MerkleResolver struct{} func ForGatherChildren(node []byte, onChild func(common.Hash)) {
// ForEach implements childResolver, decodes the provided node and
// traverses the children inside.
func (resolver MerkleResolver) ForEach(node []byte, onChild func(common.Hash)) {
forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild) forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild)
} }

View file

@ -819,7 +819,6 @@ func (s *spongeDb) Get(key []byte) ([]byte, error) { return nil, error
func (s *spongeDb) Delete(key []byte) error { panic("implement me") } func (s *spongeDb) Delete(key []byte) error { panic("implement me") }
func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewBatch() ethdb.Batch { return &spongeBatch{s} }
func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} } func (s *spongeDb) NewBatchWithSize(size int) ethdb.Batch { return &spongeBatch{s} }
func (s *spongeDb) NewSnapshot() (ethdb.Snapshot, error) { panic("implement me") }
func (s *spongeDb) Stat() (string, error) { panic("implement me") } func (s *spongeDb) Stat() (string, error) { panic("implement me") }
func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") } func (s *spongeDb) Compact(start []byte, limit []byte) error { panic("implement me") }
func (s *spongeDb) Close() error { return nil } func (s *spongeDb) Close() error { return nil }

View file

@ -199,6 +199,57 @@ func (t *VerkleTrie) DeleteAccount(addr common.Address) error {
return nil return nil
} }
// RollBackAccount removes the account info + code from the tree, unlike DeleteAccount
// that will overwrite it with 0s. The first 64 storage slots are also removed.
func (t *VerkleTrie) RollBackAccount(addr common.Address) error {
var (
evaluatedAddr = t.cache.Get(addr.Bytes())
codeSizeKey = utils.CodeSizeKeyWithEvaluatedAddress(evaluatedAddr)
)
codeSizeBytes, err := t.root.Get(codeSizeKey, t.nodeResolver)
if err != nil {
return fmt.Errorf("rollback: error finding code size: %w", err)
}
if len(codeSizeBytes) == 0 {
return errors.New("rollback: code size is not existent")
}
codeSize := binary.LittleEndian.Uint64(codeSizeBytes)
// Delete the account header + first 64 slots + first 128 code chunks
key := common.CopyBytes(codeSizeKey)
for i := 0; i < verkle.NodeWidth; i++ {
key[31] = byte(i)
// this is a workaround to avoid deleting nil leaves, the lib needs to be
// fixed to be able to handle that
v, err := t.root.Get(key, t.nodeResolver)
if err != nil {
return fmt.Errorf("error rolling back account header: %w", err)
}
if len(v) == 0 {
continue
}
_, err = t.root.Delete(key, t.nodeResolver)
if err != nil {
return fmt.Errorf("error rolling back account header: %w", err)
}
}
// Delete all further code
for i, chunknr := uint64(32*128), uint64(128); i < codeSize; i, chunknr = i+32, chunknr+1 {
// evaluate group key at the start of a new group
groupOffset := (chunknr + 128) % 256
if groupOffset == 0 {
key = utils.CodeChunkKeyWithEvaluatedAddress(evaluatedAddr, uint256.NewInt(chunknr))
}
key[31] = byte(groupOffset)
_, err = t.root.Delete(key[:], t.nodeResolver)
if err != nil {
return fmt.Errorf("error deleting code chunk (addr=%x) error: %w", addr[:], err)
}
}
return nil
}
// DeleteStorage implements state.Trie, deleting the specified storage slot from // DeleteStorage implements state.Trie, deleting the specified storage slot from
// the trie. If the storage slot was not existent in the trie, no error will be // the trie. If the storage slot was not existent in the trie, no error will be
// returned. If the trie is corrupted, an error will be returned. // returned. If the trie is corrupted, an error will be returned.

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/trie/utils" "github.com/ethereum/go-ethereum/trie/utils"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -89,3 +90,84 @@ func TestVerkleTreeReadWrite(t *testing.T) {
} }
} }
} }
func TestVerkleRollBack(t *testing.T) {
db := newTestDatabase(rawdb.NewMemoryDatabase(), rawdb.PathScheme)
tr, _ := NewVerkleTrie(types.EmptyVerkleHash, db, utils.NewPointCache(100))
for addr, acct := range accounts {
if err := tr.UpdateAccount(addr, acct); err != nil {
t.Fatalf("Failed to update account, %v", err)
}
for key, val := range storages[addr] {
if err := tr.UpdateStorage(addr, key.Bytes(), val); err != nil {
t.Fatalf("Failed to update account, %v", err)
}
}
// create more than 128 chunks of code
code := make([]byte, 129*32)
for i := 0; i < len(code); i += 2 {
code[i] = 0x60
code[i+1] = byte(i % 256)
}
hash := crypto.Keccak256Hash(code)
if err := tr.UpdateContractCode(addr, hash, code); err != nil {
t.Fatalf("Failed to update contract, %v", err)
}
}
// Check that things were created
for addr, acct := range accounts {
stored, err := tr.GetAccount(addr)
if err != nil {
t.Fatalf("Failed to get account, %v", err)
}
if !reflect.DeepEqual(stored, acct) {
t.Fatal("account is not matched")
}
for key, val := range storages[addr] {
stored, err := tr.GetStorage(addr, key.Bytes())
if err != nil {
t.Fatalf("Failed to get storage, %v", err)
}
if !bytes.Equal(stored, val) {
t.Fatal("storage is not matched")
}
}
}
// ensure there is some code in the 2nd group
keyOf2ndGroup := []byte{141, 124, 185, 236, 50, 22, 185, 39, 244, 47, 97, 209, 96, 235, 22, 13, 205, 38, 18, 201, 128, 223, 0, 59, 146, 199, 222, 119, 133, 13, 91, 0}
chunk, err := tr.root.Get(keyOf2ndGroup, nil)
if err != nil {
t.Fatalf("Failed to get account, %v", err)
}
if len(chunk) == 0 {
t.Fatal("account was not created ")
}
// Rollback first account and check that it is gone
addr1 := common.Address{1}
err = tr.RollBackAccount(addr1)
if err != nil {
t.Fatalf("error rolling back address 1: %v", err)
}
// ensure the account is gone
stored, err := tr.GetAccount(addr1)
if err != nil {
t.Fatalf("Failed to get account, %v", err)
}
if stored != nil {
t.Fatal("account was not deleted")
}
// ensure that the last code chunk is also gone from the tree
chunk, err = tr.root.Get(keyOf2ndGroup, nil)
if err != nil {
t.Fatalf("Failed to get account, %v", err)
}
if len(chunk) != 0 {
t.Fatal("account was not deleted")
}
}

View file

@ -23,7 +23,6 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/triedb/database" "github.com/ethereum/go-ethereum/triedb/database"
@ -43,9 +42,18 @@ type Config struct {
// default settings. // default settings.
var HashDefaults = &Config{ var HashDefaults = &Config{
Preimages: false, Preimages: false,
IsVerkle: false,
HashDB: hashdb.Defaults, HashDB: hashdb.Defaults,
} }
// VerkleDefaults represents a config for holding verkle trie data
// using path-based scheme with default settings.
var VerkleDefaults = &Config{
Preimages: false,
IsVerkle: true,
PathDB: pathdb.Defaults,
}
// backend defines the methods needed to access/update trie nodes in different // backend defines the methods needed to access/update trie nodes in different
// state scheme. // state scheme.
type backend interface { type backend interface {
@ -85,7 +93,6 @@ type backend interface {
// relevant with trie nodes and node preimages. // relevant with trie nodes and node preimages.
type Database struct { type Database struct {
config *Config // Configuration for trie database config *Config // Configuration for trie database
diskdb ethdb.Database // Persistent database to store the snapshot
preimages *preimageStore // The store for caching preimages preimages *preimageStore // The store for caching preimages
backend backend // The backend for managing trie nodes backend backend // The backend for managing trie nodes
} }
@ -103,7 +110,6 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
} }
db := &Database{ db := &Database{
config: config, config: config,
diskdb: diskdb,
preimages: preimages, preimages: preimages,
} }
if config.HashDB != nil && config.PathDB != nil { if config.HashDB != nil && config.PathDB != nil {
@ -112,14 +118,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
if config.PathDB != nil { if config.PathDB != nil {
db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle)
} else { } else {
var resolver hashdb.ChildResolver db.backend = hashdb.New(diskdb, config.HashDB)
if config.IsVerkle {
// TODO define verkle resolver
log.Crit("verkle does not use a hash db")
} else {
resolver = trie.MerkleResolver{}
}
db.backend = hashdb.New(diskdb, config.HashDB, resolver)
} }
return db return db
} }

View file

@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/trie/triestate"
"github.com/ethereum/go-ethereum/triedb/database" "github.com/ethereum/go-ethereum/triedb/database"
@ -60,12 +61,6 @@ var (
memcacheCommitBytesMeter = metrics.NewRegisteredMeter("hashdb/memcache/commit/bytes", nil) memcacheCommitBytesMeter = metrics.NewRegisteredMeter("hashdb/memcache/commit/bytes", nil)
) )
// ChildResolver defines the required method to decode the provided
// trie node and iterate the children on top.
type ChildResolver interface {
ForEach(node []byte, onChild func(common.Hash))
}
// Config contains the settings for database. // Config contains the settings for database.
type Config struct { type Config struct {
CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
@ -84,9 +79,7 @@ var Defaults = &Config{
// the disk database. The aim is to accumulate trie writes in-memory and only // the disk database. The aim is to accumulate trie writes in-memory and only
// periodically flush a couple tries to disk, garbage collecting the remainder. // periodically flush a couple tries to disk, garbage collecting the remainder.
type Database struct { type Database struct {
diskdb ethdb.Database // Persistent storage for matured trie nodes diskdb ethdb.Database // Persistent storage for matured trie nodes
resolver ChildResolver // The handler to resolve children of nodes
cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs
dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes
oldest common.Hash // Oldest tracked node, flush-list head oldest common.Hash // Oldest tracked node, flush-list head
@ -124,15 +117,15 @@ var cachedNodeSize = int(reflect.TypeOf(cachedNode{}).Size())
// forChildren invokes the callback for all the tracked children of this node, // forChildren invokes the callback for all the tracked children of this node,
// both the implicit ones from inside the node as well as the explicit ones // both the implicit ones from inside the node as well as the explicit ones
// from outside the node. // from outside the node.
func (n *cachedNode) forChildren(resolver ChildResolver, onChild func(hash common.Hash)) { func (n *cachedNode) forChildren(onChild func(hash common.Hash)) {
for child := range n.external { for child := range n.external {
onChild(child) onChild(child)
} }
resolver.ForEach(n.node, onChild) trie.ForGatherChildren(n.node, onChild)
} }
// New initializes the hash-based node database. // New initializes the hash-based node database.
func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Database { func New(diskdb ethdb.Database, config *Config) *Database {
if config == nil { if config == nil {
config = Defaults config = Defaults
} }
@ -141,10 +134,9 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas
cleans = fastcache.New(config.CleanCacheSize) cleans = fastcache.New(config.CleanCacheSize)
} }
return &Database{ return &Database{
diskdb: diskdb, diskdb: diskdb,
resolver: resolver, cleans: cleans,
cleans: cleans, dirties: make(map[common.Hash]*cachedNode),
dirties: make(map[common.Hash]*cachedNode),
} }
} }
@ -163,7 +155,7 @@ func (db *Database) insert(hash common.Hash, node []byte) {
node: node, node: node,
flushPrev: db.newest, flushPrev: db.newest,
} }
entry.forChildren(db.resolver, func(child common.Hash) { entry.forChildren(func(child common.Hash) {
if c := db.dirties[child]; c != nil { if c := db.dirties[child]; c != nil {
c.parents++ c.parents++
} }
@ -316,7 +308,7 @@ func (db *Database) dereference(hash common.Hash) {
db.dirties[node.flushNext].flushPrev = node.flushPrev db.dirties[node.flushNext].flushPrev = node.flushPrev
} }
// Dereference all children and delete the node // Dereference all children and delete the node
node.forChildren(db.resolver, func(child common.Hash) { node.forChildren(func(child common.Hash) {
db.dereference(child) db.dereference(child)
}) })
delete(db.dirties, hash) delete(db.dirties, hash)
@ -465,7 +457,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane
var err error var err error
// Dereference all children and delete the node // Dereference all children and delete the node
node.forChildren(db.resolver, func(child common.Hash) { node.forChildren(func(child common.Hash) {
if err == nil { if err == nil {
err = db.commit(child, batch, uncacher) err = db.commit(child, batch, uncacher)
} }

View file

@ -152,6 +152,14 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database {
} }
config = config.sanitize() config = config.sanitize()
// Establish a dedicated database namespace tailored for verkle-specific
// data, ensuring the isolation of both verkle and merkle tree data. It's
// important to note that the introduction of a prefix won't lead to
// substantial storage overhead, as the underlying database will efficiently
// compress the shared key prefix.
if isVerkle {
diskdb = rawdb.NewTable(diskdb, string(rawdb.VerklePrefix))
}
db := &Database{ db := &Database{
readOnly: config.ReadOnly, readOnly: config.ReadOnly,
isVerkle: isVerkle, isVerkle: isVerkle,
@ -190,7 +198,7 @@ func (db *Database) repairHistory() error {
// all of them. Fix the tests first. // all of them. Fix the tests first.
return nil return nil
} }
freezer, err := rawdb.NewStateFreezer(ancient, db.readOnly) freezer, err := rawdb.NewStateFreezer(ancient, db.isVerkle, db.readOnly)
if err != nil { if err != nil {
log.Crit("Failed to open state history freezer", "err", err) log.Crit("Failed to open state history freezer", "err", err)
} }

View file

@ -129,7 +129,7 @@ func TestTruncateHeadHistory(t *testing.T) {
roots []common.Hash roots []common.Hash
hs = makeHistories(10) hs = makeHistories(10)
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
) )
defer freezer.Close() defer freezer.Close()
@ -157,7 +157,7 @@ func TestTruncateTailHistory(t *testing.T) {
roots []common.Hash roots []common.Hash
hs = makeHistories(10) hs = makeHistories(10)
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
) )
defer freezer.Close() defer freezer.Close()
@ -200,7 +200,7 @@ func TestTruncateTailHistories(t *testing.T) {
roots []common.Hash roots []common.Hash
hs = makeHistories(10) hs = makeHistories(10)
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false) freezer, _ = rawdb.NewStateFreezer(t.TempDir()+fmt.Sprintf("%d", i), false, false)
) )
defer freezer.Close() defer freezer.Close()
@ -228,7 +228,7 @@ func TestTruncateOutOfRange(t *testing.T) {
var ( var (
hs = makeHistories(10) hs = makeHistories(10)
db = rawdb.NewMemoryDatabase() db = rawdb.NewMemoryDatabase()
freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false)
) )
defer freezer.Close() defer freezer.Close()

View file

@ -78,7 +78,7 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte,
if len(blob) > 0 { if len(blob) > 0 {
blobHex = hexutil.Encode(blob) blobHex = hexutil.Encode(blob)
} }
log.Error("Unexpected trie node", "location", loc.loc, "owner", owner, "path", path, "expect", hash, "got", got, "blob", blobHex) log.Error("Unexpected trie node", "location", loc.loc, "owner", owner.Hex(), "path", path, "expect", hash.Hex(), "got", got.Hex(), "blob", blobHex)
return nil, fmt.Errorf("unexpected node: (%x %v), %x!=%x, %s, blob: %s", owner, path, hash, got, loc.string(), blobHex) return nil, fmt.Errorf("unexpected node: (%x %v), %x!=%x, %s, blob: %s", owner, path, hash, got, loc.string(), blobHex)
} }
return blob, nil return blob, nil