From be5df74ed57fdb415a8823ec6d8611ab8a336743 Mon Sep 17 00:00:00 2001 From: cocoyeal <150209682+cocoyeal@users.noreply.github.com> Date: Tue, 21 May 2024 19:53:34 +0800 Subject: [PATCH 001/196] trie: update the `valid` function comments (#29809) --- trie/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/sync.go b/trie/sync.go index e609f69e2b..3b7caae5b1 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -157,7 +157,7 @@ type nodeOp struct { hash common.Hash // hash of the node content (empty for node deletion) } -// isDelete indicates if the operation is a database deletion. +// valid checks whether the node operation is valid. func (op *nodeOp) valid() bool { if op.del && len(op.blob) != 0 { return false From 7fd7c1f7dd9ba8d90399df2f080e4101ae37a255 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 21 May 2024 18:27:36 +0200 Subject: [PATCH 002/196] eth/tracers: fix basefee context for traceBlock (#29811) This fixes an issue for `debug_traceBlock*` methods where the BASEFEE opcode was returning always 0. This caused the method return invalid results. Co-authored-by: Sina Mahmoodi --- eth/tracers/api.go | 4 +- eth/tracers/api_test.go | 88 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d99531d48f..30648c4753 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -22,7 +22,6 @@ import ( "encoding/json" "errors" "fmt" - "math/big" "os" "runtime" "sync" @@ -982,7 +981,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor return nil, err } } - vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + // The actual TxContext will be created as part of ApplyTransactionWithEVM. + vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) statedb.SetLogger(tracer.Hooks) // Define a meaningful timeout of a single transaction trace diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 36caee0dda..120cb585c7 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" @@ -994,3 +995,90 @@ func TestTraceChain(t *testing.T) { } } } + +// newTestMergedBackend creates a post-merge chain +func newTestMergedBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend { + backend := &testBackend{ + chainConfig: gspec.Config, + engine: beacon.NewFaker(), + chaindb: rawdb.NewMemoryDatabase(), + } + // Generate blocks for testing + _, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator) + + // Import the canonical chain + cacheConfig := &core.CacheConfig{ + TrieCleanLimit: 256, + TrieDirtyLimit: 256, + TrieTimeLimit: 5 * time.Minute, + SnapshotLimit: 0, + TrieDirtyDisabled: true, // Archive mode + } + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil) + if err != nil { + t.Fatalf("failed to create tester chain: %v", err) + } + if n, err := chain.InsertChain(blocks); err != nil { + t.Fatalf("block %d: failed to insert into chain: %v", n, err) + } + backend.chain = chain + return backend +} + +func TestTraceBlockWithBasefee(t *testing.T) { + t.Parallel() + accounts := newAccounts(1) + target := common.HexToAddress("0x1111111111111111111111111111111111111111") + genesis := &core.Genesis{ + Config: params.AllDevChainProtocolChanges, + Alloc: types.GenesisAlloc{ + accounts[0].addr: {Balance: big.NewInt(1 * params.Ether)}, + target: {Nonce: 1, Code: []byte{ + byte(vm.BASEFEE), byte(vm.STOP), + }}, + }, + } + genBlocks := 1 + signer := types.HomesteadSigner{} + var txHash common.Hash + var baseFee = new(big.Int) + backend := newTestMergedBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) { + tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{ + Nonce: uint64(i), + To: &target, + Value: big.NewInt(0), + Gas: 5 * params.TxGas, + GasPrice: b.BaseFee(), + Data: nil}), + signer, accounts[0].key) + b.AddTx(tx) + txHash = tx.Hash() + baseFee.Set(b.BaseFee()) + }) + defer backend.chain.Stop() + api := NewAPI(backend) + + var testSuite = []struct { + blockNumber rpc.BlockNumber + config *TraceConfig + want string + }{ + // Trace head block + { + blockNumber: rpc.BlockNumber(genBlocks), + want: fmt.Sprintf(`[{"txHash":"%#x","result":{"gas":21002,"failed":false,"returnValue":"","structLogs":[{"pc":0,"op":"BASEFEE","gas":84000,"gasCost":2,"depth":1,"stack":[]},{"pc":1,"op":"STOP","gas":83998,"gasCost":0,"depth":1,"stack":["%#x"]}]}}]`, txHash, baseFee), + }, + } + for i, tc := range testSuite { + result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config) + if err != nil { + t.Errorf("test %d, want no error, have %v", i, err) + continue + } + have, _ := json.Marshal(result) + want := tc.want + if string(have) != want { + t.Errorf("test %d, result mismatch\nhave: %v\nwant: %v\n", i, string(have), want) + } + } +} From 0d4cdb3dbed9c0183110db65270bd5725bf392ec Mon Sep 17 00:00:00 2001 From: Karl Bartel Date: Thu, 23 May 2024 10:41:51 +0200 Subject: [PATCH 003/196] internal/ethapi: fix typos (#29784) Fix typos in api.go --- internal/ethapi/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d308cead62..8866a5b870 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -966,7 +966,7 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc. // of a message call. // Note, state and stateDiff can't be specified at the same time. If state is // set, message execution will only use the data in the given state. Otherwise -// if statDiff 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. type OverrideAccount struct { Nonce *hexutil.Uint64 `json:"nonce"` @@ -1203,7 +1203,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr return 0, err } call := args.ToMessage(header.BaseFee) - // Run the gas estimation andwrap any revertals into a custom return + // Run the gas estimation and wrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { if len(revert) > 0 { From fa581766f5b14f6fad9f2c7a4aa7e7ac826a8de2 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 23 May 2024 10:55:54 +0200 Subject: [PATCH 004/196] eth/tracers: fix json logger for evm blocktest (#29795) --- eth/tracers/api.go | 8 +++++-- eth/tracers/logger/logger_json.go | 37 ++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 30648c4753..51b55ffdbb 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -804,9 +804,13 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Execute the transaction and flush any traces to disk vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) statedb.SetTxContext(tx.Hash(), i) - vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) + if vmConf.Tracer.OnTxStart != nil { + vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From) + } vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) - vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + if vmConf.Tracer.OnTxEnd != nil { + vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err) + } if writer != nil { writer.Flush() } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index d66b8c4b8a..797f7ac658 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -58,6 +58,7 @@ type jsonLogger struct { encoder *json.Encoder cfg *Config env *tracing.VMContext + hooks *tracing.Hooks } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects @@ -67,12 +68,14 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { if l.cfg == nil { l.cfg = &Config{} } - return &tracing.Hooks{ - OnTxStart: l.OnTxStart, - OnExit: l.OnExit, - OnOpcode: l.OnOpcode, - OnFault: l.OnFault, + l.hooks = &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnSystemCallStart: l.onSystemCallStart, + OnExit: l.OnEnd, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, } + return l.hooks } // NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects @@ -82,13 +85,15 @@ func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks { if l.cfg == nil { l.cfg = &Config{} } - return &tracing.Hooks{ - OnTxStart: l.OnTxStart, - OnEnter: l.OnEnter, - OnExit: l.OnExit, - OnOpcode: l.OnOpcode, - OnFault: l.OnFault, + l.hooks = &tracing.Hooks{ + OnTxStart: l.OnTxStart, + OnSystemCallStart: l.onSystemCallStart, + OnEnter: l.OnEnter, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, + OnFault: l.OnFault, } + return l.hooks } func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { @@ -122,6 +127,16 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin l.encoder.Encode(log) } +func (l *jsonLogger) onSystemCallStart() { + // Process no events while in system call. + hooks := *l.hooks + *l.hooks = tracing.Hooks{ + OnSystemCallEnd: func() { + *l.hooks = hooks + }, + } +} + // OnEnter is not enabled by default. func (l *jsonLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { frame := callFrame{ From b779e469daf17d02ade66667c7adbfb8f51083a1 Mon Sep 17 00:00:00 2001 From: Mobin Mohanan <47410557+tr1sm0s1n@users.noreply.github.com> Date: Thu, 23 May 2024 15:26:32 +0530 Subject: [PATCH 005/196] Makefile: add fmt, update help (#29777) --- Makefile | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 278ae63120..857cb8c978 100644 --- a/Makefile +++ b/Makefile @@ -2,31 +2,35 @@ # with Go source code. If you know what GOPATH is then you probably # don't need to bother with make. -.PHONY: geth all test lint clean devtools help +.PHONY: geth all test lint fmt clean devtools help GOBIN = ./build/bin GO ?= latest GORUN = go run -#? geth: Build geth +#? geth: Build geth. geth: $(GORUN) build/ci.go install ./cmd/geth @echo "Done building." @echo "Run \"$(GOBIN)/geth\" to launch geth." -#? all: Build all packages and executables +#? all: Build all packages and executables. all: $(GORUN) build/ci.go install -#? test: Run the tests +#? test: Run the tests. test: all $(GORUN) build/ci.go test -#? lint: Run certain pre-selected linters +#? lint: Run certain pre-selected linters. lint: ## Run linters. $(GORUN) build/ci.go lint -#? clean: Clean go cache, built executables, and the auto generated folder +#? fmt: Ensure consistent code formatting. +fmt: + gofmt -s -w $(shell find . -name "*.go") + +#? clean: Clean go cache, built executables, and the auto generated folder. clean: go clean -cache rm -fr build/_workspace/pkg/ $(GOBIN)/* @@ -34,7 +38,7 @@ clean: # The devtools target installs tools required for 'go generate'. # You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'. -#? devtools: Install recommended developer tools +#? devtools: Install recommended developer tools. devtools: env GOBIN= go install golang.org/x/tools/cmd/stringer@latest env GOBIN= go install github.com/fjl/gencodec@latest @@ -45,5 +49,9 @@ devtools: #? help: Get more info on make commands. help: Makefile - @echo " Choose a command run in go-ethereum:" + @echo '' + @echo 'Usage:' + @echo ' make [target]' + @echo '' + @echo 'Targets:' @sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /' From 70bee977d6b6099972b2c240f182b61829cf182f Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Thu, 23 May 2024 18:34:34 +0800 Subject: [PATCH 006/196] metrics: fix out of range error message (#29821) --- metrics/sample_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 9835ec1c30..92806c65b2 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -114,7 +114,7 @@ func TestExpDecaySample(t *testing.T) { } for _, v := range values { if v > int64(tc.updates) || v < 0 { - t.Errorf("out of range [0, %d): %v", tc.updates, v) + t.Errorf("out of range [0, %d]: %v", tc.updates, v) } } } @@ -195,7 +195,7 @@ func TestUniformSample(t *testing.T) { } for _, v := range values { if v > 1000 || v < 0 { - t.Errorf("out of range [0, 100): %v\n", v) + t.Errorf("out of range [0, 1000]: %v\n", v) } } } From 6a9158bb1bea9feda96489f1d02e15f0a9f93b82 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 23 May 2024 14:26:09 +0200 Subject: [PATCH 007/196] p2p/discover: improved node revalidation (#29572) Node discovery periodically revalidates the nodes in its table by sending PING, checking if they are still alive. I recently noticed some issues with the implementation of this process, which can cause strange results such as nodes dropping unexpectedly, certain nodes not getting revalidated often enough, and bad results being returned to incoming FINDNODE queries. In this change, the revalidation process is improved with the following logic: - We maintain two 'revalidation lists' containing the table nodes, named 'fast' and 'slow'. - The process chooses random nodes from each list on a randomized interval, the interval being faster for the 'fast' list, and performs revalidation for the chosen node. - Whenever a node is newly inserted into the table, it goes into the 'fast' list. Once validation passes, it transfers to the 'slow' list. If a request fails, or the node changes endpoint, it transfers back into 'fast'. - livenessChecks is incremented by one for successful checks. Unlike the old implementation, we will not drop the node on the first failing check. We instead quickly decay the livenessChecks give it another chance. - Order of nodes in bucket doesn't matter anymore. I am also adding a debug API endpoint to dump the node table content. Co-authored-by: Martin HS --- cmd/devp2p/discv4cmd.go | 57 +++ internal/testlog/testlog.go | 2 +- node/api.go | 17 + p2p/discover/common.go | 47 ++- p2p/discover/lookup.go | 29 +- p2p/discover/node.go | 20 +- p2p/discover/table.go | 717 +++++++++++++++----------------- p2p/discover/table_reval.go | 223 ++++++++++ p2p/discover/table_test.go | 179 ++++---- p2p/discover/table_util_test.go | 118 +++++- p2p/discover/v4_udp.go | 10 +- p2p/discover/v4_udp_test.go | 2 +- p2p/discover/v5_udp.go | 4 +- p2p/discover/v5_udp_test.go | 2 +- p2p/server.go | 36 +- 15 files changed, 935 insertions(+), 528 deletions(-) create mode 100644 p2p/discover/table_reval.go diff --git a/cmd/devp2p/discv4cmd.go b/cmd/devp2p/discv4cmd.go index 45bcdcd367..3b5400ca3a 100644 --- a/cmd/devp2p/discv4cmd.go +++ b/cmd/devp2p/discv4cmd.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "net" + "net/http" "strconv" "strings" "time" @@ -28,9 +29,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" "github.com/urfave/cli/v2" ) @@ -45,6 +48,7 @@ var ( discv4ResolveJSONCommand, discv4CrawlCommand, discv4TestCommand, + discv4ListenCommand, }, } discv4PingCommand = &cli.Command{ @@ -75,6 +79,14 @@ var ( Flags: discoveryNodeFlags, ArgsUsage: "", } + discv4ListenCommand = &cli.Command{ + Name: "listen", + Usage: "Runs a discovery node", + Action: discv4Listen, + Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{ + httpAddrFlag, + }), + } discv4CrawlCommand = &cli.Command{ Name: "crawl", Usage: "Updates a nodes.json file with random nodes found in the DHT", @@ -131,6 +143,10 @@ var ( Usage: "Enode of the remote node under test", EnvVars: []string{"REMOTE_ENODE"}, } + httpAddrFlag = &cli.StringFlag{ + Name: "rpc", + Usage: "HTTP server listening address", + } ) var discoveryNodeFlags = []cli.Flag{ @@ -154,6 +170,27 @@ func discv4Ping(ctx *cli.Context) error { return nil } +func discv4Listen(ctx *cli.Context) error { + disc, _ := startV4(ctx) + defer disc.Close() + + fmt.Println(disc.Self()) + + httpAddr := ctx.String(httpAddrFlag.Name) + if httpAddr == "" { + // Non-HTTP mode. + select {} + } + + api := &discv4API{disc} + log.Info("Starting RPC API server", "addr", httpAddr) + srv := rpc.NewServer() + srv.RegisterName("discv4", api) + http.DefaultServeMux.Handle("/", srv) + httpsrv := http.Server{Addr: httpAddr, Handler: http.DefaultServeMux} + return httpsrv.ListenAndServe() +} + func discv4RequestRecord(ctx *cli.Context) error { n := getNodeArg(ctx) disc, _ := startV4(ctx) @@ -362,3 +399,23 @@ func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) { } return nodes, nil } + +type discv4API struct { + host *discover.UDPv4 +} + +func (api *discv4API) LookupRandom(n int) (ns []*enode.Node) { + it := api.host.RandomNodes() + for len(ns) < n && it.Next() { + ns = append(ns, it.Node()) + } + return ns +} + +func (api *discv4API) Buckets() [][]discover.BucketNode { + return api.host.TableBuckets() +} + +func (api *discv4API) Self() *enode.Node { + return api.host.Self() +} diff --git a/internal/testlog/testlog.go b/internal/testlog/testlog.go index 3740dd1f24..ad61af9eac 100644 --- a/internal/testlog/testlog.go +++ b/internal/testlog/testlog.go @@ -58,7 +58,7 @@ func (h *bufHandler) Handle(_ context.Context, r slog.Record) error { } func (h *bufHandler) Enabled(_ context.Context, lvl slog.Level) bool { - return lvl <= h.level + return lvl >= h.level } func (h *bufHandler) WithAttrs(attrs []slog.Attr) slog.Handler { diff --git a/node/api.go b/node/api.go index a71ae6aa29..33dfb3a1cc 100644 --- a/node/api.go +++ b/node/api.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/p2p/discover" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" ) @@ -39,6 +40,9 @@ func (n *Node) apis() []rpc.API { }, { Namespace: "debug", Service: debug.Handler, + }, { + Namespace: "debug", + Service: &p2pDebugAPI{n}, }, { Namespace: "web3", Service: &web3API{n}, @@ -333,3 +337,16 @@ func (s *web3API) ClientVersion() string { func (s *web3API) Sha3(input hexutil.Bytes) hexutil.Bytes { return crypto.Keccak256(input) } + +// p2pDebugAPI provides access to p2p internals for debugging. +type p2pDebugAPI struct { + stack *Node +} + +func (s *p2pDebugAPI) DiscoveryV4Table() [][]discover.BucketNode { + disc := s.stack.server.DiscoveryV4() + if disc != nil { + return disc.TableBuckets() + } + return nil +} diff --git a/p2p/discover/common.go b/p2p/discover/common.go index 1f763904bb..bebea8cc38 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -18,7 +18,11 @@ package discover import ( "crypto/ecdsa" + crand "crypto/rand" + "encoding/binary" + "math/rand" "net" + "sync" "time" "github.com/ethereum/go-ethereum/common/mclock" @@ -62,7 +66,7 @@ type Config struct { func (cfg Config) withDefaults() Config { // Node table configuration: if cfg.PingInterval == 0 { - cfg.PingInterval = 10 * time.Second + cfg.PingInterval = 3 * time.Second } if cfg.RefreshInterval == 0 { cfg.RefreshInterval = 30 * time.Minute @@ -92,3 +96,44 @@ type ReadPacket struct { Data []byte Addr *net.UDPAddr } + +type randomSource interface { + Intn(int) int + Int63n(int64) int64 + Shuffle(int, func(int, int)) +} + +// reseedingRandom is a random number generator that tracks when it was last re-seeded. +type reseedingRandom struct { + mu sync.Mutex + cur *rand.Rand +} + +func (r *reseedingRandom) seed() { + var b [8]byte + crand.Read(b[:]) + seed := binary.BigEndian.Uint64(b[:]) + new := rand.New(rand.NewSource(int64(seed))) + + r.mu.Lock() + r.cur = new + r.mu.Unlock() +} + +func (r *reseedingRandom) Intn(n int) int { + r.mu.Lock() + defer r.mu.Unlock() + return r.cur.Intn(n) +} + +func (r *reseedingRandom) Int63n(n int64) int64 { + r.mu.Lock() + defer r.mu.Unlock() + return r.cur.Int63n(n) +} + +func (r *reseedingRandom) Shuffle(n int, swap func(i, j int)) { + r.mu.Lock() + defer r.mu.Unlock() + r.cur.Shuffle(n, swap) +} diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index b8d97b44e1..5c3d90d6c9 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -140,32 +140,13 @@ func (it *lookup) slowdown() { } func (it *lookup) query(n *node, reply chan<- []*node) { - fails := it.tab.db.FindFails(n.ID(), n.IP()) r, err := it.queryfunc(n) - if errors.Is(err, errClosed) { - // Avoid recording failures on shutdown. - reply <- nil - return - } else if len(r) == 0 { - fails++ - it.tab.db.UpdateFindFails(n.ID(), n.IP(), fails) - // Remove the node from the local table if it fails to return anything useful too - // many times, but only if there are enough other nodes in the bucket. - dropped := false - if fails >= maxFindnodeFailures && it.tab.bucketLen(n.ID()) >= bucketSize/2 { - dropped = true - it.tab.delete(n) + if !errors.Is(err, errClosed) { // avoid recording failures on shutdown. + success := len(r) > 0 + it.tab.trackRequest(n, success, r) + if err != nil { + it.tab.log.Trace("FINDNODE failed", "id", n.ID(), "err", err) } - it.tab.log.Trace("FINDNODE failed", "id", n.ID(), "failcount", fails, "dropped", dropped, "err", err) - } else if fails > 0 { - // Reset failure counter because it counts _consecutive_ failures. - it.tab.db.UpdateFindFails(n.ID(), n.IP(), 0) - } - - // Grab as many nodes as possible. Some of them might not be alive anymore, but we'll - // just remove those again during revalidation. - for _, n := range r { - it.tab.addSeenNode(n) } reply <- r } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 9ffe101ccf..47df09e883 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -29,12 +29,22 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" ) +type BucketNode struct { + Node *enode.Node `json:"node"` + AddedToTable time.Time `json:"addedToTable"` + AddedToBucket time.Time `json:"addedToBucket"` + Checks int `json:"checks"` + Live bool `json:"live"` +} + // node represents a host on the network. // The fields of Node may not be modified. type node struct { - enode.Node - addedAt time.Time // time when the node was added to the table - livenessChecks uint // how often liveness was checked + *enode.Node + addedToTable time.Time // first time node was added to bucket or replacement list + addedToBucket time.Time // time it was added in the actual bucket + livenessChecks uint // how often liveness was checked + isValidatedLive bool // true if existence of node is considered validated right now } type encPubkey [64]byte @@ -65,7 +75,7 @@ func (e encPubkey) id() enode.ID { } func wrapNode(n *enode.Node) *node { - return &node{Node: *n} + return &node{Node: n} } func wrapNodes(ns []*enode.Node) []*node { @@ -77,7 +87,7 @@ func wrapNodes(ns []*enode.Node) []*node { } func unwrapNode(n *node) *enode.Node { - return &n.Node + return n.Node } func unwrapNodes(ns []*node) []*enode.Node { diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 2b7a28708b..74c0e930e4 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -24,16 +24,15 @@ package discover import ( "context" - crand "crypto/rand" - "encoding/binary" "fmt" - mrand "math/rand" "net" + "slices" "sort" "sync" "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p/enode" @@ -55,21 +54,21 @@ const ( bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24 tableIPLimit, tableSubnet = 10, 24 - copyNodesInterval = 30 * time.Second - seedMinTableTime = 5 * time.Minute - seedCount = 30 - seedMaxAge = 5 * 24 * time.Hour + seedMinTableTime = 5 * time.Minute + seedCount = 30 + seedMaxAge = 5 * 24 * time.Hour ) // Table is the 'node table', a Kademlia-like index of neighbor nodes. The table keeps // itself up-to-date by verifying the liveness of neighbors and requesting their node // records when announcements of a new record version are received. type Table struct { - mutex sync.Mutex // protects buckets, bucket content, nursery, rand - buckets [nBuckets]*bucket // index of known nodes by distance - nursery []*node // bootstrap nodes - rand *mrand.Rand // source of randomness, periodically reseeded - ips netutil.DistinctNetSet + mutex sync.Mutex // protects buckets, bucket content, nursery, rand + buckets [nBuckets]*bucket // index of known nodes by distance + nursery []*node // bootstrap nodes + rand reseedingRandom // source of randomness, periodically reseeded + ips netutil.DistinctNetSet + revalidation tableRevalidation db *enode.DB // database of known nodes net transport @@ -77,10 +76,14 @@ type Table struct { log log.Logger // loop channels - refreshReq chan chan struct{} - initDone chan struct{} - closeReq chan struct{} - closed chan struct{} + refreshReq chan chan struct{} + revalResponseCh chan revalidationResponse + addNodeCh chan addNodeOp + addNodeHandled chan bool + trackRequestCh chan trackRequestOp + initDone chan struct{} + closeReq chan struct{} + closed chan struct{} nodeAddedHook func(*bucket, *node) nodeRemovedHook func(*bucket, *node) @@ -104,22 +107,33 @@ type bucket struct { index int } +type addNodeOp struct { + node *node + isInbound bool +} + +type trackRequestOp struct { + node *node + foundNodes []*node + success bool +} + func newTable(t transport, db *enode.DB, cfg Config) (*Table, error) { cfg = cfg.withDefaults() tab := &Table{ - net: t, - db: db, - cfg: cfg, - log: cfg.Log, - refreshReq: make(chan chan struct{}), - initDone: make(chan struct{}), - closeReq: make(chan struct{}), - closed: make(chan struct{}), - rand: mrand.New(mrand.NewSource(0)), - ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, - } - if err := tab.setFallbackNodes(cfg.Bootnodes); err != nil { - return nil, err + net: t, + db: db, + cfg: cfg, + log: cfg.Log, + refreshReq: make(chan chan struct{}), + revalResponseCh: make(chan revalidationResponse), + addNodeCh: make(chan addNodeOp), + addNodeHandled: make(chan bool), + trackRequestCh: make(chan trackRequestOp), + initDone: make(chan struct{}), + closeReq: make(chan struct{}), + closed: make(chan struct{}), + ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, } for i := range tab.buckets { tab.buckets[i] = &bucket{ @@ -127,41 +141,34 @@ func newTable(t transport, db *enode.DB, cfg Config) (*Table, error) { ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, } } - tab.seedRand() + tab.rand.seed() + tab.revalidation.init(&cfg) + + // initial table content + if err := tab.setFallbackNodes(cfg.Bootnodes); err != nil { + return nil, err + } tab.loadSeedNodes() return tab, nil } -func newMeteredTable(t transport, db *enode.DB, cfg Config) (*Table, error) { - tab, err := newTable(t, db, cfg) - if err != nil { - return nil, err - } - if metrics.Enabled { - tab.nodeAddedHook = func(b *bucket, n *node) { - bucketsCounter[b.index].Inc(1) - } - tab.nodeRemovedHook = func(b *bucket, n *node) { - bucketsCounter[b.index].Dec(1) - } - } - return tab, nil -} - // Nodes returns all nodes contained in the table. -func (tab *Table) Nodes() []*enode.Node { - if !tab.isInitDone() { - return nil - } - +func (tab *Table) Nodes() [][]BucketNode { tab.mutex.Lock() defer tab.mutex.Unlock() - var nodes []*enode.Node - for _, b := range &tab.buckets { - for _, n := range b.entries { - nodes = append(nodes, unwrapNode(n)) + nodes := make([][]BucketNode, len(tab.buckets)) + for i, b := range &tab.buckets { + nodes[i] = make([]BucketNode, len(b.entries)) + for j, n := range b.entries { + nodes[i][j] = BucketNode{ + Node: n.Node, + Checks: int(n.livenessChecks), + Live: n.isValidatedLive, + AddedToTable: n.addedToTable, + AddedToBucket: n.addedToBucket, + } } } return nodes @@ -171,15 +178,6 @@ func (tab *Table) self() *enode.Node { return tab.net.Self() } -func (tab *Table) seedRand() { - var b [8]byte - crand.Read(b[:]) - - tab.mutex.Lock() - tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) - tab.mutex.Unlock() -} - // getNode returns the node with the given ID or nil if it isn't in the table. func (tab *Table) getNode(id enode.ID) *enode.Node { tab.mutex.Lock() @@ -239,52 +237,173 @@ func (tab *Table) refresh() <-chan struct{} { return done } -// loop schedules runs of doRefresh, doRevalidate and copyLiveNodes. +// findnodeByID returns the n nodes in the table that are closest to the given id. +// This is used by the FINDNODE/v4 handler. +// +// The preferLive parameter says whether the caller wants liveness-checked results. If +// preferLive is true and the table contains any verified nodes, the result will not +// contain unverified nodes. However, if there are no verified nodes at all, the result +// will contain unverified nodes. +func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *nodesByDistance { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + // Scan all buckets. There might be a better way to do this, but there aren't that many + // buckets, so this solution should be fine. The worst-case complexity of this loop + // is O(tab.len() * nresults). + nodes := &nodesByDistance{target: target} + liveNodes := &nodesByDistance{target: target} + for _, b := range &tab.buckets { + for _, n := range b.entries { + nodes.push(n, nresults) + if preferLive && n.isValidatedLive { + liveNodes.push(n, nresults) + } + } + } + + if preferLive && len(liveNodes.entries) > 0 { + return liveNodes + } + return nodes +} + +// appendLiveNodes adds nodes at the given distance to the result slice. +// This is used by the FINDNODE/v5 handler. +func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node { + if dist > 256 { + return result + } + if dist == 0 { + return append(result, tab.self()) + } + + tab.mutex.Lock() + for _, n := range tab.bucketAtDistance(int(dist)).entries { + if n.isValidatedLive { + result = append(result, n.Node) + } + } + tab.mutex.Unlock() + + // Shuffle result to avoid always returning same nodes in FINDNODE/v5. + tab.rand.Shuffle(len(result), func(i, j int) { + result[i], result[j] = result[j], result[i] + }) + return result +} + +// len returns the number of nodes in the table. +func (tab *Table) len() (n int) { + tab.mutex.Lock() + defer tab.mutex.Unlock() + + for _, b := range &tab.buckets { + n += len(b.entries) + } + return n +} + +// addFoundNode adds a node which may not be live. If the bucket has space available, +// adding the node succeeds immediately. Otherwise, the node is added to the replacements +// list. +// +// The caller must not hold tab.mutex. +func (tab *Table) addFoundNode(n *node) bool { + op := addNodeOp{node: n, isInbound: false} + select { + case tab.addNodeCh <- op: + return <-tab.addNodeHandled + case <-tab.closeReq: + return false + } +} + +// addInboundNode adds a node from an inbound contact. If the bucket has no space, the +// node is added to the replacements list. +// +// There is an additional safety measure: if the table is still initializing the node is +// not added. This prevents an attack where the table could be filled by just sending ping +// repeatedly. +// +// The caller must not hold tab.mutex. +func (tab *Table) addInboundNode(n *node) bool { + op := addNodeOp{node: n, isInbound: true} + select { + case tab.addNodeCh <- op: + return <-tab.addNodeHandled + case <-tab.closeReq: + return false + } +} + +func (tab *Table) trackRequest(n *node, success bool, foundNodes []*node) { + op := trackRequestOp{n, foundNodes, success} + select { + case tab.trackRequestCh <- op: + case <-tab.closeReq: + } +} + +// loop is the main loop of Table. func (tab *Table) loop() { var ( - revalidate = time.NewTimer(tab.nextRevalidateTime()) - refresh = time.NewTimer(tab.nextRefreshTime()) - copyNodes = time.NewTicker(copyNodesInterval) - refreshDone = make(chan struct{}) // where doRefresh reports completion - revalidateDone chan struct{} // where doRevalidate reports completion - waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs + refresh = time.NewTimer(tab.nextRefreshTime()) + refreshDone = make(chan struct{}) // where doRefresh reports completion + waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs + revalTimer = mclock.NewAlarm(tab.cfg.Clock) + reseedRandTimer = time.NewTicker(10 * time.Minute) ) defer refresh.Stop() - defer revalidate.Stop() - defer copyNodes.Stop() + defer revalTimer.Stop() + defer reseedRandTimer.Stop() // Start initial refresh. go tab.doRefresh(refreshDone) loop: for { + nextTime := tab.revalidation.run(tab, tab.cfg.Clock.Now()) + revalTimer.Schedule(nextTime) + select { + case <-reseedRandTimer.C: + tab.rand.seed() + + case <-revalTimer.C(): + + case r := <-tab.revalResponseCh: + tab.revalidation.handleResponse(tab, r) + + case op := <-tab.addNodeCh: + tab.mutex.Lock() + ok := tab.handleAddNode(op) + tab.mutex.Unlock() + tab.addNodeHandled <- ok + + case op := <-tab.trackRequestCh: + tab.handleTrackRequest(op) + case <-refresh.C: - tab.seedRand() if refreshDone == nil { refreshDone = make(chan struct{}) go tab.doRefresh(refreshDone) } + case req := <-tab.refreshReq: waiting = append(waiting, req) if refreshDone == nil { refreshDone = make(chan struct{}) go tab.doRefresh(refreshDone) } + case <-refreshDone: for _, ch := range waiting { close(ch) } waiting, refreshDone = nil, nil refresh.Reset(tab.nextRefreshTime()) - case <-revalidate.C: - revalidateDone = make(chan struct{}) - go tab.doRevalidate(revalidateDone) - case <-revalidateDone: - revalidate.Reset(tab.nextRevalidateTime()) - revalidateDone = nil - case <-copyNodes.C: - go tab.copyLiveNodes() + case <-tab.closeReq: break loop } @@ -296,9 +415,6 @@ loop: for _, ch := range waiting { close(ch) } - if revalidateDone != nil { - <-revalidateDone - } close(tab.closed) } @@ -335,169 +451,15 @@ func (tab *Table) loadSeedNodes() { age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) } - tab.addSeenNode(seed) + tab.handleAddNode(addNodeOp{node: seed, isInbound: false}) } } -// doRevalidate checks that the last node in a random bucket is still live and replaces or -// deletes the node if it isn't. -func (tab *Table) doRevalidate(done chan<- struct{}) { - defer func() { done <- struct{}{} }() - - last, bi := tab.nodeToRevalidate() - if last == nil { - // No non-empty bucket found. - return - } - - // Ping the selected node and wait for a pong. - remoteSeq, err := tab.net.ping(unwrapNode(last)) - - // Also fetch record if the node replied and returned a higher sequence number. - if last.Seq() < remoteSeq { - n, err := tab.net.RequestENR(unwrapNode(last)) - if err != nil { - tab.log.Debug("ENR request failed", "id", last.ID(), "addr", last.addr(), "err", err) - } else { - last = &node{Node: *n, addedAt: last.addedAt, livenessChecks: last.livenessChecks} - } - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - b := tab.buckets[bi] - if err == nil { - // The node responded, move it to the front. - last.livenessChecks++ - tab.log.Debug("Revalidated node", "b", bi, "id", last.ID(), "checks", last.livenessChecks) - tab.bumpInBucket(b, last) - return - } - // No reply received, pick a replacement or delete the node if there aren't - // any replacements. - if r := tab.replace(b, last); r != nil { - tab.log.Debug("Replaced dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks, "r", r.ID(), "rip", r.IP()) - } else { - tab.log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks) - } -} - -// nodeToRevalidate returns the last node in a random, non-empty bucket. -func (tab *Table) nodeToRevalidate() (n *node, bi int) { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - for _, bi = range tab.rand.Perm(len(tab.buckets)) { - b := tab.buckets[bi] - if len(b.entries) > 0 { - last := b.entries[len(b.entries)-1] - return last, bi - } - } - return nil, 0 -} - -func (tab *Table) nextRevalidateTime() time.Duration { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - return time.Duration(tab.rand.Int63n(int64(tab.cfg.PingInterval))) -} - func (tab *Table) nextRefreshTime() time.Duration { - tab.mutex.Lock() - defer tab.mutex.Unlock() - half := tab.cfg.RefreshInterval / 2 return half + time.Duration(tab.rand.Int63n(int64(half))) } -// copyLiveNodes adds nodes from the table to the database if they have been in the table -// longer than seedMinTableTime. -func (tab *Table) copyLiveNodes() { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - now := time.Now() - for _, b := range &tab.buckets { - for _, n := range b.entries { - if n.livenessChecks > 0 && now.Sub(n.addedAt) >= seedMinTableTime { - tab.db.UpdateNode(unwrapNode(n)) - } - } - } -} - -// findnodeByID returns the n nodes in the table that are closest to the given id. -// This is used by the FINDNODE/v4 handler. -// -// The preferLive parameter says whether the caller wants liveness-checked results. If -// preferLive is true and the table contains any verified nodes, the result will not -// contain unverified nodes. However, if there are no verified nodes at all, the result -// will contain unverified nodes. -func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) *nodesByDistance { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - // Scan all buckets. There might be a better way to do this, but there aren't that many - // buckets, so this solution should be fine. The worst-case complexity of this loop - // is O(tab.len() * nresults). - nodes := &nodesByDistance{target: target} - liveNodes := &nodesByDistance{target: target} - for _, b := range &tab.buckets { - for _, n := range b.entries { - nodes.push(n, nresults) - if preferLive && n.livenessChecks > 0 { - liveNodes.push(n, nresults) - } - } - } - - if preferLive && len(liveNodes.entries) > 0 { - return liveNodes - } - return nodes -} - -// appendLiveNodes adds nodes at the given distance to the result slice. -func (tab *Table) appendLiveNodes(dist uint, result []*enode.Node) []*enode.Node { - if dist > 256 { - return result - } - if dist == 0 { - return append(result, tab.self()) - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - for _, n := range tab.bucketAtDistance(int(dist)).entries { - if n.livenessChecks >= 1 { - node := n.Node // avoid handing out pointer to struct field - result = append(result, &node) - } - } - return result -} - -// len returns the number of nodes in the table. -func (tab *Table) len() (n int) { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - for _, b := range &tab.buckets { - n += len(b.entries) - } - return n -} - -// bucketLen returns the number of nodes in the bucket for the given ID. -func (tab *Table) bucketLen(id enode.ID) int { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - return len(tab.bucket(id).entries) -} - // bucket returns the bucket for the given node ID hash. func (tab *Table) bucket(id enode.ID) *bucket { d := enode.LogDist(tab.self().ID(), id) @@ -511,95 +473,6 @@ func (tab *Table) bucketAtDistance(d int) *bucket { return tab.buckets[d-bucketMinDistance-1] } -// addSeenNode adds a node which may or may not be live to the end of a bucket. If the -// bucket has space available, adding the node succeeds immediately. Otherwise, the node is -// added to the replacements list. -// -// The caller must not hold tab.mutex. -func (tab *Table) addSeenNode(n *node) { - if n.ID() == tab.self().ID() { - return - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - b := tab.bucket(n.ID()) - if contains(b.entries, n.ID()) { - // Already in bucket, don't add. - return - } - if len(b.entries) >= bucketSize { - // Bucket full, maybe add as replacement. - tab.addReplacement(b, n) - return - } - if !tab.addIP(b, n.IP()) { - // Can't add: IP limit reached. - return - } - - // Add to end of bucket: - b.entries = append(b.entries, n) - b.replacements = deleteNode(b.replacements, n) - n.addedAt = time.Now() - - if tab.nodeAddedHook != nil { - tab.nodeAddedHook(b, n) - } -} - -// addVerifiedNode adds a node whose existence has been verified recently to the front of a -// bucket. If the node is already in the bucket, it is moved to the front. If the bucket -// has no space, the node is added to the replacements list. -// -// There is an additional safety measure: if the table is still initializing the node -// is not added. This prevents an attack where the table could be filled by just sending -// ping repeatedly. -// -// The caller must not hold tab.mutex. -func (tab *Table) addVerifiedNode(n *node) { - if !tab.isInitDone() { - return - } - if n.ID() == tab.self().ID() { - return - } - - tab.mutex.Lock() - defer tab.mutex.Unlock() - b := tab.bucket(n.ID()) - if tab.bumpInBucket(b, n) { - // Already in bucket, moved to front. - return - } - if len(b.entries) >= bucketSize { - // Bucket full, maybe add as replacement. - tab.addReplacement(b, n) - return - } - if !tab.addIP(b, n.IP()) { - // Can't add: IP limit reached. - return - } - - // Add to front of bucket. - b.entries, _ = pushNode(b.entries, n, bucketSize) - b.replacements = deleteNode(b.replacements, n) - n.addedAt = time.Now() - - if tab.nodeAddedHook != nil { - tab.nodeAddedHook(b, n) - } -} - -// delete removes an entry from the node table. It is used to evacuate dead nodes. -func (tab *Table) delete(node *node) { - tab.mutex.Lock() - defer tab.mutex.Unlock() - - tab.deleteInBucket(tab.bucket(node.ID()), node) -} - func (tab *Table) addIP(b *bucket, ip net.IP) bool { if len(ip) == 0 { return false // Nodes without IP cannot be added. @@ -627,15 +500,51 @@ func (tab *Table) removeIP(b *bucket, ip net.IP) { b.ips.Remove(ip) } +// handleAddNode adds the node in the request to the table, if there is space. +// The caller must hold tab.mutex. +func (tab *Table) handleAddNode(req addNodeOp) bool { + if req.node.ID() == tab.self().ID() { + return false + } + // For nodes from inbound contact, there is an additional safety measure: if the table + // is still initializing the node is not added. + if req.isInbound && !tab.isInitDone() { + return false + } + + b := tab.bucket(req.node.ID()) + if tab.bumpInBucket(b, req.node.Node) { + // Already in bucket, update record. + return false + } + if len(b.entries) >= bucketSize { + // Bucket full, maybe add as replacement. + tab.addReplacement(b, req.node) + return false + } + if !tab.addIP(b, req.node.IP()) { + // Can't add: IP limit reached. + return false + } + + // Add to bucket. + b.entries = append(b.entries, req.node) + b.replacements = deleteNode(b.replacements, req.node) + tab.nodeAdded(b, req.node) + return true +} + +// addReplacement adds n to the replacement cache of bucket b. func (tab *Table) addReplacement(b *bucket, n *node) { - for _, e := range b.replacements { - if e.ID() == n.ID() { - return // already in list - } + if contains(b.replacements, n.ID()) { + // TODO: update ENR + return } if !tab.addIP(b, n.IP()) { return } + + n.addedToTable = time.Now() var removed *node b.replacements, removed = pushNode(b.replacements, n, maxReplacements) if removed != nil { @@ -643,60 +552,108 @@ func (tab *Table) addReplacement(b *bucket, n *node) { } } -// replace removes n from the replacement list and replaces 'last' with it if it is the -// last entry in the bucket. If 'last' isn't the last entry, it has either been replaced -// with someone else or became active. -func (tab *Table) replace(b *bucket, last *node) *node { - if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID() != last.ID() { - // Entry has moved, don't replace it. - return nil +func (tab *Table) nodeAdded(b *bucket, n *node) { + if n.addedToTable == (time.Time{}) { + n.addedToTable = time.Now() } - // Still the last entry. - if len(b.replacements) == 0 { - tab.deleteInBucket(b, last) - return nil + n.addedToBucket = time.Now() + tab.revalidation.nodeAdded(tab, n) + if tab.nodeAddedHook != nil { + tab.nodeAddedHook(b, n) + } + if metrics.Enabled { + bucketsCounter[b.index].Inc(1) } - r := b.replacements[tab.rand.Intn(len(b.replacements))] - b.replacements = deleteNode(b.replacements, r) - b.entries[len(b.entries)-1] = r - tab.removeIP(b, last.IP()) - return r } -// bumpInBucket moves the given node to the front of the bucket entry list -// if it is contained in that list. -func (tab *Table) bumpInBucket(b *bucket, n *node) bool { - for i := range b.entries { - if b.entries[i].ID() == n.ID() { - if !n.IP().Equal(b.entries[i].IP()) { - // Endpoint has changed, ensure that the new IP fits into table limits. - tab.removeIP(b, b.entries[i].IP()) - if !tab.addIP(b, n.IP()) { - // It doesn't, put the previous one back. - tab.addIP(b, b.entries[i].IP()) - return false - } - } - // Move it to the front. - copy(b.entries[1:], b.entries[:i]) - b.entries[0] = n - return true - } - } - return false -} - -func (tab *Table) deleteInBucket(b *bucket, n *node) { - // Check if the node is actually in the bucket so the removed hook - // isn't called multiple times for the same node. - if !contains(b.entries, n.ID()) { - return - } - b.entries = deleteNode(b.entries, n) - tab.removeIP(b, n.IP()) +func (tab *Table) nodeRemoved(b *bucket, n *node) { + tab.revalidation.nodeRemoved(n) if tab.nodeRemovedHook != nil { tab.nodeRemovedHook(b, n) } + if metrics.Enabled { + bucketsCounter[b.index].Dec(1) + } +} + +// deleteInBucket removes node n from the table. +// If there are replacement nodes in the bucket, the node is replaced. +func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { + index := slices.IndexFunc(b.entries, func(e *node) bool { return e.ID() == id }) + if index == -1 { + // Entry has been removed already. + return nil + } + + // Remove the node. + n := b.entries[index] + b.entries = slices.Delete(b.entries, index, index+1) + tab.removeIP(b, n.IP()) + tab.nodeRemoved(b, n) + + // Add replacement. + if len(b.replacements) == 0 { + tab.log.Debug("Removed dead node", "b", b.index, "id", n.ID(), "ip", n.IP()) + return nil + } + rindex := tab.rand.Intn(len(b.replacements)) + rep := b.replacements[rindex] + b.replacements = slices.Delete(b.replacements, rindex, rindex+1) + b.entries = append(b.entries, rep) + tab.nodeAdded(b, rep) + tab.log.Debug("Replaced dead node", "b", b.index, "id", n.ID(), "ip", n.IP(), "r", rep.ID(), "rip", rep.IP()) + return rep +} + +// bumpInBucket updates the node record of n in the bucket. +func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node) bool { + i := slices.IndexFunc(b.entries, func(elem *node) bool { + return elem.ID() == newRecord.ID() + }) + if i == -1 { + return false + } + + if !newRecord.IP().Equal(b.entries[i].IP()) { + // Endpoint has changed, ensure that the new IP fits into table limits. + tab.removeIP(b, b.entries[i].IP()) + if !tab.addIP(b, newRecord.IP()) { + // It doesn't, put the previous one back. + tab.addIP(b, b.entries[i].IP()) + return false + } + } + b.entries[i].Node = newRecord + return true +} + +func (tab *Table) handleTrackRequest(op trackRequestOp) { + var fails int + if op.success { + // Reset failure counter because it counts _consecutive_ failures. + tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), 0) + } else { + fails = tab.db.FindFails(op.node.ID(), op.node.IP()) + fails++ + tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), fails) + } + + tab.mutex.Lock() + defer tab.mutex.Unlock() + + b := tab.bucket(op.node.ID()) + // Remove the node from the local table if it fails to return anything useful too + // many times, but only if there are enough other nodes in the bucket. This latter + // condition specifically exists to make bootstrapping in smaller test networks more + // reliable. + if fails >= maxFindnodeFailures && len(b.entries) >= bucketSize/4 { + tab.deleteInBucket(b, op.node.ID()) + } + + // Add found nodes. + for _, n := range op.foundNodes { + tab.handleAddNode(addNodeOp{n, false}) + } } func contains(ns []*node, id enode.ID) bool { diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go new file mode 100644 index 0000000000..9a13900ebc --- /dev/null +++ b/p2p/discover/table_reval.go @@ -0,0 +1,223 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package discover + +import ( + "fmt" + "math" + "slices" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/p2p/enode" +) + +const never = mclock.AbsTime(math.MaxInt64) + +// tableRevalidation implements the node revalidation process. +// It tracks all nodes contained in Table, and schedules sending PING to them. +type tableRevalidation struct { + fast revalidationList + slow revalidationList + activeReq map[enode.ID]struct{} +} + +type revalidationResponse struct { + n *node + newRecord *enode.Node + list *revalidationList + didRespond bool +} + +func (tr *tableRevalidation) init(cfg *Config) { + tr.activeReq = make(map[enode.ID]struct{}) + tr.fast.nextTime = never + tr.fast.interval = cfg.PingInterval + tr.fast.name = "fast" + tr.slow.nextTime = never + tr.slow.interval = cfg.PingInterval * 3 + tr.slow.name = "slow" +} + +// nodeAdded is called when the table receives a new node. +func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) { + tr.fast.push(n, tab.cfg.Clock.Now(), &tab.rand) +} + +// nodeRemoved is called when a node was removed from the table. +func (tr *tableRevalidation) nodeRemoved(n *node) { + if !tr.fast.remove(n) { + tr.slow.remove(n) + } +} + +// run performs node revalidation. +// 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. +func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { + if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { + tr.startRequest(tab, &tr.fast, n) + tr.fast.schedule(now, &tab.rand) + } + if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { + tr.startRequest(tab, &tr.slow, n) + tr.slow.schedule(now, &tab.rand) + } + + return min(tr.fast.nextTime, tr.slow.nextTime) +} + +// startRequest spawns a revalidation request for node n. +func (tr *tableRevalidation) startRequest(tab *Table, list *revalidationList, n *node) { + if _, ok := tr.activeReq[n.ID()]; ok { + panic(fmt.Errorf("duplicate startRequest (list %q, node %v)", list.name, n.ID())) + } + tr.activeReq[n.ID()] = struct{}{} + resp := revalidationResponse{n: n, list: list} + + // Fetch the node while holding lock. + tab.mutex.Lock() + node := n.Node + tab.mutex.Unlock() + + go tab.doRevalidate(resp, node) +} + +func (tab *Table) doRevalidate(resp revalidationResponse, node *enode.Node) { + // Ping the selected node and wait for a pong response. + remoteSeq, err := tab.net.ping(node) + resp.didRespond = err == nil + + // Also fetch record if the node replied and returned a higher sequence number. + if remoteSeq > node.Seq() { + newrec, err := tab.net.RequestENR(node) + if err != nil { + tab.log.Debug("ENR request failed", "id", node.ID(), "err", err) + } else { + resp.newRecord = newrec + } + } + + select { + case tab.revalResponseCh <- resp: + case <-tab.closed: + } +} + +// handleResponse processes the result of a revalidation request. +func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationResponse) { + now := tab.cfg.Clock.Now() + n := resp.n + b := tab.bucket(n.ID()) + delete(tr.activeReq, n.ID()) + + tab.mutex.Lock() + defer tab.mutex.Unlock() + + if !resp.didRespond { + // Revalidation failed. + n.livenessChecks /= 3 + if n.livenessChecks <= 0 { + tab.deleteInBucket(b, n.ID()) + } else { + tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) + } + return + } + + // The node responded. + n.livenessChecks++ + n.isValidatedLive = true + var endpointChanged bool + if resp.newRecord != nil { + endpointChanged = tab.bumpInBucket(b, resp.newRecord) + if endpointChanged { + // If the node changed its advertised endpoint, the updated ENR is not served + // until it has been revalidated. + n.isValidatedLive = false + } + } + tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", resp.list.name) + + // Move node over to slow queue after first validation. + if !endpointChanged { + tr.moveToList(&tr.slow, resp.list, n, now, &tab.rand) + } else { + tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) + } + + // Store potential seeds in database. + if n.isValidatedLive && n.livenessChecks > 5 { + tab.db.UpdateNode(resp.n.Node) + } +} + +func (tr *tableRevalidation) moveToList(dest, source *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { + if source == dest { + return + } + if !source.remove(n) { + panic(fmt.Errorf("moveToList(%q -> %q): node %v not in source list", source.name, dest.name, n.ID())) + } + dest.push(n, now, rand) +} + +// revalidationList holds a list nodes and the next revalidation time. +type revalidationList struct { + nodes []*node + nextTime mclock.AbsTime + interval time.Duration + name string +} + +// 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{}) *node { + if now < list.nextTime || len(list.nodes) == 0 { + return nil + } + for i := 0; i < len(list.nodes)*3; i++ { + n := list.nodes[rand.Intn(len(list.nodes))] + _, excluded := exclude[n.ID()] + if !excluded { + return n + } + } + return nil +} + +func (list *revalidationList) schedule(now mclock.AbsTime, rand randomSource) { + list.nextTime = now.Add(time.Duration(rand.Int63n(int64(list.interval)))) +} + +func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSource) { + list.nodes = append(list.nodes, n) + if list.nextTime == never { + list.schedule(now, rand) + } +} + +func (list *revalidationList) remove(n *node) bool { + i := slices.Index(list.nodes, n) + if i == -1 { + return false + } + list.nodes = slices.Delete(list.nodes, i, i+1) + if len(list.nodes) == 0 { + list.nextTime = never + } + return true +} diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 3ba3422251..f72ecd94c9 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -20,14 +20,16 @@ import ( "crypto/ecdsa" "fmt" "math/rand" - "net" "reflect" "testing" "testing/quick" "time" + "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/testlog" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/netutil" @@ -49,106 +51,109 @@ func TestTable_pingReplace(t *testing.T) { } func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding bool) { + simclock := new(mclock.Simulated) transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{ + Clock: simclock, + Log: testlog.Logger(t, log.LevelTrace), + }) defer db.Close() defer tab.close() <-tab.initDone // Fill up the sender's bucket. - pingKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") - pingSender := wrapNode(enode.NewV4(&pingKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)) - last := fillBucket(tab, pingSender) + replacementNodeKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") + replacementNode := wrapNode(enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)) + last := fillBucket(tab, replacementNode.ID()) + tab.mutex.Lock() + nodeEvents := newNodeEventRecorder(128) + tab.nodeAddedHook = nodeEvents.nodeAdded + tab.nodeRemovedHook = nodeEvents.nodeRemoved + tab.mutex.Unlock() - // Add the sender as if it just pinged us. Revalidate should replace the last node in - // its bucket if it is unresponsive. Revalidate again to ensure that + // The revalidation process should replace + // this node in the bucket if it is unresponsive. transport.dead[last.ID()] = !lastInBucketIsResponding - transport.dead[pingSender.ID()] = !newNodeIsResponding - tab.addSeenNode(pingSender) - tab.doRevalidate(make(chan struct{}, 1)) - tab.doRevalidate(make(chan struct{}, 1)) + transport.dead[replacementNode.ID()] = !newNodeIsResponding - if !transport.pinged[last.ID()] { - // Oldest node in bucket is pinged to see whether it is still alive. - t.Error("table did not ping last node in bucket") + // Add replacement node to table. + tab.addFoundNode(replacementNode) + + t.Log("last:", last.ID()) + t.Log("replacement:", replacementNode.ID()) + + // Wait until the last node was pinged. + waitForRevalidationPing(t, transport, tab, last.ID()) + + if !lastInBucketIsResponding { + if !nodeEvents.waitNodeAbsent(last.ID(), 2*time.Second) { + t.Error("last node was not removed") + } + if !nodeEvents.waitNodePresent(replacementNode.ID(), 2*time.Second) { + t.Error("replacement node was not added") + } + + // If a replacement is expected, we also need to wait until the replacement node + // was pinged and added/removed. + waitForRevalidationPing(t, transport, tab, replacementNode.ID()) + if !newNodeIsResponding { + if !nodeEvents.waitNodeAbsent(replacementNode.ID(), 2*time.Second) { + t.Error("replacement node was not removed") + } + } } + // Check bucket content. tab.mutex.Lock() defer tab.mutex.Unlock() wantSize := bucketSize if !lastInBucketIsResponding && !newNodeIsResponding { wantSize-- } - if l := len(tab.bucket(pingSender.ID()).entries); l != wantSize { - t.Errorf("wrong bucket size after bond: got %d, want %d", l, wantSize) + bucket := tab.bucket(replacementNode.ID()) + if l := len(bucket.entries); l != wantSize { + t.Errorf("wrong bucket size after revalidation: got %d, want %d", l, wantSize) } - if found := contains(tab.bucket(pingSender.ID()).entries, last.ID()); found != lastInBucketIsResponding { - t.Errorf("last entry found: %t, want: %t", found, lastInBucketIsResponding) + if ok := contains(bucket.entries, last.ID()); ok != lastInBucketIsResponding { + t.Errorf("revalidated node found: %t, want: %t", ok, lastInBucketIsResponding) } wantNewEntry := newNodeIsResponding && !lastInBucketIsResponding - if found := contains(tab.bucket(pingSender.ID()).entries, pingSender.ID()); found != wantNewEntry { - t.Errorf("new entry found: %t, want: %t", found, wantNewEntry) + if ok := contains(bucket.entries, replacementNode.ID()); ok != wantNewEntry { + t.Errorf("replacement node found: %t, want: %t", ok, wantNewEntry) } } -func TestBucket_bumpNoDuplicates(t *testing.T) { - t.Parallel() - cfg := &quick.Config{ - MaxCount: 1000, - Rand: rand.New(rand.NewSource(time.Now().Unix())), - Values: func(args []reflect.Value, rand *rand.Rand) { - // generate a random list of nodes. this will be the content of the bucket. - n := rand.Intn(bucketSize-1) + 1 - nodes := make([]*node, n) - for i := range nodes { - nodes[i] = nodeAtDistance(enode.ID{}, 200, intIP(200)) - } - args[0] = reflect.ValueOf(nodes) - // generate random bump positions. - bumps := make([]int, rand.Intn(100)) - for i := range bumps { - bumps[i] = rand.Intn(len(nodes)) - } - args[1] = reflect.ValueOf(bumps) - }, - } +// waitForRevalidationPing waits until a PING message is sent to a node with the given id. +func waitForRevalidationPing(t *testing.T, transport *pingRecorder, tab *Table, id enode.ID) *enode.Node { + t.Helper() - prop := func(nodes []*node, bumps []int) (ok bool) { - tab, db := newTestTable(newPingRecorder()) - defer db.Close() - defer tab.close() - - b := &bucket{entries: make([]*node, len(nodes))} - copy(b.entries, nodes) - for i, pos := range bumps { - tab.bumpInBucket(b, b.entries[pos]) - if hasDuplicates(b.entries) { - t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps)) - for _, n := range b.entries { - t.Logf(" %p", n) - } - return false - } + simclock := tab.cfg.Clock.(*mclock.Simulated) + maxAttempts := tab.len() * 8 + for i := 0; i < maxAttempts; i++ { + simclock.Run(tab.cfg.PingInterval) + p := transport.waitPing(2 * time.Second) + if p == nil { + t.Fatal("Table did not send revalidation ping") + } + if id == (enode.ID{}) || p.ID() == id { + return p } - checkIPLimitInvariant(t, tab) - return true - } - if err := quick.Check(prop, cfg); err != nil { - t.Error(err) } + t.Fatalf("Table did not ping node %v (%d attempts)", id, maxAttempts) + return nil } // This checks that the table-wide IP limit is applied correctly. func TestTable_IPLimit(t *testing.T) { transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{}) defer db.Close() defer tab.close() for i := 0; i < tableIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)}) - tab.addSeenNode(n) + tab.addFoundNode(n) } if tab.len() > tableIPLimit { t.Errorf("too many nodes in table") @@ -159,14 +164,14 @@ func TestTable_IPLimit(t *testing.T) { // This checks that the per-bucket IP limit is applied correctly. func TestTable_BucketIPLimit(t *testing.T) { transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{}) defer db.Close() defer tab.close() d := 3 for i := 0; i < bucketIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), d, net.IP{172, 0, 1, byte(i)}) - tab.addSeenNode(n) + tab.addFoundNode(n) } if tab.len() > bucketIPLimit { t.Errorf("too many nodes in table") @@ -196,7 +201,7 @@ func TestTable_findnodeByID(t *testing.T) { test := func(test *closeTest) bool { // for any node table, Target and N transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{}) defer db.Close() defer tab.close() fillTable(tab, test.All, true) @@ -271,7 +276,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { } func TestTable_addVerifiedNode(t *testing.T) { - tab, db := newTestTable(newPingRecorder()) + tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() defer tab.close() @@ -279,31 +284,32 @@ func TestTable_addVerifiedNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addSeenNode(n1) - tab.addSeenNode(n2) + tab.addFoundNode(n1) + tab.addFoundNode(n2) + bucket := tab.bucket(n1.ID()) // Verify bucket content: bcontent := []*node{n1, n2} - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { - t.Fatalf("wrong bucket content: %v", tab.bucket(n1.ID()).entries) + if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(bcontent)) { + t.Fatalf("wrong bucket content: %v", bucket.entries) } // Add a changed version of n2. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addVerifiedNode(newn2) + tab.addInboundNode(newn2) // Check that bucket is updated correctly. - newBcontent := []*node{newn2, n1} - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, newBcontent) { - t.Fatalf("wrong bucket content after update: %v", tab.bucket(n1.ID()).entries) + newBcontent := []*node{n1, newn2} + if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(newBcontent)) { + t.Fatalf("wrong bucket content after update: %v", bucket.entries) } checkIPLimitInvariant(t, tab) } func TestTable_addSeenNode(t *testing.T) { - tab, db := newTestTable(newPingRecorder()) + tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() defer tab.close() @@ -311,8 +317,8 @@ func TestTable_addSeenNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addSeenNode(n1) - tab.addSeenNode(n2) + tab.addFoundNode(n1) + tab.addFoundNode(n2) // Verify bucket content: bcontent := []*node{n1, n2} @@ -324,7 +330,7 @@ func TestTable_addSeenNode(t *testing.T) { newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addSeenNode(newn2) + tab.addFoundNode(newn2) // Check that bucket content is unchanged. if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { @@ -337,7 +343,10 @@ func TestTable_addSeenNode(t *testing.T) { // announces a new sequence number, the new record should be pulled. func TestTable_revalidateSyncRecord(t *testing.T) { transport := newPingRecorder() - tab, db := newTestTable(transport) + tab, db := newTestTable(transport, Config{ + Clock: new(mclock.Simulated), + Log: testlog.Logger(t, log.LevelTrace), + }) <-tab.initDone defer db.Close() defer tab.close() @@ -347,14 +356,18 @@ func TestTable_revalidateSyncRecord(t *testing.T) { r.Set(enr.IP(net.IP{127, 0, 0, 1})) id := enode.ID{1} n1 := wrapNode(enode.SignNull(&r, id)) - tab.addSeenNode(n1) + tab.addFoundNode(n1) // Update the node record. r.Set(enr.WithEntry("foo", "bar")) n2 := enode.SignNull(&r, id) transport.updateRecord(n2) - tab.doRevalidate(make(chan struct{}, 1)) + // Wait for revalidation. We wait for the node to be revalidated two times + // in order to synchronize with the update in the able. + waitForRevalidationPing(t, transport, tab, n2.ID()) + waitForRevalidationPing(t, transport, tab, n2.ID()) + intable := tab.getNode(id) if !reflect.DeepEqual(intable, n2) { t.Fatalf("table contains old record with seq %d, want seq %d", intable.Seq(), n2.Seq()) diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index f5d4d39bdb..86c6048094 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -26,6 +26,8 @@ import ( "net" "slices" "sync" + "sync/atomic" + "time" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enode" @@ -40,8 +42,7 @@ func init() { nullNode = enode.SignNull(&r, enode.ID{}) } -func newTestTable(t transport) (*Table, *enode.DB) { - cfg := Config{} +func newTestTable(t transport, cfg Config) (*Table, *enode.DB) { db, _ := enode.OpenDB("") tab, _ := newTable(t, db, cfg) go tab.loop() @@ -98,11 +99,14 @@ func intIP(i int) net.IP { } // fillBucket inserts nodes into the given bucket until it is full. -func fillBucket(tab *Table, n *node) (last *node) { - ld := enode.LogDist(tab.self().ID(), n.ID()) - b := tab.bucket(n.ID()) +func fillBucket(tab *Table, id enode.ID) (last *node) { + ld := enode.LogDist(tab.self().ID(), id) + b := tab.bucket(id) for len(b.entries) < bucketSize { - b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld))) + node := nodeAtDistance(tab.self().ID(), ld, intIP(ld)) + if !tab.addFoundNode(node) { + panic("node not added") + } } return b.entries[bucketSize-1] } @@ -113,16 +117,19 @@ func fillTable(tab *Table, nodes []*node, setLive bool) { for _, n := range nodes { if setLive { n.livenessChecks = 1 + n.isValidatedLive = true } - tab.addSeenNode(n) + tab.addFoundNode(n) } } type pingRecorder struct { - mu sync.Mutex - dead, pinged map[enode.ID]bool - records map[enode.ID]*enode.Node - n *enode.Node + mu sync.Mutex + cond *sync.Cond + dead map[enode.ID]bool + records map[enode.ID]*enode.Node + pinged []*enode.Node + n *enode.Node } func newPingRecorder() *pingRecorder { @@ -130,12 +137,13 @@ func newPingRecorder() *pingRecorder { r.Set(enr.IP{0, 0, 0, 0}) n := enode.SignNull(&r, enode.ID{}) - return &pingRecorder{ + t := &pingRecorder{ dead: make(map[enode.ID]bool), - pinged: make(map[enode.ID]bool), records: make(map[enode.ID]*enode.Node), n: n, } + t.cond = sync.NewCond(&t.mu) + return t } // updateRecord updates a node record. Future calls to ping and @@ -151,12 +159,40 @@ func (t *pingRecorder) Self() *enode.Node { return nullNode } func (t *pingRecorder) lookupSelf() []*enode.Node { return nil } func (t *pingRecorder) lookupRandom() []*enode.Node { return nil } +func (t *pingRecorder) waitPing(timeout time.Duration) *enode.Node { + t.mu.Lock() + defer t.mu.Unlock() + + // Wake up the loop on timeout. + var timedout atomic.Bool + timer := time.AfterFunc(timeout, func() { + timedout.Store(true) + t.cond.Broadcast() + }) + defer timer.Stop() + + // Wait for a ping. + for { + if timedout.Load() { + return nil + } + if len(t.pinged) > 0 { + n := t.pinged[0] + t.pinged = append(t.pinged[:0], t.pinged[1:]...) + return n + } + t.cond.Wait() + } +} + // ping simulates a ping request. func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) { t.mu.Lock() defer t.mu.Unlock() - t.pinged[n.ID()] = true + t.pinged = append(t.pinged, n) + t.cond.Broadcast() + if t.dead[n.ID()] { return 0, errTimeout } @@ -256,3 +292,57 @@ func hexEncPubkey(h string) (ret encPubkey) { copy(ret[:], b) return ret } + +type nodeEventRecorder struct { + evc chan recordedNodeEvent +} + +type recordedNodeEvent struct { + node *node + added bool +} + +func newNodeEventRecorder(buffer int) *nodeEventRecorder { + return &nodeEventRecorder{ + evc: make(chan recordedNodeEvent, buffer), + } +} + +func (set *nodeEventRecorder) nodeAdded(b *bucket, n *node) { + select { + case set.evc <- recordedNodeEvent{n, true}: + default: + panic("no space in event buffer") + } +} + +func (set *nodeEventRecorder) nodeRemoved(b *bucket, n *node) { + select { + case set.evc <- recordedNodeEvent{n, false}: + default: + panic("no space in event buffer") + } +} + +func (set *nodeEventRecorder) waitNodePresent(id enode.ID, timeout time.Duration) bool { + return set.waitNodeEvent(id, timeout, true) +} + +func (set *nodeEventRecorder) waitNodeAbsent(id enode.ID, timeout time.Duration) bool { + return set.waitNodeEvent(id, timeout, false) +} + +func (set *nodeEventRecorder) waitNodeEvent(id enode.ID, timeout time.Duration, added bool) bool { + timer := time.NewTimer(timeout) + defer timer.Stop() + for { + select { + case ev := <-set.evc: + if ev.node.ID() == id && ev.added == added { + return true + } + case <-timer.C: + return false + } + } +} diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 7a0a0f1c77..be6058ec50 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -142,7 +142,7 @@ func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { log: cfg.Log, } - tab, err := newMeteredTable(t, ln.Database(), cfg) + tab, err := newTable(t, ln.Database(), cfg) if err != nil { return nil, err } @@ -375,6 +375,10 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { return respN, nil } +func (t *UDPv4) TableBuckets() [][]BucketNode { + return t.tab.Nodes() +} + // pending adds a reply matcher to the pending reply queue. // see the documentation of type replyMatcher for a detailed explanation. func (t *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) *replyMatcher { @@ -669,10 +673,10 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { t.sendPing(fromID, from, func() { - t.tab.addVerifiedNode(n) + t.tab.addInboundNode(n) }) } else { - t.tab.addVerifiedNode(n) + t.tab.addInboundNode(n) } // Update node database and endpoint predictor. diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9b80214f75..9c454d98e3 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -264,7 +264,7 @@ func TestUDPv4_findnode(t *testing.T) { n := wrapNode(enode.NewV4(&key.PublicKey, ip, 0, 2000)) // Ensure half of table content isn't verified live yet. if i > numCandidates/2 { - n.livenessChecks = 1 + n.isValidatedLive = true live[n.ID()] = true } nodes.push(n, numCandidates) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 20a8bccd05..8cdc9dfbce 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -175,7 +175,7 @@ func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { cancelCloseCtx: cancelCloseCtx, } t.talk = newTalkSystem(t) - tab, err := newMeteredTable(t, t.db, cfg) + tab, err := newTable(t, t.db, cfg) if err != nil { return nil, err } @@ -699,7 +699,7 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } if fromNode != nil { // Handshake succeeded, add to table. - t.tab.addSeenNode(wrapNode(fromNode)) + t.tab.addInboundNode(wrapNode(fromNode)) } if packet.Kind() != v5wire.WhoareyouPacket { // WHOAREYOU logged separately to report errors. diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 4373ea8184..0015f7cc70 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -141,7 +141,7 @@ func TestUDPv5_unknownPacket(t *testing.T) { // Make node known. n := test.getNode(test.remotekey, test.remoteaddr).Node() - test.table.addSeenNode(wrapNode(n)) + test.table.addFoundNode(wrapNode(n)) test.packetIn(&v5wire.Unknown{Nonce: nonce}) test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) { diff --git a/p2p/server.go b/p2p/server.go index 5b9a4aa71f..79c5fc76b6 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -190,8 +190,8 @@ type Server struct { nodedb *enode.DB localnode *enode.LocalNode - ntab *discover.UDPv4 - DiscV5 *discover.UDPv5 + discv4 *discover.UDPv4 + discv5 *discover.UDPv5 discmix *enode.FairMix dialsched *dialScheduler @@ -400,6 +400,16 @@ func (srv *Server) Self() *enode.Node { return ln.Node() } +// DiscoveryV4 returns the discovery v4 instance, if configured. +func (srv *Server) DiscoveryV4() *discover.UDPv4 { + return srv.discv4 +} + +// DiscoveryV4 returns the discovery v5 instance, if configured. +func (srv *Server) DiscoveryV5() *discover.UDPv5 { + return srv.discv5 +} + // Stop terminates the server and all active peer connections. // It blocks until all active connections have been closed. func (srv *Server) Stop() { @@ -547,13 +557,13 @@ func (srv *Server) setupDiscovery() error { ) // If both versions of discovery are running, setup a shared // connection, so v5 can read unhandled messages from v4. - if srv.DiscoveryV4 && srv.DiscoveryV5 { + if srv.Config.DiscoveryV4 && srv.Config.DiscoveryV5 { unhandled = make(chan discover.ReadPacket, 100) sconn = &sharedUDPConn{conn, unhandled} } // Start discovery services. - if srv.DiscoveryV4 { + if srv.Config.DiscoveryV4 { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, @@ -565,17 +575,17 @@ func (srv *Server) setupDiscovery() error { if err != nil { return err } - srv.ntab = ntab + srv.discv4 = ntab srv.discmix.AddSource(ntab.RandomNodes()) } - if srv.DiscoveryV5 { + if srv.Config.DiscoveryV5 { cfg := discover.Config{ PrivateKey: srv.PrivateKey, NetRestrict: srv.NetRestrict, Bootnodes: srv.BootstrapNodesV5, Log: srv.log, } - srv.DiscV5, err = discover.ListenV5(sconn, srv.localnode, cfg) + srv.discv5, err = discover.ListenV5(sconn, srv.localnode, cfg) if err != nil { return err } @@ -602,8 +612,8 @@ func (srv *Server) setupDialScheduler() { dialer: srv.Dialer, clock: srv.clock, } - if srv.ntab != nil { - config.resolver = srv.ntab + if srv.discv4 != nil { + config.resolver = srv.discv4 } if config.dialer == nil { config.dialer = tcpDialer{&net.Dialer{Timeout: defaultDialTimeout}} @@ -799,11 +809,11 @@ running: srv.log.Trace("P2P networking is spinning down") // Terminate discovery. If there is a running lookup it will terminate soon. - if srv.ntab != nil { - srv.ntab.Close() + if srv.discv4 != nil { + srv.discv4.Close() } - if srv.DiscV5 != nil { - srv.DiscV5.Close() + if srv.discv5 != nil { + srv.discv5.Close() } // Disconnect all peers. for _, p := range peers { From cc9e2bd9ddd538811612156965ce008efd919264 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 23 May 2024 14:27:03 +0200 Subject: [PATCH 008/196] p2p/enode: fix endpoint determination for IPv6 (#29801) enode.Node has separate accessor functions for getting the IP, UDP port and TCP port. These methods performed separate checks for attributes set in the ENR. With this PR, the accessor methods will now return cached information, and the endpoint is determined when the node is created. The logic to determine the preferred endpoint is now more correct, and considers how 'global' each address is when both IPv4 and IPv6 addresses are present in the ENR. --- p2p/enode/idscheme.go | 2 +- p2p/enode/node.go | 137 +++++++++++++++++++++++++--------- p2p/enode/node_test.go | 162 +++++++++++++++++++++++++++++++++++++++++ p2p/enode/nodedb.go | 12 +-- p2p/enode/urlv4.go | 2 +- p2p/enr/entries.go | 55 ++++++++++++++ 6 files changed, 330 insertions(+), 40 deletions(-) diff --git a/p2p/enode/idscheme.go b/p2p/enode/idscheme.go index 6ad7f809a7..db7841c047 100644 --- a/p2p/enode/idscheme.go +++ b/p2p/enode/idscheme.go @@ -157,5 +157,5 @@ func SignNull(r *enr.Record, id ID) *Node { if err := r.SetSig(NullID{}, []byte{}); err != nil { panic(err) } - return &Node{r: *r, id: id} + return newNodeWithID(r, id) } diff --git a/p2p/enode/node.go b/p2p/enode/node.go index d7a1a9a156..e7fe0e0ace 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -24,6 +24,7 @@ import ( "fmt" "math/bits" "net" + "net/netip" "strings" "github.com/ethereum/go-ethereum/p2p/enr" @@ -36,6 +37,10 @@ var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded reco type Node struct { r enr.Record id ID + // endpoint information + ip netip.Addr + udp uint16 + tcp uint16 } // New wraps a node record. The record must be valid according to the given @@ -44,11 +49,76 @@ func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { if err := r.VerifySignature(validSchemes); err != nil { return nil, err } - node := &Node{r: *r} - if n := copy(node.id[:], validSchemes.NodeAddr(&node.r)); n != len(ID{}) { - return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(ID{})) + var id ID + if n := copy(id[:], validSchemes.NodeAddr(r)); n != len(id) { + return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(id)) + } + return newNodeWithID(r, id), nil +} + +func newNodeWithID(r *enr.Record, id ID) *Node { + n := &Node{r: *r, id: id} + // Set the preferred endpoint. + // Here we decide between IPv4 and IPv6, choosing the 'most global' address. + var ip4 netip.Addr + var ip6 netip.Addr + n.Load((*enr.IPv4Addr)(&ip4)) + n.Load((*enr.IPv6Addr)(&ip6)) + valid4 := validIP(ip4) + valid6 := validIP(ip6) + switch { + case valid4 && valid6: + if localityScore(ip4) >= localityScore(ip6) { + n.setIP4(ip4) + } else { + n.setIP6(ip6) + } + case valid4: + n.setIP4(ip4) + case valid6: + n.setIP6(ip6) + } + return n +} + +// validIP reports whether 'ip' is a valid node endpoint IP address. +func validIP(ip netip.Addr) bool { + return ip.IsValid() && !ip.IsMulticast() +} + +func localityScore(ip netip.Addr) int { + switch { + case ip.IsUnspecified(): + return 0 + case ip.IsLoopback(): + return 1 + case ip.IsLinkLocalUnicast(): + return 2 + case ip.IsPrivate(): + return 3 + default: + return 4 + } +} + +func (n *Node) setIP4(ip netip.Addr) { + n.ip = ip + n.Load((*enr.UDP)(&n.udp)) + n.Load((*enr.TCP)(&n.tcp)) +} + +func (n *Node) setIP6(ip netip.Addr) { + if ip.Is4In6() { + n.setIP4(ip) + return + } + n.ip = ip + if err := n.Load((*enr.UDP6)(&n.udp)); err != nil { + n.Load((*enr.UDP)(&n.udp)) + } + if err := n.Load((*enr.TCP6)(&n.tcp)); err != nil { + n.Load((*enr.TCP)(&n.tcp)) } - return node, nil } // MustParse parses a node record or enode:// URL. It panics if the input is invalid. @@ -89,43 +159,45 @@ func (n *Node) Seq() uint64 { return n.r.Seq() } -// Incomplete returns true for nodes with no IP address. -func (n *Node) Incomplete() bool { - return n.IP() == nil -} - // Load retrieves an entry from the underlying record. func (n *Node) Load(k enr.Entry) error { return n.r.Load(k) } -// IP returns the IP address of the node. This prefers IPv4 addresses. +// IP returns the IP address of the node. func (n *Node) IP() net.IP { - var ( - ip4 enr.IPv4 - ip6 enr.IPv6 - ) - if n.Load(&ip4) == nil { - return net.IP(ip4) - } - if n.Load(&ip6) == nil { - return net.IP(ip6) - } - return nil + return net.IP(n.ip.AsSlice()) +} + +// IPAddr returns the IP address of the node. +func (n *Node) IPAddr() netip.Addr { + return n.ip } // UDP returns the UDP port of the node. func (n *Node) UDP() int { - var port enr.UDP - n.Load(&port) - return int(port) + return int(n.udp) } // TCP returns the TCP port of the node. func (n *Node) TCP() int { - var port enr.TCP - n.Load(&port) - return int(port) + return int(n.tcp) +} + +// UDPEndpoint returns the announced TCP endpoint. +func (n *Node) UDPEndpoint() (netip.AddrPort, bool) { + if !n.ip.IsValid() || n.ip.IsUnspecified() || n.udp == 0 { + return netip.AddrPort{}, false + } + return netip.AddrPortFrom(n.ip, n.udp), true +} + +// TCPEndpoint returns the announced TCP endpoint. +func (n *Node) TCPEndpoint() (netip.AddrPort, bool) { + if !n.ip.IsValid() || n.ip.IsUnspecified() || n.tcp == 0 { + return netip.AddrPort{}, false + } + return netip.AddrPortFrom(n.ip, n.udp), true } // Pubkey returns the secp256k1 public key of the node, if present. @@ -147,16 +219,15 @@ func (n *Node) Record() *enr.Record { // ValidateComplete checks whether n has a valid IP and UDP port. // Deprecated: don't use this method. func (n *Node) ValidateComplete() error { - if n.Incomplete() { + if !n.ip.IsValid() { return errors.New("missing IP address") } - if n.UDP() == 0 { - return errors.New("missing UDP port") - } - ip := n.IP() - if ip.IsMulticast() || ip.IsUnspecified() { + if n.ip.IsMulticast() || n.ip.IsUnspecified() { return errors.New("invalid IP (multicast/unspecified)") } + if n.udp == 0 { + return errors.New("missing UDP port") + } // Validate the node key (on curve, etc.). var key Secp256k1 return n.Load(&key) diff --git a/p2p/enode/node_test.go b/p2p/enode/node_test.go index d15859c477..56e196e82e 100644 --- a/p2p/enode/node_test.go +++ b/p2p/enode/node_test.go @@ -21,6 +21,7 @@ import ( "encoding/hex" "fmt" "math/big" + "net/netip" "testing" "testing/quick" @@ -64,6 +65,167 @@ func TestPythonInterop(t *testing.T) { } } +func TestNodeEndpoints(t *testing.T) { + id := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") + type endpointTest struct { + name string + node *Node + wantIP netip.Addr + wantUDP int + wantTCP int + } + tests := []endpointTest{ + { + name: "no-addr", + node: func() *Node { + var r enr.Record + return SignNull(&r, id) + }(), + }, + { + name: "udp-only", + node: func() *Node { + var r enr.Record + r.Set(enr.UDP(9000)) + return SignNull(&r, id) + }(), + }, + { + name: "tcp-only", + node: func() *Node { + var r enr.Record + r.Set(enr.TCP(9000)) + return SignNull(&r, id) + }(), + }, + { + name: "ipv4-only-loopback", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("127.0.0.1"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("127.0.0.1"), + }, + { + name: "ipv4-only-unspecified", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("0.0.0.0"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("0.0.0.0"), + }, + { + name: "ipv4-only", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("99.22.33.1"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("99.22.33.1"), + }, + { + name: "ipv6-only", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + }, + { + name: "ipv4-loopback-and-ipv6-global", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("127.0.0.1"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantUDP: 30306, + }, + { + name: "ipv4-unspecified-and-ipv6-loopback", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("0.0.0.0"))) + r.Set(enr.IPv6Addr(netip.MustParseAddr("::1"))) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("::1"), + }, + { + name: "ipv4-private-and-ipv6-global", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("192.168.2.2"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantUDP: 30306, + }, + { + name: "ipv4-local-and-ipv6-global", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("169.254.2.6"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("2001::ff00:0042:8329"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("2001::ff00:0042:8329"), + wantUDP: 30306, + }, + { + name: "ipv4-private-and-ipv6-private", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("192.168.2.2"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("fd00::abcd:1"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("192.168.2.2"), + wantUDP: 30304, + }, + { + name: "ipv4-private-and-ipv6-link-local", + node: func() *Node { + var r enr.Record + r.Set(enr.IPv4Addr(netip.MustParseAddr("192.168.2.2"))) + r.Set(enr.UDP(30304)) + r.Set(enr.IPv6Addr(netip.MustParseAddr("fe80::1"))) + r.Set(enr.UDP6(30306)) + return SignNull(&r, id) + }(), + wantIP: netip.MustParseAddr("192.168.2.2"), + wantUDP: 30304, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.wantIP != test.node.IPAddr() { + t.Errorf("node has wrong IP %v, want %v", test.node.IPAddr(), test.wantIP) + } + if test.wantUDP != test.node.UDP() { + t.Errorf("node has wrong UDP port %d, want %d", test.node.UDP(), test.wantUDP) + } + if test.wantTCP != test.node.TCP() { + t.Errorf("node has wrong TCP port %d, want %d", test.node.TCP(), test.wantTCP) + } + }) + } +} + func TestHexID(t *testing.T) { ref := ID{0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188} id1 := HexID("0x00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 6d55ce17f1..654d71d47b 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/rlp" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/errors" @@ -242,13 +243,14 @@ func (db *DB) Node(id ID) *Node { } func mustDecodeNode(id, data []byte) *Node { - node := new(Node) - if err := rlp.DecodeBytes(data, &node.r); err != nil { + var r enr.Record + if err := rlp.DecodeBytes(data, &r); err != nil { panic(fmt.Errorf("p2p/enode: can't decode node %x in DB: %v", id, err)) } - // Restore node id cache. - copy(node.id[:], id) - return node + if len(id) != len(ID{}) { + panic(fmt.Errorf("invalid id length %d", len(id))) + } + return newNodeWithID(&r, ID(id)) } // UpdateNode inserts - potentially overwriting - a node into the peer database. diff --git a/p2p/enode/urlv4.go b/p2p/enode/urlv4.go index 0272eee987..a55dfa6632 100644 --- a/p2p/enode/urlv4.go +++ b/p2p/enode/urlv4.go @@ -181,7 +181,7 @@ func (n *Node) URLv4() string { nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:]) } u := url.URL{Scheme: "enode"} - if n.Incomplete() { + if !n.ip.IsValid() { u.Host = nodeid } else { addr := net.TCPAddr{IP: n.IP(), Port: n.TCP()} diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 9945a436c9..917e1becba 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "net" + "net/netip" "github.com/ethereum/go-ethereum/rlp" ) @@ -167,6 +168,60 @@ func (v *IPv6) DecodeRLP(s *rlp.Stream) error { return nil } +// IPv4Addr is the "ip" key, which holds the IP address of the node. +type IPv4Addr netip.Addr + +func (v IPv4Addr) ENRKey() string { return "ip" } + +// EncodeRLP implements rlp.Encoder. +func (v IPv4Addr) EncodeRLP(w io.Writer) error { + addr := netip.Addr(v) + if !addr.Is4() { + return fmt.Errorf("address is not IPv4") + } + enc := rlp.NewEncoderBuffer(w) + bytes := addr.As4() + enc.WriteBytes(bytes[:]) + return enc.Flush() +} + +// DecodeRLP implements rlp.Decoder. +func (v *IPv4Addr) DecodeRLP(s *rlp.Stream) error { + var bytes [4]byte + if err := s.ReadBytes(bytes[:]); err != nil { + return err + } + *v = IPv4Addr(netip.AddrFrom4(bytes)) + return nil +} + +// IPv6Addr is the "ip6" key, which holds the IP address of the node. +type IPv6Addr netip.Addr + +func (v IPv6Addr) ENRKey() string { return "ip6" } + +// EncodeRLP implements rlp.Encoder. +func (v IPv6Addr) EncodeRLP(w io.Writer) error { + addr := netip.Addr(v) + if !addr.Is6() { + return fmt.Errorf("address is not IPv6") + } + enc := rlp.NewEncoderBuffer(w) + bytes := addr.As16() + enc.WriteBytes(bytes[:]) + return enc.Flush() +} + +// DecodeRLP implements rlp.Decoder. +func (v *IPv6Addr) DecodeRLP(s *rlp.Stream) error { + var bytes [16]byte + if err := s.ReadBytes(bytes[:]); err != nil { + return err + } + *v = IPv6Addr(netip.AddrFrom16(bytes)) + return nil +} + // KeyError is an error related to a key. type KeyError struct { Key string From 61b3d93bb02322054a00a9236658e6ac70ab0b6e Mon Sep 17 00:00:00 2001 From: Aaron Chen Date: Fri, 24 May 2024 05:17:51 +0800 Subject: [PATCH 009/196] p2p/enode: fix TCPEndpoint (#29827) --- p2p/enode/node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/enode/node.go b/p2p/enode/node.go index e7fe0e0ace..cb4ac8d172 100644 --- a/p2p/enode/node.go +++ b/p2p/enode/node.go @@ -184,7 +184,7 @@ func (n *Node) TCP() int { return int(n.tcp) } -// UDPEndpoint returns the announced TCP endpoint. +// UDPEndpoint returns the announced UDP endpoint. func (n *Node) UDPEndpoint() (netip.AddrPort, bool) { if !n.ip.IsValid() || n.ip.IsUnspecified() || n.udp == 0 { return netip.AddrPort{}, false @@ -197,7 +197,7 @@ func (n *Node) TCPEndpoint() (netip.AddrPort, bool) { if !n.ip.IsValid() || n.ip.IsUnspecified() || n.tcp == 0 { return netip.AddrPort{}, false } - return netip.AddrPortFrom(n.ip, n.udp), true + return netip.AddrPortFrom(n.ip, n.tcp), true } // Pubkey returns the secp256k1 public key of the node, if present. From 08fe6a86141861609758978a9d968072968379b6 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Fri, 24 May 2024 15:20:05 +0800 Subject: [PATCH 010/196] metrics: fix flaky test`TestExpDecaySampleNanosecondRegression` (#29832) --- metrics/sample_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 92806c65b2..87f085c704 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -125,12 +125,12 @@ func TestExpDecaySample(t *testing.T) { // The priority becomes +Inf quickly after starting if this is done, // effectively freezing the set of samples until a rescale step happens. func TestExpDecaySampleNanosecondRegression(t *testing.T) { - sw := NewExpDecaySample(100, 0.99) - for i := 0; i < 100; i++ { + sw := NewExpDecaySample(1000, 0.99) + for i := 0; i < 1000; i++ { sw.Update(10) } time.Sleep(1 * time.Millisecond) - for i := 0; i < 100; i++ { + for i := 0; i < 1000; i++ { sw.Update(20) } s := sw.Snapshot() From 64b1cd8aafd25a110087a47da2043d043de0ac79 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Fri, 24 May 2024 17:33:19 +0800 Subject: [PATCH 011/196] p2p: fix typos (#29828) --- p2p/discover/table_test.go | 2 +- p2p/server.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index f72ecd94c9..945b1a294e 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -364,7 +364,7 @@ func TestTable_revalidateSyncRecord(t *testing.T) { transport.updateRecord(n2) // Wait for revalidation. We wait for the node to be revalidated two times - // in order to synchronize with the update in the able. + // in order to synchronize with the update in the table. waitForRevalidationPing(t, transport, tab, n2.ID()) waitForRevalidationPing(t, transport, tab, n2.ID()) diff --git a/p2p/server.go b/p2p/server.go index 79c5fc76b6..a3c53b0781 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -405,7 +405,7 @@ func (srv *Server) DiscoveryV4() *discover.UDPv4 { return srv.discv4 } -// DiscoveryV4 returns the discovery v5 instance, if configured. +// DiscoveryV5 returns the discovery v5 instance, if configured. func (srv *Server) DiscoveryV5() *discover.UDPv5 { return srv.discv5 } From b6474e9f90c88003de7d7eb993ddb5f60133172e Mon Sep 17 00:00:00 2001 From: levisyin Date: Fri, 24 May 2024 17:34:30 +0800 Subject: [PATCH 012/196] metrics: add test for `SampleSnapshot.Sum` (#29831) --- metrics/sample_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/metrics/sample_test.go b/metrics/sample_test.go index 87f085c704..4227b43ef7 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -103,14 +103,14 @@ func TestExpDecaySample(t *testing.T) { } snap := sample.Snapshot() if have, want := int(snap.Count()), tc.updates; have != want { - t.Errorf("have %d want %d", have, want) + t.Errorf("unexpected count: have %d want %d", have, want) } if have, want := snap.Size(), min(tc.updates, tc.reservoirSize); have != want { - t.Errorf("have %d want %d", have, want) + t.Errorf("unexpected size: have %d want %d", have, want) } values := snap.(*sampleSnapshot).values if have, want := len(values), min(tc.updates, tc.reservoirSize); have != want { - t.Errorf("have %d want %d", have, want) + t.Errorf("unexpected values length: have %d want %d", have, want) } for _, v := range values { if v > int64(tc.updates) || v < 0 { @@ -251,6 +251,9 @@ func benchmarkSample(b *testing.B, s Sample) { } func testExpDecaySampleStatistics(t *testing.T, s SampleSnapshot) { + if sum := s.Sum(); sum != 496598 { + t.Errorf("s.Sum(): 496598 != %v\n", sum) + } if count := s.Count(); count != 10000 { t.Errorf("s.Count(): 10000 != %v\n", count) } From d1d9f34e519c25ac9d7366e760969ed2065e9426 Mon Sep 17 00:00:00 2001 From: winterjihwan <113398351+winterjihwan@users.noreply.github.com> Date: Sun, 26 May 2024 18:54:37 +0900 Subject: [PATCH 013/196] core/types: clarify set inclusion in comments (#29839) --- core/types/transaction.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/types/transaction.go b/core/types/transaction.go index 6a27ecbfec..4ac9187bdb 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -556,7 +556,7 @@ func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) { } } -// TxDifference returns a new set which is the difference between a and b. +// TxDifference returns a new set of transactions that are present in a but not in b. func TxDifference(a, b Transactions) Transactions { keep := make(Transactions, 0, len(a)) @@ -574,7 +574,7 @@ func TxDifference(a, b Transactions) Transactions { return keep } -// HashDifference returns a new set which is the difference between a and b. +// HashDifference returns a new set of hashes that are present in a but not in b. func HashDifference(a, b []common.Hash) []common.Hash { keep := make([]common.Hash, 0, len(a)) From 7f5cc02a99c5191079c9ece225778e5747013672 Mon Sep 17 00:00:00 2001 From: Wukingbow <40993922+Wukingbow@users.noreply.github.com> Date: Mon, 27 May 2024 14:34:53 +0800 Subject: [PATCH 014/196] metrics: fix function comment (#29843) --- metrics/debug.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/metrics/debug.go b/metrics/debug.go index de4a2739fe..9dfee1a866 100644 --- a/metrics/debug.go +++ b/metrics/debug.go @@ -19,18 +19,18 @@ var ( gcStats debug.GCStats ) -// Capture new values for the Go garbage collector statistics exported in -// debug.GCStats. This is designed to be called as a goroutine. +// CaptureDebugGCStats captures new values for the Go garbage collector statistics +// exported in debug.GCStats. This is designed to be called as a goroutine. func CaptureDebugGCStats(r Registry, d time.Duration) { for range time.Tick(d) { CaptureDebugGCStatsOnce(r) } } -// Capture new values for the Go garbage collector statistics exported in -// debug.GCStats. This is designed to be called in a background goroutine. -// Giving a registry which has not been given to RegisterDebugGCStats will -// panic. +// CaptureDebugGCStatsOnce captures new values for the Go garbage collector +// statistics exported in debug.GCStats. This is designed to be called in +// a background goroutine. Giving a registry which has not been given to +// RegisterDebugGCStats will panic. // // Be careful (but much less so) with this because debug.ReadGCStats calls // the C function runtime·lock(runtime·mheap) which, while not a stop-the-world @@ -50,9 +50,9 @@ func CaptureDebugGCStatsOnce(r Registry) { debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal)) } -// Register metrics for the Go garbage collector statistics exported in -// debug.GCStats. The metrics are named by their fully-qualified Go symbols, -// i.e. debug.GCStats.PauseTotal. +// RegisterDebugGCStats registers metrics for the Go garbage collector statistics +// exported in debug.GCStats. The metrics are named by their fully-qualified Go +// symbols, i.e. debug.GCStats.PauseTotal. func RegisterDebugGCStats(r Registry) { debugMetrics.GCStats.LastGC = NewGauge() debugMetrics.GCStats.NumGC = NewGauge() From 7224576fba63d30e0ddfca538b133048634281ca Mon Sep 17 00:00:00 2001 From: Mobin Mohanan <47410557+tr1sm0s1n@users.noreply.github.com> Date: Mon, 27 May 2024 12:09:39 +0530 Subject: [PATCH 015/196] core, eth/protocols/snap, internal/ethapi: remove redundant types (#29841) --- core/genesis.go | 2 +- eth/protocols/snap/progress_test.go | 2 +- internal/ethapi/api_test.go | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 042071c531..f1b4490f2e 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b // Pre-deploy EIP-4788 system contract - params.BeaconRootsAddress: types.Account{Nonce: 1, Code: params.BeaconRootsCode}, + params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode}, }, } if faucet != nil { diff --git a/eth/protocols/snap/progress_test.go b/eth/protocols/snap/progress_test.go index 9d923bd2f5..1d9a6b8474 100644 --- a/eth/protocols/snap/progress_test.go +++ b/eth/protocols/snap/progress_test.go @@ -80,7 +80,7 @@ func makeLegacyProgress() legacyProgress { Next: common.Hash{}, Last: common.Hash{0x77}, SubTasks: map[common.Hash][]*legacyStorageTask{ - common.Hash{0x1}: { + {0x1}: { { Next: common.Hash{}, Last: common.Hash{0xff}, diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index a717ebdfae..cf5160caf7 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -751,7 +751,7 @@ func TestEstimateGas(t *testing.T) { From: &accounts[0].addr, To: &accounts[1].addr, Value: (*hexutil.Big)(big.NewInt(1)), - BlobHashes: []common.Hash{common.Hash{0x01, 0x22}}, + BlobHashes: []common.Hash{{0x01, 0x22}}, BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), }, want: 21000, @@ -939,7 +939,7 @@ func TestCall(t *testing.T) { call: TransactionArgs{ From: &accounts[1].addr, To: &randomAccounts[2].addr, - BlobHashes: []common.Hash{common.Hash{0x01, 0x22}}, + BlobHashes: []common.Hash{{0x01, 0x22}}, BlobFeeCap: (*hexutil.Big)(big.NewInt(1)), }, overrides: StateOverride{ @@ -1063,7 +1063,7 @@ func TestSendBlobTransaction(t *testing.T) { From: &b.acc.Address, To: &to, Value: (*hexutil.Big)(big.NewInt(1)), - BlobHashes: []common.Hash{common.Hash{0x01, 0x22}}, + BlobHashes: []common.Hash{{0x01, 0x22}}, }) if err != nil { t.Fatalf("failed to fill tx defaults: %v\n", err) From 1a4e4a4fe1286b5dc583ba18acdd39891d98953b Mon Sep 17 00:00:00 2001 From: Steven Wang <915337710@qq.com> Date: Mon, 27 May 2024 19:42:07 +0800 Subject: [PATCH 016/196] miner: fix TestBuildPayload sporadic failure (#29853) miner: fix TestBuildPayload sporadic failure Co-authored-by: steven --- miner/payload_building_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/payload_building_test.go b/miner/payload_building_test.go index 1728b9e5bd..ac9b2ab704 100644 --- a/miner/payload_building_test.go +++ b/miner/payload_building_test.go @@ -141,7 +141,7 @@ func (b *testWorkerBackend) TxPool() *txpool.TxPool { return b.txPool } func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*Miner, *testWorkerBackend) { backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks) - backend.txPool.Add(pendingTxs, true, false) + backend.txPool.Add(pendingTxs, true, true) w := New(backend, testConfig, engine) return w, backend } From 513276864bb223bf30a3497ba08ae3d15a696903 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 27 May 2024 22:26:55 +0800 Subject: [PATCH 017/196] eth/downloader: fix flaky test (#29852) This pull request fixes the flay test TestSkeletonSyncRetrievals. In this test, we first trigger a sync cycle and wait for it to meet certain expectations. We then inject a new head and potentially also a new peer, then perform another final sync. The test now performs the newPeer addition before launching the final sync, and waits a bit for that peer to get registered. This fixes the logic race that made the test fail sometimes. Co-authored-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> --- eth/downloader/skeleton_test.go | 387 ++++++++++++++++---------------- 1 file changed, 191 insertions(+), 196 deletions(-) diff --git a/eth/downloader/skeleton_test.go b/eth/downloader/skeleton_test.go index 3693ab095f..4aa97cf1f7 100644 --- a/eth/downloader/skeleton_test.go +++ b/eth/downloader/skeleton_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/protocols/eth" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" ) @@ -376,20 +377,9 @@ func TestSkeletonSyncInit(t *testing.T) { skeleton.Terminate() // Ensure the correct resulting sync status - var progress skeletonProgress - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - - if len(progress.Subchains) != len(tt.newstate) { - t.Errorf("test %d: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.newstate)) - continue - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.newstate[j].Head { - t.Errorf("test %d: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.newstate[j].Head) - } - if progress.Subchains[j].Tail != tt.newstate[j].Tail { - t.Errorf("test %d: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.newstate[j].Tail) - } + expect := skeletonExpect{state: tt.newstate} + if err := checkSkeletonProgress(db, false, nil, expect); err != nil { + t.Errorf("test %d: %v", i, err) } } } @@ -493,28 +483,36 @@ func TestSkeletonSyncExtend(t *testing.T) { skeleton.Terminate() // Ensure the correct resulting sync status - var progress skeletonProgress - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - - if len(progress.Subchains) != len(tt.newstate) { - t.Errorf("test %d: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.newstate)) - continue - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.newstate[j].Head { - t.Errorf("test %d: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.newstate[j].Head) - } - if progress.Subchains[j].Tail != tt.newstate[j].Tail { - t.Errorf("test %d: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.newstate[j].Tail) - } + expect := skeletonExpect{state: tt.newstate} + if err := checkSkeletonProgress(db, false, nil, expect); err != nil { + t.Errorf("test %d: %v", i, err) } } } +type skeletonExpect struct { + state []*subchain // Expected sync state after the post-init event + serve uint64 // Expected number of header retrievals after initial cycle + drop uint64 // Expected number of peers dropped after initial cycle +} + +type skeletonTest struct { + fill bool // Whether to run a real backfiller in this test case + unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments + + head *types.Header // New head header to announce to reorg to + peers []*skeletonTestPeer // Initial peer set to start the sync with + mid skeletonExpect + + newHead *types.Header // New header to anoint on top of the old one + newPeer *skeletonTestPeer // New peer to join the skeleton syncer + end skeletonExpect +} + // Tests that the skeleton sync correctly retrieves headers from one or more // peers without duplicates or other strange side effects. func TestSkeletonSyncRetrievals(t *testing.T) { - //log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + //log.SetDefault(log.NewLogger(log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false)))) // Since skeleton headers don't need to be meaningful, beyond a parent hash // progression, create a long fake chain to test with. @@ -537,22 +535,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) { Extra: []byte("B"), // force a different hash }) } - tests := []struct { - fill bool // Whether to run a real backfiller in this test case - unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments - - head *types.Header // New head header to announce to reorg to - peers []*skeletonTestPeer // Initial peer set to start the sync with - midstate []*subchain // Expected sync state after initial cycle - midserve uint64 // Expected number of header retrievals after initial cycle - middrop uint64 // Expected number of peers dropped after initial cycle - - newHead *types.Header // New header to anoint on top of the old one - newPeer *skeletonTestPeer // New peer to join the skeleton syncer - endstate []*subchain // Expected sync state after the post-init event - endserve uint64 // Expected number of header retrievals after the post-init event - enddrop uint64 // Expected number of peers dropped after the post-init event - }{ + tests := []skeletonTest{ // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. No peers however, so // the sync should be stuck without any progression. @@ -560,12 +543,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) { // When a new peer is added, it should detect the join and fill the headers // to the genesis block. { - head: chain[len(chain)-1], - midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: uint64(len(chain) - 1)}}, + head: chain[len(chain)-1], + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: uint64(len(chain) - 1)}}, + }, - newPeer: newSkeletonTestPeer("test-peer", chain), - endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - endserve: uint64(len(chain) - 2), // len - head - genesis + newPeer: newSkeletonTestPeer("test-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, }, // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. With one valid peer, @@ -573,14 +560,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { // // Adding a second peer should not have any effect. { - head: chain[len(chain)-1], - peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-1", chain)}, - midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - midserve: uint64(len(chain) - 2), // len - head - genesis + head: chain[len(chain)-1], + peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-1", chain)}, + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, - newPeer: newSkeletonTestPeer("test-peer-2", chain), - endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - endserve: uint64(len(chain) - 2), // len - head - genesis + newPeer: newSkeletonTestPeer("test-peer-2", chain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, }, // Completely empty database with only the genesis set. The sync is expected // to create a single subchain with the requested head. With many valid peers, @@ -594,12 +585,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) { newSkeletonTestPeer("test-peer-2", chain), newSkeletonTestPeer("test-peer-3", chain), }, - midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - midserve: uint64(len(chain) - 2), // len - head - genesis + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, - newPeer: newSkeletonTestPeer("test-peer-4", chain), - endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, - endserve: uint64(len(chain) - 2), // len - head - genesis + newPeer: newSkeletonTestPeer("test-peer-4", chain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}}, + serve: uint64(len(chain) - 2), // len - head - genesis + }, }, // This test checks if a peer tries to withhold a header - *on* the sync // boundary - instead of sending the requested amount. The malicious short @@ -611,14 +606,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-skipper", append(append(append([]*types.Header{}, chain[:99]...), nil), chain[100:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 3, // len - head - genesis - missing - middrop: 1, // penalize shortened header deliveries + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 3, // len - head - genesis - missing + drop: 1, // penalize shortened header deliveries + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to withhold a header - *off* the sync // boundary - instead of sending the requested amount. The malicious short @@ -630,14 +629,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-skipper", append(append(append([]*types.Header{}, chain[:50]...), nil), chain[51:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 3, // len - head - genesis - missing - middrop: 1, // penalize shortened header deliveries + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 3, // len - head - genesis - missing + drop: 1, // penalize shortened header deliveries + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to duplicate a header - *on* the sync // boundary - instead of sending the correct sequence. The malicious duped @@ -649,14 +652,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-duper", append(append(append([]*types.Header{}, chain[:99]...), chain[98]), chain[100:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // penalize invalid header sequences + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // penalize invalid header sequences + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to duplicate a header - *off* the sync // boundary - instead of sending the correct sequence. The malicious duped @@ -668,14 +675,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { peers: []*skeletonTestPeer{ newSkeletonTestPeer("header-duper", append(append(append([]*types.Header{}, chain[:50]...), chain[49]), chain[51:]...)), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // penalize invalid header sequences + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // penalize invalid header sequences + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to inject a different header - *on* // the sync boundary - instead of sending the correct sequence. The bad @@ -698,14 +709,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { ), ), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // different set of headers, drop // TODO(karalabe): maybe just diff sync? + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // different set of headers, drop // TODO(karalabe): maybe just diff sync? + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test checks if a peer tries to inject a different header - *off* // the sync boundary - instead of sending the correct sequence. The bad @@ -728,14 +743,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) { ), ), }, - midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, - midserve: requestHeaders + 101 - 2, // len - head - genesis - middrop: 1, // different set of headers, drop + mid: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 100}}, + serve: requestHeaders + 101 - 2, // len - head - genesis + drop: 1, // different set of headers, drop + }, - newPeer: newSkeletonTestPeer("good-peer", chain), - endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, - endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis - enddrop: 1, // no new drops + newPeer: newSkeletonTestPeer("good-peer", chain), + end: skeletonExpect{ + state: []*subchain{{Head: requestHeaders + 100, Tail: 1}}, + serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis + drop: 1, // no new drops + }, }, // This test reproduces a bug caught during review (kudos to @holiman) // where a subchain is merged with a previously interrupted one, causing @@ -765,12 +784,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) { return nil // Fallback to default behavior, just delayed }), }, - midstate: []*subchain{{Head: 2 * requestHeaders, Tail: 1}}, - midserve: 2*requestHeaders - 1, // len - head - genesis + mid: skeletonExpect{ + state: []*subchain{{Head: 2 * requestHeaders, Tail: 1}}, + serve: 2*requestHeaders - 1, // len - head - genesis + }, - newHead: chain[2*requestHeaders+2], - endstate: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}}, - endserve: 4 * requestHeaders, + newHead: chain[2*requestHeaders+2], + end: skeletonExpect{ + state: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}}, + serve: 4 * requestHeaders, + }, }, // This test reproduces a bug caught by (@rjl493456442) where a skeleton // header goes missing, causing the sync to get stuck and/or panic. @@ -792,13 +815,17 @@ func TestSkeletonSyncRetrievals(t *testing.T) { fill: true, unpredictable: true, // We have good and bad peer too, bad may be dropped, test too short for certainty - head: chain[len(chain)/2+1], // Sync up until the sidechain common ancestor + 2 - peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-oldchain", chain)}, - midstate: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}}, + head: chain[len(chain)/2+1], // Sync up until the sidechain common ancestor + 2 + peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-oldchain", chain)}, + mid: skeletonExpect{ + state: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}}, + }, - newHead: sidechain[len(sidechain)/2+3], // Sync up until the sidechain common ancestor + 4 - newPeer: newSkeletonTestPeer("test-peer-newchain", sidechain), - endstate: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}}, + newHead: sidechain[len(sidechain)/2+3], // Sync up until the sidechain common ancestor + 4 + newPeer: newSkeletonTestPeer("test-peer-newchain", sidechain), + end: skeletonExpect{ + state: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}}, + }, }, } for i, tt := range tests { @@ -861,115 +888,83 @@ func TestSkeletonSyncRetrievals(t *testing.T) { skeleton := newSkeleton(db, peerset, drop, filler) skeleton.Sync(tt.head, nil, true) - var progress skeletonProgress // Wait a bit (bleah) for the initial sync loop to go to idle. This might // be either a finish or a never-start hence why there's no event to hook. - check := func() error { - if len(progress.Subchains) != len(tt.midstate) { - return fmt.Errorf("test %d, mid state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.midstate)) - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.midstate[j].Head { - return fmt.Errorf("test %d, mid state: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.midstate[j].Head) - } - if progress.Subchains[j].Tail != tt.midstate[j].Tail { - return fmt.Errorf("test %d, mid state: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.midstate[j].Tail) - } - } - return nil - } - waitStart := time.Now() for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 { time.Sleep(waitTime) - // Check the post-init end state if it matches the required results - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - if err := check(); err == nil { + if err := checkSkeletonProgress(db, tt.unpredictable, tt.peers, tt.mid); err == nil { break } } - if err := check(); err != nil { - t.Error(err) + if err := checkSkeletonProgress(db, tt.unpredictable, tt.peers, tt.mid); err != nil { + t.Errorf("test %d, mid: %v", i, err) continue } - if !tt.unpredictable { - var served uint64 - for _, peer := range tt.peers { - served += peer.served.Load() - } - if served != tt.midserve { - t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve) - } - var drops uint64 - for _, peer := range tt.peers { - drops += peer.dropped.Load() - } - if drops != tt.middrop { - t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) - } - } + // Apply the post-init events if there's any - if tt.newHead != nil { - skeleton.Sync(tt.newHead, nil, true) - } + endpeers := tt.peers if tt.newPeer != nil { if err := peerset.Register(newPeerConnection(tt.newPeer.id, eth.ETH68, tt.newPeer, log.New("id", tt.newPeer.id))); err != nil { t.Errorf("test %d: failed to register new peer: %v", i, err) } + time.Sleep(time.Millisecond * 50) // given time for peer registration + endpeers = append(tt.peers, tt.newPeer) } + if tt.newHead != nil { + skeleton.Sync(tt.newHead, nil, true) + } + // Wait a bit (bleah) for the second sync loop to go to idle. This might // be either a finish or a never-start hence why there's no event to hook. - check = func() error { - if len(progress.Subchains) != len(tt.endstate) { - return fmt.Errorf("test %d, end state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.endstate)) - } - for j := 0; j < len(progress.Subchains); j++ { - if progress.Subchains[j].Head != tt.endstate[j].Head { - return fmt.Errorf("test %d, end state: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.endstate[j].Head) - } - if progress.Subchains[j].Tail != tt.endstate[j].Tail { - return fmt.Errorf("test %d, end state: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.endstate[j].Tail) - } - } - return nil - } waitStart = time.Now() for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 { time.Sleep(waitTime) - // Check the post-init end state if it matches the required results - json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) - if err := check(); err == nil { + if err := checkSkeletonProgress(db, tt.unpredictable, endpeers, tt.end); err == nil { break } } - if err := check(); err != nil { - t.Error(err) + if err := checkSkeletonProgress(db, tt.unpredictable, endpeers, tt.end); err != nil { + t.Errorf("test %d, end: %v", i, err) continue } // Check that the peers served no more headers than we actually needed - if !tt.unpredictable { - served := uint64(0) - for _, peer := range tt.peers { - served += peer.served.Load() - } - if tt.newPeer != nil { - served += tt.newPeer.served.Load() - } - if served != tt.endserve { - t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve) - } - drops := uint64(0) - for _, peer := range tt.peers { - drops += peer.dropped.Load() - } - if tt.newPeer != nil { - drops += tt.newPeer.dropped.Load() - } - if drops != tt.enddrop { - t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop) - } - } // Clean up any leftover skeleton sync resources skeleton.Terminate() } } + +func checkSkeletonProgress(db ethdb.KeyValueReader, unpredictable bool, peers []*skeletonTestPeer, expected skeletonExpect) error { + var progress skeletonProgress + // Check the post-init end state if it matches the required results + json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress) + + if len(progress.Subchains) != len(expected.state) { + return fmt.Errorf("subchain count mismatch: have %d, want %d", len(progress.Subchains), len(expected.state)) + } + for j := 0; j < len(progress.Subchains); j++ { + if progress.Subchains[j].Head != expected.state[j].Head { + return fmt.Errorf("subchain %d head mismatch: have %d, want %d", j, progress.Subchains[j].Head, expected.state[j].Head) + } + if progress.Subchains[j].Tail != expected.state[j].Tail { + return fmt.Errorf("subchain %d tail mismatch: have %d, want %d", j, progress.Subchains[j].Tail, expected.state[j].Tail) + } + } + if !unpredictable { + var served uint64 + for _, peer := range peers { + served += peer.served.Load() + } + if served != expected.serve { + return fmt.Errorf("served headers mismatch: have %d, want %d", served, expected.serve) + } + var drops uint64 + for _, peer := range peers { + drops += peer.dropped.Load() + } + if drops != expected.drop { + return fmt.Errorf("dropped peers mismatch: have %d, want %d", drops, expected.drop) + } + } + return nil +} From ea6c16007c30468ad92c45a13ba1d74514f2d9cf Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 28 May 2024 13:12:46 +0200 Subject: [PATCH 018/196] eth/tracers: clear error for non-reverting pre-homestead fail (#29824) --- .../call_tracer_withLog/frontier_create_outofstorage.json | 3 ++- eth/tracers/native/call.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json index c46fe080f7..a9092bbcf0 100644 --- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json +++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json @@ -80,8 +80,9 @@ "from": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8", "gas": "0x1b7740", "gasUsed": "0x9274f", + "to": "0xc24431c1a1147456414355b1f1769de450e524da", "input": "0x606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056", - "error": "contract creation code storage out of gas", + "output": "0x606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056", "calls": [ { "from": "0xc24431c1a1147456414355b1f1769de450e524da", diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index 3b63506580..2b84ecaf40 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -74,6 +74,11 @@ func (f callFrame) failed() bool { func (f *callFrame) processOutput(output []byte, err error, reverted bool) { output = common.CopyBytes(output) + // Clear error if tx wasn't reverted. This happened + // for pre-homestead contract storage OOG. + if err != nil && !reverted { + err = nil + } if err == nil { f.Output = output return From caafa93598927303d8dbe0aa53bf43ca08632805 Mon Sep 17 00:00:00 2001 From: trillo Date: Tue, 28 May 2024 20:44:40 +0900 Subject: [PATCH 019/196] all: improve some error strings (#29842) --- beacon/types/exec_payload.go | 2 +- cmd/clef/main.go | 2 +- core/chain_indexer_test.go | 2 +- core/types/transaction_test.go | 2 +- eth/backend.go | 2 +- eth/catalyst/api_test.go | 6 +++--- log/logger_test.go | 6 +++--- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/beacon/types/exec_payload.go b/beacon/types/exec_payload.go index 4448f854ad..b159687dfc 100644 --- a/beacon/types/exec_payload.go +++ b/beacon/types/exec_payload.go @@ -65,7 +65,7 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ block := types.NewBlockWithHeader(&header).WithBody(types.Body{Transactions: transactions, Withdrawals: withdrawals}) if hash := block.Hash(); hash != expectedHash { - return nil, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) + return nil, fmt.Errorf("sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash) } return block, nil } diff --git a/cmd/clef/main.go b/cmd/clef/main.go index f9b00e4a12..88d4c99e78 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -552,7 +552,7 @@ func listWallets(c *cli.Context) error { // accountImport imports a raw hexadecimal private key via CLI. func accountImport(c *cli.Context) error { if c.Args().Len() != 1 { - return errors.New(" must be given as first argument.") + return errors.New(" must be given as first argument") } internalApi, ui, err := initInternalApi(c) if err != nil { diff --git a/core/chain_indexer_test.go b/core/chain_indexer_test.go index f099609015..bf3bde756c 100644 --- a/core/chain_indexer_test.go +++ b/core/chain_indexer_test.go @@ -228,7 +228,7 @@ func (b *testChainIndexBackend) Process(ctx context.Context, header *types.Heade b.t.Error("Unexpected call to Process") // Can't use Fatal since this is not the test's goroutine. // Returning error stops the chainIndexer's updateLoop - return errors.New("Unexpected call to Process") + return errors.New("unexpected call to Process") case b.processCh <- header.Number.Uint64(): } return nil diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 361b977611..5dbf367073 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -379,7 +379,7 @@ func assertEqual(orig *Transaction, cpy *Transaction) error { } if orig.AccessList() != nil { if !reflect.DeepEqual(orig.AccessList(), cpy.AccessList()) { - return errors.New("access list wrong!") + return errors.New("access list wrong") } } return nil diff --git a/eth/backend.go b/eth/backend.go index e616b5f2f1..97e68b8cf0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -208,7 +208,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig) if err != nil { - return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err) + return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err) } vmConfig.Tracer = t } diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index 0586959f06..64e6684be1 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -979,11 +979,11 @@ func TestSimultaneousNewBlock(t *testing.T) { defer wg.Done() if newResp, err := api.NewPayloadV1(*execData); err != nil { errMu.Lock() - testErr = fmt.Errorf("Failed to insert block: %w", err) + testErr = fmt.Errorf("failed to insert block: %w", err) errMu.Unlock() } else if newResp.Status != "VALID" { errMu.Lock() - testErr = fmt.Errorf("Failed to insert block: %v", newResp.Status) + testErr = fmt.Errorf("failed to insert block: %v", newResp.Status) errMu.Unlock() } }() @@ -1018,7 +1018,7 @@ func TestSimultaneousNewBlock(t *testing.T) { defer wg.Done() if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil { errMu.Lock() - testErr = fmt.Errorf("Failed to insert block: %w", err) + testErr = fmt.Errorf("failed to insert block: %w", err) errMu.Unlock() } }() diff --git a/log/logger_test.go b/log/logger_test.go index 2ea0858547..6f415eb471 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -97,7 +97,7 @@ func benchmarkLogger(b *testing.B, l Logger) { tt = time.Now() bigint = big.NewInt(100) nilbig *big.Int - err = errors.New("Oh nooes it's crap") + err = errors.New("oh nooes it's crap") ) b.ReportAllocs() b.ResetTimer() @@ -126,7 +126,7 @@ func TestLoggerOutput(t *testing.T) { tt = time.Time{} bigint = big.NewInt(100) nilbig *big.Int - err = errors.New("Oh nooes it's crap") + err = errors.New("oh nooes it's crap") smallUint = uint256.NewInt(500_000) bigUint = &uint256.Int{0xff, 0xff, 0xff, 0xff} ) @@ -150,7 +150,7 @@ func TestLoggerOutput(t *testing.T) { have := out.String() t.Logf("output %v", out.String()) - want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig= err="Oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095 + want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig= err="oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095 ` if !bytes.Equal([]byte(have)[25:], []byte(want)[25:]) { t.Errorf("Error\nhave: %q\nwant: %q", have, want) From 42471d7a3e78296ed99b3d9ac804385931f80ec5 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 28 May 2024 13:45:16 +0200 Subject: [PATCH 020/196] core/vm/runtime: set random to enable merge-opcodes (#29799) --- core/vm/runtime/runtime.go | 45 +++++++++++++++++++++------------ core/vm/runtime/runtime_test.go | 6 ++--- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index b587d6d5a0..1181e5fccd 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -57,24 +57,33 @@ type Config struct { // sets defaults on the config func setDefaults(cfg *Config) { if cfg.ChainConfig == nil { + var ( + shanghaiTime = uint64(0) + cancunTime = uint64(0) + ) cfg.ChainConfig = ¶ms.ChainConfig{ - ChainID: big.NewInt(1), - HomesteadBlock: new(big.Int), - DAOForkBlock: new(big.Int), - DAOForkSupport: false, - EIP150Block: new(big.Int), - EIP155Block: new(big.Int), - EIP158Block: new(big.Int), - ByzantiumBlock: new(big.Int), - ConstantinopleBlock: new(big.Int), - PetersburgBlock: new(big.Int), - IstanbulBlock: new(big.Int), - MuirGlacierBlock: new(big.Int), - BerlinBlock: new(big.Int), - LondonBlock: new(big.Int), - } + ChainID: big.NewInt(1), + HomesteadBlock: new(big.Int), + DAOForkBlock: new(big.Int), + DAOForkSupport: false, + EIP150Block: new(big.Int), + EIP155Block: new(big.Int), + EIP158Block: new(big.Int), + ByzantiumBlock: new(big.Int), + ConstantinopleBlock: new(big.Int), + PetersburgBlock: new(big.Int), + IstanbulBlock: new(big.Int), + MuirGlacierBlock: new(big.Int), + BerlinBlock: new(big.Int), + LondonBlock: new(big.Int), + ArrowGlacierBlock: nil, + GrayGlacierBlock: nil, + TerminalTotalDifficulty: big.NewInt(0), + TerminalTotalDifficultyPassed: true, + MergeNetsplitBlock: nil, + ShanghaiTime: &shanghaiTime, + CancunTime: &cancunTime} } - if cfg.Difficulty == nil { cfg.Difficulty = new(big.Int) } @@ -101,6 +110,10 @@ func setDefaults(cfg *Config) { if cfg.BlobBaseFee == nil { cfg.BlobBaseFee = big.NewInt(params.BlobTxMinBlobGasprice) } + // Merge indicators + if t := cfg.ChainConfig.ShanghaiTime; cfg.ChainConfig.TerminalTotalDifficultyPassed || (t != nil && *t == 0) { + cfg.Random = &(common.Hash{}) + } } // Execute executes the code using the input as call data during the execution. diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 45228e78c4..04abc5480e 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -105,7 +105,7 @@ func TestExecute(t *testing.T) { func TestCall(t *testing.T) { state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil) - address := common.HexToAddress("0x0a") + address := common.HexToAddress("0xaa") state.SetCode(address, []byte{ byte(vm.PUSH1), 10, byte(vm.PUSH1), 0, @@ -725,7 +725,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CREATE), byte(vm.POP), }, - results: []string{`"1,1,952855,6,12"`, `"1,1,952855,6,0"`}, + results: []string{`"1,1,952853,6,12"`, `"1,1,952853,6,0"`}, }, { // CREATE2 @@ -741,7 +741,7 @@ func TestRuntimeJSTracer(t *testing.T) { byte(vm.CREATE2), byte(vm.POP), }, - results: []string{`"1,1,952846,6,13"`, `"1,1,952846,6,0"`}, + results: []string{`"1,1,952844,6,13"`, `"1,1,952844,6,0"`}, }, { // CALL From 871e55d93e8b0aeb85c71eff4adf1460547b01d0 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Tue, 28 May 2024 20:10:27 +0800 Subject: [PATCH 021/196] core/state: fix typos in comments (#29767) --- core/state/state_object.go | 6 +++--- core/state/trie_prefetcher.go | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 85cb8b44de..4011425c2a 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -127,7 +127,7 @@ func (s *stateObject) touch() { } } -// getTrie returns the associated storage trie. The trie will be opened if it' +// getTrie returns the associated storage trie. The trie will be opened if it's // not loaded previously. An error will be returned if trie can't be loaded. // // If a new trie is opened, it will be cached within the state object to allow @@ -156,7 +156,7 @@ func (s *stateObject) getPrefetchedTrie() (Trie, error) { if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil { return nil, nil } - // Attempt to retrieve the trie from the pretecher + // Attempt to retrieve the trie from the prefetcher return s.db.prefetcher.trie(s.addrHash, s.data.Root) } @@ -311,7 +311,7 @@ func (s *stateObject) updateTrie() (Trie, error) { if len(s.pendingStorage) == 0 { return s.trie, nil } - // Retrieve a pretecher populated trie, or fall back to the database + // Retrieve a prefetcher populated trie, or fall back to the database tr, err := s.getPrefetchedTrie() switch { case err != nil: diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 7e08964e41..0b45660ac1 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -72,7 +72,7 @@ func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePre } } -// terminate iterates over all the subfetchers and issues a terminateion request +// terminate iterates over all the subfetchers and issues a termination request // to all of them. Depending on the async parameter, the method will either block // until all subfetchers spin down, or return immediately. func (p *triePrefetcher) terminate(async bool) { @@ -234,7 +234,7 @@ func (sf *subfetcher) schedule(keys [][]byte) error { case sf.wake <- struct{}{}: // Wake signal sent default: - // Wake signal not sent as a previous is already queued + // Wake signal not sent as a previous one is already queued } return nil } @@ -250,7 +250,7 @@ func (sf *subfetcher) wait() { // peeks for the original data. The method will block until all the scheduled // data has been loaded and the fethcer terminated. func (sf *subfetcher) peek() Trie { - // Block until the fertcher terminates, then retrieve the trie + // Block until the fetcher terminates, then retrieve the trie sf.wait() return sf.trie } @@ -296,7 +296,7 @@ func (sf *subfetcher) loop() { for { select { case <-sf.wake: - // Execute all remaining tasks in single run + // Execute all remaining tasks in a single run sf.lock.Lock() tasks := sf.tasks sf.tasks = nil From 61932e47106168a4eeb93ee68211752a25e031c5 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 28 May 2024 14:16:45 +0200 Subject: [PATCH 022/196] cmd/geth: update testdata (vulncheck) (#29714) --- cmd/geth/testdata/vcheck/vulnerabilities.json | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/cmd/geth/testdata/vcheck/vulnerabilities.json b/cmd/geth/testdata/vcheck/vulnerabilities.json index bee0e66dd8..31a34de6be 100644 --- a/cmd/geth/testdata/vcheck/vulnerabilities.json +++ b/cmd/geth/testdata/vcheck/vulnerabilities.json @@ -166,5 +166,37 @@ "severity": "Low", "CVE": "CVE-2022-29177", "check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$" + }, + { + "name": "DoS via malicious p2p message", + "uid": "GETH-2023-01", + "summary": "A vulnerable node can be made to consume unbounded amounts of memory when handling specially crafted p2p messages sent from an attacker node.", + "description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.", + "links": [ + "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm", + "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities" + ], + "introduced": "v1.10.0", + "fixed": "v1.12.1", + "published": "2023-09-06", + "severity": "High", + "CVE": "CVE-2023-40591", + "check": "(Geth\\/v1\\.(10|11)\\..*)|(Geth\\/v1\\.12\\.0-.*)$" + }, + { + "name": "DoS via malicious p2p message", + "uid": "GETH-2024-01", + "summary": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node.", + "description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)", + "links": [ + "https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652", + "https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities" + ], + "introduced": "v1.10.0", + "fixed": "v1.13.15", + "published": "2024-05-06", + "severity": "High", + "CVE": "CVE-2024-32972", + "check": "(Geth\\/v1\\.(10|11|12)\\..*)|(Geth\\/v1\\.13\\.\\d-.*)|(Geth\\/v1\\.13\\.1(0|1|2|3|4)-.*)$" } ] From b88051ec83bba7882b59ab9cee573a9c111063e9 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 28 May 2024 20:41:11 +0800 Subject: [PATCH 023/196] core/rawdb, triedb/pathdb: fix freezer read-only option (#29823) --- core/rawdb/freezer_resettable.go | 19 ++++++++++++------- triedb/pathdb/database.go | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index 7fa59b8d21..6f8541f43b 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -33,10 +33,11 @@ type freezerOpenFunc = func() (*Freezer, error) // resettableFreezer is a wrapper of the freezer which makes the // freezer resettable. type resettableFreezer struct { - freezer *Freezer - opener freezerOpenFunc - datadir string - lock sync.RWMutex + readOnly bool + freezer *Freezer + opener freezerOpenFunc + datadir string + lock sync.RWMutex } // newResettableFreezer creates a resettable freezer, note freezer is @@ -60,9 +61,10 @@ func newResettableFreezer(datadir string, namespace string, readonly bool, maxTa return nil, err } return &resettableFreezer{ - freezer: freezer, - opener: opener, - datadir: datadir, + readOnly: readonly, + freezer: freezer, + opener: opener, + datadir: datadir, }, nil } @@ -74,6 +76,9 @@ func (f *resettableFreezer) Reset() error { f.lock.Lock() defer f.lock.Unlock() + if f.readOnly { + return errReadOnly + } if err := f.freezer.Close(); err != nil { return err } diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 05a28aa1ef..bd6aeaa6ab 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -190,7 +190,7 @@ func (db *Database) repairHistory() error { // all of them. Fix the tests first. return nil } - freezer, err := rawdb.NewStateFreezer(ancient, false) + freezer, err := rawdb.NewStateFreezer(ancient, db.readOnly) if err != nil { log.Crit("Failed to open state history freezer", "err", err) } From af0a3274be0f948f4816142394559f2d02475980 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 28 May 2024 18:13:03 +0200 Subject: [PATCH 024/196] p2p/discover: fix crash when revalidated node is removed (#29864) In #29572, I assumed the revalidation list that the node is contained in could only ever be changed by the outcome of a revalidation request. But turns out that's not true: if the node gets removed due to FINDNODE failure, it will also be removed from the list it is in. This causes a crash. The invariant is: while node is in table, it is always in exactly one of the two lists. So it seems best to store a pointer to the current list within the node itself. --- p2p/discover/node.go | 1 + p2p/discover/table_reval.go | 74 ++++++++++++++++++++------------ p2p/discover/table_reval_test.go | 70 ++++++++++++++++++++++++++++++ p2p/discover/table_util_test.go | 8 +++- 4 files changed, 125 insertions(+), 28 deletions(-) create mode 100644 p2p/discover/table_reval_test.go diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 47df09e883..47788248f4 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -41,6 +41,7 @@ type BucketNode struct { // The fields of Node may not be modified. type node struct { *enode.Node + revalList *revalidationList addedToTable time.Time // first time node was added to bucket or replacement list addedToBucket time.Time // time it was added in the actual bucket livenessChecks uint // how often liveness was checked diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 9a13900ebc..01a5bdb6fa 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -39,7 +39,6 @@ type tableRevalidation struct { type revalidationResponse struct { n *node newRecord *enode.Node - list *revalidationList didRespond bool } @@ -60,9 +59,10 @@ func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) { // nodeRemoved is called when a node was removed from the table. func (tr *tableRevalidation) nodeRemoved(n *node) { - if !tr.fast.remove(n) { - tr.slow.remove(n) + if n.revalList == nil { + panic(fmt.Errorf("removed node %v has nil revalList", n.ID())) } + n.revalList.remove(n) } // run performs node revalidation. @@ -70,11 +70,11 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { // to schedule a timer. However, run can be called at any time. func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, &tr.fast, n) + tr.startRequest(tab, n) tr.fast.schedule(now, &tab.rand) } if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, &tr.slow, n) + tr.startRequest(tab, n) tr.slow.schedule(now, &tab.rand) } @@ -82,12 +82,12 @@ func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mcloc } // startRequest spawns a revalidation request for node n. -func (tr *tableRevalidation) startRequest(tab *Table, list *revalidationList, n *node) { +func (tr *tableRevalidation) startRequest(tab *Table, n *node) { if _, ok := tr.activeReq[n.ID()]; ok { - panic(fmt.Errorf("duplicate startRequest (list %q, node %v)", list.name, n.ID())) + panic(fmt.Errorf("duplicate startRequest (node %v)", n.ID())) } tr.activeReq[n.ID()] = struct{}{} - resp := revalidationResponse{n: n, list: list} + resp := revalidationResponse{n: n} // Fetch the node while holding lock. tab.mutex.Lock() @@ -120,11 +120,28 @@ func (tab *Table) doRevalidate(resp revalidationResponse, node *enode.Node) { // handleResponse processes the result of a revalidation request. func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationResponse) { - now := tab.cfg.Clock.Now() - n := resp.n - b := tab.bucket(n.ID()) + var ( + now = tab.cfg.Clock.Now() + n = resp.n + b = tab.bucket(n.ID()) + ) delete(tr.activeReq, n.ID()) + // If the node was removed from the table while getting checked, we need to stop + // processing here to avoid re-adding it. + if n.revalList == nil { + return + } + + // Store potential seeds in database. + // This is done via defer to avoid holding Table lock while writing to DB. + defer func() { + if n.isValidatedLive && n.livenessChecks > 5 { + tab.db.UpdateNode(resp.n.Node) + } + }() + + // Remaining logic needs access to Table internals. tab.mutex.Lock() defer tab.mutex.Unlock() @@ -134,7 +151,7 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons if n.livenessChecks <= 0 { tab.deleteInBucket(b, n.ID()) } else { - tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) + tr.moveToList(&tr.fast, n, now, &tab.rand) } return } @@ -151,27 +168,23 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons n.isValidatedLive = false } } - tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", resp.list.name) + tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList) // Move node over to slow queue after first validation. if !endpointChanged { - tr.moveToList(&tr.slow, resp.list, n, now, &tab.rand) + tr.moveToList(&tr.slow, n, now, &tab.rand) } else { - tr.moveToList(&tr.fast, resp.list, n, now, &tab.rand) - } - - // Store potential seeds in database. - if n.isValidatedLive && n.livenessChecks > 5 { - tab.db.UpdateNode(resp.n.Node) + tr.moveToList(&tr.fast, n, now, &tab.rand) } } -func (tr *tableRevalidation) moveToList(dest, source *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { - if source == dest { +// moveToList ensures n is in the 'dest' list. +func (tr *tableRevalidation) moveToList(dest *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { + if n.revalList == dest { return } - if !source.remove(n) { - panic(fmt.Errorf("moveToList(%q -> %q): node %v not in source list", source.name, dest.name, n.ID())) + if n.revalList != nil { + n.revalList.remove(n) } dest.push(n, now, rand) } @@ -208,16 +221,23 @@ func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSourc if list.nextTime == never { list.schedule(now, rand) } + n.revalList = list } -func (list *revalidationList) remove(n *node) bool { +func (list *revalidationList) remove(n *node) { i := slices.Index(list.nodes, n) if i == -1 { - return false + panic(fmt.Errorf("node %v not found in list", n.ID())) } list.nodes = slices.Delete(list.nodes, i, i+1) if len(list.nodes) == 0 { list.nextTime = never } - return true + n.revalList = nil +} + +func (list *revalidationList) contains(id enode.ID) bool { + return slices.ContainsFunc(list.nodes, func(n *node) bool { + return n.ID() == id + }) } diff --git a/p2p/discover/table_reval_test.go b/p2p/discover/table_reval_test.go new file mode 100644 index 0000000000..3adf577ae4 --- /dev/null +++ b/p2p/discover/table_reval_test.go @@ -0,0 +1,70 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package discover + +import ( + "net" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common/mclock" +) + +// This test checks that revalidation can handle a node disappearing while +// a request is active. +func TestRevalidationNodeRemoved(t *testing.T) { + var ( + clock mclock.Simulated + transport = newPingRecorder() + tab, db = newInactiveTestTable(transport, Config{Clock: &clock}) + tr = &tab.revalidation + ) + defer db.Close() + + // Fill a bucket. + node := nodeAtDistance(tab.self().ID(), 255, net.IP{77, 88, 99, 1}) + tab.handleAddNode(addNodeOp{node: node}) + + // Start a revalidation request. Schedule once to get the next start time, + // then advance the clock to that point and schedule again to start. + next := tr.run(tab, clock.Now()) + clock.Run(time.Duration(next + 1)) + tr.run(tab, clock.Now()) + if len(tr.activeReq) != 1 { + t.Fatal("revalidation request did not start:", tr.activeReq) + } + + // Delete the node. + tab.deleteInBucket(tab.bucket(node.ID()), node.ID()) + + // Now finish the revalidation request. + var resp revalidationResponse + select { + case resp = <-tab.revalResponseCh: + case <-time.After(1 * time.Second): + t.Fatal("timed out waiting for revalidation") + } + tr.handleResponse(tab, resp) + + // Ensure the node was not re-added to the table. + if tab.getNode(node.ID()) != nil { + t.Fatal("node was re-added to Table") + } + if tr.fast.contains(node.ID()) || tr.slow.contains(node.ID()) { + t.Fatal("removed node contained in revalidation list") + } +} diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 86c6048094..59045bf2a8 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -43,9 +43,15 @@ func init() { } func newTestTable(t transport, cfg Config) (*Table, *enode.DB) { + tab, db := newInactiveTestTable(t, cfg) + go tab.loop() + return tab, db +} + +// newInactiveTestTable creates a Table without running the main loop. +func newInactiveTestTable(t transport, cfg Config) (*Table, *enode.DB) { db, _ := enode.OpenDB("") tab, _ := newTable(t, db, cfg) - go tab.loop() return tab, db } From e517183719dab4214aa74a9a19ff005ab77c36e1 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 28 May 2024 10:52:08 -0700 Subject: [PATCH 025/196] eth, eth/downloader: remove references to LightChain, LightSync (#29711) Co-authored-by: Gary Rong --- eth/backend.go | 4 -- eth/downloader/beaconsync.go | 6 +-- eth/downloader/downloader.go | 65 ++++++++++++------------------- eth/downloader/downloader_test.go | 44 +++++++-------------- eth/downloader/modes.go | 15 ++----- eth/handler.go | 2 +- 6 files changed, 46 insertions(+), 90 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 97e68b8cf0..798ffa600b 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -19,7 +19,6 @@ package eth import ( "encoding/json" - "errors" "fmt" "math/big" "runtime" @@ -105,9 +104,6 @@ type Ethereum struct { // whose lifecycle will be managed by the provided node. func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { // Ensure configuration values are compatible and sane - if config.SyncMode == downloader.LightSync { - return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated") - } if !config.SyncMode.IsValid() { return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) } diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 8088f16af9..57c6eee40a 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -202,7 +202,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { case SnapSync: chainHead = d.blockchain.CurrentSnapBlock() default: - chainHead = d.lightchain.CurrentHeader() + panic("unknown sync mode") } number := chainHead.Number.Uint64() @@ -222,7 +222,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { case SnapSync: linked = d.blockchain.HasFastBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1) default: - linked = d.blockchain.HasHeader(beaconTail.ParentHash, beaconTail.Number.Uint64()-1) + panic("unknown sync mode") } if !linked { // This is a programming error. The chain backfiller was called with a @@ -257,7 +257,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) { case SnapSync: known = d.blockchain.HasFastBlock(h.Hash(), n) default: - known = d.lightchain.HasHeader(h.Hash(), n) + panic("unknown sync mode") } if !known { end = check diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index bb083260e4..d147414859 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -67,7 +67,6 @@ var ( errCancelContentProcessing = errors.New("content processing canceled (requested)") errCanceled = errors.New("syncing canceled (requested)") errNoPivotHeader = errors.New("pivot header is not found") - ErrMergeTransition = errors.New("legacy sync reached the merge") ) // peerDropFn is a callback type for dropping a peer detected as malicious. @@ -98,7 +97,6 @@ type Downloader struct { syncStatsChainHeight uint64 // Highest block number known when syncing started syncStatsLock sync.RWMutex // Lock protecting the sync stats fields - lightchain LightChain blockchain BlockChain // Callbacks @@ -143,8 +141,8 @@ type Downloader struct { syncLogTime time.Time // Time instance when status was last reported } -// LightChain encapsulates functions required to synchronise a light chain. -type LightChain interface { +// BlockChain encapsulates functions required to sync a (full or snap) blockchain. +type BlockChain interface { // HasHeader verifies a header's presence in the local chain. HasHeader(common.Hash, uint64) bool @@ -162,11 +160,6 @@ type LightChain interface { // SetHead rewinds the local chain to a new head. SetHead(uint64) error -} - -// BlockChain encapsulates functions required to sync a (full or snap) blockchain. -type BlockChain interface { - LightChain // HasBlock verifies a block's presence in the local chain. HasBlock(common.Hash, uint64) bool @@ -201,17 +194,13 @@ type BlockChain interface { } // New creates a new downloader to fetch hashes and blocks from remote peers. -func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader { - if lightchain == nil { - lightchain = chain - } +func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, dropPeer peerDropFn, success func()) *Downloader { dl := &Downloader{ stateDB: stateDb, mux: mux, queue: newQueue(blockCacheMaxItems, blockCacheInitialItems), peers: newPeerSet(), blockchain: chain, - lightchain: lightchain, dropPeer: dropPeer, headerProcCh: make(chan *headerTask, 1), quitCh: make(chan struct{}), @@ -240,15 +229,13 @@ func (d *Downloader) Progress() ethereum.SyncProgress { current := uint64(0) mode := d.getMode() - switch { - case d.blockchain != nil && mode == FullSync: + switch mode { + case FullSync: current = d.blockchain.CurrentBlock().Number.Uint64() - case d.blockchain != nil && mode == SnapSync: + case SnapSync: current = d.blockchain.CurrentSnapBlock().Number.Uint64() - case d.lightchain != nil: - current = d.lightchain.CurrentHeader().Number.Uint64() default: - log.Error("Unknown downloader chain/mode combo", "light", d.lightchain != nil, "full", d.blockchain != nil, "mode", mode) + log.Error("Unknown downloader mode", "mode", mode) } progress, pending := d.SnapSyncer.Progress() @@ -402,7 +389,7 @@ func (d *Downloader) syncToHead() (err error) { if err != nil { d.mux.Post(FailedEvent{err}) } else { - latest := d.lightchain.CurrentHeader() + latest := d.blockchain.CurrentHeader() d.mux.Post(DoneEvent{latest}) } }() @@ -520,7 +507,7 @@ func (d *Downloader) syncToHead() (err error) { } // Rewind the ancient store and blockchain if reorg happens. if origin+1 < frozen { - if err := d.lightchain.SetHead(origin); err != nil { + if err := d.blockchain.SetHead(origin); err != nil { return err } log.Info("Truncated excess ancient chain segment", "oldhead", frozen-1, "newhead", origin) @@ -690,34 +677,32 @@ func (d *Downloader) processHeaders(origin uint64) error { chunkHashes := hashes[:limit] // In case of header only syncing, validate the chunk immediately - if mode == SnapSync || mode == LightSync { + if mode == SnapSync { // Although the received headers might be all valid, a legacy // PoW/PoA sync must not accept post-merge headers. Make sure // that any transition is rejected at this point. if len(chunkHeaders) > 0 { - if n, err := d.lightchain.InsertHeaderChain(chunkHeaders); err != nil { + if n, err := d.blockchain.InsertHeaderChain(chunkHeaders); err != nil { log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err) return fmt.Errorf("%w: %v", errInvalidChain, err) } } } - // Unless we're doing light chains, schedule the headers for associated content retrieval - if mode == FullSync || mode == SnapSync { - // If we've reached the allowed number of pending headers, stall a bit - for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { - timer.Reset(time.Second) - select { - case <-d.cancelCh: - return errCanceled - case <-timer.C: - } - } - // Otherwise insert the headers for content retrieval - inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) - if len(inserts) != len(chunkHeaders) { - return fmt.Errorf("%w: stale headers", errBadPeer) + // If we've reached the allowed number of pending headers, stall a bit + for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { + timer.Reset(time.Second) + select { + case <-d.cancelCh: + return errCanceled + case <-timer.C: } } + // Otherwise insert the headers for content retrieval + inserts := d.queue.Schedule(chunkHeaders, chunkHashes, origin) + if len(inserts) != len(chunkHeaders) { + return fmt.Errorf("%w: stale headers", errBadPeer) + } + headers = headers[limit:] hashes = hashes[limit:] origin += uint64(limit) @@ -1056,7 +1041,7 @@ func (d *Downloader) readHeaderRange(last *types.Header, count int) []*types.Hea headers []*types.Header ) for { - parent := d.lightchain.GetHeaderByHash(current.ParentHash) + parent := d.blockchain.GetHeaderByHash(current.ParentHash) if parent == nil { break // The chain is not continuous, or the chain is exhausted } diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index e5329b7b39..0cbddee6bf 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -76,7 +76,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester { chain: chain, peers: make(map[string]*downloadTesterPeer), } - tester.downloader = New(db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success) + tester.downloader = New(db, new(event.TypeMux), tester.chain, tester.dropPeer, success) return tester } @@ -384,9 +384,6 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) { t.Helper() headers, blocks, receipts := length, length, length - if tester.downloader.getMode() == LightSync { - blocks, receipts = 1, 1 - } if hs := int(tester.chain.CurrentHeader().Number.Uint64()) + 1; hs != headers { t.Fatalf("synchronised headers mismatch: have %v, want %v", hs, headers) } @@ -398,9 +395,8 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) { } } -func TestCanonicalSynchronisation68Full(t *testing.T) { testCanonSync(t, eth.ETH68, FullSync) } -func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ETH68, SnapSync) } -func TestCanonicalSynchronisation68Light(t *testing.T) { testCanonSync(t, eth.ETH68, LightSync) } +func TestCanonicalSynchronisation68Full(t *testing.T) { testCanonSync(t, eth.ETH68, FullSync) } +func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ETH68, SnapSync) } func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) @@ -505,9 +501,8 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) { } // Tests that a canceled download wipes all previously accumulated state. -func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) } -func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) } -func TestCancel68Light(t *testing.T) { testCancel(t, eth.ETH68, LightSync) } +func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) } +func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) } func testCancel(t *testing.T, protocol uint, mode SyncMode) { complete := make(chan struct{}) @@ -538,9 +533,8 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) { // Tests that synchronisations behave well in multi-version protocol environments // and not wreak havoc on other nodes in the network. -func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) } -func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH68, SnapSync) } -func TestMultiProtoSynchronisation68Light(t *testing.T) { testMultiProtoSync(t, eth.ETH68, LightSync) } +func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) } +func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH68, SnapSync) } func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { complete := make(chan struct{}) @@ -578,9 +572,8 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) { // Tests that if a block is empty (e.g. header only), no body request should be // made, and instead the header should be assembled into a whole block in itself. -func TestEmptyShortCircuit68Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, FullSync) } -func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, SnapSync) } -func TestEmptyShortCircuit68Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, LightSync) } +func TestEmptyShortCircuit68Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, FullSync) } +func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, SnapSync) } func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) @@ -619,7 +612,7 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { // Validate the number of block bodies that should have been requested bodiesNeeded, receiptsNeeded := 0, 0 for _, block := range chain.blocks[1:] { - if mode != LightSync && (len(block.Transactions()) > 0 || len(block.Uncles()) > 0) { + if len(block.Transactions()) > 0 || len(block.Uncles()) > 0 { bodiesNeeded++ } } @@ -694,9 +687,8 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { // Tests that synchronisation progress (origin block number, current block number // and highest block number) is tracked and updated correctly. -func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } -func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } -func TestSyncProgress68Light(t *testing.T) { testSyncProgress(t, eth.ETH68, LightSync) } +func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } +func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { success := make(chan struct{}) @@ -734,17 +726,7 @@ func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil { t.Fatalf("failed to beacon-sync chain: %v", err) } - var startingBlock uint64 - if mode == LightSync { - // in light-sync mode: - // * the starting block is 0 on the second sync cycle because blocks - // are never downloaded. - // * The current/highest blocks reported in the progress reflect the - // current/highest header. - startingBlock = 0 - } else { - startingBlock = uint64(len(chain.blocks)/2 - 1) - } + startingBlock := uint64(len(chain.blocks)/2 - 1) select { case <-success: diff --git a/eth/downloader/modes.go b/eth/downloader/modes.go index d388b9ee4d..9d8e1f313c 100644 --- a/eth/downloader/modes.go +++ b/eth/downloader/modes.go @@ -23,13 +23,12 @@ import "fmt" type SyncMode uint32 const ( - FullSync SyncMode = iota // Synchronise the entire blockchain history from full blocks - SnapSync // Download the chain and the state via compact snapshots - LightSync // Download only the headers and terminate afterwards + FullSync SyncMode = iota // Synchronise the entire blockchain history from full blocks + SnapSync // Download the chain and the state via compact snapshots ) func (mode SyncMode) IsValid() bool { - return mode >= FullSync && mode <= LightSync + return mode == FullSync || mode == SnapSync } // String implements the stringer interface. @@ -39,8 +38,6 @@ func (mode SyncMode) String() string { return "full" case SnapSync: return "snap" - case LightSync: - return "light" default: return "unknown" } @@ -52,8 +49,6 @@ func (mode SyncMode) MarshalText() ([]byte, error) { return []byte("full"), nil case SnapSync: return []byte("snap"), nil - case LightSync: - return []byte("light"), nil default: return nil, fmt.Errorf("unknown sync mode %d", mode) } @@ -65,10 +60,8 @@ func (mode *SyncMode) UnmarshalText(text []byte) error { *mode = FullSync case "snap": *mode = SnapSync - case "light": - *mode = LightSync default: - return fmt.Errorf(`unknown sync mode %q, want "full", "snap" or "light"`, text) + return fmt.Errorf(`unknown sync mode %q, want "full" or "snap"`, text) } return nil } diff --git a/eth/handler.go b/eth/handler.go index 143ac2a8a5..d5117584c0 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -180,7 +180,7 @@ func newHandler(config *handlerConfig) (*handler, error) { return nil, errors.New("snap sync not supported with snapshots disabled") } // Construct the downloader (long sync) - h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, h.enableSyncedFeatures) + h.downloader = downloader.New(config.Database, h.eventMux, h.chain, h.removePeer, h.enableSyncedFeatures) fetchTx := func(peer string, hashes []common.Hash) error { p := h.peers.peer(peer) From 171430c3f5d474327bc1721c7c36ad83ad21b4b2 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 28 May 2024 10:54:55 -0700 Subject: [PATCH 026/196] core/state: remove unused error from prefetcher trie method (#29768) Co-authored-by: Gary Rong Co-authored-by: Felix Lange --- core/state/state_object.go | 25 ++++++++++--------------- core/state/statedb.go | 6 +++--- core/state/trie_prefetcher.go | 6 +++--- core/state/trie_prefetcher_test.go | 4 ++-- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/core/state/state_object.go b/core/state/state_object.go index 4011425c2a..252dcdf2b0 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -150,11 +150,11 @@ func (s *stateObject) getTrie() (Trie, error) { // trie in the state object. The caller might want to do that, but it's cleaner // to break the hidden interdependency between retrieving tries from the db or // from the prefetcher. -func (s *stateObject) getPrefetchedTrie() (Trie, error) { +func (s *stateObject) getPrefetchedTrie() Trie { // If there's nothing to meaningfully return, let the user figure it out by // pulling the trie from disk. if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil { - return nil, nil + return nil } // Attempt to retrieve the trie from the prefetcher return s.db.prefetcher.trie(s.addrHash, s.data.Root) @@ -311,26 +311,21 @@ func (s *stateObject) updateTrie() (Trie, error) { if len(s.pendingStorage) == 0 { return s.trie, nil } - // Retrieve a prefetcher populated trie, or fall back to the database - tr, err := s.getPrefetchedTrie() - switch { - case err != nil: - // Fetcher retrieval failed, something's very wrong, abort - s.db.setError(err) - return nil, err - - case tr == nil: + // Retrieve a pretecher populated trie, or fall back to the database + tr := s.getPrefetchedTrie() + if tr != nil { + // Prefetcher returned a live trie, swap it out for the current one + s.trie = tr + } else { // Fetcher not running or empty trie, fallback to the database trie + var err error tr, err = s.getTrie() if err != nil { s.db.setError(err) return nil, err } - - default: - // Prefetcher returned a live trie, swap it out for the current one - s.trie = tr } + // The snapshot storage map for the object var ( storage map[common.Hash][]byte diff --git a/core/state/statedb.go b/core/state/statedb.go index 0ef52a88f6..ccc7ca4ba2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -878,9 +878,9 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { start = time.Now() if s.prefetcher != nil { - if trie, err := s.prefetcher.trie(common.Hash{}, s.originalRoot); err != nil { - log.Error("Failed to retrieve account pre-fetcher trie", "err", err) - } else if trie != nil { + if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { + log.Error("Failed to retrieve account pre-fetcher trie") + } else { s.trie = trie } } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 0b45660ac1..ce94ab5139 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -145,16 +145,16 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm // trie returns the trie matching the root hash, blocking until the fetcher of // the given trie terminates. If no fetcher exists for the request, nil will be // returned. -func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) (Trie, error) { +func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie { // Bail if no trie was prefetched for this root fetcher := p.fetchers[p.trieID(owner, root)] if fetcher == nil { log.Error("Prefetcher missed to load trie", "owner", owner, "root", root) p.deliveryMissMeter.Mark(1) - return nil, nil + return nil } // Subfetcher exists, retrieve its trie - return fetcher.peek(), nil + return fetcher.peek() } // used marks a batch of state items used to allow creating statistics as to diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index d6788fad99..478407dfbb 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -58,7 +58,7 @@ func TestUseAfterTerminate(t *testing.T) { if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil { t.Errorf("Prefetch succeeded after terminate: %v", err) } - if _, err := prefetcher.trie(common.Hash{}, db.originalRoot); err != nil { - t.Errorf("Trie retrieval failed after terminate: %v", err) + if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil { + t.Errorf("Prefetcher returned nil trie after terminate") } } From cc22e0cdf0468947265883921b0c29119ca0327a Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 28 May 2024 13:30:17 -0600 Subject: [PATCH 027/196] p2p/discover: fix update logic in handleAddNode (#29836) It seems the semantic differences between addFoundNode and addInboundNode were lost in #29572. My understanding is addFoundNode is for a node you have not contacted directly (and are unsure if is available) whereas addInboundNode is for adding nodes that have contacted the local node and we can verify they are active. handleAddNode seems to be the consolidation of those two methods, yet it bumps the node in the bucket (updating it's IP addr) even if the node was not an inbound. This PR fixes this. It wasn't originally caught in tests like TestTable_addSeenNode because the manipulation of the node object actually modified the node value used by the test. New logic is added to reject non-inbound updates unless the sequence number of the (signed) ENR increases. Inbound updates, which are published by the updated node itself, are always accepted. If an inbound update changes the endpoint, the node will be revalidated on an expedited schedule. Co-authored-by: Felix Lange --- p2p/discover/table.go | 46 ++++++++---- p2p/discover/table_reval.go | 25 +++---- p2p/discover/table_reval_test.go | 53 +++++++++++++- p2p/discover/table_test.go | 120 +++++++++++++++++++++++-------- 4 files changed, 186 insertions(+), 58 deletions(-) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 74c0e930e4..2b4ba7f5d8 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -513,8 +513,9 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } b := tab.bucket(req.node.ID()) - if tab.bumpInBucket(b, req.node.Node) { - // Already in bucket, update record. + n, _ := tab.bumpInBucket(b, req.node.Node, req.isInbound) + if n != nil { + // Already in bucket. return false } if len(b.entries) >= bucketSize { @@ -605,26 +606,45 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { return rep } -// bumpInBucket updates the node record of n in the bucket. -func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node) bool { +// bumpInBucket updates a node record if it exists in the bucket. +// The second return value reports whether the node's endpoint (IP/port) was updated. +func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) (n *node, endpointChanged bool) { i := slices.IndexFunc(b.entries, func(elem *node) bool { return elem.ID() == newRecord.ID() }) if i == -1 { - return false + return nil, false // not in bucket + } + n = b.entries[i] + + // For inbound updates (from the node itself) we accept any change, even if it sets + // back the sequence number. For found nodes (!isInbound), seq has to advance. Note + // this check also ensures found discv4 nodes (which always have seq=0) can't be + // updated. + if newRecord.Seq() <= n.Seq() && !isInbound { + return n, false } - if !newRecord.IP().Equal(b.entries[i].IP()) { - // Endpoint has changed, ensure that the new IP fits into table limits. - tab.removeIP(b, b.entries[i].IP()) + // Check endpoint update against IP limits. + ipchanged := newRecord.IPAddr() != n.IPAddr() + portchanged := newRecord.UDP() != n.UDP() + if ipchanged { + tab.removeIP(b, n.IP()) if !tab.addIP(b, newRecord.IP()) { - // It doesn't, put the previous one back. - tab.addIP(b, b.entries[i].IP()) - return false + // It doesn't fit with the limit, put the previous record back. + tab.addIP(b, n.IP()) + return n, false } } - b.entries[i].Node = newRecord - return true + + // Apply update. + n.Node = newRecord + if ipchanged || portchanged { + // Ensure node is revalidated quickly for endpoint changes. + tab.revalidation.nodeEndpointChanged(tab, n) + return n, true + } + return n, false } func (tab *Table) handleTrackRequest(op trackRequestOp) { diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 01a5bdb6fa..5d185aa8b4 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -28,6 +28,8 @@ import ( const never = mclock.AbsTime(math.MaxInt64) +const slowRevalidationFactor = 3 + // tableRevalidation implements the node revalidation process. // It tracks all nodes contained in Table, and schedules sending PING to them. type tableRevalidation struct { @@ -48,7 +50,7 @@ func (tr *tableRevalidation) init(cfg *Config) { tr.fast.interval = cfg.PingInterval tr.fast.name = "fast" tr.slow.nextTime = never - tr.slow.interval = cfg.PingInterval * 3 + tr.slow.interval = cfg.PingInterval * slowRevalidationFactor tr.slow.name = "slow" } @@ -65,6 +67,12 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { n.revalList.remove(n) } +// nodeEndpointChanged is called when a change in IP or port is detected. +func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *node) { + n.isValidatedLive = false + tr.moveToList(&tr.fast, n, tab.cfg.Clock.Now(), &tab.rand) +} + // run performs node revalidation. // 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. @@ -146,11 +154,11 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons defer tab.mutex.Unlock() if !resp.didRespond { - // Revalidation failed. n.livenessChecks /= 3 if n.livenessChecks <= 0 { tab.deleteInBucket(b, n.ID()) } else { + tab.log.Debug("Node revalidation failed", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList.name) tr.moveToList(&tr.fast, n, now, &tab.rand) } return @@ -159,22 +167,15 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons // The node responded. n.livenessChecks++ n.isValidatedLive = true + tab.log.Debug("Node revalidated", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList.name) var endpointChanged bool if resp.newRecord != nil { - endpointChanged = tab.bumpInBucket(b, resp.newRecord) - if endpointChanged { - // If the node changed its advertised endpoint, the updated ENR is not served - // until it has been revalidated. - n.isValidatedLive = false - } + _, endpointChanged = tab.bumpInBucket(b, resp.newRecord, false) } - tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList) - // Move node over to slow queue after first validation. + // Node moves to slow list if it passed and hasn't changed. if !endpointChanged { tr.moveToList(&tr.slow, n, now, &tab.rand) - } else { - tr.moveToList(&tr.fast, n, now, &tab.rand) } } diff --git a/p2p/discover/table_reval_test.go b/p2p/discover/table_reval_test.go index 3adf577ae4..d168767e0d 100644 --- a/p2p/discover/table_reval_test.go +++ b/p2p/discover/table_reval_test.go @@ -22,11 +22,13 @@ import ( "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/p2p/enr" ) // This test checks that revalidation can handle a node disappearing while // a request is active. -func TestRevalidationNodeRemoved(t *testing.T) { +func TestRevalidation_nodeRemoved(t *testing.T) { var ( clock mclock.Simulated transport = newPingRecorder() @@ -35,7 +37,7 @@ func TestRevalidationNodeRemoved(t *testing.T) { ) defer db.Close() - // Fill a bucket. + // Add a node to the table. node := nodeAtDistance(tab.self().ID(), 255, net.IP{77, 88, 99, 1}) tab.handleAddNode(addNodeOp{node: node}) @@ -68,3 +70,50 @@ func TestRevalidationNodeRemoved(t *testing.T) { t.Fatal("removed node contained in revalidation list") } } + +// This test checks that nodes with an updated endpoint remain in the fast revalidation list. +func TestRevalidation_endpointUpdate(t *testing.T) { + var ( + clock mclock.Simulated + transport = newPingRecorder() + tab, db = newInactiveTestTable(transport, Config{Clock: &clock}) + tr = &tab.revalidation + ) + defer db.Close() + + // Add node to table. + node := nodeAtDistance(tab.self().ID(), 255, net.IP{77, 88, 99, 1}) + tab.handleAddNode(addNodeOp{node: node}) + + // Update the record in transport, including endpoint update. + record := node.Record() + record.Set(enr.IP{100, 100, 100, 100}) + record.Set(enr.UDP(9999)) + nodev2 := enode.SignNull(record, node.ID()) + transport.updateRecord(nodev2) + + // Start a revalidation request. Schedule once to get the next start time, + // then advance the clock to that point and schedule again to start. + next := tr.run(tab, clock.Now()) + clock.Run(time.Duration(next + 1)) + tr.run(tab, clock.Now()) + if len(tr.activeReq) != 1 { + t.Fatal("revalidation request did not start:", tr.activeReq) + } + + // Now finish the revalidation request. + var resp revalidationResponse + select { + case resp = <-tab.revalResponseCh: + case <-time.After(1 * time.Second): + t.Fatal("timed out waiting for revalidation") + } + tr.handleResponse(tab, resp) + + if !tr.fast.contains(node.ID()) { + t.Fatal("node not contained in fast revalidation list") + } + if node.isValidatedLive { + t.Fatal("node is marked live after endpoint change") + } +} diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 945b1a294e..b0be2a94c5 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -131,7 +131,7 @@ func waitForRevalidationPing(t *testing.T, transport *pingRecorder, tab *Table, simclock := tab.cfg.Clock.(*mclock.Simulated) maxAttempts := tab.len() * 8 for i := 0; i < maxAttempts; i++ { - simclock.Run(tab.cfg.PingInterval) + simclock.Run(tab.cfg.PingInterval * slowRevalidationFactor) p := transport.waitPing(2 * time.Second) if p == nil { t.Fatal("Table did not send revalidation ping") @@ -275,7 +275,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { return reflect.ValueOf(t) } -func TestTable_addVerifiedNode(t *testing.T) { +func TestTable_addInboundNode(t *testing.T) { tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() @@ -286,29 +286,26 @@ func TestTable_addVerifiedNode(t *testing.T) { n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) tab.addFoundNode(n1) tab.addFoundNode(n2) - bucket := tab.bucket(n1.ID()) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) - // Verify bucket content: - bcontent := []*node{n1, n2} - if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(bcontent)) { - t.Fatalf("wrong bucket content: %v", bucket.entries) - } - - // Add a changed version of n2. + // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) - newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addInboundNode(newn2) + n2v2 := enode.SignNull(newrec, n2.ID()) + tab.addInboundNode(wrapNode(n2v2)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) - // Check that bucket is updated correctly. - newBcontent := []*node{n1, newn2} - if !reflect.DeepEqual(unwrapNodes(bucket.entries), unwrapNodes(newBcontent)) { - t.Fatalf("wrong bucket content after update: %v", bucket.entries) - } - checkIPLimitInvariant(t, tab) + // Try updating n2 without sequence number change. The update is accepted + // because it's inbound. + newrec = n2.Record() + newrec.Set(enr.IP{100, 100, 100, 100}) + newrec.SetSeq(n2.Seq()) + n2v3 := enode.SignNull(newrec, n2.ID()) + tab.addInboundNode(wrapNode(n2v3)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v3}) } -func TestTable_addSeenNode(t *testing.T) { +func TestTable_addFoundNode(t *testing.T) { tab, db := newTestTable(newPingRecorder(), Config{}) <-tab.initDone defer db.Close() @@ -319,23 +316,84 @@ func TestTable_addSeenNode(t *testing.T) { n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) tab.addFoundNode(n1) tab.addFoundNode(n2) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) - // Verify bucket content: - bcontent := []*node{n1, n2} - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { - t.Fatalf("wrong bucket content: %v", tab.bucket(n1.ID()).entries) - } - - // Add a changed version of n2. + // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) - newn2 := wrapNode(enode.SignNull(newrec, n2.ID())) - tab.addFoundNode(newn2) + n2v2 := enode.SignNull(newrec, n2.ID()) + tab.addFoundNode(wrapNode(n2v2)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) - // Check that bucket content is unchanged. - if !reflect.DeepEqual(tab.bucket(n1.ID()).entries, bcontent) { - t.Fatalf("wrong bucket content after update: %v", tab.bucket(n1.ID()).entries) + // Try updating n2 without a sequence number change. + // The update should not be accepted. + newrec = n2.Record() + newrec.Set(enr.IP{100, 100, 100, 100}) + newrec.SetSeq(n2.Seq()) + n2v3 := enode.SignNull(newrec, n2.ID()) + tab.addFoundNode(wrapNode(n2v3)) + checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) +} + +// This test checks that discv4 nodes can update their own endpoint via PING. +func TestTable_addInboundNodeUpdateV4Accept(t *testing.T) { + tab, db := newTestTable(newPingRecorder(), Config{}) + <-tab.initDone + defer db.Close() + defer tab.close() + + // Add a v4 node. + key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") + n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) + tab.addInboundNode(wrapNode(n1)) + checkBucketContent(t, tab, []*enode.Node{n1}) + + // Add an updated version with changed IP. + // The update will be accepted because it is inbound. + n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) + tab.addInboundNode(wrapNode(n1v2)) + checkBucketContent(t, tab, []*enode.Node{n1v2}) +} + +// This test checks that discv4 node entries will NOT be updated when a +// changed record is found. +func TestTable_addFoundNodeV4UpdateReject(t *testing.T) { + tab, db := newTestTable(newPingRecorder(), Config{}) + <-tab.initDone + defer db.Close() + defer tab.close() + + // Add a v4 node. + key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") + n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) + tab.addFoundNode(wrapNode(n1)) + checkBucketContent(t, tab, []*enode.Node{n1}) + + // Add an updated version with changed IP. + // The update won't be accepted because it isn't inbound. + n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) + tab.addFoundNode(wrapNode(n1v2)) + checkBucketContent(t, tab, []*enode.Node{n1}) +} + +func checkBucketContent(t *testing.T, tab *Table, nodes []*enode.Node) { + t.Helper() + + b := tab.bucket(nodes[0].ID()) + if reflect.DeepEqual(unwrapNodes(b.entries), nodes) { + return } + t.Log("wrong bucket content. have nodes:") + for _, n := range b.entries { + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + } + t.Log("want nodes:") + for _, n := range nodes { + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + } + t.FailNow() + + // Also check IP limits. checkIPLimitInvariant(t, tab) } From 5534c849b6f426604a572d54d65a209df42a047a Mon Sep 17 00:00:00 2001 From: Martin HS Date: Wed, 29 May 2024 10:30:25 +0200 Subject: [PATCH 028/196] go.mod: update a number of dependencies (#29763) * deps: update go-winio * deps: update fastcache * deps: update golang-set * update fatih/color * update natefinch/lumberjack.v2 --- go.mod | 16 ++++++++-------- go.sum | 39 ++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index cf76ae35eb..8968140fbf 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.21 require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 - github.com/Microsoft/go-winio v0.6.1 - github.com/VictoriaMetrics/fastcache v1.12.1 + github.com/Microsoft/go-winio v0.6.2 + github.com/VictoriaMetrics/fastcache v1.12.2 github.com/aws/aws-sdk-go-v2 v1.21.2 github.com/aws/aws-sdk-go-v2/config v1.18.45 github.com/aws/aws-sdk-go-v2/credentials v1.13.43 @@ -18,12 +18,12 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 github.com/davecgh/go-spew v1.1.1 - github.com/deckarep/golang-set/v2 v2.1.0 + github.com/deckarep/golang-set/v2 v2.6.0 github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 github.com/ethereum/c-kzg-4844 v1.0.0 github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.2 github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/memsize v0.0.2 @@ -51,7 +51,7 @@ require ( github.com/kilic/bls12-381 v0.1.0 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-isatty v0.0.17 + github.com/mattn/go-isatty v0.0.20 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 @@ -69,11 +69,11 @@ require ( go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.22.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.19.0 + golang.org/x/sys v0.20.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.20.0 - gopkg.in/natefinch/lumberjack.v2 v2.0.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -93,7 +93,7 @@ require ( github.com/aws/smithy-go v1.15.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cockroachdb/errors v1.11.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect diff --git a/go.sum b/go.sum index 76e6feccdb..5e4b38e9a6 100644 --- a/go.sum +++ b/go.sum @@ -44,17 +44,15 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgx github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= -github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= +github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= +github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -103,8 +101,9 @@ github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -142,8 +141,8 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= @@ -171,8 +170,8 @@ github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHE github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY= @@ -377,16 +376,14 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= @@ -682,7 +679,6 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -690,11 +686,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -851,8 +848,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From daf4f720770d7f7e99fee02f26eb08607d8ddc79 Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Wed, 29 May 2024 18:09:58 +0800 Subject: [PATCH 029/196] p2p/simulations: remove stale information about docker adapter (#29874) --- p2p/simulations/adapters/types.go | 1 - p2p/simulations/examples/ping-pong.go | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go index f34315f170..e18aaacc33 100644 --- a/p2p/simulations/adapters/types.go +++ b/p2p/simulations/adapters/types.go @@ -42,7 +42,6 @@ import ( // // - SimNode, an in-memory node in the same process // - ExecNode, a child process node -// - DockerNode, a node running in a Docker container type Node interface { // Addr returns the node's address (e.g. an Enode URL) Addr() []byte diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go index 70b35ad777..b0b8f22fdb 100644 --- a/p2p/simulations/examples/ping-pong.go +++ b/p2p/simulations/examples/ping-pong.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" ) -var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim", "exec" or "docker")`) +var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim" or "exec")`) // main() starts a simulation network which contains nodes running a simple // ping-pong protocol From 153f8da8875930d2a7634939595b38c7bf7a6b10 Mon Sep 17 00:00:00 2001 From: lilasxie Date: Wed, 29 May 2024 18:11:18 +0800 Subject: [PATCH 030/196] p2p/nodestate: remove unused package (#29872) --- p2p/nodestate/nodestate.go | 1023 ------------------------------- p2p/nodestate/nodestate_test.go | 407 ------------ 2 files changed, 1430 deletions(-) delete mode 100644 p2p/nodestate/nodestate.go delete mode 100644 p2p/nodestate/nodestate_test.go diff --git a/p2p/nodestate/nodestate.go b/p2p/nodestate/nodestate.go deleted file mode 100644 index 8052144465..0000000000 --- a/p2p/nodestate/nodestate.go +++ /dev/null @@ -1,1023 +0,0 @@ -// Copyright 2020 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 . - -package nodestate - -import ( - "errors" - "reflect" - "sync" - "time" - "unsafe" - - "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rlp" -) - -var ( - ErrInvalidField = errors.New("invalid field type") - ErrClosed = errors.New("already closed") -) - -type ( - // NodeStateMachine implements a network node-related event subscription system. - // It can assign binary state flags and fields of arbitrary type to each node and allows - // subscriptions to flag/field changes which can also modify further flags and fields, - // potentially triggering further subscriptions. An operation includes an initial change - // and all resulting subsequent changes and always ends in a consistent global state. - // It is initiated by a "top level" SetState/SetField call that blocks (also blocking other - // top-level functions) until the operation is finished. Callbacks making further changes - // should use the non-blocking SetStateSub/SetFieldSub functions. The tree of events - // resulting from the initial changes is traversed in a breadth-first order, ensuring for - // each subscription callback that all other callbacks caused by the same change triggering - // the current callback are processed before anything is triggered by the changes made in the - // current callback. In practice this logic ensures that all subscriptions "see" events in - // the logical order, callbacks are never called concurrently and "back and forth" effects - // are also possible. The state machine design should ensure that infinite event cycles - // cannot happen. - // The caller can also add timeouts assigned to a certain node and a subset of state flags. - // If the timeout elapses, the flags are reset. If all relevant flags are reset then the timer - // is dropped. State flags with no timeout are persisted in the database if the flag - // descriptor enables saving. If a node has no state flags set at any moment then it is discarded. - // Note: in order to avoid mutex deadlocks the callbacks should never lock a mutex that - // might be locked when the top level SetState/SetField functions are called. If a function - // potentially performs state/field changes then it is recommended to mention this fact in the - // function description, along with whether it should run inside an operation callback. - NodeStateMachine struct { - started, closed bool - lock sync.Mutex - clock mclock.Clock - db ethdb.KeyValueStore - dbNodeKey []byte - nodes map[enode.ID]*nodeInfo - offlineCallbackList []offlineCallback - opFlag bool // an operation has started - opWait *sync.Cond // signaled when the operation ends - opPending []func() // pending callback list of the current operation - - // Registered state flags or fields. Modifications are allowed - // only when the node state machine has not been started. - setup *Setup - fields []*fieldInfo - saveFlags bitMask - - // Installed callbacks. Modifications are allowed only when the - // node state machine has not been started. - stateSubs []stateSub - - // Testing hooks, only for testing purposes. - saveNodeHook func(*nodeInfo) - } - - // Flags represents a set of flags from a certain setup - Flags struct { - mask bitMask - setup *Setup - } - - // Field represents a field from a certain setup - Field struct { - index int - setup *Setup - } - - // flagDefinition describes a node state flag. Each registered instance is automatically - // mapped to a bit of the 64 bit node states. - // If persistent is true then the node is saved when state machine is shutdown. - flagDefinition struct { - name string - persistent bool - } - - // fieldDefinition describes an optional node field of the given type. The contents - // of the field are only retained for each node as long as at least one of the - // state flags is set. - fieldDefinition struct { - name string - ftype reflect.Type - encode func(interface{}) ([]byte, error) - decode func([]byte) (interface{}, error) - } - - // Setup contains the list of flags and fields used by the application - Setup struct { - Version uint - flags []flagDefinition - fields []fieldDefinition - } - - // bitMask describes a node state or state mask. It represents a subset - // of node flags with each bit assigned to a flag index (LSB represents flag 0). - bitMask uint64 - - // StateCallback is a subscription callback which is called when one of the - // state flags that is included in the subscription state mask is changed. - // Note: oldState and newState are also masked with the subscription mask so only - // the relevant bits are included. - StateCallback func(n *enode.Node, oldState, newState Flags) - - // FieldCallback is a subscription callback which is called when the value of - // a specific field is changed. - FieldCallback func(n *enode.Node, state Flags, oldValue, newValue interface{}) - - // nodeInfo contains node state, fields and state timeouts - nodeInfo struct { - node *enode.Node - state bitMask - timeouts []*nodeStateTimeout - fields []interface{} - fieldCount int - db, dirty bool - } - - nodeInfoEnc struct { - Enr enr.Record - Version uint - State bitMask - Fields [][]byte - } - - stateSub struct { - mask bitMask - callback StateCallback - } - - nodeStateTimeout struct { - mask bitMask - timer mclock.Timer - } - - fieldInfo struct { - fieldDefinition - subs []FieldCallback - } - - offlineCallback struct { - node *nodeInfo - state bitMask - fields []interface{} - } -) - -// offlineState is a special state that is assumed to be set before a node is loaded from -// the database and after it is shut down. -const offlineState = bitMask(1) - -// NewFlag creates a new node state flag -func (s *Setup) NewFlag(name string) Flags { - if s.flags == nil { - s.flags = []flagDefinition{{name: "offline"}} - } - f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} - s.flags = append(s.flags, flagDefinition{name: name}) - return f -} - -// NewPersistentFlag creates a new persistent node state flag -func (s *Setup) NewPersistentFlag(name string) Flags { - if s.flags == nil { - s.flags = []flagDefinition{{name: "offline"}} - } - f := Flags{mask: bitMask(1) << uint(len(s.flags)), setup: s} - s.flags = append(s.flags, flagDefinition{name: name, persistent: true}) - return f -} - -// OfflineFlag returns the system-defined offline flag belonging to the given setup -func (s *Setup) OfflineFlag() Flags { - return Flags{mask: offlineState, setup: s} -} - -// NewField creates a new node state field -func (s *Setup) NewField(name string, ftype reflect.Type) Field { - f := Field{index: len(s.fields), setup: s} - s.fields = append(s.fields, fieldDefinition{ - name: name, - ftype: ftype, - }) - return f -} - -// NewPersistentField creates a new persistent node field -func (s *Setup) NewPersistentField(name string, ftype reflect.Type, encode func(interface{}) ([]byte, error), decode func([]byte) (interface{}, error)) Field { - f := Field{index: len(s.fields), setup: s} - s.fields = append(s.fields, fieldDefinition{ - name: name, - ftype: ftype, - encode: encode, - decode: decode, - }) - return f -} - -// flagOp implements binary flag operations and also checks whether the operands belong to the same setup -func flagOp(a, b Flags, trueIfA, trueIfB, trueIfBoth bool) Flags { - if a.setup == nil { - if a.mask != 0 { - panic("Node state flags have no setup reference") - } - a.setup = b.setup - } - if b.setup == nil { - if b.mask != 0 { - panic("Node state flags have no setup reference") - } - b.setup = a.setup - } - if a.setup != b.setup { - panic("Node state flags belong to a different setup") - } - res := Flags{setup: a.setup} - if trueIfA { - res.mask |= a.mask & ^b.mask - } - if trueIfB { - res.mask |= b.mask & ^a.mask - } - if trueIfBoth { - res.mask |= a.mask & b.mask - } - return res -} - -// And returns the set of flags present in both a and b -func (a Flags) And(b Flags) Flags { return flagOp(a, b, false, false, true) } - -// AndNot returns the set of flags present in a but not in b -func (a Flags) AndNot(b Flags) Flags { return flagOp(a, b, true, false, false) } - -// Or returns the set of flags present in either a or b -func (a Flags) Or(b Flags) Flags { return flagOp(a, b, true, true, true) } - -// Xor returns the set of flags present in either a or b but not both -func (a Flags) Xor(b Flags) Flags { return flagOp(a, b, true, true, false) } - -// HasAll returns true if b is a subset of a -func (a Flags) HasAll(b Flags) bool { return flagOp(a, b, false, true, false).mask == 0 } - -// HasNone returns true if a and b have no shared flags -func (a Flags) HasNone(b Flags) bool { return flagOp(a, b, false, false, true).mask == 0 } - -// Equals returns true if a and b have the same flags set -func (a Flags) Equals(b Flags) bool { return flagOp(a, b, true, true, false).mask == 0 } - -// IsEmpty returns true if a has no flags set -func (a Flags) IsEmpty() bool { return a.mask == 0 } - -// MergeFlags merges multiple sets of state flags -func MergeFlags(list ...Flags) Flags { - if len(list) == 0 { - return Flags{} - } - res := list[0] - for i := 1; i < len(list); i++ { - res = res.Or(list[i]) - } - return res -} - -// String returns a list of the names of the flags specified in the bit mask -func (f Flags) String() string { - if f.mask == 0 { - return "[]" - } - s := "[" - comma := false - for index, flag := range f.setup.flags { - if f.mask&(bitMask(1)< 8*int(unsafe.Sizeof(bitMask(0))) { - panic("Too many node state flags") - } - ns := &NodeStateMachine{ - db: db, - dbNodeKey: dbKey, - clock: clock, - setup: setup, - nodes: make(map[enode.ID]*nodeInfo), - fields: make([]*fieldInfo, len(setup.fields)), - } - ns.opWait = sync.NewCond(&ns.lock) - stateNameMap := make(map[string]int, len(setup.flags)) - for index, flag := range setup.flags { - if _, ok := stateNameMap[flag.name]; ok { - panic("Node state flag name collision: " + flag.name) - } - stateNameMap[flag.name] = index - if flag.persistent { - ns.saveFlags |= bitMask(1) << uint(index) - } - } - fieldNameMap := make(map[string]int, len(setup.fields)) - for index, field := range setup.fields { - if _, ok := fieldNameMap[field.name]; ok { - panic("Node field name collision: " + field.name) - } - ns.fields[index] = &fieldInfo{fieldDefinition: field} - fieldNameMap[field.name] = index - } - return ns -} - -// stateMask checks whether the set of flags belongs to the same setup and returns its internal bit mask -func (ns *NodeStateMachine) stateMask(flags Flags) bitMask { - if flags.setup != ns.setup && flags.mask != 0 { - panic("Node state flags belong to a different setup") - } - return flags.mask -} - -// fieldIndex checks whether the field belongs to the same setup and returns its internal index -func (ns *NodeStateMachine) fieldIndex(field Field) int { - if field.setup != ns.setup { - panic("Node field belongs to a different setup") - } - return field.index -} - -// SubscribeState adds a node state subscription. The callback is called while the state -// machine mutex is not held and it is allowed to make further state updates using the -// non-blocking SetStateSub/SetFieldSub functions. All callbacks of an operation are running -// from the thread/goroutine of the initial caller and parallel operations are not permitted. -// Therefore the callback is never called concurrently. It is the responsibility of the -// implemented state logic to avoid deadlocks and to reach a stable state in a finite amount -// of steps. -// State subscriptions should be installed before loading the node database or making the -// first state update. -func (ns *NodeStateMachine) SubscribeState(flags Flags, callback StateCallback) { - ns.lock.Lock() - defer ns.lock.Unlock() - - if ns.started { - panic("state machine already started") - } - ns.stateSubs = append(ns.stateSubs, stateSub{ns.stateMask(flags), callback}) -} - -// SubscribeField adds a node field subscription. Same rules apply as for SubscribeState. -func (ns *NodeStateMachine) SubscribeField(field Field, callback FieldCallback) { - ns.lock.Lock() - defer ns.lock.Unlock() - - if ns.started { - panic("state machine already started") - } - f := ns.fields[ns.fieldIndex(field)] - f.subs = append(f.subs, callback) -} - -// newNode creates a new nodeInfo -func (ns *NodeStateMachine) newNode(n *enode.Node) *nodeInfo { - return &nodeInfo{node: n, fields: make([]interface{}, len(ns.fields))} -} - -// checkStarted checks whether the state machine has already been started and panics otherwise. -func (ns *NodeStateMachine) checkStarted() { - if !ns.started { - panic("state machine not started yet") - } -} - -// Start starts the state machine, enabling state and field operations and disabling -// further subscriptions. -func (ns *NodeStateMachine) Start() { - ns.lock.Lock() - if ns.started { - panic("state machine already started") - } - ns.started = true - if ns.db != nil { - ns.loadFromDb() - } - - ns.opStart() - ns.offlineCallbacks(true) - ns.opFinish() - ns.lock.Unlock() -} - -// Stop stops the state machine and saves its state if a database was supplied -func (ns *NodeStateMachine) Stop() { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if !ns.opStart() { - panic("already closed") - } - for _, node := range ns.nodes { - fields := make([]interface{}, len(node.fields)) - copy(fields, node.fields) - ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) - } - if ns.db != nil { - ns.saveToDb() - } - ns.offlineCallbacks(false) - ns.closed = true - ns.opFinish() -} - -// loadFromDb loads persisted node states from the database -func (ns *NodeStateMachine) loadFromDb() { - it := ns.db.NewIterator(ns.dbNodeKey, nil) - for it.Next() { - var id enode.ID - if len(it.Key()) != len(ns.dbNodeKey)+len(id) { - log.Error("Node state db entry with invalid length", "found", len(it.Key()), "expected", len(ns.dbNodeKey)+len(id)) - continue - } - copy(id[:], it.Key()[len(ns.dbNodeKey):]) - ns.decodeNode(id, it.Value()) - } -} - -type dummyIdentity enode.ID - -func (id dummyIdentity) Verify(r *enr.Record, sig []byte) error { return nil } -func (id dummyIdentity) NodeAddr(r *enr.Record) []byte { return id[:] } - -// decodeNode decodes a node database entry and adds it to the node set if successful -func (ns *NodeStateMachine) decodeNode(id enode.ID, data []byte) { - var enc nodeInfoEnc - if err := rlp.DecodeBytes(data, &enc); err != nil { - log.Error("Failed to decode node info", "id", id, "error", err) - return - } - n, _ := enode.New(dummyIdentity(id), &enc.Enr) - node := ns.newNode(n) - node.db = true - - if enc.Version != ns.setup.Version { - log.Debug("Removing stored node with unknown version", "current", ns.setup.Version, "stored", enc.Version) - ns.deleteNode(id) - return - } - if len(enc.Fields) > len(ns.setup.fields) { - log.Error("Invalid node field count", "id", id, "stored", len(enc.Fields)) - return - } - // Resolve persisted node fields - for i, encField := range enc.Fields { - if len(encField) == 0 { - continue - } - if decode := ns.fields[i].decode; decode != nil { - if field, err := decode(encField); err == nil { - node.fields[i] = field - node.fieldCount++ - } else { - log.Error("Failed to decode node field", "id", id, "field name", ns.fields[i].name, "error", err) - return - } - } else { - log.Error("Cannot decode node field", "id", id, "field name", ns.fields[i].name) - return - } - } - // It's a compatible node record, add it to set. - ns.nodes[id] = node - node.state = enc.State - fields := make([]interface{}, len(node.fields)) - copy(fields, node.fields) - ns.offlineCallbackList = append(ns.offlineCallbackList, offlineCallback{node, node.state, fields}) - log.Debug("Loaded node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) -} - -// saveNode saves the given node info to the database -func (ns *NodeStateMachine) saveNode(id enode.ID, node *nodeInfo) error { - if ns.db == nil { - return nil - } - - storedState := node.state & ns.saveFlags - for _, t := range node.timeouts { - storedState &= ^t.mask - } - enc := nodeInfoEnc{ - Enr: *node.node.Record(), - Version: ns.setup.Version, - State: storedState, - Fields: make([][]byte, len(ns.fields)), - } - log.Debug("Saved node state", "id", id, "state", Flags{mask: enc.State, setup: ns.setup}) - lastIndex := -1 - for i, f := range node.fields { - if f == nil { - continue - } - encode := ns.fields[i].encode - if encode == nil { - continue - } - blob, err := encode(f) - if err != nil { - return err - } - enc.Fields[i] = blob - lastIndex = i - } - if storedState == 0 && lastIndex == -1 { - if node.db { - node.db = false - ns.deleteNode(id) - } - node.dirty = false - return nil - } - enc.Fields = enc.Fields[:lastIndex+1] - data, err := rlp.EncodeToBytes(&enc) - if err != nil { - return err - } - if err := ns.db.Put(append(ns.dbNodeKey, id[:]...), data); err != nil { - return err - } - node.dirty, node.db = false, true - - if ns.saveNodeHook != nil { - ns.saveNodeHook(node) - } - return nil -} - -// deleteNode removes a node info from the database -func (ns *NodeStateMachine) deleteNode(id enode.ID) { - ns.db.Delete(append(ns.dbNodeKey, id[:]...)) -} - -// saveToDb saves the persistent flags and fields of all nodes that have been changed -func (ns *NodeStateMachine) saveToDb() { - for id, node := range ns.nodes { - if node.dirty { - err := ns.saveNode(id, node) - if err != nil { - log.Error("Failed to save node", "id", id, "error", err) - } - } - } -} - -// updateEnode updates the enode entry belonging to the given node if it already exists -func (ns *NodeStateMachine) updateEnode(n *enode.Node) (enode.ID, *nodeInfo) { - id := n.ID() - node := ns.nodes[id] - if node != nil && n.Seq() > node.node.Seq() { - node.node = n - node.dirty = true - } - return id, node -} - -// Persist saves the persistent state and fields of the given node immediately -func (ns *NodeStateMachine) Persist(n *enode.Node) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if id, node := ns.updateEnode(n); node != nil && node.dirty { - err := ns.saveNode(id, node) - if err != nil { - log.Error("Failed to save node", "id", id, "error", err) - } - return err - } - return nil -} - -// SetState updates the given node state flags and blocks until the operation is finished. -// If a flag with a timeout is set again, the operation removes or replaces the existing timeout. -func (ns *NodeStateMachine) SetState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - if !ns.opStart() { - return ErrClosed - } - ns.setState(n, setFlags, resetFlags, timeout) - ns.opFinish() - return nil -} - -// SetStateSub updates the given node state flags without blocking (should be called -// from a subscription/operation callback). -func (ns *NodeStateMachine) SetStateSub(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.opCheck() - ns.setState(n, setFlags, resetFlags, timeout) -} - -func (ns *NodeStateMachine) setState(n *enode.Node, setFlags, resetFlags Flags, timeout time.Duration) { - ns.checkStarted() - set, reset := ns.stateMask(setFlags), ns.stateMask(resetFlags) - id, node := ns.updateEnode(n) - if node == nil { - if set == 0 { - return - } - node = ns.newNode(n) - ns.nodes[id] = node - } - oldState := node.state - newState := (node.state & (^reset)) | set - changed := oldState ^ newState - node.state = newState - - // Remove the timeout callbacks for all reset and set flags, - // even they are not existent(it's noop). - ns.removeTimeouts(node, set|reset) - - // Register the timeout callback if required - if timeout != 0 && set != 0 { - ns.addTimeout(n, set, timeout) - } - if newState == oldState { - return - } - if newState == 0 && node.fieldCount == 0 { - delete(ns.nodes, id) - if node.db { - ns.deleteNode(id) - } - } else { - if changed&ns.saveFlags != 0 { - node.dirty = true - } - } - callback := func() { - for _, sub := range ns.stateSubs { - if changed&sub.mask != 0 { - sub.callback(n, Flags{mask: oldState & sub.mask, setup: ns.setup}, Flags{mask: newState & sub.mask, setup: ns.setup}) - } - } - } - ns.opPending = append(ns.opPending, callback) -} - -// opCheck checks whether an operation is active -func (ns *NodeStateMachine) opCheck() { - if !ns.opFlag { - panic("Operation has not started") - } -} - -// opStart waits until other operations are finished and starts a new one -func (ns *NodeStateMachine) opStart() bool { - for ns.opFlag { - ns.opWait.Wait() - } - if ns.closed { - return false - } - ns.opFlag = true - return true -} - -// opFinish finishes the current operation by running all pending callbacks. -// Callbacks resulting from a state/field change performed in a previous callback are always -// put at the end of the pending list and therefore processed after all callbacks resulting -// from the previous state/field change. -func (ns *NodeStateMachine) opFinish() { - for len(ns.opPending) != 0 { - list := ns.opPending - ns.lock.Unlock() - for _, cb := range list { - cb() - } - ns.lock.Lock() - ns.opPending = ns.opPending[len(list):] - } - ns.opPending = nil - ns.opFlag = false - ns.opWait.Broadcast() -} - -// Operation calls the given function as an operation callback. This allows the caller -// to start an operation with multiple initial changes. The same rules apply as for -// subscription callbacks. -func (ns *NodeStateMachine) Operation(fn func()) error { - ns.lock.Lock() - started := ns.opStart() - ns.lock.Unlock() - if !started { - return ErrClosed - } - fn() - ns.lock.Lock() - ns.opFinish() - ns.lock.Unlock() - return nil -} - -// offlineCallbacks calls state update callbacks at startup or shutdown -func (ns *NodeStateMachine) offlineCallbacks(start bool) { - for _, cb := range ns.offlineCallbackList { - cb := cb - callback := func() { - for _, sub := range ns.stateSubs { - offState := offlineState & sub.mask - onState := cb.state & sub.mask - if offState == onState { - continue - } - if start { - sub.callback(cb.node.node, Flags{mask: offState, setup: ns.setup}, Flags{mask: onState, setup: ns.setup}) - } else { - sub.callback(cb.node.node, Flags{mask: onState, setup: ns.setup}, Flags{mask: offState, setup: ns.setup}) - } - } - for i, f := range cb.fields { - if f == nil || ns.fields[i].subs == nil { - continue - } - for _, fsub := range ns.fields[i].subs { - if start { - fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, nil, f) - } else { - fsub(cb.node.node, Flags{mask: offlineState, setup: ns.setup}, f, nil) - } - } - } - } - ns.opPending = append(ns.opPending, callback) - } - ns.offlineCallbackList = nil -} - -// AddTimeout adds a node state timeout associated to the given state flag(s). -// After the specified time interval, the relevant states will be reset. -func (ns *NodeStateMachine) AddTimeout(n *enode.Node, flags Flags, timeout time.Duration) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if ns.closed { - return ErrClosed - } - ns.addTimeout(n, ns.stateMask(flags), timeout) - return nil -} - -// addTimeout adds a node state timeout associated to the given state flag(s). -func (ns *NodeStateMachine) addTimeout(n *enode.Node, mask bitMask, timeout time.Duration) { - _, node := ns.updateEnode(n) - if node == nil { - return - } - mask &= node.state - if mask == 0 { - return - } - ns.removeTimeouts(node, mask) - t := &nodeStateTimeout{mask: mask} - t.timer = ns.clock.AfterFunc(timeout, func() { - ns.lock.Lock() - defer ns.lock.Unlock() - - if !ns.opStart() { - return - } - ns.setState(n, Flags{}, Flags{mask: t.mask, setup: ns.setup}, 0) - ns.opFinish() - }) - node.timeouts = append(node.timeouts, t) - if mask&ns.saveFlags != 0 { - node.dirty = true - } -} - -// removeTimeouts removes node state timeouts associated to the given state flag(s). -// If a timeout was associated to multiple flags which are not all included in the -// specified remove mask then only the included flags are de-associated and the timer -// stays active. -func (ns *NodeStateMachine) removeTimeouts(node *nodeInfo, mask bitMask) { - for i := 0; i < len(node.timeouts); i++ { - t := node.timeouts[i] - match := t.mask & mask - if match == 0 { - continue - } - t.mask -= match - if t.mask != 0 { - continue - } - t.timer.Stop() - node.timeouts[i] = node.timeouts[len(node.timeouts)-1] - node.timeouts = node.timeouts[:len(node.timeouts)-1] - i-- - if match&ns.saveFlags != 0 { - node.dirty = true - } - } -} - -// GetField retrieves the given field of the given node. Note that when used in a -// subscription callback the result can be out of sync with the state change represented -// by the callback parameters so extra safety checks might be necessary. -func (ns *NodeStateMachine) GetField(n *enode.Node, field Field) interface{} { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if ns.closed { - return nil - } - if _, node := ns.updateEnode(n); node != nil { - return node.fields[ns.fieldIndex(field)] - } - return nil -} - -// GetState retrieves the current state of the given node. Note that when used in a -// subscription callback the result can be out of sync with the state change represented -// by the callback parameters so extra safety checks might be necessary. -func (ns *NodeStateMachine) GetState(n *enode.Node) Flags { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if ns.closed { - return Flags{} - } - if _, node := ns.updateEnode(n); node != nil { - return Flags{mask: node.state, setup: ns.setup} - } - return Flags{} -} - -// SetField sets the given field of the given node and blocks until the operation is finished -func (ns *NodeStateMachine) SetField(n *enode.Node, field Field, value interface{}) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - if !ns.opStart() { - return ErrClosed - } - err := ns.setField(n, field, value) - ns.opFinish() - return err -} - -// SetFieldSub sets the given field of the given node without blocking (should be called -// from a subscription/operation callback). -func (ns *NodeStateMachine) SetFieldSub(n *enode.Node, field Field, value interface{}) error { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.opCheck() - return ns.setField(n, field, value) -} - -func (ns *NodeStateMachine) setField(n *enode.Node, field Field, value interface{}) error { - ns.checkStarted() - id, node := ns.updateEnode(n) - if node == nil { - if value == nil { - return nil - } - node = ns.newNode(n) - ns.nodes[id] = node - } - fieldIndex := ns.fieldIndex(field) - f := ns.fields[fieldIndex] - if value != nil && reflect.TypeOf(value) != f.ftype { - log.Error("Invalid field type", "type", reflect.TypeOf(value), "required", f.ftype) - return ErrInvalidField - } - oldValue := node.fields[fieldIndex] - if value == oldValue { - return nil - } - if oldValue != nil { - node.fieldCount-- - } - if value != nil { - node.fieldCount++ - } - node.fields[fieldIndex] = value - if node.state == 0 && node.fieldCount == 0 { - delete(ns.nodes, id) - if node.db { - ns.deleteNode(id) - } - } else { - if f.encode != nil { - node.dirty = true - } - } - state := node.state - callback := func() { - for _, cb := range f.subs { - cb(n, Flags{mask: state, setup: ns.setup}, oldValue, value) - } - } - ns.opPending = append(ns.opPending, callback) - return nil -} - -// ForEach calls the callback for each node having all of the required and none of the -// disabled flags set. -// Note that this callback is not an operation callback but ForEach can be called from an -// Operation callback or Operation can also be called from a ForEach callback if necessary. -func (ns *NodeStateMachine) ForEach(requireFlags, disableFlags Flags, cb func(n *enode.Node, state Flags)) { - ns.lock.Lock() - ns.checkStarted() - type callback struct { - node *enode.Node - state bitMask - } - require, disable := ns.stateMask(requireFlags), ns.stateMask(disableFlags) - var callbacks []callback - for _, node := range ns.nodes { - if node.state&require == require && node.state&disable == 0 { - callbacks = append(callbacks, callback{node.node, node.state & (require | disable)}) - } - } - ns.lock.Unlock() - for _, c := range callbacks { - cb(c.node, Flags{mask: c.state, setup: ns.setup}) - } -} - -// GetNode returns the enode currently associated with the given ID -func (ns *NodeStateMachine) GetNode(id enode.ID) *enode.Node { - ns.lock.Lock() - defer ns.lock.Unlock() - - ns.checkStarted() - if node := ns.nodes[id]; node != nil { - return node.node - } - return nil -} - -// AddLogMetrics adds logging and/or metrics for nodes entering, exiting and currently -// being in a given set specified by required and disabled state flags -func (ns *NodeStateMachine) AddLogMetrics(requireFlags, disableFlags Flags, name string, inMeter, outMeter metrics.Meter, gauge metrics.Gauge) { - var count int64 - ns.SubscribeState(requireFlags.Or(disableFlags), func(n *enode.Node, oldState, newState Flags) { - oldMatch := oldState.HasAll(requireFlags) && oldState.HasNone(disableFlags) - newMatch := newState.HasAll(requireFlags) && newState.HasNone(disableFlags) - if newMatch == oldMatch { - return - } - - if newMatch { - count++ - if name != "" { - log.Debug("Node entered", "set", name, "id", n.ID(), "count", count) - } - if inMeter != nil { - inMeter.Mark(1) - } - } else { - count-- - if name != "" { - log.Debug("Node left", "set", name, "id", n.ID(), "count", count) - } - if outMeter != nil { - outMeter.Mark(1) - } - } - if gauge != nil { - gauge.Update(count) - } - }) -} diff --git a/p2p/nodestate/nodestate_test.go b/p2p/nodestate/nodestate_test.go deleted file mode 100644 index d06ad755e2..0000000000 --- a/p2p/nodestate/nodestate_test.go +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright 2020 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 . - -package nodestate - -import ( - "errors" - "fmt" - "reflect" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common/mclock" - "github.com/ethereum/go-ethereum/core/rawdb" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rlp" -) - -func testSetup(flagPersist []bool, fieldType []reflect.Type) (*Setup, []Flags, []Field) { - setup := &Setup{} - flags := make([]Flags, len(flagPersist)) - for i, persist := range flagPersist { - if persist { - flags[i] = setup.NewPersistentFlag(fmt.Sprintf("flag-%d", i)) - } else { - flags[i] = setup.NewFlag(fmt.Sprintf("flag-%d", i)) - } - } - fields := make([]Field, len(fieldType)) - for i, ftype := range fieldType { - switch ftype { - case reflect.TypeOf(uint64(0)): - fields[i] = setup.NewPersistentField(fmt.Sprintf("field-%d", i), ftype, uint64FieldEnc, uint64FieldDec) - case reflect.TypeOf(""): - fields[i] = setup.NewPersistentField(fmt.Sprintf("field-%d", i), ftype, stringFieldEnc, stringFieldDec) - default: - fields[i] = setup.NewField(fmt.Sprintf("field-%d", i), ftype) - } - } - return setup, flags, fields -} - -func testNode(b byte) *enode.Node { - r := &enr.Record{} - r.SetSig(dummyIdentity{b}, []byte{42}) - n, _ := enode.New(dummyIdentity{b}, r) - return n -} - -func TestCallback(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{false, false, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - set0 := make(chan struct{}, 1) - set1 := make(chan struct{}, 1) - set2 := make(chan struct{}, 1) - ns.SubscribeState(flags[0], func(n *enode.Node, oldState, newState Flags) { set0 <- struct{}{} }) - ns.SubscribeState(flags[1], func(n *enode.Node, oldState, newState Flags) { set1 <- struct{}{} }) - ns.SubscribeState(flags[2], func(n *enode.Node, oldState, newState Flags) { set2 <- struct{}{} }) - - ns.Start() - - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetState(testNode(1), flags[1], Flags{}, time.Second) - ns.SetState(testNode(1), flags[2], Flags{}, 2*time.Second) - - for i := 0; i < 3; i++ { - select { - case <-set0: - case <-set1: - case <-set2: - case <-time.After(time.Second): - t.Fatalf("failed to invoke callback") - } - } -} - -func TestPersistentFlags(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{true, true, true, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - saveNode := make(chan *nodeInfo, 5) - ns.saveNodeHook = func(node *nodeInfo) { - saveNode <- node - } - - ns.Start() - - ns.SetState(testNode(1), flags[0], Flags{}, time.Second) // state with timeout should not be saved - ns.SetState(testNode(2), flags[1], Flags{}, 0) - ns.SetState(testNode(3), flags[2], Flags{}, 0) - ns.SetState(testNode(4), flags[3], Flags{}, 0) - ns.SetState(testNode(5), flags[0], Flags{}, 0) - ns.Persist(testNode(5)) - select { - case <-saveNode: - case <-time.After(time.Second): - t.Fatalf("Timeout") - } - ns.Stop() - - for i := 0; i < 2; i++ { - select { - case <-saveNode: - case <-time.After(time.Second): - t.Fatalf("Timeout") - } - } - select { - case <-saveNode: - t.Fatalf("Unexpected saveNode") - case <-time.After(time.Millisecond * 100): - } -} - -func TestSetField(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, fields := testSetup([]bool{true}, []reflect.Type{reflect.TypeOf("")}) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - saveNode := make(chan *nodeInfo, 1) - ns.saveNodeHook = func(node *nodeInfo) { - saveNode <- node - } - - ns.Start() - - // Set field before setting state - ns.SetField(testNode(1), fields[0], "hello world") - field := ns.GetField(testNode(1), fields[0]) - if field == nil { - t.Fatalf("Field should be set before setting states") - } - ns.SetField(testNode(1), fields[0], nil) - field = ns.GetField(testNode(1), fields[0]) - if field != nil { - t.Fatalf("Field should be unset") - } - // Set field after setting state - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetField(testNode(1), fields[0], "hello world") - field = ns.GetField(testNode(1), fields[0]) - if field == nil { - t.Fatalf("Field should be set after setting states") - } - if err := ns.SetField(testNode(1), fields[0], 123); err == nil { - t.Fatalf("Invalid field should be rejected") - } - // Dirty node should be written back - ns.Stop() - select { - case <-saveNode: - case <-time.After(time.Second): - t.Fatalf("Timeout") - } -} - -func TestSetState(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{false, false, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - type change struct{ old, new Flags } - set := make(chan change, 1) - ns.SubscribeState(flags[0].Or(flags[1]), func(n *enode.Node, oldState, newState Flags) { - set <- change{ - old: oldState, - new: newState, - } - }) - - ns.Start() - - check := func(expectOld, expectNew Flags, expectChange bool) { - if expectChange { - select { - case c := <-set: - if !c.old.Equals(expectOld) { - t.Fatalf("Old state mismatch") - } - if !c.new.Equals(expectNew) { - t.Fatalf("New state mismatch") - } - case <-time.After(time.Second): - } - return - } - select { - case <-set: - t.Fatalf("Unexpected change") - case <-time.After(time.Millisecond * 100): - return - } - } - ns.SetState(testNode(1), flags[0], Flags{}, 0) - check(Flags{}, flags[0], true) - - ns.SetState(testNode(1), flags[1], Flags{}, 0) - check(flags[0], flags[0].Or(flags[1]), true) - - ns.SetState(testNode(1), flags[2], Flags{}, 0) - check(Flags{}, Flags{}, false) - - ns.SetState(testNode(1), Flags{}, flags[0], 0) - check(flags[0].Or(flags[1]), flags[1], true) - - ns.SetState(testNode(1), Flags{}, flags[1], 0) - check(flags[1], Flags{}, true) - - ns.SetState(testNode(1), Flags{}, flags[2], 0) - check(Flags{}, Flags{}, false) - - ns.SetState(testNode(1), flags[0].Or(flags[1]), Flags{}, time.Second) - check(Flags{}, flags[0].Or(flags[1]), true) - clock.Run(time.Second) - check(flags[0].Or(flags[1]), Flags{}, true) -} - -func uint64FieldEnc(field interface{}) ([]byte, error) { - if u, ok := field.(uint64); ok { - enc, err := rlp.EncodeToBytes(&u) - return enc, err - } - return nil, errors.New("invalid field type") -} - -func uint64FieldDec(enc []byte) (interface{}, error) { - var u uint64 - err := rlp.DecodeBytes(enc, &u) - return u, err -} - -func stringFieldEnc(field interface{}) ([]byte, error) { - if s, ok := field.(string); ok { - return []byte(s), nil - } - return nil, errors.New("invalid field type") -} - -func stringFieldDec(enc []byte) (interface{}, error) { - return string(enc), nil -} - -func TestPersistentFields(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, fields := testSetup([]bool{true}, []reflect.Type{reflect.TypeOf(uint64(0)), reflect.TypeOf("")}) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - ns.Start() - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetField(testNode(1), fields[0], uint64(100)) - ns.SetField(testNode(1), fields[1], "hello world") - ns.Stop() - - ns2 := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - ns2.Start() - field0 := ns2.GetField(testNode(1), fields[0]) - if !reflect.DeepEqual(field0, uint64(100)) { - t.Fatalf("Field changed") - } - field1 := ns2.GetField(testNode(1), fields[1]) - if !reflect.DeepEqual(field1, "hello world") { - t.Fatalf("Field changed") - } - - s.Version++ - ns3 := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - ns3.Start() - if ns3.GetField(testNode(1), fields[0]) != nil { - t.Fatalf("Old field version should have been discarded") - } -} - -func TestFieldSub(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, fields := testSetup([]bool{true}, []reflect.Type{reflect.TypeOf(uint64(0))}) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - var ( - lastState Flags - lastOldValue, lastNewValue interface{} - ) - ns.SubscribeField(fields[0], func(n *enode.Node, state Flags, oldValue, newValue interface{}) { - lastState, lastOldValue, lastNewValue = state, oldValue, newValue - }) - check := func(state Flags, oldValue, newValue interface{}) { - if !lastState.Equals(state) || lastOldValue != oldValue || lastNewValue != newValue { - t.Fatalf("Incorrect field sub callback (expected [%v %v %v], got [%v %v %v])", state, oldValue, newValue, lastState, lastOldValue, lastNewValue) - } - } - ns.Start() - ns.SetState(testNode(1), flags[0], Flags{}, 0) - ns.SetField(testNode(1), fields[0], uint64(100)) - check(flags[0], nil, uint64(100)) - ns.Stop() - check(s.OfflineFlag(), uint64(100), nil) - - ns2 := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - ns2.SubscribeField(fields[0], func(n *enode.Node, state Flags, oldValue, newValue interface{}) { - lastState, lastOldValue, lastNewValue = state, oldValue, newValue - }) - ns2.Start() - check(s.OfflineFlag(), nil, uint64(100)) - ns2.SetState(testNode(1), Flags{}, flags[0], 0) - ns2.SetField(testNode(1), fields[0], nil) - check(Flags{}, uint64(100), nil) - ns2.Stop() -} - -func TestDuplicatedFlags(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{true}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - type change struct{ old, new Flags } - set := make(chan change, 1) - ns.SubscribeState(flags[0], func(n *enode.Node, oldState, newState Flags) { - set <- change{oldState, newState} - }) - - ns.Start() - defer ns.Stop() - - check := func(expectOld, expectNew Flags, expectChange bool) { - if expectChange { - select { - case c := <-set: - if !c.old.Equals(expectOld) { - t.Fatalf("Old state mismatch") - } - if !c.new.Equals(expectNew) { - t.Fatalf("New state mismatch") - } - case <-time.After(time.Second): - } - return - } - select { - case <-set: - t.Fatalf("Unexpected change") - case <-time.After(time.Millisecond * 100): - return - } - } - ns.SetState(testNode(1), flags[0], Flags{}, time.Second) - check(Flags{}, flags[0], true) - ns.SetState(testNode(1), flags[0], Flags{}, 2*time.Second) // extend the timeout to 2s - check(Flags{}, flags[0], false) - - clock.Run(2 * time.Second) - check(flags[0], Flags{}, true) -} - -func TestCallbackOrder(t *testing.T) { - mdb, clock := rawdb.NewMemoryDatabase(), &mclock.Simulated{} - - s, flags, _ := testSetup([]bool{false, false, false, false}, nil) - ns := NewNodeStateMachine(mdb, []byte("-ns"), clock, s) - - ns.SubscribeState(flags[0], func(n *enode.Node, oldState, newState Flags) { - if newState.Equals(flags[0]) { - ns.SetStateSub(n, flags[1], Flags{}, 0) - ns.SetStateSub(n, flags[2], Flags{}, 0) - } - }) - ns.SubscribeState(flags[1], func(n *enode.Node, oldState, newState Flags) { - if newState.Equals(flags[1]) { - ns.SetStateSub(n, flags[3], Flags{}, 0) - } - }) - lastState := Flags{} - ns.SubscribeState(MergeFlags(flags[1], flags[2], flags[3]), func(n *enode.Node, oldState, newState Flags) { - if !oldState.Equals(lastState) { - t.Fatalf("Wrong callback order") - } - lastState = newState - }) - - ns.Start() - defer ns.Stop() - - ns.SetState(testNode(1), flags[0], Flags{}, 0) -} From b8cf1636d4af9bf1eaea51294ad78885c4474091 Mon Sep 17 00:00:00 2001 From: Steven Wang <915337710@qq.com> Date: Wed, 29 May 2024 18:12:57 +0800 Subject: [PATCH 031/196] accounts: fix TestUpdateKeyfileContents (#29867) Create the directory before NewKeyStore. This ensures the watcher successfully starts on the first attempt, and waitWatcherStart functions as intended. --- accounts/keystore/account_cache_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 1a9f9a4714..6bc14f5bb6 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -326,6 +326,11 @@ func TestUpdatedKeyfileContents(t *testing.T) { // Create a temporary keystore to test with dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int())) + + // Create the directory + os.MkdirAll(dir, 0700) + defer os.RemoveAll(dir) + ks := NewKeyStore(dir, LightScryptN, LightScryptP) list := ks.Accounts() @@ -335,9 +340,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { if !waitWatcherStart(ks) { t.Fatal("keystore watcher didn't start in time") } - // Create the directory and copy a key file into it. - os.MkdirAll(dir, 0700) - defer os.RemoveAll(dir) + // Copy a key file into it file := filepath.Join(dir, "aaa") // Place one of our testfiles in there From 06263b1b356dde3e2509aef4efef295744e4f6c3 Mon Sep 17 00:00:00 2001 From: PolyMa <151764357+polymaer@users.noreply.github.com> Date: Wed, 29 May 2024 18:24:10 +0800 Subject: [PATCH 032/196] all: fix typos in comments (#29873) fix using `a` & `the` simutaneously --- cmd/geth/snapshot.go | 2 +- core/bloombits/scheduler.go | 2 +- eth/protocols/snap/sync.go | 2 +- ethdb/leveldb/leveldb.go | 2 +- ethdb/memorydb/memorydb.go | 2 +- ethdb/pebble/pebble.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index 192c850868..cf7093e605 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -91,7 +91,7 @@ data, and verifies that all snapshot storage data has a corresponding account. }, { Name: "inspect-account", - Usage: "Check all snapshot layers for the a specific account", + Usage: "Check all snapshot layers for the specific account", ArgsUsage: "
", Action: checkAccount, Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags), diff --git a/core/bloombits/scheduler.go b/core/bloombits/scheduler.go index 6449c7465a..a523bc55ab 100644 --- a/core/bloombits/scheduler.go +++ b/core/bloombits/scheduler.go @@ -23,7 +23,7 @@ import ( // request represents a bloom retrieval task to prioritize and pull from the local // database or remotely from the network. type request struct { - section uint64 // Section index to retrieve the a bit-vector from + section uint64 // Section index to retrieve the bit-vector from bit uint // Bit index within the section to retrieve the vector of } diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 8671aebc90..53cba5d115 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -103,7 +103,7 @@ var ( // to allow concurrent retrievals. accountConcurrency = 16 - // storageConcurrency is the number of chunks to split the a large contract + // storageConcurrency is the number of chunks to split a large contract // storage trie into to allow concurrent retrievals. storageConcurrency = 16 ) diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index e58efbddbe..64f51cf217 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -400,7 +400,7 @@ func (b *batch) Put(key, value []byte) error { return nil } -// Delete inserts the a key removal into the batch for later committing. +// Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { b.b.Delete(key) b.size += len(key) diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 2a939f9a18..d1233acb21 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -227,7 +227,7 @@ func (b *batch) Put(key, value []byte) error { return nil } -// Delete inserts the a key removal into the batch for later committing. +// Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { b.writes = append(b.writes, keyvalue{string(key), nil, true}) b.size += len(key) diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index ee4e5dd75a..dda084ae3b 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -575,7 +575,7 @@ func (b *batch) Put(key, value []byte) error { return nil } -// Delete inserts the a key removal into the batch for later committing. +// Delete inserts the key removal into the batch for later committing. func (b *batch) Delete(key []byte) error { b.b.Delete(key, nil) b.size += len(key) From 2f0e63e5ac6e1c1c85b5831a19bf7bbd6a63ca1d Mon Sep 17 00:00:00 2001 From: trillo Date: Wed, 29 May 2024 21:43:07 +0900 Subject: [PATCH 033/196] eth/downloader, eth/tracer: fix typos in comments (#29707) --- eth/downloader/api.go | 2 +- eth/tracers/api_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/downloader/api.go b/eth/downloader/api.go index 90c36afbb5..ac175672a0 100644 --- a/eth/downloader/api.go +++ b/eth/downloader/api.go @@ -129,7 +129,7 @@ func (api *DownloaderAPI) eventLoop() { } } -// Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished. +// Syncing provides information when this node starts synchronising with the Ethereum network and when it's finished. func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) { notifier, supported := rpc.NotifierFromContext(ctx) if !supported { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 120cb585c7..6fbb50848d 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -312,7 +312,7 @@ func TestTraceCall(t *testing.T) { config: &TraceCallConfig{TxIndex: uintPtr(1)}, expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr), }, - // After the target transaction, should be succeed + // After the target transaction, should be succeeded { blockNumber: rpc.BlockNumber(genBlocks - 1), call: ethapi.TransactionArgs{ From e26fa9e40ebddc39247ca11cae28c7f6bd8337e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=9B=E6=99=93=E5=A9=95?= <30611384+niuxiaojie81@users.noreply.github.com> Date: Wed, 29 May 2024 20:44:14 +0800 Subject: [PATCH 034/196] core/state: fix typo in comment (#29639) --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index ccc7ca4ba2..fe262d4695 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -351,7 +351,7 @@ func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash { return common.Hash{} } -// TxIndex returns the current transaction index set by Prepare. +// TxIndex returns the current transaction index set by SetTxContext. func (s *StateDB) TxIndex() int { return s.txIndex } From 94a8b296e4c0abb90e31f35d0fc433869740207d Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 May 2024 15:02:26 +0200 Subject: [PATCH 035/196] p2p/discover: refactor node and endpoint representation (#29844) Here we clean up internal uses of type discover.node, converting most code to use enode.Node instead. The discover.node type used to be the canonical representation of network hosts before ENR was introduced. Most code worked with *node to avoid conversions when interacting with Table methods. Since *node also contains internal state of Table and is a mutable type, using *node outside of Table code is prone to data races. It's also cleaner not having to wrap/unwrap *enode.Node all the time. discover.node has been renamed to tableNode to clarify its purpose. While here, we also change most uses of net.UDPAddr into netip.AddrPort. While this is technically a separate refactoring from the *node -> *enode.Node change, it is more convenient because *enode.Node handles IP addresses as netip.Addr. The switch to package netip in discovery would've happened very soon anyway. The change to netip.AddrPort stops at certain interface points. For example, since package p2p/netutil has not been converted to use netip.Addr yet, we still have to convert to net.IP/net.UDPAddr in a few places. --- cmd/devp2p/internal/v4test/framework.go | 2 +- p2p/discover/common.go | 7 +- p2p/discover/lookup.go | 18 +-- p2p/discover/metrics.go | 14 +-- p2p/discover/node.go | 79 ++++++++----- p2p/discover/table.go | 125 +++++++------------- p2p/discover/table_reval.go | 22 ++-- p2p/discover/table_reval_test.go | 4 +- p2p/discover/table_test.go | 80 ++++++------- p2p/discover/table_util_test.go | 34 +++--- p2p/discover/v4_lookup_test.go | 27 ++--- p2p/discover/v4_udp.go | 146 ++++++++++++++---------- p2p/discover/v4_udp_test.go | 107 +++++++++-------- p2p/discover/v4wire/v4wire.go | 16 +-- p2p/discover/v5_talk.go | 6 +- p2p/discover/v5_udp.go | 80 +++++++------ p2p/discover/v5_udp_test.go | 93 ++++++++------- p2p/server.go | 7 +- 18 files changed, 434 insertions(+), 433 deletions(-) diff --git a/cmd/devp2p/internal/v4test/framework.go b/cmd/devp2p/internal/v4test/framework.go index 9286594181..e8f4c021b8 100644 --- a/cmd/devp2p/internal/v4test/framework.go +++ b/cmd/devp2p/internal/v4test/framework.go @@ -110,7 +110,7 @@ func (te *testenv) localEndpoint(c net.PacketConn) v4wire.Endpoint { } func (te *testenv) remoteEndpoint() v4wire.Endpoint { - return v4wire.NewEndpoint(te.remoteAddr, 0) + return v4wire.NewEndpoint(te.remoteAddr.AddrPort(), 0) } func contains(ns []v4wire.Node, key v4wire.Pubkey) bool { diff --git a/p2p/discover/common.go b/p2p/discover/common.go index bebea8cc38..0716f7472f 100644 --- a/p2p/discover/common.go +++ b/p2p/discover/common.go @@ -22,6 +22,7 @@ import ( "encoding/binary" "math/rand" "net" + "net/netip" "sync" "time" @@ -34,8 +35,8 @@ import ( // UDPConn is a network connection on which discovery can operate. type UDPConn interface { - ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) - WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) + ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) + WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (n int, err error) Close() error LocalAddr() net.Addr } @@ -94,7 +95,7 @@ func ListenUDP(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { // channel if configured. type ReadPacket struct { Data []byte - Addr *net.UDPAddr + Addr netip.AddrPort } type randomSource interface { diff --git a/p2p/discover/lookup.go b/p2p/discover/lookup.go index 5c3d90d6c9..09808b71e0 100644 --- a/p2p/discover/lookup.go +++ b/p2p/discover/lookup.go @@ -29,16 +29,16 @@ import ( // not need to be an actual node identifier. type lookup struct { tab *Table - queryfunc func(*node) ([]*node, error) - replyCh chan []*node + queryfunc queryFunc + replyCh chan []*enode.Node cancelCh <-chan struct{} asked, seen map[enode.ID]bool result nodesByDistance - replyBuffer []*node + replyBuffer []*enode.Node queries int } -type queryFunc func(*node) ([]*node, error) +type queryFunc func(*enode.Node) ([]*enode.Node, error) func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *lookup { it := &lookup{ @@ -47,7 +47,7 @@ func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *l asked: make(map[enode.ID]bool), seen: make(map[enode.ID]bool), result: nodesByDistance{target: target}, - replyCh: make(chan []*node, alpha), + replyCh: make(chan []*enode.Node, alpha), cancelCh: ctx.Done(), queries: -1, } @@ -61,7 +61,7 @@ func newLookup(ctx context.Context, tab *Table, target enode.ID, q queryFunc) *l func (it *lookup) run() []*enode.Node { for it.advance() { } - return unwrapNodes(it.result.entries) + return it.result.entries } // advance advances the lookup until any new nodes have been found. @@ -139,7 +139,7 @@ func (it *lookup) slowdown() { } } -func (it *lookup) query(n *node, reply chan<- []*node) { +func (it *lookup) query(n *enode.Node, reply chan<- []*enode.Node) { r, err := it.queryfunc(n) if !errors.Is(err, errClosed) { // avoid recording failures on shutdown. success := len(r) > 0 @@ -154,7 +154,7 @@ func (it *lookup) query(n *node, reply chan<- []*node) { // lookupIterator performs lookup operations and iterates over all seen nodes. // When a lookup finishes, a new one is created through nextLookup. type lookupIterator struct { - buffer []*node + buffer []*enode.Node nextLookup lookupFunc ctx context.Context cancel func() @@ -173,7 +173,7 @@ func (it *lookupIterator) Node() *enode.Node { if len(it.buffer) == 0 { return nil } - return unwrapNode(it.buffer[0]) + return it.buffer[0] } // Next moves to the next node. diff --git a/p2p/discover/metrics.go b/p2p/discover/metrics.go index 3cd0ab0414..8deafbbce4 100644 --- a/p2p/discover/metrics.go +++ b/p2p/discover/metrics.go @@ -18,7 +18,7 @@ package discover import ( "fmt" - "net" + "net/netip" "github.com/ethereum/go-ethereum/metrics" ) @@ -58,16 +58,16 @@ func newMeteredConn(conn UDPConn) UDPConn { return &meteredUdpConn{UDPConn: conn} } -// ReadFromUDP delegates a network read to the underlying connection, bumping the udp ingress traffic meter along the way. -func (c *meteredUdpConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { - n, addr, err = c.UDPConn.ReadFromUDP(b) +// ReadFromUDPAddrPort delegates a network read to the underlying connection, bumping the udp ingress traffic meter along the way. +func (c *meteredUdpConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { + n, addr, err = c.UDPConn.ReadFromUDPAddrPort(b) ingressTrafficMeter.Mark(int64(n)) return n, addr, err } -// Write delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. -func (c *meteredUdpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) { - n, err = c.UDPConn.WriteToUDP(b, addr) +// WriteToUDP delegates a network write to the underlying connection, bumping the udp egress traffic meter along the way. +func (c *meteredUdpConn) WriteToUDP(b []byte, addr netip.AddrPort) (n int, err error) { + n, err = c.UDPConn.WriteToUDPAddrPort(b, addr) egressTrafficMeter.Mark(int64(n)) return n, err } diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 47788248f4..042619221b 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -21,7 +21,8 @@ import ( "crypto/elliptic" "errors" "math/big" - "net" + "slices" + "sort" "time" "github.com/ethereum/go-ethereum/common/math" @@ -37,9 +38,8 @@ type BucketNode struct { Live bool `json:"live"` } -// node represents a host on the network. -// The fields of Node may not be modified. -type node struct { +// tableNode is an entry in Table. +type tableNode struct { *enode.Node revalList *revalidationList addedToTable time.Time // first time node was added to bucket or replacement list @@ -75,34 +75,59 @@ func (e encPubkey) id() enode.ID { return enode.ID(crypto.Keccak256Hash(e[:])) } -func wrapNode(n *enode.Node) *node { - return &node{Node: n} -} - -func wrapNodes(ns []*enode.Node) []*node { - result := make([]*node, len(ns)) - for i, n := range ns { - result[i] = wrapNode(n) - } - return result -} - -func unwrapNode(n *node) *enode.Node { - return n.Node -} - -func unwrapNodes(ns []*node) []*enode.Node { +func unwrapNodes(ns []*tableNode) []*enode.Node { result := make([]*enode.Node, len(ns)) for i, n := range ns { - result[i] = unwrapNode(n) + result[i] = n.Node } return result } -func (n *node) addr() *net.UDPAddr { - return &net.UDPAddr{IP: n.IP(), Port: n.UDP()} -} - -func (n *node) String() string { +func (n *tableNode) String() string { return n.Node.String() } + +// nodesByDistance is a list of nodes, ordered by distance to target. +type nodesByDistance struct { + entries []*enode.Node + target enode.ID +} + +// push adds the given node to the list, keeping the total size below maxElems. +func (h *nodesByDistance) push(n *enode.Node, maxElems int) { + ix := sort.Search(len(h.entries), func(i int) bool { + return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 + }) + + end := len(h.entries) + if len(h.entries) < maxElems { + h.entries = append(h.entries, n) + } + if ix < end { + // Slide existing entries down to make room. + // This will overwrite the entry we just appended. + copy(h.entries[ix+1:], h.entries[ix:]) + h.entries[ix] = n + } +} + +type nodeType interface { + ID() enode.ID +} + +// containsID reports whether ns contains a node with the given ID. +func containsID[N nodeType](ns []N, id enode.ID) bool { + for _, n := range ns { + if n.ID() == id { + return true + } + } + return false +} + +// deleteNode removes a node from the list. +func deleteNode[N nodeType](list []N, id enode.ID) []N { + return slices.DeleteFunc(list, func(n N) bool { + return n.ID() == id + }) +} diff --git a/p2p/discover/table.go b/p2p/discover/table.go index 2b4ba7f5d8..bd3c9b4143 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -27,7 +27,6 @@ import ( "fmt" "net" "slices" - "sort" "sync" "time" @@ -65,7 +64,7 @@ const ( type Table struct { mutex sync.Mutex // protects buckets, bucket content, nursery, rand buckets [nBuckets]*bucket // index of known nodes by distance - nursery []*node // bootstrap nodes + nursery []*enode.Node // bootstrap nodes rand reseedingRandom // source of randomness, periodically reseeded ips netutil.DistinctNetSet revalidation tableRevalidation @@ -85,8 +84,8 @@ type Table struct { closeReq chan struct{} closed chan struct{} - nodeAddedHook func(*bucket, *node) - nodeRemovedHook func(*bucket, *node) + nodeAddedHook func(*bucket, *tableNode) + nodeRemovedHook func(*bucket, *tableNode) } // transport is implemented by the UDP transports. @@ -101,20 +100,21 @@ type transport interface { // bucket contains nodes, ordered by their last activity. the entry // that was most recently active is the first element in entries. type bucket struct { - entries []*node // live entries, sorted by time of last contact - replacements []*node // recently seen nodes to be used if revalidation fails + entries []*tableNode // live entries, sorted by time of last contact + replacements []*tableNode // recently seen nodes to be used if revalidation fails ips netutil.DistinctNetSet index int } type addNodeOp struct { - node *node - isInbound bool + node *enode.Node + isInbound bool + forceSetLive bool // for tests } type trackRequestOp struct { - node *node - foundNodes []*node + node *enode.Node + foundNodes []*enode.Node success bool } @@ -186,7 +186,7 @@ func (tab *Table) getNode(id enode.ID) *enode.Node { b := tab.bucket(id) for _, e := range b.entries { if e.ID() == id { - return unwrapNode(e) + return e.Node } } return nil @@ -202,7 +202,7 @@ func (tab *Table) close() { // are used to connect to the network if the table is empty and there // are no known nodes in the database. func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { - nursery := make([]*node, 0, len(nodes)) + nursery := make([]*enode.Node, 0, len(nodes)) for _, n := range nodes { if err := n.ValidateComplete(); err != nil { return fmt.Errorf("bad bootstrap node %q: %v", n, err) @@ -211,7 +211,7 @@ func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IP()) continue } - nursery = append(nursery, wrapNode(n)) + nursery = append(nursery, n) } tab.nursery = nursery return nil @@ -255,9 +255,9 @@ func (tab *Table) findnodeByID(target enode.ID, nresults int, preferLive bool) * liveNodes := &nodesByDistance{target: target} for _, b := range &tab.buckets { for _, n := range b.entries { - nodes.push(n, nresults) + nodes.push(n.Node, nresults) if preferLive && n.isValidatedLive { - liveNodes.push(n, nresults) + liveNodes.push(n.Node, nresults) } } } @@ -309,8 +309,8 @@ func (tab *Table) len() (n int) { // list. // // The caller must not hold tab.mutex. -func (tab *Table) addFoundNode(n *node) bool { - op := addNodeOp{node: n, isInbound: false} +func (tab *Table) addFoundNode(n *enode.Node, forceSetLive bool) bool { + op := addNodeOp{node: n, isInbound: false, forceSetLive: forceSetLive} select { case tab.addNodeCh <- op: return <-tab.addNodeHandled @@ -327,7 +327,7 @@ func (tab *Table) addFoundNode(n *node) bool { // repeatedly. // // The caller must not hold tab.mutex. -func (tab *Table) addInboundNode(n *node) bool { +func (tab *Table) addInboundNode(n *enode.Node) bool { op := addNodeOp{node: n, isInbound: true} select { case tab.addNodeCh <- op: @@ -337,7 +337,7 @@ func (tab *Table) addInboundNode(n *node) bool { } } -func (tab *Table) trackRequest(n *node, success bool, foundNodes []*node) { +func (tab *Table) trackRequest(n *enode.Node, success bool, foundNodes []*enode.Node) { op := trackRequestOp{n, foundNodes, success} select { case tab.trackRequestCh <- op: @@ -443,13 +443,14 @@ func (tab *Table) doRefresh(done chan struct{}) { } func (tab *Table) loadSeedNodes() { - seeds := wrapNodes(tab.db.QuerySeeds(seedCount, seedMaxAge)) + seeds := tab.db.QuerySeeds(seedCount, seedMaxAge) seeds = append(seeds, tab.nursery...) for i := range seeds { seed := seeds[i] if tab.log.Enabled(context.Background(), log.LevelTrace) { age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) - tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age) + addr, _ := seed.UDPEndpoint() + tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age) } tab.handleAddNode(addNodeOp{node: seed, isInbound: false}) } @@ -513,7 +514,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } b := tab.bucket(req.node.ID()) - n, _ := tab.bumpInBucket(b, req.node.Node, req.isInbound) + n, _ := tab.bumpInBucket(b, req.node, req.isInbound) if n != nil { // Already in bucket. return false @@ -529,15 +530,20 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } // Add to bucket. - b.entries = append(b.entries, req.node) - b.replacements = deleteNode(b.replacements, req.node) - tab.nodeAdded(b, req.node) + wn := &tableNode{Node: req.node} + if req.forceSetLive { + wn.livenessChecks = 1 + wn.isValidatedLive = true + } + b.entries = append(b.entries, wn) + b.replacements = deleteNode(b.replacements, wn.ID()) + tab.nodeAdded(b, wn) return true } // addReplacement adds n to the replacement cache of bucket b. -func (tab *Table) addReplacement(b *bucket, n *node) { - if contains(b.replacements, n.ID()) { +func (tab *Table) addReplacement(b *bucket, n *enode.Node) { + if containsID(b.replacements, n.ID()) { // TODO: update ENR return } @@ -545,15 +551,15 @@ func (tab *Table) addReplacement(b *bucket, n *node) { return } - n.addedToTable = time.Now() - var removed *node - b.replacements, removed = pushNode(b.replacements, n, maxReplacements) + wn := &tableNode{Node: n, addedToTable: time.Now()} + var removed *tableNode + b.replacements, removed = pushNode(b.replacements, wn, maxReplacements) if removed != nil { tab.removeIP(b, removed.IP()) } } -func (tab *Table) nodeAdded(b *bucket, n *node) { +func (tab *Table) nodeAdded(b *bucket, n *tableNode) { if n.addedToTable == (time.Time{}) { n.addedToTable = time.Now() } @@ -567,7 +573,7 @@ func (tab *Table) nodeAdded(b *bucket, n *node) { } } -func (tab *Table) nodeRemoved(b *bucket, n *node) { +func (tab *Table) nodeRemoved(b *bucket, n *tableNode) { tab.revalidation.nodeRemoved(n) if tab.nodeRemovedHook != nil { tab.nodeRemovedHook(b, n) @@ -579,8 +585,8 @@ func (tab *Table) nodeRemoved(b *bucket, n *node) { // deleteInBucket removes node n from the table. // If there are replacement nodes in the bucket, the node is replaced. -func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { - index := slices.IndexFunc(b.entries, func(e *node) bool { return e.ID() == id }) +func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *tableNode { + index := slices.IndexFunc(b.entries, func(e *tableNode) bool { return e.ID() == id }) if index == -1 { // Entry has been removed already. return nil @@ -608,8 +614,8 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node { // bumpInBucket updates a node record if it exists in the bucket. // The second return value reports whether the node's endpoint (IP/port) was updated. -func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) (n *node, endpointChanged bool) { - i := slices.IndexFunc(b.entries, func(elem *node) bool { +func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) (n *tableNode, endpointChanged bool) { + i := slices.IndexFunc(b.entries, func(elem *tableNode) bool { return elem.ID() == newRecord.ID() }) if i == -1 { @@ -672,21 +678,12 @@ func (tab *Table) handleTrackRequest(op trackRequestOp) { // Add found nodes. for _, n := range op.foundNodes { - tab.handleAddNode(addNodeOp{n, false}) + tab.handleAddNode(addNodeOp{n, false, false}) } } -func contains(ns []*node, id enode.ID) bool { - for _, n := range ns { - if n.ID() == id { - return true - } - } - return false -} - // pushNode adds n to the front of list, keeping at most max items. -func pushNode(list []*node, n *node, max int) ([]*node, *node) { +func pushNode(list []*tableNode, n *tableNode, max int) ([]*tableNode, *tableNode) { if len(list) < max { list = append(list, nil) } @@ -695,37 +692,3 @@ func pushNode(list []*node, n *node, max int) ([]*node, *node) { list[0] = n return list, removed } - -// deleteNode removes n from list. -func deleteNode(list []*node, n *node) []*node { - for i := range list { - if list[i].ID() == n.ID() { - return append(list[:i], list[i+1:]...) - } - } - return list -} - -// nodesByDistance is a list of nodes, ordered by distance to target. -type nodesByDistance struct { - entries []*node - target enode.ID -} - -// push adds the given node to the list, keeping the total size below maxElems. -func (h *nodesByDistance) push(n *node, maxElems int) { - ix := sort.Search(len(h.entries), func(i int) bool { - return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0 - }) - - end := len(h.entries) - if len(h.entries) < maxElems { - h.entries = append(h.entries, n) - } - if ix < end { - // Slide existing entries down to make room. - // This will overwrite the entry we just appended. - copy(h.entries[ix+1:], h.entries[ix:]) - h.entries[ix] = n - } -} diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index 5d185aa8b4..f2ea8b34fa 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -39,7 +39,7 @@ type tableRevalidation struct { } type revalidationResponse struct { - n *node + n *tableNode newRecord *enode.Node didRespond bool } @@ -55,12 +55,12 @@ func (tr *tableRevalidation) init(cfg *Config) { } // nodeAdded is called when the table receives a new node. -func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) { +func (tr *tableRevalidation) nodeAdded(tab *Table, n *tableNode) { tr.fast.push(n, tab.cfg.Clock.Now(), &tab.rand) } // nodeRemoved is called when a node was removed from the table. -func (tr *tableRevalidation) nodeRemoved(n *node) { +func (tr *tableRevalidation) nodeRemoved(n *tableNode) { if n.revalList == nil { panic(fmt.Errorf("removed node %v has nil revalList", n.ID())) } @@ -68,7 +68,7 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { } // nodeEndpointChanged is called when a change in IP or port is detected. -func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *node) { +func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *tableNode) { n.isValidatedLive = false tr.moveToList(&tr.fast, n, tab.cfg.Clock.Now(), &tab.rand) } @@ -90,7 +90,7 @@ func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mcloc } // startRequest spawns a revalidation request for node n. -func (tr *tableRevalidation) startRequest(tab *Table, n *node) { +func (tr *tableRevalidation) startRequest(tab *Table, n *tableNode) { if _, ok := tr.activeReq[n.ID()]; ok { panic(fmt.Errorf("duplicate startRequest (node %v)", n.ID())) } @@ -180,7 +180,7 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons } // moveToList ensures n is in the 'dest' list. -func (tr *tableRevalidation) moveToList(dest *revalidationList, n *node, now mclock.AbsTime, rand randomSource) { +func (tr *tableRevalidation) moveToList(dest *revalidationList, n *tableNode, now mclock.AbsTime, rand randomSource) { if n.revalList == dest { return } @@ -192,14 +192,14 @@ func (tr *tableRevalidation) moveToList(dest *revalidationList, n *node, now mcl // revalidationList holds a list nodes and the next revalidation time. type revalidationList struct { - nodes []*node + nodes []*tableNode nextTime mclock.AbsTime interval time.Duration name string } // 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{}) *node { +func (list *revalidationList) get(now mclock.AbsTime, rand randomSource, exclude map[enode.ID]struct{}) *tableNode { if now < list.nextTime || len(list.nodes) == 0 { return nil } @@ -217,7 +217,7 @@ func (list *revalidationList) schedule(now mclock.AbsTime, rand randomSource) { list.nextTime = now.Add(time.Duration(rand.Int63n(int64(list.interval)))) } -func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSource) { +func (list *revalidationList) push(n *tableNode, now mclock.AbsTime, rand randomSource) { list.nodes = append(list.nodes, n) if list.nextTime == never { list.schedule(now, rand) @@ -225,7 +225,7 @@ func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSourc n.revalList = list } -func (list *revalidationList) remove(n *node) { +func (list *revalidationList) remove(n *tableNode) { i := slices.Index(list.nodes, n) if i == -1 { panic(fmt.Errorf("node %v not found in list", n.ID())) @@ -238,7 +238,7 @@ func (list *revalidationList) remove(n *node) { } func (list *revalidationList) contains(id enode.ID) bool { - return slices.ContainsFunc(list.nodes, func(n *node) bool { + return slices.ContainsFunc(list.nodes, func(n *tableNode) bool { return n.ID() == id }) } diff --git a/p2p/discover/table_reval_test.go b/p2p/discover/table_reval_test.go index d168767e0d..3605443934 100644 --- a/p2p/discover/table_reval_test.go +++ b/p2p/discover/table_reval_test.go @@ -110,10 +110,10 @@ func TestRevalidation_endpointUpdate(t *testing.T) { } tr.handleResponse(tab, resp) - if !tr.fast.contains(node.ID()) { + if tr.fast.nodes[0].ID() != node.ID() { t.Fatal("node not contained in fast revalidation list") } - if node.isValidatedLive { + if tr.fast.nodes[0].isValidatedLive { t.Fatal("node is marked live after endpoint change") } } diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index b0be2a94c5..30e7d56f4a 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -22,6 +22,7 @@ import ( "math/rand" "net" "reflect" + "slices" "testing" "testing/quick" "time" @@ -64,7 +65,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding // Fill up the sender's bucket. replacementNodeKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") - replacementNode := wrapNode(enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99)) + replacementNode := enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99) last := fillBucket(tab, replacementNode.ID()) tab.mutex.Lock() nodeEvents := newNodeEventRecorder(128) @@ -78,7 +79,7 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding transport.dead[replacementNode.ID()] = !newNodeIsResponding // Add replacement node to table. - tab.addFoundNode(replacementNode) + tab.addFoundNode(replacementNode, false) t.Log("last:", last.ID()) t.Log("replacement:", replacementNode.ID()) @@ -115,11 +116,11 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding if l := len(bucket.entries); l != wantSize { t.Errorf("wrong bucket size after revalidation: got %d, want %d", l, wantSize) } - if ok := contains(bucket.entries, last.ID()); ok != lastInBucketIsResponding { + if ok := containsID(bucket.entries, last.ID()); ok != lastInBucketIsResponding { t.Errorf("revalidated node found: %t, want: %t", ok, lastInBucketIsResponding) } wantNewEntry := newNodeIsResponding && !lastInBucketIsResponding - if ok := contains(bucket.entries, replacementNode.ID()); ok != wantNewEntry { + if ok := containsID(bucket.entries, replacementNode.ID()); ok != wantNewEntry { t.Errorf("replacement node found: %t, want: %t", ok, wantNewEntry) } } @@ -153,7 +154,7 @@ func TestTable_IPLimit(t *testing.T) { for i := 0; i < tableIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), i, net.IP{172, 0, 1, byte(i)}) - tab.addFoundNode(n) + tab.addFoundNode(n, false) } if tab.len() > tableIPLimit { t.Errorf("too many nodes in table") @@ -171,7 +172,7 @@ func TestTable_BucketIPLimit(t *testing.T) { d := 3 for i := 0; i < bucketIPLimit+1; i++ { n := nodeAtDistance(tab.self().ID(), d, net.IP{172, 0, 1, byte(i)}) - tab.addFoundNode(n) + tab.addFoundNode(n, false) } if tab.len() > bucketIPLimit { t.Errorf("too many nodes in table") @@ -232,7 +233,7 @@ func TestTable_findnodeByID(t *testing.T) { // check that the result nodes have minimum distance to target. for _, b := range tab.buckets { for _, n := range b.entries { - if contains(result, n.ID()) { + if containsID(result, n.ID()) { continue // don't run the check below for nodes in result } farthestResult := result[len(result)-1].ID() @@ -255,7 +256,7 @@ func TestTable_findnodeByID(t *testing.T) { type closeTest struct { Self enode.ID Target enode.ID - All []*node + All []*enode.Node N int } @@ -268,8 +269,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { for _, id := range gen([]enode.ID{}, rand).([]enode.ID) { r := new(enr.Record) r.Set(enr.IP(genIP(rand))) - n := wrapNode(enode.SignNull(r, id)) - n.livenessChecks = 1 + n := enode.SignNull(r, id) t.All = append(t.All, n) } return reflect.ValueOf(t) @@ -284,16 +284,16 @@ func TestTable_addInboundNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addFoundNode(n1) - tab.addFoundNode(n2) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) + tab.addFoundNode(n1, false) + tab.addFoundNode(n2, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2}) // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) n2v2 := enode.SignNull(newrec, n2.ID()) - tab.addInboundNode(wrapNode(n2v2)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + tab.addInboundNode(n2v2) + checkBucketContent(t, tab, []*enode.Node{n1, n2v2}) // Try updating n2 without sequence number change. The update is accepted // because it's inbound. @@ -301,8 +301,8 @@ func TestTable_addInboundNode(t *testing.T) { newrec.Set(enr.IP{100, 100, 100, 100}) newrec.SetSeq(n2.Seq()) n2v3 := enode.SignNull(newrec, n2.ID()) - tab.addInboundNode(wrapNode(n2v3)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v3}) + tab.addInboundNode(n2v3) + checkBucketContent(t, tab, []*enode.Node{n1, n2v3}) } func TestTable_addFoundNode(t *testing.T) { @@ -314,16 +314,16 @@ func TestTable_addFoundNode(t *testing.T) { // Insert two nodes. n1 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 1}) n2 := nodeAtDistance(tab.self().ID(), 256, net.IP{88, 77, 66, 2}) - tab.addFoundNode(n1) - tab.addFoundNode(n2) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2.Node}) + tab.addFoundNode(n1, false) + tab.addFoundNode(n2, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2}) // Add a changed version of n2. The bucket should be updated. newrec := n2.Record() newrec.Set(enr.IP{99, 99, 99, 99}) n2v2 := enode.SignNull(newrec, n2.ID()) - tab.addFoundNode(wrapNode(n2v2)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + tab.addFoundNode(n2v2, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2v2}) // Try updating n2 without a sequence number change. // The update should not be accepted. @@ -331,8 +331,8 @@ func TestTable_addFoundNode(t *testing.T) { newrec.Set(enr.IP{100, 100, 100, 100}) newrec.SetSeq(n2.Seq()) n2v3 := enode.SignNull(newrec, n2.ID()) - tab.addFoundNode(wrapNode(n2v3)) - checkBucketContent(t, tab, []*enode.Node{n1.Node, n2v2}) + tab.addFoundNode(n2v3, false) + checkBucketContent(t, tab, []*enode.Node{n1, n2v2}) } // This test checks that discv4 nodes can update their own endpoint via PING. @@ -345,13 +345,13 @@ func TestTable_addInboundNodeUpdateV4Accept(t *testing.T) { // Add a v4 node. key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) - tab.addInboundNode(wrapNode(n1)) + tab.addInboundNode(n1) checkBucketContent(t, tab, []*enode.Node{n1}) // Add an updated version with changed IP. // The update will be accepted because it is inbound. n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) - tab.addInboundNode(wrapNode(n1v2)) + tab.addInboundNode(n1v2) checkBucketContent(t, tab, []*enode.Node{n1v2}) } @@ -366,13 +366,13 @@ func TestTable_addFoundNodeV4UpdateReject(t *testing.T) { // Add a v4 node. key, _ := crypto.HexToECDSA("dd3757a8075e88d0f2b1431e7d3c5b1562e1c0aab9643707e8cbfcc8dae5cfe3") n1 := enode.NewV4(&key.PublicKey, net.IP{88, 77, 66, 1}, 9000, 9000) - tab.addFoundNode(wrapNode(n1)) + tab.addFoundNode(n1, false) checkBucketContent(t, tab, []*enode.Node{n1}) // Add an updated version with changed IP. // The update won't be accepted because it isn't inbound. n1v2 := enode.NewV4(&key.PublicKey, net.IP{99, 99, 99, 99}, 9000, 9000) - tab.addFoundNode(wrapNode(n1v2)) + tab.addFoundNode(n1v2, false) checkBucketContent(t, tab, []*enode.Node{n1}) } @@ -413,8 +413,8 @@ func TestTable_revalidateSyncRecord(t *testing.T) { var r enr.Record r.Set(enr.IP(net.IP{127, 0, 0, 1})) id := enode.ID{1} - n1 := wrapNode(enode.SignNull(&r, id)) - tab.addFoundNode(n1) + n1 := enode.SignNull(&r, id) + tab.addFoundNode(n1, false) // Update the node record. r.Set(enr.WithEntry("foo", "bar")) @@ -437,7 +437,7 @@ func TestNodesPush(t *testing.T) { n1 := nodeAtDistance(target, 255, intIP(1)) n2 := nodeAtDistance(target, 254, intIP(2)) n3 := nodeAtDistance(target, 253, intIP(3)) - perm := [][]*node{ + perm := [][]*enode.Node{ {n3, n2, n1}, {n3, n1, n2}, {n2, n3, n1}, @@ -452,7 +452,7 @@ func TestNodesPush(t *testing.T) { for _, n := range nodes { list.push(n, 3) } - if !slicesEqual(list.entries, perm[0], nodeIDEqual) { + if !slices.EqualFunc(list.entries, perm[0], nodeIDEqual) { t.Fatal("not equal") } } @@ -463,28 +463,16 @@ func TestNodesPush(t *testing.T) { for _, n := range nodes { list.push(n, 2) } - if !slicesEqual(list.entries, perm[0][:2], nodeIDEqual) { + if !slices.EqualFunc(list.entries, perm[0][:2], nodeIDEqual) { t.Fatal("not equal") } } } -func nodeIDEqual(n1, n2 *node) bool { +func nodeIDEqual[N nodeType](n1, n2 N) bool { return n1.ID() == n2.ID() } -func slicesEqual[T any](s1, s2 []T, check func(e1, e2 T) bool) bool { - if len(s1) != len(s2) { - return false - } - for i := range s1 { - if !check(s1[i], s2[i]) { - return false - } - } - return true -} - // gen wraps quick.Value so it's easier to use. // it generates a random value of the given value's type. func gen(typ interface{}, rand *rand.Rand) interface{} { diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 59045bf2a8..997ac37799 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -56,18 +56,18 @@ func newInactiveTestTable(t transport, cfg Config) (*Table, *enode.DB) { } // nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld. -func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node { +func nodeAtDistance(base enode.ID, ld int, ip net.IP) *enode.Node { var r enr.Record r.Set(enr.IP(ip)) r.Set(enr.UDP(30303)) - return wrapNode(enode.SignNull(&r, idAtDistance(base, ld))) + return enode.SignNull(&r, idAtDistance(base, ld)) } // nodesAtDistance creates n nodes for which enode.LogDist(base, node.ID()) == ld. func nodesAtDistance(base enode.ID, ld int, n int) []*enode.Node { results := make([]*enode.Node, n) for i := range results { - results[i] = unwrapNode(nodeAtDistance(base, ld, intIP(i))) + results[i] = nodeAtDistance(base, ld, intIP(i)) } return results } @@ -105,12 +105,12 @@ func intIP(i int) net.IP { } // fillBucket inserts nodes into the given bucket until it is full. -func fillBucket(tab *Table, id enode.ID) (last *node) { +func fillBucket(tab *Table, id enode.ID) (last *tableNode) { ld := enode.LogDist(tab.self().ID(), id) b := tab.bucket(id) for len(b.entries) < bucketSize { node := nodeAtDistance(tab.self().ID(), ld, intIP(ld)) - if !tab.addFoundNode(node) { + if !tab.addFoundNode(node, false) { panic("node not added") } } @@ -119,13 +119,9 @@ func fillBucket(tab *Table, id enode.ID) (last *node) { // fillTable adds nodes the table to the end of their corresponding bucket // if the bucket is not full. The caller must not hold tab.mutex. -func fillTable(tab *Table, nodes []*node, setLive bool) { +func fillTable(tab *Table, nodes []*enode.Node, setLive bool) { for _, n := range nodes { - if setLive { - n.livenessChecks = 1 - n.isValidatedLive = true - } - tab.addFoundNode(n) + tab.addFoundNode(n, setLive) } } @@ -219,7 +215,7 @@ func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) { return t.records[n.ID()], nil } -func hasDuplicates(slice []*node) bool { +func hasDuplicates(slice []*enode.Node) bool { seen := make(map[enode.ID]bool, len(slice)) for i, e := range slice { if e == nil { @@ -261,14 +257,14 @@ func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool { return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP()) } -func sortByID(nodes []*enode.Node) { - slices.SortFunc(nodes, func(a, b *enode.Node) int { +func sortByID[N nodeType](nodes []N) { + slices.SortFunc(nodes, func(a, b N) int { return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) }) } -func sortedByDistanceTo(distbase enode.ID, slice []*node) bool { - return slices.IsSortedFunc(slice, func(a, b *node) int { +func sortedByDistanceTo(distbase enode.ID, slice []*enode.Node) bool { + return slices.IsSortedFunc(slice, func(a, b *enode.Node) int { return enode.DistCmp(distbase, a.ID(), b.ID()) }) } @@ -304,7 +300,7 @@ type nodeEventRecorder struct { } type recordedNodeEvent struct { - node *node + node *tableNode added bool } @@ -314,7 +310,7 @@ func newNodeEventRecorder(buffer int) *nodeEventRecorder { } } -func (set *nodeEventRecorder) nodeAdded(b *bucket, n *node) { +func (set *nodeEventRecorder) nodeAdded(b *bucket, n *tableNode) { select { case set.evc <- recordedNodeEvent{n, true}: default: @@ -322,7 +318,7 @@ func (set *nodeEventRecorder) nodeAdded(b *bucket, n *node) { } } -func (set *nodeEventRecorder) nodeRemoved(b *bucket, n *node) { +func (set *nodeEventRecorder) nodeRemoved(b *bucket, n *tableNode) { select { case set.evc <- recordedNodeEvent{n, false}: default: diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index 5682f262be..bc9475a8b3 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -19,7 +19,7 @@ package discover import ( "crypto/ecdsa" "fmt" - "net" + "net/netip" "slices" "testing" @@ -40,7 +40,7 @@ func TestUDPv4_Lookup(t *testing.T) { } // Seed table with initial node. - fillTable(test.table, []*node{wrapNode(lookupTestnet.node(256, 0))}, true) + fillTable(test.table, []*enode.Node{lookupTestnet.node(256, 0)}, true) // Start the lookup. resultC := make(chan []*enode.Node, 1) @@ -70,9 +70,9 @@ func TestUDPv4_LookupIterator(t *testing.T) { defer test.close() // Seed table with initial nodes. - bootnodes := make([]*node, len(lookupTestnet.dists[256])) + bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256])) for i := range lookupTestnet.dists[256] { - bootnodes[i] = wrapNode(lookupTestnet.node(256, i)) + bootnodes[i] = lookupTestnet.node(256, i) } fillTable(test.table, bootnodes, true) go serveTestnet(test, lookupTestnet) @@ -105,9 +105,9 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) { defer test.close() // Seed table with initial nodes. - bootnodes := make([]*node, len(lookupTestnet.dists[256])) + bootnodes := make([]*enode.Node, len(lookupTestnet.dists[256])) for i := range lookupTestnet.dists[256] { - bootnodes[i] = wrapNode(lookupTestnet.node(256, i)) + bootnodes[i] = lookupTestnet.node(256, i) } fillTable(test.table, bootnodes, true) go serveTestnet(test, lookupTestnet) @@ -136,7 +136,7 @@ func TestUDPv4_LookupIteratorClose(t *testing.T) { func serveTestnet(test *udpTest, testnet *preminedTestnet) { for done := false; !done; { - done = test.waitPacketOut(func(p v4wire.Packet, to *net.UDPAddr, hash []byte) { + done = test.waitPacketOut(func(p v4wire.Packet, to netip.AddrPort, hash []byte) { n, key := testnet.nodeByAddr(to) switch p.(type) { case *v4wire.Ping: @@ -158,10 +158,10 @@ func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node for _, e := range results { t.Logf(" ld=%d, %x", enode.LogDist(tn.target.id(), e.ID()), e.ID().Bytes()) } - if hasDuplicates(wrapNodes(results)) { + if hasDuplicates(results) { t.Errorf("result set contains duplicate entries") } - if !sortedByDistanceTo(tn.target.id(), wrapNodes(results)) { + if !sortedByDistanceTo(tn.target.id(), results) { t.Errorf("result set not sorted by distance to target") } wantNodes := tn.closest(len(results)) @@ -264,9 +264,10 @@ func (tn *preminedTestnet) node(dist, index int) *enode.Node { return n } -func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.PrivateKey) { - dist := int(addr.IP[1])<<8 + int(addr.IP[2]) - index := int(addr.IP[3]) +func (tn *preminedTestnet) nodeByAddr(addr netip.AddrPort) (*enode.Node, *ecdsa.PrivateKey) { + ip := addr.Addr().As4() + dist := int(ip[1])<<8 + int(ip[2]) + index := int(ip[3]) key := tn.dists[dist][index] return tn.node(dist, index), key } @@ -274,7 +275,7 @@ func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *ecdsa.Pr func (tn *preminedTestnet) nodesAtDistance(dist int) []v4wire.Node { result := make([]v4wire.Node, len(tn.dists[dist])) for i := range result { - result[i] = nodeToRPC(wrapNode(tn.node(dist, i))) + result[i] = nodeToRPC(tn.node(dist, i)) } return result } diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index be6058ec50..3880ca34a7 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -26,6 +26,7 @@ import ( "fmt" "io" "net" + "net/netip" "sync" "time" @@ -45,6 +46,7 @@ var ( errClockWarp = errors.New("reply deadline too far in the future") errClosed = errors.New("socket closed") errLowPort = errors.New("low port") + errNoUDPEndpoint = errors.New("node has no UDP endpoint") ) const ( @@ -93,7 +95,7 @@ type UDPv4 struct { type replyMatcher struct { // these fields must match in the reply. from enode.ID - ip net.IP + ip netip.Addr ptype byte // time when the request must complete @@ -119,7 +121,7 @@ type replyMatchFunc func(v4wire.Packet) (matched bool, requestDone bool) // reply is a reply packet from a certain node. type reply struct { from enode.ID - ip net.IP + ip netip.Addr data v4wire.Packet // loop indicates whether there was // a matching request by sending on this channel. @@ -201,9 +203,12 @@ func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { } func (t *UDPv4) ourEndpoint() v4wire.Endpoint { - n := t.Self() - a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} - return v4wire.NewEndpoint(a, uint16(n.TCP())) + node := t.Self() + addr, ok := node.UDPEndpoint() + if !ok { + return v4wire.Endpoint{} + } + return v4wire.NewEndpoint(addr, uint16(node.TCP())) } // Ping sends a ping message to the given node. @@ -214,7 +219,11 @@ func (t *UDPv4) Ping(n *enode.Node) error { // ping sends a ping message to the given node and waits for a reply. func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { - rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil) + addr, ok := n.UDPEndpoint() + if !ok { + return 0, errNoUDPEndpoint + } + rm := t.sendPing(n.ID(), addr, nil) if err = <-rm.errc; err == nil { seq = rm.reply.(*v4wire.Pong).ENRSeq } @@ -223,7 +232,7 @@ func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { // sendPing sends a ping message to the given node and invokes the callback // when the reply arrives. -func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *replyMatcher { +func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) *replyMatcher { req := t.makePing(toaddr) packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { @@ -233,7 +242,7 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *r } // Add a matcher for the reply to the pending reply queue. Pongs are matched if they // reference the ping we're about to send. - rm := t.pending(toid, toaddr.IP, v4wire.PongPacket, func(p v4wire.Packet) (matched bool, requestDone bool) { + rm := t.pending(toid, toaddr.Addr(), v4wire.PongPacket, func(p v4wire.Packet) (matched bool, requestDone bool) { matched = bytes.Equal(p.(*v4wire.Pong).ReplyTok, hash) if matched && callback != nil { callback() @@ -241,12 +250,13 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *r return matched, matched }) // Send the packet. - t.localNode.UDPContact(toaddr) + toUDPAddr := &net.UDPAddr{IP: toaddr.Addr().AsSlice()} + t.localNode.UDPContact(toUDPAddr) t.write(toaddr, toid, req.Name(), packet) return rm } -func (t *UDPv4) makePing(toaddr *net.UDPAddr) *v4wire.Ping { +func (t *UDPv4) makePing(toaddr netip.AddrPort) *v4wire.Ping { return &v4wire.Ping{ Version: 4, From: t.ourEndpoint(), @@ -290,35 +300,39 @@ func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup { func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup { target := enode.ID(crypto.Keccak256Hash(targetKey[:])) ekey := v4wire.Pubkey(targetKey) - it := newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { - return t.findnode(n.ID(), n.addr(), ekey) + it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { + addr, ok := n.UDPEndpoint() + if !ok { + return nil, errNoUDPEndpoint + } + return t.findnode(n.ID(), addr, ekey) }) return it } // findnode sends a findnode request to the given node and waits until // the node has sent up to k neighbors. -func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubkey) ([]*node, error) { - t.ensureBond(toid, toaddr) +func (t *UDPv4) findnode(toid enode.ID, toAddrPort netip.AddrPort, target v4wire.Pubkey) ([]*enode.Node, error) { + t.ensureBond(toid, toAddrPort) // Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is // active until enough nodes have been received. - nodes := make([]*node, 0, bucketSize) + nodes := make([]*enode.Node, 0, bucketSize) nreceived := 0 - rm := t.pending(toid, toaddr.IP, v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) { + rm := t.pending(toid, toAddrPort.Addr(), v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) { reply := r.(*v4wire.Neighbors) for _, rn := range reply.Nodes { nreceived++ - n, err := t.nodeFromRPC(toaddr, rn) + n, err := t.nodeFromRPC(toAddrPort, rn) if err != nil { - t.log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err) + t.log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toAddrPort, "err", err) continue } nodes = append(nodes, n) } return true, nreceived >= bucketSize }) - t.send(toaddr, toid, &v4wire.Findnode{ + t.send(toAddrPort, toid, &v4wire.Findnode{ Target: target, Expiration: uint64(time.Now().Add(expiration).Unix()), }) @@ -336,7 +350,7 @@ func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubke // RequestENR sends ENRRequest to the given node and waits for a response. func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { - addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} + addr, _ := n.UDPEndpoint() t.ensureBond(n.ID(), addr) req := &v4wire.ENRRequest{ @@ -349,7 +363,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { // Add a matcher for the reply to the pending reply queue. Responses are matched if // they reference the request we're about to send. - rm := t.pending(n.ID(), addr.IP, v4wire.ENRResponsePacket, func(r v4wire.Packet) (matched bool, requestDone bool) { + rm := t.pending(n.ID(), addr.Addr(), v4wire.ENRResponsePacket, func(r v4wire.Packet) (matched bool, requestDone bool) { matched = bytes.Equal(r.(*v4wire.ENRResponse).ReplyTok, hash) return matched, matched }) @@ -369,7 +383,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { if respN.Seq() < n.Seq() { return n, nil // response record is older } - if err := netutil.CheckRelayIP(addr.IP, respN.IP()); err != nil { + if err := netutil.CheckRelayIP(addr.Addr().AsSlice(), respN.IP()); err != nil { return nil, fmt.Errorf("invalid IP in response record: %v", err) } return respN, nil @@ -381,7 +395,7 @@ func (t *UDPv4) TableBuckets() [][]BucketNode { // pending adds a reply matcher to the pending reply queue. // see the documentation of type replyMatcher for a detailed explanation. -func (t *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) *replyMatcher { +func (t *UDPv4) pending(id enode.ID, ip netip.Addr, ptype byte, callback replyMatchFunc) *replyMatcher { ch := make(chan error, 1) p := &replyMatcher{from: id, ip: ip, ptype: ptype, callback: callback, errc: ch} select { @@ -395,7 +409,7 @@ func (t *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchF // handleReply dispatches a reply packet, invoking reply matchers. It returns // whether any matcher considered the packet acceptable. -func (t *UDPv4) handleReply(from enode.ID, fromIP net.IP, req v4wire.Packet) bool { +func (t *UDPv4) handleReply(from enode.ID, fromIP netip.Addr, req v4wire.Packet) bool { matched := make(chan bool, 1) select { case t.gotreply <- reply{from, fromIP, req, matched}: @@ -461,7 +475,7 @@ func (t *UDPv4) loop() { var matched bool // whether any replyMatcher considered the reply acceptable. for el := plist.Front(); el != nil; el = el.Next() { p := el.Value.(*replyMatcher) - if p.from == r.from && p.ptype == r.data.Kind() && p.ip.Equal(r.ip) { + if p.from == r.from && p.ptype == r.data.Kind() && p.ip == r.ip { ok, requestDone := p.callback(r.data) matched = matched || ok p.reply = r.data @@ -500,7 +514,7 @@ func (t *UDPv4) loop() { } } -func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]byte, error) { +func (t *UDPv4) send(toaddr netip.AddrPort, toid enode.ID, req v4wire.Packet) ([]byte, error) { packet, hash, err := v4wire.Encode(t.priv, req) if err != nil { return hash, err @@ -508,8 +522,8 @@ func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]b return hash, t.write(toaddr, toid, req.Name(), packet) } -func (t *UDPv4) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error { - _, err := t.conn.WriteToUDP(packet, toaddr) +func (t *UDPv4) write(toaddr netip.AddrPort, toid enode.ID, what string, packet []byte) error { + _, err := t.conn.WriteToUDPAddrPort(packet, toaddr) t.log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err) return err } @@ -523,7 +537,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { buf := make([]byte, maxPacketSize) for { - nbytes, from, err := t.conn.ReadFromUDP(buf) + nbytes, from, err := t.conn.ReadFromUDPAddrPort(buf) if netutil.IsTemporaryError(err) { // Ignore temporary read errors. t.log.Debug("Temporary UDP read error", "err", err) @@ -544,7 +558,7 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { } } -func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { +func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { rawpacket, fromKey, hash, err := v4wire.Decode(buf) if err != nil { t.log.Debug("Bad discv4 packet", "addr", from, "err", err) @@ -563,15 +577,16 @@ func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { } // checkBond checks if the given node has a recent enough endpoint proof. -func (t *UDPv4) checkBond(id enode.ID, ip net.IP) bool { - return time.Since(t.db.LastPongReceived(id, ip)) < bondExpiration +func (t *UDPv4) checkBond(id enode.ID, ip netip.AddrPort) bool { + return time.Since(t.db.LastPongReceived(id, ip.Addr().AsSlice())) < bondExpiration } // ensureBond solicits a ping from a node if we haven't seen a ping from it for a while. // This ensures there is a valid endpoint proof on the remote end. -func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { - tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration - if tooOld || t.db.FindFails(toid, toaddr.IP) > maxFindnodeFailures { +func (t *UDPv4) ensureBond(toid enode.ID, toaddr netip.AddrPort) { + ip := toaddr.Addr().AsSlice() + tooOld := time.Since(t.db.LastPingReceived(toid, ip)) > bondExpiration + if tooOld || t.db.FindFails(toid, ip) > maxFindnodeFailures { rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -579,11 +594,11 @@ func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { } } -func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) { +func (t *UDPv4) nodeFromRPC(sender netip.AddrPort, rn v4wire.Node) (*enode.Node, error) { if rn.UDP <= 1024 { return nil, errLowPort } - if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { + if err := netutil.CheckRelayIP(sender.Addr().AsSlice(), rn.IP); err != nil { return nil, err } if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { @@ -593,12 +608,12 @@ func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) if err != nil { return nil, err } - n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP))) + n := enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP)) err = n.ValidateComplete() return n, err } -func nodeToRPC(n *node) v4wire.Node { +func nodeToRPC(n *enode.Node) v4wire.Node { var key ecdsa.PublicKey var ekey v4wire.Pubkey if err := n.Load((*enode.Secp256k1)(&key)); err == nil { @@ -637,14 +652,14 @@ type packetHandlerV4 struct { senderKey *ecdsa.PublicKey // used for ping // preverify checks whether the packet is valid and should be handled at all. - preverify func(p *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error + preverify func(p *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error // handle handles the packet. - handle func(req *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) + handle func(req *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) } // PING/v4 -func (t *UDPv4) verifyPing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyPing(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Ping) if v4wire.Expired(req.Expiration) { @@ -658,7 +673,7 @@ func (t *UDPv4) verifyPing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I return nil } -func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { +func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) { req := h.Packet.(*v4wire.Ping) // Reply. @@ -670,8 +685,9 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I }) // Ping back if our last pong on file is too far in the past. - n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) - if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { + fromIP := from.Addr().AsSlice() + n := enode.NewV4(h.senderKey, fromIP, int(req.From.TCP), int(from.Port())) + if time.Since(t.db.LastPongReceived(n.ID(), fromIP)) > bondExpiration { t.sendPing(fromID, from, func() { t.tab.addInboundNode(n) }) @@ -680,35 +696,40 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.I } // Update node database and endpoint predictor. - t.db.UpdateLastPingReceived(n.ID(), from.IP, time.Now()) - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) + t.db.UpdateLastPingReceived(n.ID(), fromIP, time.Now()) + fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} + toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} + t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) } // PONG/v4 -func (t *UDPv4) verifyPong(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Pong) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.handleReply(fromID, from.IP, req) { + if !t.handleReply(fromID, from.Addr(), req) { return errUnsolicitedReply } - t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) - t.db.UpdateLastPongReceived(fromID, from.IP, time.Now()) + fromIP := from.Addr().AsSlice() + fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} + toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} + t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) + t.db.UpdateLastPongReceived(fromID, fromIP, time.Now()) return nil } // FINDNODE/v4 -func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Findnode) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { + if !t.checkBond(fromID, from) { // No endpoint proof pong exists, we don't process the packet. This prevents an // attack vector where the discovery protocol could be used to amplify traffic in a // DDOS attack. A malicious actor would send a findnode request with the IP address @@ -720,7 +741,7 @@ func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno return nil } -func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { +func (t *UDPv4) handleFindnode(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) { req := h.Packet.(*v4wire.Findnode) // Determine closest nodes. @@ -732,7 +753,8 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool for _, n := range closest { - if netutil.CheckRelayIP(from.IP, n.IP()) == nil { + fromIP := from.Addr().AsSlice() + if netutil.CheckRelayIP(fromIP, n.IP()) == nil { p.Nodes = append(p.Nodes, nodeToRPC(n)) } if len(p.Nodes) == v4wire.MaxNeighbors { @@ -748,13 +770,13 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID eno // NEIGHBORS/v4 -func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.Neighbors) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.handleReply(fromID, from.IP, h.Packet) { + if !t.handleReply(fromID, from.Addr(), h.Packet) { return errUnsolicitedReply } return nil @@ -762,19 +784,19 @@ func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from *net.UDPAddr, fromID en // ENRREQUEST/v4 -func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { +func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { req := h.Packet.(*v4wire.ENRRequest) if v4wire.Expired(req.Expiration) { return errExpired } - if !t.checkBond(fromID, from.IP) { + if !t.checkBond(fromID, from) { return errUnknownNode } return nil } -func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { +func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, mac []byte) { t.send(from, fromID, &v4wire.ENRResponse{ ReplyTok: mac, Record: *t.localNode.Node().Record(), @@ -783,8 +805,8 @@ func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID e // ENRRESPONSE/v4 -func (t *UDPv4) verifyENRResponse(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { - if !t.handleReply(fromID, from.IP, h.Packet) { +func (t *UDPv4) verifyENRResponse(h *packetHandlerV4, from netip.AddrPort, fromID enode.ID, fromKey v4wire.Pubkey) error { + if !t.handleReply(fromID, from.Addr(), h.Packet) { return errUnsolicitedReply } return nil diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9c454d98e3..28a6fb8675 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -26,6 +26,7 @@ import ( "io" "math/rand" "net" + "net/netip" "reflect" "sync" "testing" @@ -55,7 +56,7 @@ type udpTest struct { udp *UDPv4 sent [][]byte localkey, remotekey *ecdsa.PrivateKey - remoteaddr *net.UDPAddr + remoteaddr netip.AddrPort } func newUDPTest(t *testing.T) *udpTest { @@ -64,7 +65,7 @@ func newUDPTest(t *testing.T) *udpTest { pipe: newpipe(), localkey: newkey(), remotekey: newkey(), - remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303}, + remoteaddr: netip.MustParseAddrPort("10.0.1.99:30303"), } test.db, _ = enode.OpenDB("") @@ -92,7 +93,7 @@ func (test *udpTest) packetIn(wantError error, data v4wire.Packet) { } // handles a packet as if it had been sent to the transport by the key/endpoint. -func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr *net.UDPAddr, data v4wire.Packet) { +func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr netip.AddrPort, data v4wire.Packet) { test.t.Helper() enc, _, err := v4wire.Encode(key, data) @@ -106,7 +107,7 @@ func (test *udpTest) packetInFrom(wantError error, key *ecdsa.PrivateKey, addr * } // waits for a packet to be sent by the transport. -// validate should have type func(X, *net.UDPAddr, []byte), where X is a packet type. +// validate should have type func(X, netip.AddrPort, []byte), where X is a packet type. func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) { test.t.Helper() @@ -128,7 +129,7 @@ func (test *udpTest) waitPacketOut(validate interface{}) (closed bool) { test.t.Errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype) return false } - fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(&dgram.to), reflect.ValueOf(hash)}) + fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(dgram.to), reflect.ValueOf(hash)}) return false } @@ -236,7 +237,7 @@ func TestUDPv4_findnodeTimeout(t *testing.T) { test := newUDPTest(t) defer test.close() - toaddr := &net.UDPAddr{IP: net.ParseIP("1.2.3.4"), Port: 2222} + toaddr := netip.AddrPortFrom(netip.MustParseAddr("1.2.3.4"), 2222) toid := enode.ID{1, 2, 3, 4} target := v4wire.Pubkey{4, 5, 6, 7} result, err := test.udp.findnode(toid, toaddr, target) @@ -261,26 +262,25 @@ func TestUDPv4_findnode(t *testing.T) { for i := 0; i < numCandidates; i++ { key := newkey() ip := net.IP{10, 13, 0, byte(i)} - n := wrapNode(enode.NewV4(&key.PublicKey, ip, 0, 2000)) + n := enode.NewV4(&key.PublicKey, ip, 0, 2000) // Ensure half of table content isn't verified live yet. if i > numCandidates/2 { - n.isValidatedLive = true live[n.ID()] = true } + test.table.addFoundNode(n, live[n.ID()]) nodes.push(n, numCandidates) } - fillTable(test.table, nodes.entries, false) // ensure there's a bond with the test node, // findnode won't be accepted otherwise. remoteID := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() - test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.IP, time.Now()) + test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr().AsSlice(), time.Now()) // check that closest neighbors are returned. expected := test.table.findnodeByID(testTarget.ID(), bucketSize, true) test.packetIn(nil, &v4wire.Findnode{Target: testTarget, Expiration: futureExp}) - waitNeighbors := func(want []*node) { - test.waitPacketOut(func(p *v4wire.Neighbors, to *net.UDPAddr, hash []byte) { + waitNeighbors := func(want []*enode.Node) { + test.waitPacketOut(func(p *v4wire.Neighbors, to netip.AddrPort, hash []byte) { if len(p.Nodes) != len(want) { t.Errorf("wrong number of results: got %d, want %d", len(p.Nodes), len(want)) return @@ -309,10 +309,10 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { defer test.close() rid := enode.PubkeyToIDV4(&test.remotekey.PublicKey) - test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.IP, time.Now()) + test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr().AsSlice(), time.Now()) // queue a pending findnode request - resultc, errc := make(chan []*node, 1), make(chan error, 1) + resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) go func() { rid := encodePubkey(&test.remotekey.PublicKey).id() ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) @@ -325,18 +325,18 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { // wait for the findnode to be sent. // after it is sent, the transport is waiting for a reply - test.waitPacketOut(func(p *v4wire.Findnode, to *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Findnode, to netip.AddrPort, hash []byte) { if p.Target != testTarget { t.Errorf("wrong target: got %v, want %v", p.Target, testTarget) } }) // send the reply as two packets. - list := []*node{ - wrapNode(enode.MustParse("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")), - wrapNode(enode.MustParse("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")), - wrapNode(enode.MustParse("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")), - wrapNode(enode.MustParse("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")), + list := []*enode.Node{ + enode.MustParse("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304"), + enode.MustParse("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303"), + enode.MustParse("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17"), + enode.MustParse("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303"), } rpclist := make([]v4wire.Node, len(list)) for i := range list { @@ -368,8 +368,8 @@ func TestUDPv4_pingMatch(t *testing.T) { crand.Read(randToken) test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) - test.waitPacketOut(func(*v4wire.Pong, *net.UDPAddr, []byte) {}) - test.waitPacketOut(func(*v4wire.Ping, *net.UDPAddr, []byte) {}) + test.waitPacketOut(func(*v4wire.Pong, netip.AddrPort, []byte) {}) + test.waitPacketOut(func(*v4wire.Ping, netip.AddrPort, []byte) {}) test.packetIn(errUnsolicitedReply, &v4wire.Pong{ReplyTok: randToken, To: testLocalAnnounced, Expiration: futureExp}) } @@ -379,10 +379,10 @@ func TestUDPv4_pingMatchIP(t *testing.T) { defer test.close() test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) - test.waitPacketOut(func(*v4wire.Pong, *net.UDPAddr, []byte) {}) + test.waitPacketOut(func(*v4wire.Pong, netip.AddrPort, []byte) {}) - test.waitPacketOut(func(p *v4wire.Ping, to *net.UDPAddr, hash []byte) { - wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 1, 2}, Port: 30000} + test.waitPacketOut(func(p *v4wire.Ping, to netip.AddrPort, hash []byte) { + wrongAddr := netip.MustParseAddrPort("33.44.1.2:30000") test.packetInFrom(errUnsolicitedReply, test.remotekey, wrongAddr, &v4wire.Pong{ ReplyTok: hash, To: testLocalAnnounced, @@ -393,41 +393,36 @@ func TestUDPv4_pingMatchIP(t *testing.T) { func TestUDPv4_successfulPing(t *testing.T) { test := newUDPTest(t) - added := make(chan *node, 1) - test.table.nodeAddedHook = func(b *bucket, n *node) { added <- n } + added := make(chan *tableNode, 1) + test.table.nodeAddedHook = func(b *bucket, n *tableNode) { added <- n } defer test.close() // The remote side sends a ping packet to initiate the exchange. go test.packetIn(nil, &v4wire.Ping{From: testRemote, To: testLocalAnnounced, Version: 4, Expiration: futureExp}) // The ping is replied to. - test.waitPacketOut(func(p *v4wire.Pong, to *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Pong, to netip.AddrPort, hash []byte) { pinghash := test.sent[0][:32] if !bytes.Equal(p.ReplyTok, pinghash) { t.Errorf("got pong.ReplyTok %x, want %x", p.ReplyTok, pinghash) } - wantTo := v4wire.Endpoint{ - // The mirrored UDP address is the UDP packet sender - IP: test.remoteaddr.IP, UDP: uint16(test.remoteaddr.Port), - // The mirrored TCP port is the one from the ping packet - TCP: testRemote.TCP, - } + // The mirrored UDP address is the UDP packet sender. + // The mirrored TCP port is the one from the ping packet. + wantTo := v4wire.NewEndpoint(test.remoteaddr, testRemote.TCP) if !reflect.DeepEqual(p.To, wantTo) { t.Errorf("got pong.To %v, want %v", p.To, wantTo) } }) // Remote is unknown, the table pings back. - test.waitPacketOut(func(p *v4wire.Ping, to *net.UDPAddr, hash []byte) { - if !reflect.DeepEqual(p.From, test.udp.ourEndpoint()) { + test.waitPacketOut(func(p *v4wire.Ping, to netip.AddrPort, hash []byte) { + wantFrom := test.udp.ourEndpoint() + wantFrom.IP = net.IP{} + if !reflect.DeepEqual(p.From, wantFrom) { t.Errorf("got ping.From %#v, want %#v", p.From, test.udp.ourEndpoint()) } - wantTo := v4wire.Endpoint{ - // The mirrored UDP address is the UDP packet sender. - IP: test.remoteaddr.IP, - UDP: uint16(test.remoteaddr.Port), - TCP: 0, - } + // The mirrored UDP address is the UDP packet sender. + wantTo := v4wire.NewEndpoint(test.remoteaddr, 0) if !reflect.DeepEqual(p.To, wantTo) { t.Errorf("got ping.To %v, want %v", p.To, wantTo) } @@ -442,11 +437,11 @@ func TestUDPv4_successfulPing(t *testing.T) { if n.ID() != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } - if !n.IP().Equal(test.remoteaddr.IP) { - t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.IP) + if !n.IP().Equal(test.remoteaddr.Addr().AsSlice()) { + t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.Addr()) } - if n.UDP() != test.remoteaddr.Port { - t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port) + if n.UDP() != int(test.remoteaddr.Port()) { + t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port()) } if n.TCP() != int(testRemote.TCP) { t.Errorf("node has wrong TCP port: got %v, want: %v", n.TCP(), testRemote.TCP) @@ -469,12 +464,12 @@ func TestUDPv4_EIP868(t *testing.T) { // Perform endpoint proof and check for sequence number in packet tail. test.packetIn(nil, &v4wire.Ping{Expiration: futureExp}) - test.waitPacketOut(func(p *v4wire.Pong, addr *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Pong, addr netip.AddrPort, hash []byte) { if p.ENRSeq != wantNode.Seq() { t.Errorf("wrong sequence number in pong: %d, want %d", p.ENRSeq, wantNode.Seq()) } }) - test.waitPacketOut(func(p *v4wire.Ping, addr *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.Ping, addr netip.AddrPort, hash []byte) { if p.ENRSeq != wantNode.Seq() { t.Errorf("wrong sequence number in ping: %d, want %d", p.ENRSeq, wantNode.Seq()) } @@ -483,7 +478,7 @@ func TestUDPv4_EIP868(t *testing.T) { // Request should work now. test.packetIn(nil, &v4wire.ENRRequest{Expiration: futureExp}) - test.waitPacketOut(func(p *v4wire.ENRResponse, addr *net.UDPAddr, hash []byte) { + test.waitPacketOut(func(p *v4wire.ENRResponse, addr netip.AddrPort, hash []byte) { n, err := enode.New(enode.ValidSchemes, &p.Record) if err != nil { t.Fatalf("invalid record: %v", err) @@ -584,7 +579,7 @@ type dgramPipe struct { } type dgram struct { - to net.UDPAddr + to netip.AddrPort data []byte } @@ -597,8 +592,8 @@ func newpipe() *dgramPipe { } } -// WriteToUDP queues a datagram. -func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) { +// WriteToUDPAddrPort queues a datagram. +func (c *dgramPipe) WriteToUDPAddrPort(b []byte, to netip.AddrPort) (n int, err error) { msg := make([]byte, len(b)) copy(msg, b) c.mu.Lock() @@ -606,15 +601,15 @@ func (c *dgramPipe) WriteToUDP(b []byte, to *net.UDPAddr) (n int, err error) { if c.closed { return 0, errors.New("closed") } - c.queue = append(c.queue, dgram{*to, b}) + c.queue = append(c.queue, dgram{to, b}) c.cond.Signal() return len(b), nil } -// ReadFromUDP just hangs until the pipe is closed. -func (c *dgramPipe) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { +// ReadFromUDPAddrPort just hangs until the pipe is closed. +func (c *dgramPipe) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { <-c.closing - return 0, nil, io.EOF + return 0, netip.AddrPort{}, io.EOF } func (c *dgramPipe) Close() error { diff --git a/p2p/discover/v4wire/v4wire.go b/p2p/discover/v4wire/v4wire.go index 9c59359fb2..958cca324d 100644 --- a/p2p/discover/v4wire/v4wire.go +++ b/p2p/discover/v4wire/v4wire.go @@ -25,6 +25,7 @@ import ( "fmt" "math/big" "net" + "net/netip" "time" "github.com/ethereum/go-ethereum/common/math" @@ -150,14 +151,15 @@ type Endpoint struct { } // NewEndpoint creates an endpoint. -func NewEndpoint(addr *net.UDPAddr, tcpPort uint16) Endpoint { - ip := net.IP{} - if ip4 := addr.IP.To4(); ip4 != nil { - ip = ip4 - } else if ip6 := addr.IP.To16(); ip6 != nil { - ip = ip6 +func NewEndpoint(addr netip.AddrPort, tcpPort uint16) Endpoint { + var ip net.IP + if addr.Addr().Is4() || addr.Addr().Is4In6() { + ip4 := addr.Addr().As4() + ip = ip4[:] + } else { + ip = addr.Addr().AsSlice() } - return Endpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} + return Endpoint{IP: ip, UDP: addr.Port(), TCP: tcpPort} } type Packet interface { diff --git a/p2p/discover/v5_talk.go b/p2p/discover/v5_talk.go index c1f6787940..2246b47141 100644 --- a/p2p/discover/v5_talk.go +++ b/p2p/discover/v5_talk.go @@ -18,6 +18,7 @@ package discover import ( "net" + "net/netip" "sync" "time" @@ -70,7 +71,7 @@ func (t *talkSystem) register(protocol string, handler TalkRequestHandler) { } // handleRequest handles a talk request. -func (t *talkSystem) handleRequest(id enode.ID, addr *net.UDPAddr, req *v5wire.TalkRequest) { +func (t *talkSystem) handleRequest(id enode.ID, addr netip.AddrPort, req *v5wire.TalkRequest) { t.mutex.Lock() handler, ok := t.handlers[req.Protocol] t.mutex.Unlock() @@ -88,7 +89,8 @@ func (t *talkSystem) handleRequest(id enode.ID, addr *net.UDPAddr, req *v5wire.T case <-t.slots: go func() { defer func() { t.slots <- struct{}{} }() - respMessage := handler(id, addr, req.Message) + udpAddr := &net.UDPAddr{IP: addr.Addr().AsSlice(), Port: int(addr.Port())} + respMessage := handler(id, udpAddr, req.Message) resp := &v5wire.TalkResponse{ReqID: req.ReqID, Message: respMessage} t.transport.sendFromAnotherThread(id, addr, resp) }() diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 8cdc9dfbce..9ba54b3d40 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -25,6 +25,7 @@ import ( "fmt" "io" "net" + "net/netip" "slices" "sync" "time" @@ -101,14 +102,14 @@ type UDPv5 struct { type sendRequest struct { destID enode.ID - destAddr *net.UDPAddr + destAddr netip.AddrPort msg v5wire.Packet } // callV5 represents a remote procedure call against another node. type callV5 struct { id enode.ID - addr *net.UDPAddr + addr netip.AddrPort node *enode.Node // This is required to perform handshakes. packet v5wire.Packet @@ -233,7 +234,7 @@ func (t *UDPv5) AllNodes() []*enode.Node { for _, b := range &t.tab.buckets { for _, n := range b.entries { - nodes = append(nodes, unwrapNode(n)) + nodes = append(nodes, n.Node) } } return nodes @@ -266,7 +267,7 @@ func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]b } // TalkRequestToID sends a talk request to a node and waits for a response. -func (t *UDPv5) TalkRequestToID(id enode.ID, addr *net.UDPAddr, protocol string, request []byte) ([]byte, error) { +func (t *UDPv5) TalkRequestToID(id enode.ID, addr netip.AddrPort, protocol string, request []byte) ([]byte, error) { req := &v5wire.TalkRequest{Protocol: protocol, Message: request} resp := t.callToID(id, addr, v5wire.TalkResponseMsg, req) defer t.callDone(resp) @@ -314,26 +315,26 @@ func (t *UDPv5) newRandomLookup(ctx context.Context) *lookup { } func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *lookup { - return newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { + return newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { return t.lookupWorker(n, target) }) } // lookupWorker performs FINDNODE calls against a single node during lookup. -func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { +func (t *UDPv5) lookupWorker(destNode *enode.Node, target enode.ID) ([]*enode.Node, error) { var ( dists = lookupDistances(target, destNode.ID()) nodes = nodesByDistance{target: target} err error ) var r []*enode.Node - r, err = t.findnode(unwrapNode(destNode), dists) + r, err = t.findnode(destNode, dists) if errors.Is(err, errClosed) { return nil, err } for _, n := range r { if n.ID() != t.Self().ID() { - nodes.push(wrapNode(n), findnodeResultLimit) + nodes.push(n, findnodeResultLimit) } } return nodes.entries, err @@ -427,7 +428,7 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err != nil { return nil, err } - if err := netutil.CheckRelayIP(c.addr.IP, node.IP()); err != nil { + if err := netutil.CheckRelayIP(c.addr.Addr().AsSlice(), node.IP()); err != nil { return nil, err } if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { @@ -452,14 +453,14 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s // callToNode sends the given call and sets up a handler for response packets (of message // type responseType). Responses are dispatched to the call's response channel. func (t *UDPv5) callToNode(n *enode.Node, responseType byte, req v5wire.Packet) *callV5 { - addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} + addr, _ := n.UDPEndpoint() c := &callV5{id: n.ID(), addr: addr, node: n} t.initCall(c, responseType, req) return c } // callToID is like callToNode, but for cases where the node record is not available. -func (t *UDPv5) callToID(id enode.ID, addr *net.UDPAddr, responseType byte, req v5wire.Packet) *callV5 { +func (t *UDPv5) callToID(id enode.ID, addr netip.AddrPort, responseType byte, req v5wire.Packet) *callV5 { c := &callV5{id: id, addr: addr} t.initCall(c, responseType, req) return c @@ -619,12 +620,12 @@ func (t *UDPv5) sendCall(c *callV5) { // sendResponse sends a response packet to the given node. // This doesn't trigger a handshake even if no keys are available. -func (t *UDPv5) sendResponse(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) error { +func (t *UDPv5) sendResponse(toID enode.ID, toAddr netip.AddrPort, packet v5wire.Packet) error { _, err := t.send(toID, toAddr, packet, nil) return err } -func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) { +func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr netip.AddrPort, packet v5wire.Packet) { select { case t.sendCh <- sendRequest{toID, toAddr, packet}: case <-t.closeCtx.Done(): @@ -632,7 +633,7 @@ func (t *UDPv5) sendFromAnotherThread(toID enode.ID, toAddr *net.UDPAddr, packet } // send sends a packet to the given node. -func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { +func (t *UDPv5) send(toID enode.ID, toAddr netip.AddrPort, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { addr := toAddr.String() t.logcontext = append(t.logcontext[:0], "id", toID, "addr", addr) t.logcontext = packet.AppendLogInfo(t.logcontext) @@ -644,7 +645,7 @@ func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c return nonce, err } - _, err = t.conn.WriteToUDP(enc, toAddr) + _, err = t.conn.WriteToUDPAddrPort(enc, toAddr) t.log.Trace(">> "+packet.Name(), t.logcontext...) return nonce, err } @@ -655,7 +656,7 @@ func (t *UDPv5) readLoop() { buf := make([]byte, maxPacketSize) for range t.readNextCh { - nbytes, from, err := t.conn.ReadFromUDP(buf) + nbytes, from, err := t.conn.ReadFromUDPAddrPort(buf) if netutil.IsTemporaryError(err) { // Ignore temporary read errors. t.log.Debug("Temporary UDP read error", "err", err) @@ -672,7 +673,7 @@ func (t *UDPv5) readLoop() { } // dispatchReadPacket sends a packet into the dispatch loop. -func (t *UDPv5) dispatchReadPacket(from *net.UDPAddr, content []byte) bool { +func (t *UDPv5) dispatchReadPacket(from netip.AddrPort, content []byte) bool { select { case t.packetInCh <- ReadPacket{content, from}: return true @@ -682,7 +683,7 @@ func (t *UDPv5) dispatchReadPacket(from *net.UDPAddr, content []byte) bool { } // handlePacket decodes and processes an incoming packet from the network. -func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { +func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr netip.AddrPort) error { addr := fromAddr.String() fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr) if err != nil { @@ -699,7 +700,7 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } if fromNode != nil { // Handshake succeeded, add to table. - t.tab.addInboundNode(wrapNode(fromNode)) + t.tab.addInboundNode(fromNode) } if packet.Kind() != v5wire.WhoareyouPacket { // WHOAREYOU logged separately to report errors. @@ -712,13 +713,13 @@ func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { } // handleCallResponse dispatches a response packet to the call waiting for it. -func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr *net.UDPAddr, p v5wire.Packet) bool { +func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr netip.AddrPort, p v5wire.Packet) bool { ac := t.activeCallByNode[fromID] if ac == nil || !bytes.Equal(p.RequestID(), ac.reqid) { t.log.Debug(fmt.Sprintf("Unsolicited/late %s response", p.Name()), "id", fromID, "addr", fromAddr) return false } - if !fromAddr.IP.Equal(ac.addr.IP) || fromAddr.Port != ac.addr.Port { + if fromAddr != ac.addr { t.log.Debug(fmt.Sprintf("%s from wrong endpoint", p.Name()), "id", fromID, "addr", fromAddr) return false } @@ -743,7 +744,7 @@ func (t *UDPv5) getNode(id enode.ID) *enode.Node { } // handle processes incoming packets according to their message type. -func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort) { switch p := p.(type) { case *v5wire.Unknown: t.handleUnknown(p, fromID, fromAddr) @@ -753,7 +754,9 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) t.handlePing(p, fromID, fromAddr) case *v5wire.Pong: if t.handleCallResponse(fromID, fromAddr, p) { - t.localNode.UDPEndpointStatement(fromAddr, &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)}) + fromUDPAddr := &net.UDPAddr{IP: fromAddr.Addr().AsSlice(), Port: int(fromAddr.Port())} + toUDPAddr := &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)} + t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) } case *v5wire.Findnode: t.handleFindnode(p, fromID, fromAddr) @@ -767,7 +770,7 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) } // handleUnknown initiates a handshake by responding with WHOAREYOU. -func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr netip.AddrPort) { challenge := &v5wire.Whoareyou{Nonce: p.Nonce} crand.Read(challenge.IDNonce[:]) if n := t.getNode(fromID); n != nil { @@ -783,7 +786,7 @@ var ( ) // handleWhoareyou resends the active call as a handshake packet. -func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr *net.UDPAddr) { +func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr netip.AddrPort) { c, err := t.matchWithCall(fromID, p.Nonce) if err != nil { t.log.Debug("Invalid "+p.Name(), "addr", fromAddr, "err", err) @@ -817,32 +820,35 @@ func (t *UDPv5) matchWithCall(fromID enode.ID, nonce v5wire.Nonce) (*callV5, err } // handlePing sends a PONG response. -func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr *net.UDPAddr) { - remoteIP := fromAddr.IP - // Handle IPv4 mapped IPv6 addresses in the - // event the local node is binded to an - // ipv6 interface. - if remoteIP.To4() != nil { - remoteIP = remoteIP.To4() +func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr netip.AddrPort) { + var remoteIP net.IP + // Handle IPv4 mapped IPv6 addresses in the event the local node is binded + // to an ipv6 interface. + if fromAddr.Addr().Is4() || fromAddr.Addr().Is4In6() { + ip4 := fromAddr.Addr().As4() + remoteIP = ip4[:] + } else { + remoteIP = fromAddr.Addr().AsSlice() } t.sendResponse(fromID, fromAddr, &v5wire.Pong{ ReqID: p.ReqID, ToIP: remoteIP, - ToPort: uint16(fromAddr.Port), + ToPort: fromAddr.Port(), ENRSeq: t.localNode.Node().Seq(), }) } // handleFindnode returns nodes to the requester. -func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr *net.UDPAddr) { - nodes := t.collectTableNodes(fromAddr.IP, p.Distances, findnodeResultLimit) +func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr netip.AddrPort) { + nodes := t.collectTableNodes(fromAddr.Addr(), p.Distances, findnodeResultLimit) for _, resp := range packNodes(p.ReqID, nodes) { t.sendResponse(fromID, fromAddr, resp) } } // collectTableNodes creates a FINDNODE result set for the given distances. -func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*enode.Node { +func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) []*enode.Node { + ripSlice := rip.AsSlice() var bn []*enode.Node var nodes []*enode.Node var processed = make(map[uint]struct{}) @@ -857,7 +863,7 @@ func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*en for _, n := range t.tab.appendLiveNodes(dist, bn[:0]) { // Apply some pre-checks to avoid sending invalid nodes. // Note liveness is checked by appendLiveNodes. - if netutil.CheckRelayIP(rip, n.IP()) != nil { + if netutil.CheckRelayIP(ripSlice, n.IP()) != nil { continue } nodes = append(nodes, n) diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 0015f7cc70..1f8e972200 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -23,6 +23,7 @@ import ( "fmt" "math/rand" "net" + "net/netip" "reflect" "slices" "testing" @@ -103,7 +104,7 @@ func TestUDPv5_pingHandling(t *testing.T) { defer test.close() test.packetIn(&v5wire.Ping{ReqID: []byte("foo")}) - test.waitPacketOut(func(p *v5wire.Pong, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Pong, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, []byte("foo")) { t.Error("wrong request ID in response:", p.ReqID) } @@ -135,16 +136,16 @@ func TestUDPv5_unknownPacket(t *testing.T) { // Unknown packet from unknown node. test.packetIn(&v5wire.Unknown{Nonce: nonce}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { check(p, 0) }) // Make node known. n := test.getNode(test.remotekey, test.remoteaddr).Node() - test.table.addFoundNode(wrapNode(n)) + test.table.addFoundNode(n, false) test.packetIn(&v5wire.Unknown{Nonce: nonce}) - test.waitPacketOut(func(p *v5wire.Whoareyou, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Whoareyou, addr netip.AddrPort, _ v5wire.Nonce) { check(p, n.Seq()) }) } @@ -159,9 +160,9 @@ func TestUDPv5_findnodeHandling(t *testing.T) { nodes253 := nodesAtDistance(test.table.self().ID(), 253, 16) nodes249 := nodesAtDistance(test.table.self().ID(), 249, 4) nodes248 := nodesAtDistance(test.table.self().ID(), 248, 10) - fillTable(test.table, wrapNodes(nodes253), true) - fillTable(test.table, wrapNodes(nodes249), true) - fillTable(test.table, wrapNodes(nodes248), true) + fillTable(test.table, nodes253, true) + fillTable(test.table, nodes249, true) + fillTable(test.table, nodes248, true) // Requesting with distance zero should return the node's own record. test.packetIn(&v5wire.Findnode{ReqID: []byte{0}, Distances: []uint{0}}) @@ -199,7 +200,7 @@ func (test *udpV5Test) expectNodes(wantReqID []byte, wantTotal uint8, wantNodes } for { - test.waitPacketOut(func(p *v5wire.Nodes, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Nodes, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, wantReqID) { test.t.Fatalf("wrong request ID %v in response, want %v", p.ReqID, wantReqID) } @@ -238,7 +239,7 @@ func TestUDPv5_pingCall(t *testing.T) { _, err := test.udp.ping(remote) done <- err }() - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) {}) + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) {}) if err := <-done; err != errTimeout { t.Fatalf("want errTimeout, got %q", err) } @@ -248,7 +249,7 @@ func TestUDPv5_pingCall(t *testing.T) { _, err := test.udp.ping(remote) done <- err }() - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { test.packetInFrom(test.remotekey, test.remoteaddr, &v5wire.Pong{ReqID: p.ReqID}) }) if err := <-done; err != nil { @@ -260,8 +261,8 @@ func TestUDPv5_pingCall(t *testing.T) { _, err := test.udp.ping(remote) done <- err }() - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { - wrongAddr := &net.UDPAddr{IP: net.IP{33, 44, 55, 22}, Port: 10101} + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { + wrongAddr := netip.MustParseAddrPort("33.44.55.22:10101") test.packetInFrom(test.remotekey, wrongAddr, &v5wire.Pong{ReqID: p.ReqID}) }) if err := <-done; err != errTimeout { @@ -291,7 +292,7 @@ func TestUDPv5_findnodeCall(t *testing.T) { }() // Serve the responses: - test.waitPacketOut(func(p *v5wire.Findnode, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Findnode, addr netip.AddrPort, _ v5wire.Nonce) { if !reflect.DeepEqual(p.Distances, distances) { t.Fatalf("wrong distances in request: %v", p.Distances) } @@ -337,15 +338,15 @@ func TestUDPv5_callResend(t *testing.T) { }() // Ping answered by WHOAREYOU. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, nonce v5wire.Nonce) { test.packetIn(&v5wire.Whoareyou{Nonce: nonce}) }) // Ping should be re-sent. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { test.packetIn(&v5wire.Pong{ReqID: p.ReqID}) }) // Answer the other ping. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, _ v5wire.Nonce) { test.packetIn(&v5wire.Pong{ReqID: p.ReqID}) }) if err := <-done; err != nil { @@ -370,11 +371,11 @@ func TestUDPv5_multipleHandshakeRounds(t *testing.T) { }() // Ping answered by WHOAREYOU. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, nonce v5wire.Nonce) { test.packetIn(&v5wire.Whoareyou{Nonce: nonce}) }) // Ping answered by WHOAREYOU again. - test.waitPacketOut(func(p *v5wire.Ping, addr *net.UDPAddr, nonce v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Ping, addr netip.AddrPort, nonce v5wire.Nonce) { test.packetIn(&v5wire.Whoareyou{Nonce: nonce}) }) if err := <-done; err != errTimeout { @@ -401,7 +402,7 @@ func TestUDPv5_callTimeoutReset(t *testing.T) { }() // Serve two responses, slowly. - test.waitPacketOut(func(p *v5wire.Findnode, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Findnode, addr netip.AddrPort, _ v5wire.Nonce) { time.Sleep(respTimeout - 50*time.Millisecond) test.packetIn(&v5wire.Nodes{ ReqID: p.ReqID, @@ -439,7 +440,7 @@ func TestUDPv5_talkHandling(t *testing.T) { Protocol: "test", Message: []byte("test request"), }) - test.waitPacketOut(func(p *v5wire.TalkResponse, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkResponse, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, []byte("foo")) { t.Error("wrong request ID in response:", p.ReqID) } @@ -458,7 +459,7 @@ func TestUDPv5_talkHandling(t *testing.T) { Protocol: "wrong", Message: []byte("test request"), }) - test.waitPacketOut(func(p *v5wire.TalkResponse, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkResponse, addr netip.AddrPort, _ v5wire.Nonce) { if !bytes.Equal(p.ReqID, []byte("2")) { t.Error("wrong request ID in response:", p.ReqID) } @@ -485,7 +486,7 @@ func TestUDPv5_talkRequest(t *testing.T) { _, err := test.udp.TalkRequest(remote, "test", []byte("test request")) done <- err }() - test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) {}) + test.waitPacketOut(func(p *v5wire.TalkRequest, addr netip.AddrPort, _ v5wire.Nonce) {}) if err := <-done; err != errTimeout { t.Fatalf("want errTimeout, got %q", err) } @@ -495,7 +496,7 @@ func TestUDPv5_talkRequest(t *testing.T) { _, err := test.udp.TalkRequest(remote, "test", []byte("test request")) done <- err }() - test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkRequest, addr netip.AddrPort, _ v5wire.Nonce) { if p.Protocol != "test" { t.Errorf("wrong protocol ID in talk request: %q", p.Protocol) } @@ -516,7 +517,7 @@ func TestUDPv5_talkRequest(t *testing.T) { _, err := test.udp.TalkRequestToID(remote.ID(), test.remoteaddr, "test", []byte("test request 2")) done <- err }() - test.waitPacketOut(func(p *v5wire.TalkRequest, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.TalkRequest, addr netip.AddrPort, _ v5wire.Nonce) { if p.Protocol != "test" { t.Errorf("wrong protocol ID in talk request: %q", p.Protocol) } @@ -583,13 +584,14 @@ func TestUDPv5_lookup(t *testing.T) { for d, nn := range lookupTestnet.dists { for i, key := range nn { n := lookupTestnet.node(d, i) - test.getNode(key, &net.UDPAddr{IP: n.IP(), Port: n.UDP()}) + addr, _ := n.UDPEndpoint() + test.getNode(key, addr) } } // Seed table with initial node. initialNode := lookupTestnet.node(256, 0) - fillTable(test.table, []*node{wrapNode(initialNode)}, true) + fillTable(test.table, []*enode.Node{initialNode}, true) // Start the lookup. resultC := make(chan []*enode.Node, 1) @@ -601,7 +603,7 @@ func TestUDPv5_lookup(t *testing.T) { // Answer lookup packets. asked := make(map[enode.ID]bool) for done := false; !done; { - done = test.waitPacketOut(func(p v5wire.Packet, to *net.UDPAddr, _ v5wire.Nonce) { + done = test.waitPacketOut(func(p v5wire.Packet, to netip.AddrPort, _ v5wire.Nonce) { recipient, key := lookupTestnet.nodeByAddr(to) switch p := p.(type) { case *v5wire.Ping: @@ -652,11 +654,8 @@ func TestUDPv5_PingWithIPV4MappedAddress(t *testing.T) { test := newUDPV5Test(t) defer test.close() - rawIP := net.IPv4(0xFF, 0x12, 0x33, 0xE5) - test.remoteaddr = &net.UDPAddr{ - IP: rawIP.To16(), - Port: 0, - } + rawIP := netip.AddrFrom4([4]byte{0xFF, 0x12, 0x33, 0xE5}) + test.remoteaddr = netip.AddrPortFrom(netip.AddrFrom16(rawIP.As16()), 0) remote := test.getNode(test.remotekey, test.remoteaddr).Node() done := make(chan struct{}, 1) @@ -665,14 +664,14 @@ func TestUDPv5_PingWithIPV4MappedAddress(t *testing.T) { test.udp.handlePing(&v5wire.Ping{ENRSeq: 1}, remote.ID(), test.remoteaddr) done <- struct{}{} }() - test.waitPacketOut(func(p *v5wire.Pong, addr *net.UDPAddr, _ v5wire.Nonce) { + test.waitPacketOut(func(p *v5wire.Pong, addr netip.AddrPort, _ v5wire.Nonce) { if len(p.ToIP) == net.IPv6len { t.Error("Received untruncated ip address") } if len(p.ToIP) != net.IPv4len { t.Errorf("Received ip address with incorrect length: %d", len(p.ToIP)) } - if !p.ToIP.Equal(rawIP) { + if !p.ToIP.Equal(rawIP.AsSlice()) { t.Errorf("Received incorrect ip address: wanted %s but received %s", rawIP.String(), p.ToIP.String()) } }) @@ -688,9 +687,9 @@ type udpV5Test struct { db *enode.DB udp *UDPv5 localkey, remotekey *ecdsa.PrivateKey - remoteaddr *net.UDPAddr + remoteaddr netip.AddrPort nodesByID map[enode.ID]*enode.LocalNode - nodesByIP map[string]*enode.LocalNode + nodesByIP map[netip.Addr]*enode.LocalNode } // testCodec is the packet encoding used by protocol tests. This codec does not perform encryption. @@ -750,9 +749,9 @@ func newUDPV5Test(t *testing.T) *udpV5Test { pipe: newpipe(), localkey: newkey(), remotekey: newkey(), - remoteaddr: &net.UDPAddr{IP: net.IP{10, 0, 1, 99}, Port: 30303}, + remoteaddr: netip.MustParseAddrPort("10.0.1.99:30303"), nodesByID: make(map[enode.ID]*enode.LocalNode), - nodesByIP: make(map[string]*enode.LocalNode), + nodesByIP: make(map[netip.Addr]*enode.LocalNode), } test.db, _ = enode.OpenDB("") ln := enode.NewLocalNode(test.db, test.localkey) @@ -777,8 +776,8 @@ func (test *udpV5Test) packetIn(packet v5wire.Packet) { test.packetInFrom(test.remotekey, test.remoteaddr, packet) } -// handles a packet as if it had been sent to the transport by the key/endpoint. -func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, packet v5wire.Packet) { +// packetInFrom handles a packet as if it had been sent to the transport by the key/endpoint. +func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr netip.AddrPort, packet v5wire.Packet) { test.t.Helper() ln := test.getNode(key, addr) @@ -793,22 +792,22 @@ func (test *udpV5Test) packetInFrom(key *ecdsa.PrivateKey, addr *net.UDPAddr, pa } // getNode ensures the test knows about a node at the given endpoint. -func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr *net.UDPAddr) *enode.LocalNode { +func (test *udpV5Test) getNode(key *ecdsa.PrivateKey, addr netip.AddrPort) *enode.LocalNode { id := encodePubkey(&key.PublicKey).id() ln := test.nodesByID[id] if ln == nil { db, _ := enode.OpenDB("") ln = enode.NewLocalNode(db, key) - ln.SetStaticIP(addr.IP) - ln.Set(enr.UDP(addr.Port)) + ln.SetStaticIP(addr.Addr().AsSlice()) + ln.Set(enr.UDP(addr.Port())) test.nodesByID[id] = ln } - test.nodesByIP[string(addr.IP)] = ln + test.nodesByIP[addr.Addr()] = ln return ln } // waitPacketOut waits for the next output packet and handles it using the given 'validate' -// function. The function must be of type func (X, *net.UDPAddr, v5wire.Nonce) where X is +// function. The function must be of type func (X, netip.AddrPort, v5wire.Nonce) where X is // assignable to packetV5. func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { test.t.Helper() @@ -824,7 +823,7 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { test.t.Fatalf("timed out waiting for %v", exptype) return false } - ln := test.nodesByIP[string(dgram.to.IP)] + ln := test.nodesByIP[dgram.to.Addr()] if ln == nil { test.t.Fatalf("attempt to send to non-existing node %v", &dgram.to) return false @@ -839,7 +838,7 @@ func (test *udpV5Test) waitPacketOut(validate interface{}) (closed bool) { test.t.Errorf("sent packet type mismatch, got: %v, want: %v", reflect.TypeOf(p), exptype) return false } - fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(&dgram.to), reflect.ValueOf(frame.AuthTag)}) + fn.Call([]reflect.Value{reflect.ValueOf(p), reflect.ValueOf(dgram.to), reflect.ValueOf(frame.AuthTag)}) return false } diff --git a/p2p/server.go b/p2p/server.go index a3c53b0781..13eebed3f4 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -24,6 +24,7 @@ import ( "errors" "fmt" "net" + "net/netip" "slices" "sync" "sync/atomic" @@ -435,11 +436,11 @@ type sharedUDPConn struct { unhandled chan discover.ReadPacket } -// ReadFromUDP implements discover.UDPConn -func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) { +// ReadFromUDPAddrPort implements discover.UDPConn +func (s *sharedUDPConn) ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) { packet, ok := <-s.unhandled if !ok { - return 0, nil, errors.New("connection was closed") + return 0, netip.AddrPort{}, errors.New("connection was closed") } l := len(packet.Data) if l > len(b) { From 3fef53447f39878e5ebca1938db90e79a363f535 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 May 2024 15:31:27 +0200 Subject: [PATCH 036/196] build: upgrade to golangci-lint v1.59.0 (#29875) --- .golangci.yml | 6 +++-- build/checksums.txt | 59 +++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 0343c4b4eb..46844d1e90 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,8 +6,6 @@ run: # default is true. Enables skipping of directories: # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ skip-dirs-use-default: true - skip-files: - - core/genesis_alloc.go linters: disable-all: true @@ -26,6 +24,8 @@ linters: - exportloopref - whitespace + ### linters we tried and will not be using: + ### # - structcheck # lots of false positives # - errcheck #lot of false positives # - contextcheck @@ -40,6 +40,8 @@ linters-settings: simplify: true issues: + exclude-files: + - core/genesis_alloc.go exclude-rules: - path: crypto/bn256/cloudflare/optate.go linters: diff --git a/build/checksums.txt b/build/checksums.txt index da2988452a..94cac9738c 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -48,36 +48,37 @@ cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windo 40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip 59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.windows-arm64.zip -# version:golangci 1.55.2 +# version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ -# https://github.com/golangci/golangci-lint/releases/download/v1.55.2/ -632e96e6d5294fbbe7b2c410a49c8fa01c60712a0af85a567de85bcc1623ea21 golangci-lint-1.55.2-darwin-amd64.tar.gz -234463f059249f82045824afdcdd5db5682d0593052f58f6a3039a0a1c3899f6 golangci-lint-1.55.2-darwin-arm64.tar.gz -2bdd105e2d4e003a9058c33a22bb191a1e0f30fa0790acca0d8fbffac1d6247c golangci-lint-1.55.2-freebsd-386.tar.gz -e75056e8b082386676ce23eba455cf893931a792c0d87e1e3743c0aec33c7fb5 golangci-lint-1.55.2-freebsd-amd64.tar.gz -5789b933facaf6136bd23f1d50add67b79bbcf8dfdfc9069a37f729395940a66 golangci-lint-1.55.2-freebsd-armv6.tar.gz -7f21ab1008d05f32c954f99470fc86a83a059e530fe2add1d0b7d8ed4d8992a7 golangci-lint-1.55.2-freebsd-armv7.tar.gz -33ab06139b9219a28251f10821da94423db30285cc2af97494cbb2a281927de9 golangci-lint-1.55.2-illumos-amd64.tar.gz -57ce6f8ce3ad6ee45d7cc3d9a047545a851c2547637834a3fcb086c7b40b1e6b golangci-lint-1.55.2-linux-386.tar.gz -ca21c961a33be3bc15e4292dc40c98c8dcc5463a7b6768a3afc123761630c09c golangci-lint-1.55.2-linux-amd64.tar.gz -8eb0cee9b1dbf0eaa49871798c7f8a5b35f2960c52d776a5f31eb7d886b92746 golangci-lint-1.55.2-linux-arm64.tar.gz -3195f3e0f37d353fd5bd415cabcd4e263f5c29d3d0ffb176c26ff3d2c75eb3bb golangci-lint-1.55.2-linux-armv6.tar.gz -c823ee36eb1a719e171de1f2f5ca3068033dce8d9817232fd10ed71fd6650406 golangci-lint-1.55.2-linux-armv7.tar.gz -758a5d2a356dc494bd13ed4c0d4bf5a54a4dc91267ea5ecdd87b86c7ca0624e7 golangci-lint-1.55.2-linux-loong64.tar.gz -2c7b9abdce7cae802a67d583cd7c6dca520bff6d0e17c8535a918e2f2b437aa0 golangci-lint-1.55.2-linux-mips64.tar.gz -024e0a15b85352cc27271285526e16a4ab66d3e67afbbe446c9808c06cb8dbed golangci-lint-1.55.2-linux-mips64le.tar.gz -6b00f89ba5506c1de1efdd9fa17c54093013a294fefd8b9b31534db626a672ee golangci-lint-1.55.2-linux-ppc64le.tar.gz -0faa0d047d9bf7b703ed3ea65b6117043c93504f9ca1de25ae929d3901c73d4a golangci-lint-1.55.2-linux-riscv64.tar.gz -30dec9b22e7d5bb4e9d5ccea96da20f71cd7db3c8cf30b8ddc7cb9174c4d742a golangci-lint-1.55.2-linux-s390x.tar.gz -5a0ede48f79ad707902fdb29be8cd2abd8302dc122b65ebae3fdfc86751c7698 golangci-lint-1.55.2-netbsd-386.tar.gz -95af20a2e617126dd5b08122ece7819101070e1582a961067ce8c41172f901ad golangci-lint-1.55.2-netbsd-amd64.tar.gz -94fb7dacb7527847cc95d7120904e19a2a0a81a0d50d61766c9e0251da72ab9d golangci-lint-1.55.2-netbsd-armv6.tar.gz -ca906bce5fee9619400e4a321c56476fe4a4efb6ac4fc989d340eb5563348873 golangci-lint-1.55.2-netbsd-armv7.tar.gz -45b442f69fc8915c4500201c0247b7f3f69544dbc9165403a61f9095f2c57355 golangci-lint-1.55.2-windows-386.zip -f57d434d231d43417dfa631587522f8c1991220b43c8ffadb9c7bd279508bf81 golangci-lint-1.55.2-windows-amd64.zip -fd7dc8f4c6829ee6fafb252a4d81d2155cd35da7833665cbb25d53ce7cecd990 golangci-lint-1.55.2-windows-arm64.zip -1892c3c24f9e7ef44b02f6750c703864b6dc350129f3ec39510300007b2376f1 golangci-lint-1.55.2-windows-armv6.zip -a5e68ae73d38748b5269fad36ac7575e3c162a5dc63ef58abdea03cc5da4522a golangci-lint-1.55.2-windows-armv7.zip +# https://github.com/golangci/golangci-lint/releases/download/v1.59.0/ +418acf7e255ddc0783e97129c9b03d9311b77826a5311d425a01c708a86417e7 golangci-lint-1.59.0-darwin-amd64.tar.gz +5f6a1d95a6dd69f6e328eb56dd311a38e04cfab79a1305fbf4957f4e203f47b6 golangci-lint-1.59.0-darwin-arm64.tar.gz +8899bf589185d49f747f3e5db9f0bde8a47245a100c64a3dd4d65e8e92cfc4f2 golangci-lint-1.59.0-freebsd-386.tar.gz +658212f138d9df2ac89427e22115af34bf387c0871d70f2a25101718946a014f golangci-lint-1.59.0-freebsd-amd64.tar.gz +4c6395ea40f314d3b6fa17d8997baab93464d5d1deeaab513155e625473bd03a golangci-lint-1.59.0-freebsd-armv6.tar.gz +ff37da4fbaacdb6bbae70fdbdbb1ba932a859956f788c82822fa06bef5b7c6b3 golangci-lint-1.59.0-freebsd-armv7.tar.gz +439739469ed2bda182b1ec276d40c40e02f195537f78e3672996741ad223d6b6 golangci-lint-1.59.0-illumos-amd64.tar.gz +940801d46790e40d0a097d8fee34e2606f0ef148cd039654029b0b8750a15ed6 golangci-lint-1.59.0-linux-386.tar.gz +3b14a439f33c4fff83dbe0349950d984042b9a1feb6c62f82787b598fc3ab5f4 golangci-lint-1.59.0-linux-amd64.tar.gz +c57e6c0b0fa03089a2611dceddd5bc5d206716cccdff8b149da8baac598719a1 golangci-lint-1.59.0-linux-arm64.tar.gz +93149e2d3b25ac754df9a23172403d8aa6d021a7e0d9c090a12f51897f68c9a0 golangci-lint-1.59.0-linux-armv6.tar.gz +d10ac38239d9efee3ee87b55c96cdf3fa09e1a525babe3ffdaaf65ccc48cf3dc golangci-lint-1.59.0-linux-armv7.tar.gz +047338114b4f0d5f08f0fb9a397b03cc171916ed0960be7dfb355c2320cd5e9c golangci-lint-1.59.0-linux-loong64.tar.gz +5632df0f7f8fc03a80a266130faef0b5902d280cf60621f1b2bdc1aef6d97ee9 golangci-lint-1.59.0-linux-mips64.tar.gz +71dd638c82fa4439171e7126d2c7a32b5d103bfdef282cea40c83632cb3d1f4b golangci-lint-1.59.0-linux-mips64le.tar.gz +6cf9ea0d34e91669948483f9ae7f07da319a879344373a1981099fbd890cde00 golangci-lint-1.59.0-linux-ppc64le.tar.gz +af0205fa6fbab197cee613c359947711231739095d21b5c837086233b36ad971 golangci-lint-1.59.0-linux-riscv64.tar.gz +a9d2fb93f3c688ebccef94f5dc96c0b07c4d20bf6556cddebd8442159b0c80f6 golangci-lint-1.59.0-linux-s390x.tar.gz +68ab4c57a847b8ace9679887f2f8b2b6760e57ee29dcde8c3f40dd8bb2654fa2 golangci-lint-1.59.0-netbsd-386.tar.gz +d277b8b435c19406d00de4d509eadf5a024a5782878332e9a1b7c02bb76e87a7 golangci-lint-1.59.0-netbsd-amd64.tar.gz +83211656be8dcfa1545af4f92894409f412d1f37566798cb9460a526593ad62c golangci-lint-1.59.0-netbsd-arm64.tar.gz +6c6866d28bf79fa9817a0f7d2b050890ed109cae80bdb4dfa39536a7226da237 golangci-lint-1.59.0-netbsd-armv6.tar.gz +11587566363bd03ca586b7df9776ccaed569fcd1f3489930ac02f9375b307503 golangci-lint-1.59.0-netbsd-armv7.tar.gz +466181a8967bafa495e41494f93a0bec829c2cf715de874583b0460b3b8ae2b8 golangci-lint-1.59.0-windows-386.zip +3317d8a87a99a49a0a1321d295c010790e6dbf43ee96b318f4b8bb23eae7a565 golangci-lint-1.59.0-windows-amd64.zip +b3af955c7fceac8220a36fc799e1b3f19d3b247d32f422caac5f9845df8f7316 golangci-lint-1.59.0-windows-arm64.zip +6f083c7d0c764e5a0e5bde46ee3e91ae357d80c194190fe1d9754392e9064c7e golangci-lint-1.59.0-windows-armv6.zip +3709b4dd425deadab27748778d08e03c0f804d7748f7dd5b6bb488d98aa031c7 golangci-lint-1.59.0-windows-armv7.zip # This is the builder on PPA that will build Go itself (inception-y), don't modify! # From 2f06c1e854de1d916547a539679649e359dad476 Mon Sep 17 00:00:00 2001 From: hattizai Date: Wed, 29 May 2024 21:55:51 +0800 Subject: [PATCH 037/196] cmd/devp2p: fix node.TCP -> node.UDP (#29879) --- cmd/devp2p/internal/v4test/framework.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/internal/v4test/framework.go b/cmd/devp2p/internal/v4test/framework.go index e8f4c021b8..df1f1f8aba 100644 --- a/cmd/devp2p/internal/v4test/framework.go +++ b/cmd/devp2p/internal/v4test/framework.go @@ -62,7 +62,7 @@ func newTestEnv(remote string, listen1, listen2 string) *testenv { if tcpPort = node.TCP(); tcpPort == 0 { tcpPort = 30303 } - if udpPort = node.TCP(); udpPort == 0 { + if udpPort = node.UDP(); udpPort == 0 { udpPort = 30303 } node = enode.NewV4(node.Pubkey(), ip, tcpPort, udpPort) From 6bb13e8e2be3aa8c41460eb11837baba514e19be Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 29 May 2024 15:56:52 +0200 Subject: [PATCH 038/196] eth/catalyst: ensure TxPool is synced in Fork (#29876) This should fix an occasional test failure in ethclient/simulated.TestForkResendTx. Inspection of logs revealed the cause of the failure to be that the txpool was not done reorganizing by the time Fork is called. --- eth/catalyst/simulated_beacon.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index fecd83f276..2d6569e422 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -279,9 +279,12 @@ func (c *SimulatedBeacon) Rollback() { // Fork sets the head to the provided hash. func (c *SimulatedBeacon) Fork(parentHash common.Hash) error { + // Ensure no pending transactions. + c.eth.TxPool().Sync() if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 { return errors.New("pending block dirty") } + parent := c.eth.BlockChain().GetBlockByHash(parentHash) if parent == nil { return errors.New("parent not found") From e015c1116f2c78a5b140d3fdc368f5d1abcd2eaf Mon Sep 17 00:00:00 2001 From: SuiYuan <165623542+suiyuan1314@users.noreply.github.com> Date: Thu, 30 May 2024 21:23:04 +0800 Subject: [PATCH 039/196] ethdb: remove unnecessary function wrapper (#29888) --- ethdb/dbtest/testsuite.go | 2 +- ethdb/pebble/pebble.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 7137d29396..29a773ced4 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -530,7 +530,7 @@ func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) { vals = append(vals, randBytes(vsize)) } if order { - slices.SortFunc(keys, func(a, b []byte) int { return bytes.Compare(a, b) }) + slices.SortFunc(keys, bytes.Compare) } return keys, vals } diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index dda084ae3b..0fac07c960 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -207,7 +207,7 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e // The default compaction concurrency(1 thread), // Here use all available CPUs for faster compaction. - MaxConcurrentCompactions: func() int { return runtime.NumCPU() }, + MaxConcurrentCompactions: runtime.NumCPU, // Per-level options. Options for at least one level must be specified. The // options for the last level are used for all subsequent levels. From 2262bf34158e184a2440f325ad355a45fa15ba9d Mon Sep 17 00:00:00 2001 From: SuiYuan <165623542+suiyuan1314@users.noreply.github.com> Date: Thu, 30 May 2024 22:24:16 +0800 Subject: [PATCH 040/196] crypto/secp256k1: change receiver variable name to lowercase (#29889) --- crypto/secp256k1/curve.go | 88 +++++++++++++-------------- crypto/secp256k1/scalar_mult_cgo.go | 2 +- crypto/secp256k1/scalar_mult_nocgo.go | 2 +- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index 9b26ab2928..85ba885d6f 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -79,52 +79,52 @@ type BitCurve struct { BitSize int // the size of the underlying field } -func (BitCurve *BitCurve) Params() *elliptic.CurveParams { +func (bitCurve *BitCurve) Params() *elliptic.CurveParams { return &elliptic.CurveParams{ - P: BitCurve.P, - N: BitCurve.N, - B: BitCurve.B, - Gx: BitCurve.Gx, - Gy: BitCurve.Gy, - BitSize: BitCurve.BitSize, + P: bitCurve.P, + N: bitCurve.N, + B: bitCurve.B, + Gx: bitCurve.Gx, + Gy: bitCurve.Gy, + BitSize: bitCurve.BitSize, } } // IsOnCurve returns true if the given (x,y) lies on the BitCurve. -func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { +func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { // y² = x³ + b y2 := new(big.Int).Mul(y, y) //y² - y2.Mod(y2, BitCurve.P) //y²%P + y2.Mod(y2, bitCurve.P) //y²%P x3 := new(big.Int).Mul(x, x) //x² x3.Mul(x3, x) //x³ - x3.Add(x3, BitCurve.B) //x³+B - x3.Mod(x3, BitCurve.P) //(x³+B)%P + x3.Add(x3, bitCurve.B) //x³+B + x3.Mod(x3, bitCurve.P) //(x³+B)%P return x3.Cmp(y2) == 0 } // affineFromJacobian reverses the Jacobian transform. See the comment at the // top of the file. -func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { +func (bitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { if z.Sign() == 0 { return new(big.Int), new(big.Int) } - zinv := new(big.Int).ModInverse(z, BitCurve.P) + zinv := new(big.Int).ModInverse(z, bitCurve.P) zinvsq := new(big.Int).Mul(zinv, zinv) xOut = new(big.Int).Mul(x, zinvsq) - xOut.Mod(xOut, BitCurve.P) + xOut.Mod(xOut, bitCurve.P) zinvsq.Mul(zinvsq, zinv) yOut = new(big.Int).Mul(y, zinvsq) - yOut.Mod(yOut, BitCurve.P) + yOut.Mod(yOut, bitCurve.P) return } // Add returns the sum of (x1,y1) and (x2,y2) -func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { // If one point is at infinity, return the other point. // Adding the point at infinity to any point will preserve the other point. if x1.Sign() == 0 && y1.Sign() == 0 { @@ -135,27 +135,27 @@ func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { } z := new(big.Int).SetInt64(1) if x1.Cmp(x2) == 0 && y1.Cmp(y2) == 0 { - return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z)) + return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z)) } - return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z)) + return bitCurve.affineFromJacobian(bitCurve.addJacobian(x1, y1, z, x2, y2, z)) } // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and // (x2, y2, z2) and returns their sum, also in Jacobian form. -func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { +func (bitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl z1z1 := new(big.Int).Mul(z1, z1) - z1z1.Mod(z1z1, BitCurve.P) + z1z1.Mod(z1z1, bitCurve.P) z2z2 := new(big.Int).Mul(z2, z2) - z2z2.Mod(z2z2, BitCurve.P) + z2z2.Mod(z2z2, bitCurve.P) u1 := new(big.Int).Mul(x1, z2z2) - u1.Mod(u1, BitCurve.P) + u1.Mod(u1, bitCurve.P) u2 := new(big.Int).Mul(x2, z1z1) - u2.Mod(u2, BitCurve.P) + u2.Mod(u2, bitCurve.P) h := new(big.Int).Sub(u2, u1) if h.Sign() == -1 { - h.Add(h, BitCurve.P) + h.Add(h, bitCurve.P) } i := new(big.Int).Lsh(h, 1) i.Mul(i, i) @@ -163,13 +163,13 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int s1 := new(big.Int).Mul(y1, z2) s1.Mul(s1, z2z2) - s1.Mod(s1, BitCurve.P) + s1.Mod(s1, bitCurve.P) s2 := new(big.Int).Mul(y2, z1) s2.Mul(s2, z1z1) - s2.Mod(s2, BitCurve.P) + s2.Mod(s2, bitCurve.P) r := new(big.Int).Sub(s2, s1) if r.Sign() == -1 { - r.Add(r, BitCurve.P) + r.Add(r, bitCurve.P) } r.Lsh(r, 1) v := new(big.Int).Mul(u1, i) @@ -179,7 +179,7 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int x3.Sub(x3, j) x3.Sub(x3, v) x3.Sub(x3, v) - x3.Mod(x3, BitCurve.P) + x3.Mod(x3, bitCurve.P) y3 := new(big.Int).Set(r) v.Sub(v, x3) @@ -187,33 +187,33 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int s1.Mul(s1, j) s1.Lsh(s1, 1) y3.Sub(y3, s1) - y3.Mod(y3, BitCurve.P) + y3.Mod(y3, bitCurve.P) z3 := new(big.Int).Add(z1, z2) z3.Mul(z3, z3) z3.Sub(z3, z1z1) if z3.Sign() == -1 { - z3.Add(z3, BitCurve.P) + z3.Add(z3, bitCurve.P) } z3.Sub(z3, z2z2) if z3.Sign() == -1 { - z3.Add(z3, BitCurve.P) + z3.Add(z3, bitCurve.P) } z3.Mul(z3, h) - z3.Mod(z3, BitCurve.P) + z3.Mod(z3, bitCurve.P) return x3, y3, z3 } // Double returns 2*(x,y) -func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { z1 := new(big.Int).SetInt64(1) - return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1)) + return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z1)) } // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and // returns its double, also in Jacobian form. -func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { +func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l a := new(big.Int).Mul(x, x) //X1² @@ -231,30 +231,30 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D x3.Sub(f, x3) //F-2*D - x3.Mod(x3, BitCurve.P) + x3.Mod(x3, bitCurve.P) y3 := new(big.Int).Sub(d, x3) //D-X3 y3.Mul(e, y3) //E*(D-X3) y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C - y3.Mod(y3, BitCurve.P) + y3.Mod(y3, bitCurve.P) z3 := new(big.Int).Mul(y, z) //Y1*Z1 z3.Mul(big.NewInt(2), z3) //3*Y1*Z1 - z3.Mod(z3, BitCurve.P) + z3.Mod(z3, bitCurve.P) return x3, y3, z3 } // ScalarBaseMult returns k*G, where G is the base point of the group and k is // an integer in big-endian form. -func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { - return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k) +func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + return bitCurve.ScalarMult(bitCurve.Gx, bitCurve.Gy, k) } // Marshal converts a point into the form specified in section 4.3.6 of ANSI // X9.62. -func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { - byteLen := (BitCurve.BitSize + 7) >> 3 +func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte { + byteLen := (bitCurve.BitSize + 7) >> 3 ret := make([]byte, 1+2*byteLen) ret[0] = 4 // uncompressed point flag readBits(x, ret[1:1+byteLen]) @@ -264,8 +264,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { // Unmarshal converts a point, serialised by Marshal, into an x, y pair. On // error, x = nil. -func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { - byteLen := (BitCurve.BitSize + 7) >> 3 +func (bitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) { + byteLen := (bitCurve.BitSize + 7) >> 3 if len(data) != 1+2*byteLen { return } diff --git a/crypto/secp256k1/scalar_mult_cgo.go b/crypto/secp256k1/scalar_mult_cgo.go index bdf8eeede7..d11c11faf8 100644 --- a/crypto/secp256k1/scalar_mult_cgo.go +++ b/crypto/secp256k1/scalar_mult_cgo.go @@ -21,7 +21,7 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned */ import "C" -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { // Ensure scalar is exactly 32 bytes. We pad always, even if // scalar is 32 bytes long, to avoid a timing side channel. if len(scalar) > 32 { diff --git a/crypto/secp256k1/scalar_mult_nocgo.go b/crypto/secp256k1/scalar_mult_nocgo.go index 22f53ac6ae..feb13a8dfd 100644 --- a/crypto/secp256k1/scalar_mult_nocgo.go +++ b/crypto/secp256k1/scalar_mult_nocgo.go @@ -9,6 +9,6 @@ package secp256k1 import "math/big" -func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { +func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { panic("ScalarMult is not available when secp256k1 is built without cgo") } From 5d7d48fc3e862237f97a9a27ba737816ab641a55 Mon Sep 17 00:00:00 2001 From: yujinpark Date: Fri, 31 May 2024 01:22:23 +0900 Subject: [PATCH 041/196] eth/gasprice: add comment to constant (#29892) Co-authored-by: Felix Lange --- eth/gasprice/feehistory.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index d039bcb401..1e625e21c0 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -44,7 +44,8 @@ const ( // maxBlockFetchers is the max number of goroutines to spin up to pull blocks // for the fee history calculation (mostly relevant for LES). maxBlockFetchers = 4 - maxQueryLimit = 100 + // maxQueryLimit is the max number of requested percentiles. + maxQueryLimit = 100 ) // blockFees represents a single block for processing From bdc62f9bebc6f0762b77568a421a35125fa7db61 Mon Sep 17 00:00:00 2001 From: tianyeyouyou <150894831+tianyeyouyou@users.noreply.github.com> Date: Fri, 31 May 2024 15:25:49 +0800 Subject: [PATCH 042/196] common/math: rename variable name `int` to `n` (#29890) * chore: rename variable name `int` to `in` * chore: rename variable name `int` to `n` --- common/math/big_test.go | 4 ++-- common/math/integer.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/math/big_test.go b/common/math/big_test.go index 803b5e1cc6..ee8f09e7b4 100644 --- a/common/math/big_test.go +++ b/common/math/big_test.go @@ -180,9 +180,9 @@ func BenchmarkByteAtOld(b *testing.B) { func TestReadBits(t *testing.T) { check := func(input string) { want, _ := hex.DecodeString(input) - int, _ := new(big.Int).SetString(input, 16) + n, _ := new(big.Int).SetString(input, 16) buf := make([]byte, len(want)) - ReadBits(int, buf) + ReadBits(n, buf) if !bytes.Equal(buf, want) { t.Errorf("have: %x\nwant: %x", buf, want) } diff --git a/common/math/integer.go b/common/math/integer.go index da01c0a08e..080fba8fea 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -54,11 +54,11 @@ func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error { // UnmarshalText implements encoding.TextUnmarshaler. func (i *HexOrDecimal64) UnmarshalText(input []byte) error { - int, ok := ParseUint64(string(input)) + n, ok := ParseUint64(string(input)) if !ok { return fmt.Errorf("invalid hex or decimal integer %q", input) } - *i = HexOrDecimal64(int) + *i = HexOrDecimal64(n) return nil } From 2613523cb510a2e3ab956214c447e95c8a3d2d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 31 May 2024 10:39:40 +0300 Subject: [PATCH 043/196] miner: lower default min miner tip from 1 gwei to 0.001 gwei (#29895) --- miner/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/miner.go b/miner/miner.go index 430efcb2fc..ff81d0e8f5 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -53,7 +53,7 @@ type Config struct { // DefaultConfig contains default settings for miner. var DefaultConfig = Config{ GasCeil: 30_000_000, - GasPrice: big.NewInt(params.GWei), + GasPrice: big.NewInt(params.GWei / 1000), // The default recommit time is chosen as two seconds since // consensus-layer usually will wait a half slot of time(6s) From d4b81f0e087a660cffcbc6c660b43b46115e62ee Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 31 May 2024 18:40:09 +0200 Subject: [PATCH 044/196] CODEOWNERS: @s1na owns core/tracing (#29899) Update CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index faf922df01..0dabaf4df5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -10,6 +10,7 @@ core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 eth/catalyst/ @gballet eth/tracers/ @s1na +core/tracing/ @s1na graphql/ @s1na les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 From c9e0b3105baa68e58780340cbaf146b1f0b46636 Mon Sep 17 00:00:00 2001 From: Chris Ziogas Date: Mon, 3 Jun 2024 13:30:27 +0300 Subject: [PATCH 045/196] Supply delta live tracer (#29347) Introduces the first built-in live tracer. The supply tracer tracks ETH supply changes across blocks and writes the output to disk. This will need to be enabled through CLI using the `--vmtrace supply` flag. Co-authored-by: Sina Mahmoodi --- .../gen_balance_change_reason_stringer.go | 37 ++ core/tracing/hooks.go | 2 + eth/tracers/internal/tracetest/supply_test.go | 613 ++++++++++++++++++ eth/tracers/live/gen_supplyinfoburn.go | 49 ++ eth/tracers/live/gen_supplyinfoissuance.go | 49 ++ eth/tracers/live/supply.go | 310 +++++++++ 6 files changed, 1060 insertions(+) create mode 100644 core/tracing/gen_balance_change_reason_stringer.go create mode 100644 eth/tracers/internal/tracetest/supply_test.go create mode 100644 eth/tracers/live/gen_supplyinfoburn.go create mode 100644 eth/tracers/live/gen_supplyinfoissuance.go create mode 100644 eth/tracers/live/supply.go diff --git a/core/tracing/gen_balance_change_reason_stringer.go b/core/tracing/gen_balance_change_reason_stringer.go new file mode 100644 index 0000000000..d3a515a12d --- /dev/null +++ b/core/tracing/gen_balance_change_reason_stringer.go @@ -0,0 +1,37 @@ +// Code generated by "stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go"; DO NOT EDIT. + +package tracing + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[BalanceChangeUnspecified-0] + _ = x[BalanceIncreaseRewardMineUncle-1] + _ = x[BalanceIncreaseRewardMineBlock-2] + _ = x[BalanceIncreaseWithdrawal-3] + _ = x[BalanceIncreaseGenesisBalance-4] + _ = x[BalanceIncreaseRewardTransactionFee-5] + _ = x[BalanceDecreaseGasBuy-6] + _ = x[BalanceIncreaseGasReturn-7] + _ = x[BalanceIncreaseDaoContract-8] + _ = x[BalanceDecreaseDaoAccount-9] + _ = x[BalanceChangeTransfer-10] + _ = x[BalanceChangeTouchAccount-11] + _ = x[BalanceIncreaseSelfdestruct-12] + _ = x[BalanceDecreaseSelfdestruct-13] + _ = x[BalanceDecreaseSelfdestructBurn-14] +} + +const _BalanceChangeReason_name = "BalanceChangeUnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountBalanceChangeTransferBalanceChangeTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurn" + +var _BalanceChangeReason_index = [...]uint16{0, 24, 54, 84, 109, 138, 173, 194, 218, 244, 269, 290, 315, 342, 369, 400} + +func (i BalanceChangeReason) String() string { + if i >= BalanceChangeReason(len(_BalanceChangeReason_index)-1) { + return "BalanceChangeReason(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _BalanceChangeReason_name[_BalanceChangeReason_index[i]:_BalanceChangeReason_index[i+1]] +} diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 9b08cffd45..db058e847c 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -199,6 +199,8 @@ type Hooks struct { // for tracing and reporting. type BalanceChangeReason byte +//go:generate stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go + const ( BalanceChangeUnspecified BalanceChangeReason = 0 diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go new file mode 100644 index 0000000000..2d4f1b0890 --- /dev/null +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -0,0 +1,613 @@ +// Copyright 2021 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 . + +package tracetest + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "math/big" + "os" + "path" + "path/filepath" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/params" + + // Force-load live packages, to trigger registration + _ "github.com/ethereum/go-ethereum/eth/tracers/live" +) + +type supplyInfoIssuance struct { + GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"` + Reward *hexutil.Big `json:"reward,omitempty"` + Withdrawals *hexutil.Big `json:"withdrawals,omitempty"` +} + +type supplyInfoBurn struct { + EIP1559 *hexutil.Big `json:"1559,omitempty"` + Blob *hexutil.Big `json:"blob,omitempty"` + Misc *hexutil.Big `json:"misc,omitempty"` +} + +type supplyInfo struct { + Issuance *supplyInfoIssuance `json:"issuance,omitempty"` + Burn *supplyInfoBurn `json:"burn,omitempty"` + + // Block info + Number uint64 `json:"blockNumber"` + Hash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash"` +} + +func emptyBlockGenerationFunc(b *core.BlockGen) {} + +func TestSupplyOmittedFields(t *testing.T) { + var ( + config = *params.MergedTestChainConfig + gspec = &core.Genesis{ + Config: &config, + } + ) + + gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + + out, _, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) { + b.SetPoS() + }) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + expected := supplyInfo{ + Number: 0, + Hash: common.HexToHash("0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"), + ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + } + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyGenesisAlloc(t *testing.T) { + var ( + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + addr2 = crypto.PubkeyToAddress(key2.PublicKey) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + + config = *params.AllEthashProtocolChanges + + gspec = &core.Genesis{ + Config: &config, + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + addr2: {Balance: eth1}, + }, + } + ) + + expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))), + }, + Number: 0, + Hash: common.HexToHash("0xbcc9466e9fc6a8b56f4b29ca353a421ff8b51a0c1a58ca4743b427605b08f2ca"), + ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + } + + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyRewards(t *testing.T) { + var ( + config = *params.AllEthashProtocolChanges + + gspec = &core.Genesis{ + Config: &config, + } + ) + + expected := supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))), + }, + Number: 1, + Hash: common.HexToHash("0xcbb08370505be503dafedc4e96d139ea27aba3cbc580148568b8a307b3f51052"), + ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"), + } + + out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + actual := out[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func TestSupplyEip1559Burn(t *testing.T) { + var ( + config = *params.AllEthashProtocolChanges + + aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa") + // A sender who makes transactions, has some eth1 + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei)) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + + gspec = &core.Genesis{ + Config: &config, + BaseFee: big.NewInt(params.InitialBaseFee), + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + }, + } + ) + + signer := types.LatestSigner(gspec.Config) + + eip1559BlockGenerationFunc := func(b *core.BlockGen) { + txdata := &types.DynamicFeeTx{ + ChainID: gspec.Config.ChainID, + Nonce: 0, + To: &aa, + Gas: 21000, + GasFeeCap: gwei5, + GasTipCap: big.NewInt(2), + } + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + } + + out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + var ( + head = chain.CurrentBlock() + reward = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether)) + burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee) + expected = supplyInfo{ + Issuance: &supplyInfoIssuance{ + Reward: (*hexutil.Big)(reward), + }, + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(burn), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + ) + + actual := out[expected.Number] + compareAsJSON(t, expected, actual) +} + +func TestSupplyWithdrawals(t *testing.T) { + var ( + config = *params.MergedTestChainConfig + gspec = &core.Genesis{ + Config: &config, + } + ) + + withdrawalsBlockGenerationFunc := func(b *core.BlockGen) { + b.SetPoS() + + b.AddWithdrawal(&types.Withdrawal{ + Validator: 42, + Address: common.Address{0xee}, + Amount: 1337, + }) + } + + out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + var ( + head = chain.CurrentBlock() + expected = supplyInfo{ + Issuance: &supplyInfoIssuance{ + Withdrawals: (*hexutil.Big)(big.NewInt(1337000000000)), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + actual = out[expected.Number] + ) + + compareAsJSON(t, expected, actual) +} + +// Tests fund retrieval after contract's selfdestruct. +// Contract A calls contract B which selfdestructs, but B receives eth1 +// after the selfdestruct opcode executes from Contract A. +// Because Contract B is removed only at the end of the transaction +// the ether sent in between is burnt before Cancun hard fork. +func TestSupplySelfdestruct(t *testing.T) { + var ( + config = *params.TestChainConfig + + aa = common.HexToAddress("0x1111111111111111111111111111111111111111") + bb = common.HexToAddress("0x2222222222222222222222222222222222222222") + dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei)) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + + gspec = &core.Genesis{ + Config: &config, + BaseFee: big.NewInt(params.InitialBaseFee), + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + aa: { + Code: common.FromHex("0x61face60f01b6000527322222222222222222222222222222222222222226000806002600080855af160008103603457600080fd5b60008060008034865af1905060008103604c57600080fd5b5050"), + // Nonce: 0, + Balance: big.NewInt(0), + }, + bb: { + Code: common.FromHex("0x6000357fface000000000000000000000000000000000000000000000000000000000000808203602f57610dad80ff5b5050"), + Nonce: 0, + Balance: eth1, + }, + }, + } + ) + + gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + + signer := types.LatestSigner(gspec.Config) + + testBlockGenerationFunc := func(b *core.BlockGen) { + b.SetPoS() + + txdata := &types.LegacyTx{ + Nonce: 0, + To: &aa, + Value: gwei5, + Gas: 150000, + GasPrice: gwei5, + Data: []byte{}, + } + + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + } + + // 1. Test pre Cancun + preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + if err != nil { + t.Fatalf("Pre-cancun failed to test supply tracer: %v", err) + } + + // Check balance at state: + // 1. 0x0000...000dad has 1 ether + // 2. A has 0 ether + // 3. B has 0 ether + statedb, _ := preCancunChain.State() + if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 { + t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", dad, got, exp) + } + if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 { + t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", aa, got, exp) + } + if got, exp := statedb.GetBalance(bb), big.NewInt(0); got.CmpBig(exp) != 0 { + t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + + head := preCancunChain.CurrentBlock() + // Check live trace output + expected := supplyInfo{ + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)), + Misc: (*hexutil.Big)(big.NewInt(5000000000)), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + + actual := preCancunOutput[expected.Number] + + compareAsJSON(t, expected, actual) + + // 2. Test post Cancun + cancunTime := uint64(0) + gspec.Config.ShanghaiTime = &cancunTime + gspec.Config.CancunTime = &cancunTime + + postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + if err != nil { + t.Fatalf("Post-cancun failed to test supply tracer: %v", err) + } + + // Check balance at state: + // 1. 0x0000...000dad has 1 ether + // 3. A has 0 ether + // 3. B has 5 gwei + statedb, _ = postCancunChain.State() + if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 { + t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", dad, got, exp) + } + if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 { + t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", aa, got, exp) + } + if got, exp := statedb.GetBalance(bb), gwei5; got.CmpBig(exp) != 0 { + t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + + // Check live trace output + head = postCancunChain.CurrentBlock() + expected = supplyInfo{ + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)), + }, + Number: 1, + Hash: head.Hash(), + ParentHash: head.ParentHash, + } + + actual = postCancunOutput[expected.Number] + + compareAsJSON(t, expected, actual) +} + +// Tests selfdestructing contract to send its balance to itself (burn). +// It tests both cases of selfdestructing succeding and being reverted. +// - Contract A calls B and D. +// - Contract B selfdestructs and sends the eth1 to itself (Burn amount to be counted). +// - Contract C selfdestructs and sends the eth1 to itself. +// - Contract D calls C and reverts (Burn amount of C +// has to be reverted as well). +func TestSupplySelfdestructItselfAndRevert(t *testing.T) { + var ( + config = *params.TestChainConfig + + aa = common.HexToAddress("0x1111111111111111111111111111111111111111") + bb = common.HexToAddress("0x2222222222222222222222222222222222222222") + cc = common.HexToAddress("0x3333333333333333333333333333333333333333") + dd = common.HexToAddress("0x4444444444444444444444444444444444444444") + key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + addr1 = crypto.PubkeyToAddress(key1.PublicKey) + gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei)) + eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether)) + eth2 = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether)) + eth5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.Ether)) + + gspec = &core.Genesis{ + Config: &config, + // BaseFee: big.NewInt(params.InitialBaseFee), + Alloc: types.GenesisAlloc{ + addr1: {Balance: eth1}, + aa: { + // Contract code in YUL: + // + // object "ContractA" { + // code { + // let B := 0x2222222222222222222222222222222222222222 + // let D := 0x4444444444444444444444444444444444444444 + + // // Call to Contract B + // let resB:= call(gas(), B, 0, 0x0, 0x0, 0, 0) + + // // Call to Contract D + // let resD := call(gas(), D, 0, 0x0, 0x0, 0, 0) + // } + // } + Code: common.FromHex("0x73222222222222222222222222222222222222222273444444444444444444444444444444444444444460006000600060006000865af160006000600060006000865af150505050"), + Balance: common.Big0, + }, + bb: { + // Contract code in YUL: + // + // object "ContractB" { + // code { + // let self := address() + // selfdestruct(self) + // } + // } + Code: common.FromHex("0x3080ff50"), + Balance: eth5, + }, + cc: { + Code: common.FromHex("0x3080ff50"), + Balance: eth1, + }, + dd: { + // Contract code in YUL: + // + // object "ContractD" { + // code { + // let C := 0x3333333333333333333333333333333333333333 + + // // Call to Contract C + // let resC := call(gas(), C, 0, 0x0, 0x0, 0, 0) + + // // Revert + // revert(0, 0) + // } + // } + Code: common.FromHex("0x73333333333333333333333333333333333333333360006000600060006000855af160006000fd5050"), + Balance: eth2, + }, + }, + } + ) + + gspec.Config.TerminalTotalDifficulty = big.NewInt(0) + + signer := types.LatestSigner(gspec.Config) + + testBlockGenerationFunc := func(b *core.BlockGen) { + b.SetPoS() + + txdata := &types.LegacyTx{ + Nonce: 0, + To: &aa, + Value: common.Big0, + Gas: 150000, + GasPrice: gwei5, + Data: []byte{}, + } + + tx := types.NewTx(txdata) + tx, _ = types.SignTx(tx, signer, key1) + + b.AddTx(tx) + } + + output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc) + if err != nil { + t.Fatalf("failed to test supply tracer: %v", err) + } + + // Check balance at state: + // 1. A has 0 ether + // 2. B has 0 ether, burned + // 3. C has 2 ether, selfdestructed but parent D reverted + // 4. D has 1 ether, reverted + statedb, _ := chain.State() + if got, exp := statedb.GetBalance(aa), common.Big0; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", aa, got, exp) + } + if got, exp := statedb.GetBalance(bb), common.Big0; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + if got, exp := statedb.GetBalance(cc), eth1; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + if got, exp := statedb.GetBalance(dd), eth2; got.CmpBig(exp) != 0 { + t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp) + } + + // Check live trace output + block := chain.GetBlockByNumber(1) + + expected := supplyInfo{ + Burn: &supplyInfoBurn{ + EIP1559: (*hexutil.Big)(new(big.Int).Mul(block.BaseFee(), big.NewInt(int64(block.GasUsed())))), + Misc: (*hexutil.Big)(eth5), // 5ETH burned from contract B + }, + Number: 1, + Hash: block.Hash(), + ParentHash: block.ParentHash(), + } + + actual := output[expected.Number] + + compareAsJSON(t, expected, actual) +} + +func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) { + var ( + engine = beacon.New(ethash.NewFaker()) + ) + + traceOutputPath := filepath.ToSlash(t.TempDir()) + traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl") + + // Load supply tracer + tracer, err := tracers.LiveDirectory.New("supply", json.RawMessage(fmt.Sprintf(`{"path":"%s"}`, traceOutputPath))) + if err != nil { + return nil, nil, fmt.Errorf("failed to create call tracer: %v", err) + } + + chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil, nil) + if err != nil { + return nil, nil, fmt.Errorf("failed to create tester chain: %v", err) + } + defer chain.Stop() + + _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, 1, func(i int, b *core.BlockGen) { + b.SetCoinbase(common.Address{1}) + gen(b) + }) + + if n, err := chain.InsertChain(blocks); err != nil { + return nil, chain, fmt.Errorf("block %d: failed to insert into chain: %v", n, err) + } + + // Check and compare the results + file, err := os.OpenFile(traceOutputFilename, os.O_RDONLY, 0666) + if err != nil { + return nil, chain, fmt.Errorf("failed to open output file: %v", err) + } + defer file.Close() + + var output []supplyInfo + scanner := bufio.NewScanner(file) + + for scanner.Scan() { + blockBytes := scanner.Bytes() + + var info supplyInfo + if err := json.Unmarshal(blockBytes, &info); err != nil { + return nil, chain, fmt.Errorf("failed to unmarshal result: %v", err) + } + + output = append(output, info) + } + + return output, chain, nil +} + +func compareAsJSON(t *testing.T, expected interface{}, actual interface{}) { + want, err := json.Marshal(expected) + if err != nil { + t.Fatalf("failed to marshal expected value to JSON: %v", err) + } + + have, err := json.Marshal(actual) + if err != nil { + t.Fatalf("failed to marshal actual value to JSON: %v", err) + } + + if !bytes.Equal(want, have) { + t.Fatalf("incorrect supply info: expected %s, got %s", string(want), string(have)) + } +} diff --git a/eth/tracers/live/gen_supplyinfoburn.go b/eth/tracers/live/gen_supplyinfoburn.go new file mode 100644 index 0000000000..d01eda3975 --- /dev/null +++ b/eth/tracers/live/gen_supplyinfoburn.go @@ -0,0 +1,49 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package live + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*supplyInfoBurnMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s supplyInfoBurn) MarshalJSON() ([]byte, error) { + type supplyInfoBurn struct { + EIP1559 *hexutil.Big `json:"1559,omitempty"` + Blob *hexutil.Big `json:"blob,omitempty"` + Misc *hexutil.Big `json:"misc,omitempty"` + } + var enc supplyInfoBurn + enc.EIP1559 = (*hexutil.Big)(s.EIP1559) + enc.Blob = (*hexutil.Big)(s.Blob) + enc.Misc = (*hexutil.Big)(s.Misc) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *supplyInfoBurn) UnmarshalJSON(input []byte) error { + type supplyInfoBurn struct { + EIP1559 *hexutil.Big `json:"1559,omitempty"` + Blob *hexutil.Big `json:"blob,omitempty"` + Misc *hexutil.Big `json:"misc,omitempty"` + } + var dec supplyInfoBurn + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.EIP1559 != nil { + s.EIP1559 = (*big.Int)(dec.EIP1559) + } + if dec.Blob != nil { + s.Blob = (*big.Int)(dec.Blob) + } + if dec.Misc != nil { + s.Misc = (*big.Int)(dec.Misc) + } + return nil +} diff --git a/eth/tracers/live/gen_supplyinfoissuance.go b/eth/tracers/live/gen_supplyinfoissuance.go new file mode 100644 index 0000000000..e2536ee325 --- /dev/null +++ b/eth/tracers/live/gen_supplyinfoissuance.go @@ -0,0 +1,49 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package live + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +var _ = (*supplyInfoIssuanceMarshaling)(nil) + +// MarshalJSON marshals as JSON. +func (s supplyInfoIssuance) MarshalJSON() ([]byte, error) { + type supplyInfoIssuance struct { + GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"` + Reward *hexutil.Big `json:"reward,omitempty"` + Withdrawals *hexutil.Big `json:"withdrawals,omitempty"` + } + var enc supplyInfoIssuance + enc.GenesisAlloc = (*hexutil.Big)(s.GenesisAlloc) + enc.Reward = (*hexutil.Big)(s.Reward) + enc.Withdrawals = (*hexutil.Big)(s.Withdrawals) + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (s *supplyInfoIssuance) UnmarshalJSON(input []byte) error { + type supplyInfoIssuance struct { + GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"` + Reward *hexutil.Big `json:"reward,omitempty"` + Withdrawals *hexutil.Big `json:"withdrawals,omitempty"` + } + var dec supplyInfoIssuance + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.GenesisAlloc != nil { + s.GenesisAlloc = (*big.Int)(dec.GenesisAlloc) + } + if dec.Reward != nil { + s.Reward = (*big.Int)(dec.Reward) + } + if dec.Withdrawals != nil { + s.Withdrawals = (*big.Int)(dec.Withdrawals) + } + return nil +} diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go new file mode 100644 index 0000000000..0c9141e99d --- /dev/null +++ b/eth/tracers/live/supply.go @@ -0,0 +1,310 @@ +package live + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "path/filepath" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/log" + "gopkg.in/natefinch/lumberjack.v2" +) + +func init() { + tracers.LiveDirectory.Register("supply", newSupply) +} + +type supplyInfoIssuance struct { + GenesisAlloc *big.Int `json:"genesisAlloc,omitempty"` + Reward *big.Int `json:"reward,omitempty"` + Withdrawals *big.Int `json:"withdrawals,omitempty"` +} + +//go:generate go run github.com/fjl/gencodec -type supplyInfoIssuance -field-override supplyInfoIssuanceMarshaling -out gen_supplyinfoissuance.go +type supplyInfoIssuanceMarshaling struct { + GenesisAlloc *hexutil.Big + Reward *hexutil.Big + Withdrawals *hexutil.Big +} + +type supplyInfoBurn struct { + EIP1559 *big.Int `json:"1559,omitempty"` + Blob *big.Int `json:"blob,omitempty"` + Misc *big.Int `json:"misc,omitempty"` +} + +//go:generate go run github.com/fjl/gencodec -type supplyInfoBurn -field-override supplyInfoBurnMarshaling -out gen_supplyinfoburn.go +type supplyInfoBurnMarshaling struct { + EIP1559 *hexutil.Big + Blob *hexutil.Big + Misc *hexutil.Big +} + +type supplyInfo struct { + Issuance *supplyInfoIssuance `json:"issuance,omitempty"` + Burn *supplyInfoBurn `json:"burn,omitempty"` + + // Block info + Number uint64 `json:"blockNumber"` + Hash common.Hash `json:"hash"` + ParentHash common.Hash `json:"parentHash"` +} + +type supplyTxCallstack struct { + calls []supplyTxCallstack + burn *big.Int +} + +type supply struct { + delta supplyInfo + txCallstack []supplyTxCallstack // Callstack for current transaction + logger *lumberjack.Logger +} + +type supplyTracerConfig struct { + Path string `json:"path"` // Path to the directory where the tracer logs will be stored + MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes. +} + +func newSupply(cfg json.RawMessage) (*tracing.Hooks, error) { + var config supplyTracerConfig + if cfg != nil { + if err := json.Unmarshal(cfg, &config); err != nil { + return nil, fmt.Errorf("failed to parse config: %v", err) + } + } + if config.Path == "" { + return nil, errors.New("supply tracer output path is required") + } + + // Store traces in a rotating file + logger := &lumberjack.Logger{ + Filename: filepath.Join(config.Path, "supply.jsonl"), + } + if config.MaxSize > 0 { + logger.MaxSize = config.MaxSize + } + + t := &supply{ + delta: newSupplyInfo(), + logger: logger, + } + return &tracing.Hooks{ + OnBlockStart: t.OnBlockStart, + OnBlockEnd: t.OnBlockEnd, + OnGenesisBlock: t.OnGenesisBlock, + OnTxStart: t.OnTxStart, + OnBalanceChange: t.OnBalanceChange, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnClose: t.OnClose, + }, nil +} + +func newSupplyInfo() supplyInfo { + return supplyInfo{ + Issuance: &supplyInfoIssuance{ + GenesisAlloc: big.NewInt(0), + Reward: big.NewInt(0), + Withdrawals: big.NewInt(0), + }, + Burn: &supplyInfoBurn{ + EIP1559: big.NewInt(0), + Blob: big.NewInt(0), + Misc: big.NewInt(0), + }, + + Number: 0, + Hash: common.Hash{}, + ParentHash: common.Hash{}, + } +} + +func (s *supply) resetDelta() { + s.delta = newSupplyInfo() +} + +func (s *supply) OnBlockStart(ev tracing.BlockEvent) { + s.resetDelta() + + s.delta.Number = ev.Block.NumberU64() + s.delta.Hash = ev.Block.Hash() + s.delta.ParentHash = ev.Block.ParentHash() + + // Calculate Burn for this block + if ev.Block.BaseFee() != nil { + burn := new(big.Int).Mul(new(big.Int).SetUint64(ev.Block.GasUsed()), ev.Block.BaseFee()) + s.delta.Burn.EIP1559 = burn + } + // Blob burnt gas + if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil { + var ( + excess = *ev.Block.ExcessBlobGas() + baseFee = eip4844.CalcBlobFee(excess) + burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee) + ) + s.delta.Burn.Blob = burn + } +} + +func (s *supply) OnBlockEnd(err error) { + s.write(s.delta) +} + +func (s *supply) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) { + s.resetDelta() + + s.delta.Number = b.NumberU64() + s.delta.Hash = b.Hash() + s.delta.ParentHash = b.ParentHash() + + // Initialize supply with total allocation in genesis block + for _, account := range alloc { + s.delta.Issuance.GenesisAlloc.Add(s.delta.Issuance.GenesisAlloc, account.Balance) + } + + s.write(s.delta) +} + +func (s *supply) OnBalanceChange(a common.Address, prevBalance, newBalance *big.Int, reason tracing.BalanceChangeReason) { + diff := new(big.Int).Sub(newBalance, prevBalance) + + // NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in OnGenesisBlock + switch reason { + case tracing.BalanceIncreaseRewardMineUncle: + case tracing.BalanceIncreaseRewardMineBlock: + s.delta.Issuance.Reward.Add(s.delta.Issuance.Reward, diff) + case tracing.BalanceIncreaseWithdrawal: + s.delta.Issuance.Withdrawals.Add(s.delta.Issuance.Withdrawals, diff) + case tracing.BalanceDecreaseSelfdestructBurn: + // BalanceDecreaseSelfdestructBurn is non-reversible as it happens + // at the end of the transaction. + s.delta.Burn.Misc.Sub(s.delta.Burn.Misc, diff) + default: + return + } +} + +func (s *supply) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) { + s.txCallstack = make([]supplyTxCallstack, 0, 1) +} + +// internalTxsHandler handles internal transactions burned amount +func (s *supply) internalTxsHandler(call *supplyTxCallstack) { + // Handle Burned amount + if call.burn != nil { + s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn) + } + + if len(call.calls) > 0 { + // Recursivelly handle internal calls + for _, call := range call.calls { + callCopy := call + s.internalTxsHandler(&callCopy) + } + } +} + +func (s *supply) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + call := supplyTxCallstack{ + calls: make([]supplyTxCallstack, 0), + } + + // This is a special case of burned amount which has to be handled here + // which happens when type == selfdestruct and from == to. + if vm.OpCode(typ) == vm.SELFDESTRUCT && from == to && value.Cmp(common.Big0) == 1 { + call.burn = value + } + + // Append call to the callstack, so we can fill the details in CaptureExit + s.txCallstack = append(s.txCallstack, call) +} + +func (s *supply) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if depth == 0 { + // No need to handle Burned amount if transaction is reverted + if !reverted { + s.internalTxsHandler(&s.txCallstack[0]) + } + return + } + + size := len(s.txCallstack) + if size <= 1 { + return + } + // Pop call + call := s.txCallstack[size-1] + s.txCallstack = s.txCallstack[:size-1] + size -= 1 + + // In case of a revert, we can drop the call and all its subcalls. + // Caution, that this has to happen after popping the call from the stack. + if reverted { + return + } + s.txCallstack[size-1].calls = append(s.txCallstack[size-1].calls, call) +} + +func (s *supply) OnClose() { + if err := s.logger.Close(); err != nil { + log.Warn("failed to close supply tracer log file", "error", err) + } +} + +func (s *supply) write(data any) { + supply, ok := data.(supplyInfo) + if !ok { + log.Warn("failed to cast supply tracer data on write to log file") + return + } + + // Remove empty fields + if supply.Issuance.GenesisAlloc.Sign() == 0 { + supply.Issuance.GenesisAlloc = nil + } + + if supply.Issuance.Reward.Sign() == 0 { + supply.Issuance.Reward = nil + } + + if supply.Issuance.Withdrawals.Sign() == 0 { + supply.Issuance.Withdrawals = nil + } + + if supply.Issuance.GenesisAlloc == nil && supply.Issuance.Reward == nil && supply.Issuance.Withdrawals == nil { + supply.Issuance = nil + } + + if supply.Burn.EIP1559.Sign() == 0 { + supply.Burn.EIP1559 = nil + } + + if supply.Burn.Blob.Sign() == 0 { + supply.Burn.Blob = nil + } + + if supply.Burn.Misc.Sign() == 0 { + supply.Burn.Misc = nil + } + + if supply.Burn.EIP1559 == nil && supply.Burn.Blob == nil && supply.Burn.Misc == nil { + supply.Burn = nil + } + + out, _ := json.Marshal(supply) + if _, err := s.logger.Write(out); err != nil { + log.Warn("failed to write to supply tracer log file", "error", err) + } + if _, err := s.logger.Write([]byte{'\n'}); err != nil { + log.Warn("failed to write to supply tracer log file", "error", err) + } +} From d38b88a5a10800e1632833e284c6500c240c012e Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 3 Jun 2024 19:17:12 +0800 Subject: [PATCH 046/196] core/state: introduce stateupdate structure (#29530) * core/state: introduce stateUpate structure * core/state: remove outdated function description * core/state: address comments --- core/genesis_test.go | 4 +- core/state/state_object.go | 270 +++++++++++----------- core/state/statedb.go | 391 ++++++++++++++------------------ core/state/statedb_fuzz_test.go | 30 ++- core/state/stateupdate.go | 133 +++++++++++ 5 files changed, 462 insertions(+), 366 deletions(-) create mode 100644 core/state/stateupdate.go diff --git a/core/genesis_test.go b/core/genesis_test.go index 31401e214c..ab408327d4 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -304,7 +304,7 @@ func TestVerkleGenesisCommit(t *testing.T) { }, } - expected := common.Hex2Bytes("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b") + expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b") got := genesis.ToBlock().Root().Bytes() if !bytes.Equal(got, expected) { t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) @@ -314,7 +314,7 @@ func TestVerkleGenesisCommit(t *testing.T) { triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults}) block := genesis.MustCommit(db, triedb) if !bytes.Equal(block.Root().Bytes(), expected) { - t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) + t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root()) } // Test that the trie is verkle diff --git a/core/state/state_object.go b/core/state/state_object.go index 252dcdf2b0..b7a215bd17 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -19,9 +19,7 @@ package state import ( "bytes" "fmt" - "io" "maps" - "sync" "time" "github.com/ethereum/go-ethereum/common" @@ -34,14 +32,6 @@ import ( "github.com/holiman/uint256" ) -// hasherPool holds a pool of hashers used by state objects during concurrent -// trie updates. -var hasherPool = sync.Pool{ - New: func() interface{} { - return crypto.NewKeccakState() - }, -} - type Storage map[common.Hash]common.Hash func (s Storage) Copy() Storage { @@ -65,9 +55,20 @@ type stateObject struct { trie Trie // storage trie, which becomes non-nil on first access code []byte // contract bytecode, which gets set when code is loaded - originStorage Storage // Storage cache of original entries to dedup rewrites - pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block - dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction + originStorage Storage // Storage entries that have been accessed within the current block + dirtyStorage Storage // Storage entries that have been modified within the current transaction + pendingStorage Storage // Storage entries that have been modified within the current block + + // uncommittedStorage tracks a set of storage entries that have been modified + // but not yet committed since the "last commit operation", along with their + // original values before mutation. + // + // Specifically, the commit will be performed after each transaction before + // the byzantium fork, therefore the map is already reset at the transaction + // boundary; however post the byzantium fork, the commit will only be performed + // at the end of block, this set essentially tracks all the modifications + // made within the block. + uncommittedStorage Storage // Cache flags. dirtyCode bool // true if the code was updated @@ -96,22 +97,18 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s acct = types.NewEmptyStateAccount() } return &stateObject{ - db: db, - address: address, - addrHash: crypto.Keccak256Hash(address[:]), - origin: origin, - data: *acct, - originStorage: make(Storage), - pendingStorage: make(Storage), - dirtyStorage: make(Storage), + db: db, + address: address, + addrHash: crypto.Keccak256Hash(address[:]), + origin: origin, + data: *acct, + originStorage: make(Storage), + dirtyStorage: make(Storage), + pendingStorage: make(Storage), + uncommittedStorage: make(Storage), } } -// EncodeRLP implements rlp.Encoder. -func (s *stateObject) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, &s.data) -} - func (s *stateObject) markSelfdestructed() { s.selfDestructed = true } @@ -160,7 +157,7 @@ func (s *stateObject) getPrefetchedTrie() Trie { return s.db.prefetcher.trie(s.addrHash, s.data.Root) } -// GetState retrieves a value from the account storage trie. +// GetState retrieves a value associated with the given storage key. func (s *stateObject) GetState(key common.Hash) common.Hash { value, _ := s.getState(key) return value @@ -177,7 +174,8 @@ func (s *stateObject) getState(key common.Hash) (common.Hash, common.Hash) { return origin, origin } -// GetCommittedState retrieves a value from the committed account storage trie. +// GetCommittedState retrieves the value associated with the specific key +// without any mutations caused in the current execution. func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { // If we have a pending write or clean cached, return that if value, pending := s.pendingStorage[key]; pending { @@ -193,6 +191,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { // have been handles via pendingStorage above. // 2) we don't have new values, and can deliver empty response back if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed { + s.originStorage[key] = common.Hash{} // track the empty slot as origin value return common.Hash{} } // If no live objects are available, attempt to use snapshots @@ -272,17 +271,26 @@ func (s *stateObject) setState(key common.Hash, value common.Hash, origin common func (s *stateObject) finalise() { slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) for key, value := range s.dirtyStorage { - // If the slot is different from its original value, move it into the - // pending area to be committed at the end of the block (and prefetch - // the pathways). - if value != s.originStorage[key] { - s.pendingStorage[key] = value - slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure + if origin, exist := s.uncommittedStorage[key]; exist && origin == value { + // The slot is reverted to its original value, delete the entry + // to avoid thrashing the data structures. + delete(s.uncommittedStorage, key) + } else if exist { + // The slot is modified to another value and the slot has been + // tracked for commit, do nothing here. } else { - // Otherwise, the slot was reverted to its original value, remove it - // from the pending area to avoid thrashing the data structure. - delete(s.pendingStorage, key) + // The slot is different from its original value and hasn't been + // tracked for commit yet. + s.uncommittedStorage[key] = s.GetCommittedState(key) + slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure } + // Aggregate the dirty storage slots into the pending area. It might + // be possible that the value of tracked slot here is same with the + // one in originStorage (e.g. the slot was modified in tx_a and then + // modified back in tx_b). We can't blindly remove it from pending + // map as the dirty slot might have been committed already (before the + // byzantium fork) and entry is necessary to modify the value back. + s.pendingStorage[key] = value } if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil { @@ -308,7 +316,7 @@ func (s *stateObject) finalise() { // It assumes all the dirty storage slots have been finalized before. func (s *stateObject) updateTrie() (Trie, error) { // Short circuit if nothing changed, don't bother with hashing anything - if len(s.pendingStorage) == 0 { + if len(s.uncommittedStorage) == 0 { return s.trie, nil } // Retrieve a pretecher populated trie, or fall back to the database @@ -325,20 +333,8 @@ func (s *stateObject) updateTrie() (Trie, error) { return nil, err } } - - // The snapshot storage map for the object - var ( - storage map[common.Hash][]byte - origin map[common.Hash][]byte - ) - // Insert all the pending storage updates into the trie - usedStorage := make([][]byte, 0, len(s.pendingStorage)) - - hasher := hasherPool.Get().(crypto.KeccakState) - defer hasherPool.Put(hasher) - - // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes - // in circumstances similar to the following: + // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes + // in circumstances similar to the following: // // Consider nodes `A` and `B` who share the same full node parent `P` and have no other siblings. // During the execution of a block: @@ -347,21 +343,23 @@ func (s *stateObject) updateTrie() (Trie, error) { // If the deletion is handled first, then `P` would be left with only one child, thus collapsed // into a shortnode. This requires `B` to be resolved from disk. // Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved. - var deletions []common.Hash - for key, value := range s.pendingStorage { + var ( + deletions []common.Hash + used = make([][]byte, 0, len(s.uncommittedStorage)) + ) + for key, origin := range s.uncommittedStorage { // Skip noop changes, persist actual changes - if value == s.originStorage[key] { + value, exist := s.pendingStorage[key] + if value == origin { + log.Error("Storage update was noop", "address", s.address, "slot", key) + continue + } + if !exist { + log.Error("Storage slot is not found in pending area", s.address, "slot", key) continue } - prev := s.originStorage[key] - s.originStorage[key] = value - - var encoded []byte // rlp-encoded value to be used by the snapshot if (value != common.Hash{}) { - // Encoding []byte cannot fail, ok to ignore the error. - trimmed := common.TrimLeftZeroes(value[:]) - encoded, _ = rlp.EncodeToBytes(trimmed) - if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil { + if err := tr.UpdateStorage(s.address, key[:], common.TrimLeftZeroes(value[:])); err != nil { s.db.setError(err) return nil, err } @@ -369,39 +367,8 @@ func (s *stateObject) updateTrie() (Trie, error) { } else { deletions = append(deletions, key) } - // Cache the mutated storage slots until commit - if storage == nil { - s.db.storagesLock.Lock() - if storage = s.db.storages[s.addrHash]; storage == nil { - storage = make(map[common.Hash][]byte) - s.db.storages[s.addrHash] = storage - } - s.db.storagesLock.Unlock() - } - khash := crypto.HashData(hasher, key[:]) - storage[khash] = encoded // encoded will be nil if it's deleted - - // Cache the original value of mutated storage slots - if origin == nil { - s.db.storagesLock.Lock() - if origin = s.db.storagesOrigin[s.address]; origin == nil { - origin = make(map[common.Hash][]byte) - s.db.storagesOrigin[s.address] = origin - } - s.db.storagesLock.Unlock() - } - // Track the original value of slot only if it's mutated first time - if _, ok := origin[khash]; !ok { - if prev == (common.Hash{}) { - origin[khash] = nil // nil if it was not present previously - } else { - // Encoding []byte cannot fail, ok to ignore the error. - b, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(prev[:])) - origin[khash] = b - } - } // Cache the items for preloading - usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure + used = append(used, common.CopyBytes(key[:])) // Copy needed for closure } for _, key := range deletions { if err := tr.DeleteStorage(s.address, key[:]); err != nil { @@ -410,15 +377,10 @@ func (s *stateObject) updateTrie() (Trie, error) { } s.db.StorageDeleted.Add(1) } - // If no slots were touched, issue a warning as we shouldn't have done all - // the above work in the first place - if len(usedStorage) == 0 { - log.Error("State object update was noop", "addr", s.address, "slots", len(s.pendingStorage)) - } if s.db.prefetcher != nil { - s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage) + s.db.prefetcher.used(s.addrHash, s.data.Root, used) } - s.pendingStorage = make(Storage) // reset pending map + s.uncommittedStorage = make(Storage) // empties the commit markers return tr, nil } @@ -434,30 +396,79 @@ func (s *stateObject) updateRoot() { s.data.Root = tr.Hash() } -// commit obtains a set of dirty storage trie nodes and updates the account data. -// The returned set can be nil if nothing to commit. This function assumes all -// storage mutations have already been flushed into trie by updateRoot. +// commitStorage overwrites the clean storage with the storage changes and +// fulfills the storage diffs into the given accountUpdate struct. +func (s *stateObject) commitStorage(op *accountUpdate) { + var ( + buf = crypto.NewKeccakState() + encode = func(val common.Hash) []byte { + if val == (common.Hash{}) { + return nil + } + blob, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(val[:])) + return blob + } + ) + for key, val := range s.pendingStorage { + // Skip the noop storage changes, it might be possible the value + // of tracked slot is same in originStorage and pendingStorage + // map, e.g. the storage slot is modified in tx_a and then reset + // back in tx_b. + if val == s.originStorage[key] { + continue + } + hash := crypto.HashData(buf, key[:]) + if op.storages == nil { + op.storages = make(map[common.Hash][]byte) + } + op.storages[hash] = encode(val) + if op.storagesOrigin == nil { + op.storagesOrigin = make(map[common.Hash][]byte) + } + op.storagesOrigin[hash] = encode(s.originStorage[key]) + + // Overwrite the clean value of storage slots + s.originStorage[key] = val + } + s.pendingStorage = make(Storage) +} + +// commit obtains the account changes (metadata, storage slots, code) caused by +// state execution along with the dirty storage trie nodes. // // Note, commit may run concurrently across all the state objects. Do not assume // thread-safe access to the statedb. -func (s *stateObject) commit() (*trienode.NodeSet, error) { - // Short circuit if trie is not even loaded, don't bother with committing anything - if s.trie == nil { - s.origin = s.data.Copy() - return nil, nil +func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) { + // commit the account metadata changes + op := &accountUpdate{ + address: s.address, + data: types.SlimAccountRLP(s.data), + } + if s.origin != nil { + op.origin = types.SlimAccountRLP(*s.origin) + } + // commit the contract code if it's modified + if s.dirtyCode { + op.code = &contractCode{ + hash: common.BytesToHash(s.CodeHash()), + blob: s.code, + } + s.dirtyCode = false // reset the dirty flag + } + // Commit storage changes and the associated storage trie + s.commitStorage(op) + if len(op.storages) == 0 { + // nothing changed, don't bother to commit the trie + s.origin = s.data.Copy() + return op, nil, nil } - // The trie is currently in an open state and could potentially contain - // cached mutations. Call commit to acquire a set of nodes that have been - // modified, the set can be nil if nothing to commit. root, nodes, err := s.trie.Commit(false) if err != nil { - return nil, err + return nil, nil, err } s.data.Root = root - - // Update original account data after commit s.origin = s.data.Copy() - return nodes, nil + return op, nodes, nil } // AddBalance adds amount to s's balance. @@ -500,18 +511,19 @@ func (s *stateObject) setBalance(amount *uint256.Int) { func (s *stateObject) deepCopy(db *StateDB) *stateObject { obj := &stateObject{ - db: db, - address: s.address, - addrHash: s.addrHash, - origin: s.origin, - data: s.data, - code: s.code, - originStorage: s.originStorage.Copy(), - pendingStorage: s.pendingStorage.Copy(), - dirtyStorage: s.dirtyStorage.Copy(), - dirtyCode: s.dirtyCode, - selfDestructed: s.selfDestructed, - newContract: s.newContract, + db: db, + address: s.address, + addrHash: s.addrHash, + origin: s.origin, + data: s.data, + code: s.code, + originStorage: s.originStorage.Copy(), + pendingStorage: s.pendingStorage.Copy(), + dirtyStorage: s.dirtyStorage.Copy(), + uncommittedStorage: s.uncommittedStorage.Copy(), + dirtyCode: s.dirtyCode, + selfDestructed: s.selfDestructed, + newContract: s.newContract, } if s.trie != nil { obj.trie = db.db.CopyTrie(s.trie) diff --git a/core/state/statedb.go b/core/state/statedb.go index fe262d4695..659c500c3b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -18,6 +18,7 @@ package state import ( + "errors" "fmt" "maps" "math/big" @@ -95,15 +96,6 @@ type StateDB struct { // It will be updated when the Commit is called. originalRoot common.Hash - // These maps hold the state changes (including the corresponding - // original value) that occurred in this **block**. - accounts map[common.Hash][]byte // The mutated accounts in 'slim RLP' encoding - accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding - - storages map[common.Hash]map[common.Hash][]byte // The mutated slots in prefix-zero trimmed rlp format - storagesOrigin map[common.Address]map[common.Hash][]byte // The original value of mutated slots in prefix-zero trimmed rlp format - storagesLock sync.Mutex // Mutex protecting the maps during concurrent updates/commits - // This map holds 'live' objects, which will get modified while // processing a state transition. stateObjects map[common.Address]*stateObject @@ -171,9 +163,6 @@ type StateDB struct { StorageUpdated atomic.Int64 AccountDeleted int StorageDeleted atomic.Int64 - - // Testing hooks - onCommit func(states *triestate.Set) // Hook invoked when commit is performed } // New creates a new state from a given trie. @@ -187,10 +176,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) trie: tr, originalRoot: root, snaps: snaps, - accounts: make(map[common.Hash][]byte), - storages: make(map[common.Hash]map[common.Hash][]byte), - accountsOrigin: make(map[common.Address][]byte), - storagesOrigin: make(map[common.Address]map[common.Hash][]byte), stateObjects: make(map[common.Address]*stateObject), stateObjectsDestruct: make(map[common.Address]*types.StateAccount), mutations: make(map[common.Address]*mutation), @@ -380,7 +365,7 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { return common.Hash{} } -// GetState retrieves a value from the given account's storage trie. +// GetState retrieves the value associated with the specific key. func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { @@ -389,7 +374,8 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { return common.Hash{} } -// GetCommittedState retrieves a value from the given account's committed storage trie. +// GetCommittedState retrieves the value associated with the specific key +// without any mutations caused in the current execution. func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { stateObject := s.getStateObject(addr) if stateObject != nil { @@ -557,22 +543,6 @@ func (s *StateDB) updateStateObject(obj *stateObject) { if obj.dirtyCode { s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code) } - // Cache the data until commit. Note, this update mechanism is not symmetric - // to the deletion, because whereas it is enough to track account updates - // at commit time, deletions need tracking at transaction boundary level to - // ensure we capture state clearing. - s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data) - - // Track the original value of mutated account, nil means it was not present. - // Skip if it has been tracked (because updateStateObject may be called - // multiple times in a block). - if _, ok := s.accountsOrigin[obj.address]; !ok { - if obj.origin == nil { - s.accountsOrigin[obj.address] = nil - } else { - s.accountsOrigin[obj.address] = types.SlimAccountRLP(*obj.origin) - } - } } // deleteStateObject removes the given object from the state trie. @@ -691,10 +661,6 @@ func (s *StateDB) Copy() *StateDB { trie: s.db.CopyTrie(s.trie), hasher: crypto.NewKeccakState(), originalRoot: s.originalRoot, - accounts: copySet(s.accounts), - storages: copy2DSet(s.storages), - accountsOrigin: copySet(s.accountsOrigin), - storagesOrigin: copy2DSet(s.storagesOrigin), stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), mutations: make(map[common.Address]*mutation, len(s.mutations)), @@ -803,13 +769,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { if _, ok := s.stateObjectsDestruct[obj.address]; !ok { s.stateObjectsDestruct[obj.address] = obj.origin } - // Note, we can't do this only at the end of a block because multiple - // transactions within the same block might self destruct and then - // resurrect an account; but the snapshotter needs both events. - delete(s.accounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.storages, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect) - delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect) - delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect) } else { obj.finalise() s.markUpdate(addr) @@ -1020,10 +979,9 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r } // deleteStorage is designed to delete the storage trie of a designated account. -// It could potentially be terminated if the storage size is excessively large, -// potentially leading to an out-of-memory panic. The function will make an attempt -// to utilize an efficient strategy if the associated state snapshot is reachable; -// otherwise, it will resort to a less-efficient approach. +// The function will make an attempt to utilize an efficient strategy if the +// associated state snapshot is reachable; otherwise, it will resort to a less +// efficient approach. func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { var ( start = time.Now() @@ -1058,75 +1016,61 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root } // handleDestruction processes all destruction markers and deletes the account -// and associated storage slots if necessary. There are four possible situations -// here: +// and associated storage slots if necessary. There are four potential scenarios +// as following: // -// - the account was not existent and be marked as destructed -// -// - the account was not existent and be marked as destructed, -// however, it's resurrected later in the same block. -// -// - the account was existent and be marked as destructed -// -// - the account was existent and be marked as destructed, -// however it's resurrected later in the same block. +// (a) the account was not existent and be marked as destructed +// (b) the account was not existent and be marked as destructed, +// however, it's resurrected later in the same block. +// (c) the account was existent and be marked as destructed +// (d) the account was existent and be marked as destructed, +// however it's resurrected later in the same block. // // In case (a), nothing needs be deleted, nil to nil transition can be ignored. -// // In case (b), nothing needs be deleted, nil is used as the original value for // newly created account and storages -// // In case (c), **original** account along with its storages should be deleted, // with their values be tracked as original value. -// // In case (d), **original** account along with its storages should be deleted, // with their values be tracked as original value. -func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) error { - // Short circuit if geth is running with hash mode. This procedure can consume - // considerable time and storage deletion isn't supported in hash mode, thus - // preemptively avoiding unnecessary expenses. - if s.db.TrieDB().Scheme() == rawdb.HashScheme { - return nil - } +func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trienode.NodeSet, error) { + var ( + nodes []*trienode.NodeSet + buf = crypto.NewKeccakState() + deletes = make(map[common.Hash]*accountDelete) + ) for addr, prev := range s.stateObjectsDestruct { - // The original account was non-existing, and it's marked as destructed - // in the scope of block. It can be case (a) or (b). - // - for (a), skip it without doing anything. - // - for (b), track account's original value as nil. It may overwrite - // the data cached in s.accountsOrigin set by 'updateStateObject'. - addrHash := crypto.Keccak256Hash(addr[:]) + // The account was non-existent, and it's marked as destructed in the scope + // of block. It can be either case (a) or (b) and will be interpreted as + // null->null state transition. + // - for (a), skip it without doing anything + // - for (b), the resurrected account with nil as original will be handled afterwards if prev == nil { - if _, ok := s.accounts[addrHash]; ok { - s.accountsOrigin[addr] = nil // case (b) - } continue } - // It can overwrite the data in s.accountsOrigin set by 'updateStateObject'. - s.accountsOrigin[addr] = types.SlimAccountRLP(*prev) // case (c) or (d) + // The account was existent, it can be either case (c) or (d). + addrHash := crypto.HashData(buf, addr.Bytes()) + op := &accountDelete{ + address: addr, + origin: types.SlimAccountRLP(*prev), + } + deletes[addrHash] = op - // Short circuit if the storage was empty. + // Short circuit if the origin storage was empty. if prev.Root == types.EmptyRootHash { continue } - // Remove storage slots belong to the account. + // Remove storage slots belonging to the account. slots, set, err := s.deleteStorage(addr, addrHash, prev.Root) if err != nil { - return fmt.Errorf("failed to delete storage, err: %w", err) - } - if s.storagesOrigin[addr] == nil { - s.storagesOrigin[addr] = slots - } else { - // It can overwrite the data in s.storagesOrigin[addrHash] set by - // 'object.updateTrie'. - for key, val := range slots { - s.storagesOrigin[addr][key] = val - } - } - if err := nodes.Merge(set); err != nil { - return err + return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err) } + op.storagesOrigin = slots + + // Aggregate the associated trie node changes. + nodes = append(nodes, set) } - return nil + return deletes, nodes, nil } // GetTrie returns the account trie. @@ -1134,18 +1078,12 @@ func (s *StateDB) GetTrie() Trie { return s.trie } -// Commit writes the state to the underlying in-memory trie database. -// Once the state is committed, tries cached in stateDB (including account -// trie, storage tries) will no longer be functional. A new state instance -// must be created with new root and updated database for accessing post- -// commit states. -// -// The associated block number of the state transition is also provided -// for more chain context. -func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) { +// commit gathers the state mutations accumulated along with the associated +// trie changes, resetting all internal flags with the new state as the base. +func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // Short circuit in case any database failure occurred earlier. if s.dbErr != nil { - return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) + return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries s.IntermediateRoot(deleteEmptyObjects) @@ -1156,19 +1094,56 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er accountTrieNodesDeleted int storageTrieNodesUpdated int storageTrieNodesDeleted int - nodes = trienode.NewMergedNodeSet() + + lock sync.Mutex // protect two maps below + nodes = trienode.NewMergedNodeSet() // aggregated trie nodes + updates = make(map[common.Hash]*accountUpdate, len(s.mutations)) // aggregated account updates + + // merge aggregates the dirty trie nodes into the global set. + // + // Given that some accounts may be destroyed and then recreated within + // the same block, it's possible that a node set with the same owner + // may already exists. In such cases, these two sets are combined, with + // the later one overwriting the previous one if any nodes are modified + // or deleted in both sets. + // + // merge run concurrently across all the state objects and account trie. + merge = func(set *trienode.NodeSet) error { + if set == nil { + return nil + } + lock.Lock() + defer lock.Unlock() + + updates, deletes := set.Size() + if set.Owner == (common.Hash{}) { + accountTrieNodesUpdated += updates + accountTrieNodesDeleted += deletes + } else { + storageTrieNodesUpdated += updates + storageTrieNodesDeleted += deletes + } + return nodes.Merge(set) + } ) - // Handle all state deletions first - if err := s.handleDestruction(nodes); err != nil { - return common.Hash{}, err + // Given that some accounts could be destroyed and then recreated within + // the same block, account deletions must be processed first. This ensures + // that the storage trie nodes deleted during destruction and recreated + // during subsequent resurrection can be combined correctly. + deletes, delNodes, err := s.handleDestruction() + if err != nil { + return nil, err + } + for _, set := range delNodes { + if err := merge(set); err != nil { + return nil, err + } } // Handle all state updates afterwards, concurrently to one another to shave // off some milliseconds from the commit operation. Also accumulate the code // writes to run in parallel with the computations. - start := time.Now() var ( - code = s.db.DiskDB().NewBatch() - lock sync.Mutex + start = time.Now() root common.Hash workers errgroup.Group ) @@ -1189,15 +1164,8 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } root = newroot - // Merge the dirty nodes of account trie into global set - lock.Lock() - defer lock.Unlock() - - if set != nil { - if err = nodes.Merge(set); err != nil { - return err - } - accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size() + if err := merge(set); err != nil { + return err } s.AccountCommits = time.Since(start) return nil @@ -1215,49 +1183,29 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er } // Write any contract code associated with the state object obj := s.stateObjects[addr] - if obj.code != nil && obj.dirtyCode { - rawdb.WriteCode(code, common.BytesToHash(obj.CodeHash()), obj.code) - obj.dirtyCode = false + if obj == nil { + return nil, errors.New("missing state object") } // Run the storage updates concurrently to one another workers.Go(func() error { // Write any storage changes in the state object to its storage trie - set, err := obj.commit() + update, set, err := obj.commit() if err != nil { return err } - // Merge the dirty nodes of storage trie into global set. It is possible - // that the account was destructed and then resurrected in the same block. - // In this case, the node set is shared by both accounts. - lock.Lock() - defer lock.Unlock() - - if set != nil { - if err = nodes.Merge(set); err != nil { - return err - } - updates, deleted := set.Size() - storageTrieNodesUpdated += updates - storageTrieNodesDeleted += deleted + if err := merge(set); err != nil { + return err } + lock.Lock() + updates[obj.addrHash] = update + lock.Unlock() s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime return nil }) } - // Schedule the code commits to run concurrently too. This shouldn't really - // take much since we don't often commit code, but since it's disk access, - // it's always yolo. - workers.Go(func() error { - if code.ValueSize() > 0 { - if err := code.Write(); err != nil { - log.Crit("Failed to commit dirty codes", "error", err) - } - } - return nil - }) // Wait for everything to finish and update the metrics if err := workers.Wait(); err != nil { - return common.Hash{}, err + return nil, err } accountUpdatedMeter.Mark(int64(s.AccountUpdated)) storageUpdatedMeter.Mark(s.StorageUpdated.Load()) @@ -1271,53 +1219,78 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er s.StorageUpdated.Store(0) s.StorageDeleted.Store(0) - // If snapshotting is enabled, update the snapshot tree with this new version - if s.snap != nil { - start = time.Now() - // Only update if there's a state transition (skip empty Clique blocks) - if parent := s.snap.Root(); parent != root { - if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { - log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) + // Clear all internal flags and update state root at the end. + s.mutations = make(map[common.Address]*mutation) + s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) + + origin := s.originalRoot + s.originalRoot = root + return newStateUpdate(origin, root, deletes, updates, nodes), nil +} + +// commitAndFlush is a wrapper of commit which also commits the state mutations +// to the configured data stores. +func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateUpdate, error) { + ret, err := s.commit(deleteEmptyObjects) + if err != nil { + return nil, err + } + // Commit dirty contract code if any exists + if db := s.db.DiskDB(); db != nil && len(ret.codes) > 0 { + batch := db.NewBatch() + for _, code := range ret.codes { + rawdb.WriteCode(batch, code.hash, code.blob) + } + if err := batch.Write(); err != nil { + return nil, err + } + } + if !ret.empty() { + // If snapshotting is enabled, update the snapshot tree with this new version + if s.snap != nil { + s.snap = nil + + start := time.Now() + if err := s.snaps.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil { + log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err) } - // Keep TriesInMemory diff layers in the memory, persistent layer is 129th. + // Keep 128 diff layers in the memory, persistent layer is 129th. // - head layer is paired with HEAD state // - head-1 layer is paired with HEAD-1 state // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state - if err := s.snaps.Cap(root, TriesInMemory); err != nil { - log.Warn("Failed to cap snapshot tree", "root", root, "layers", TriesInMemory, "err", err) + if err := s.snaps.Cap(ret.root, TriesInMemory); err != nil { + log.Warn("Failed to cap snapshot tree", "root", ret.root, "layers", TriesInMemory, "err", err) } + s.SnapshotCommits += time.Since(start) } - s.SnapshotCommits += time.Since(start) - s.snap = nil - } - if root == (common.Hash{}) { - root = types.EmptyRootHash - } - origin := s.originalRoot - if origin == (common.Hash{}) { - origin = types.EmptyRootHash - } - if root != origin { - start = time.Now() - set := triestate.New(s.accountsOrigin, s.storagesOrigin) - if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil { - return common.Hash{}, err + // If trie database is enabled, commit the state update as a new layer + if db := s.db.TrieDB(); db != nil { + start := time.Now() + set := triestate.New(ret.accountsOrigin, ret.storagesOrigin) + if err := db.Update(ret.root, ret.originRoot, block, ret.nodes, set); err != nil { + return nil, err + } + s.TrieDBCommits += time.Since(start) } - s.originalRoot = root - s.TrieDBCommits += time.Since(start) + } + return ret, err +} - if s.onCommit != nil { - s.onCommit(set) - } +// Commit writes the state mutations into the configured data stores. +// +// Once the state is committed, tries cached in stateDB (including account +// trie, storage tries) will no longer be functional. A new state instance +// must be created with new root and updated database for accessing post- +// commit states. +// +// The associated block number of the state transition is also provided +// for more chain context. +func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) { + ret, err := s.commitAndFlush(block, deleteEmptyObjects) + if err != nil { + return common.Hash{}, err } - // Clear all internal flags at the end of commit operation. - s.accounts = make(map[common.Hash][]byte) - s.storages = make(map[common.Hash]map[common.Hash][]byte) - s.accountsOrigin = make(map[common.Address][]byte) - s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte) - s.mutations = make(map[common.Address]*mutation) - s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) - return root, nil + return ret.root, nil } // Prepare handles the preparatory steps for executing a state transition with. @@ -1399,41 +1372,9 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre return s.accessList.Contains(addr, slot) } -// convertAccountSet converts a provided account set from address keyed to hash keyed. -func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount) map[common.Hash]struct{} { - ret := make(map[common.Hash]struct{}, len(set)) - for addr := range set { - obj, exist := s.stateObjects[addr] - if !exist { - ret[crypto.Keccak256Hash(addr[:])] = struct{}{} - } else { - ret[obj.addrHash] = struct{}{} - } - } - return ret -} - -// copySet returns a deep-copied set. -func copySet[k comparable](set map[k][]byte) map[k][]byte { - copied := make(map[k][]byte, len(set)) - for key, val := range set { - copied[key] = common.CopyBytes(val) - } - return copied -} - -// copy2DSet returns a two-dimensional deep-copied set. -func copy2DSet[k comparable](set map[k]map[common.Hash][]byte) map[k]map[common.Hash][]byte { - copied := make(map[k]map[common.Hash][]byte, len(set)) - for addr, subset := range set { - copied[addr] = make(map[common.Hash][]byte, len(subset)) - for key, val := range subset { - copied[addr][key] = common.CopyBytes(val) - } - } - return copied -} - +// markDelete is invoked when an account is deleted but the deletion is +// not yet committed. The pending mutation is cached and will be applied +// all together func (s *StateDB) markDelete(addr common.Address) { if _, ok := s.mutations[addr]; !ok { s.mutations[addr] = &mutation{} diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index 6317681a7f..40b079cd8a 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -36,7 +36,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/pathdb" "github.com/holiman/uint256" @@ -180,9 +179,21 @@ func (test *stateTest) run() bool { roots []common.Hash accountList []map[common.Address][]byte storageList []map[common.Address]map[common.Hash][]byte - onCommit = func(states *triestate.Set) { - accountList = append(accountList, copySet(states.Accounts)) - storageList = append(storageList, copy2DSet(states.Storages)) + copyUpdate = func(update *stateUpdate) { + accounts := make(map[common.Address][]byte, len(update.accountsOrigin)) + for key, val := range update.accountsOrigin { + accounts[key] = common.CopyBytes(val) + } + accountList = append(accountList, accounts) + + storages := make(map[common.Address]map[common.Hash][]byte, len(update.storagesOrigin)) + for addr, subset := range update.storagesOrigin { + storages[addr] = make(map[common.Hash][]byte, len(subset)) + for key, val := range subset { + storages[addr][key] = common.CopyBytes(val) + } + } + storageList = append(storageList, storages) } disk = rawdb.NewMemoryDatabase() tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults}) @@ -210,8 +221,6 @@ func (test *stateTest) run() bool { if err != nil { panic(err) } - state.onCommit = onCommit - for i, action := range actions { if i%test.chunk == 0 && i != 0 { if byzantium { @@ -227,14 +236,15 @@ func (test *stateTest) run() bool { } else { state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary } - nroot, err := state.Commit(0, true) // call commit at the block boundary + ret, err := state.commitAndFlush(0, true) // call commit at the block boundary if err != nil { panic(err) } - if nroot == root { - return true // filter out non-change state transition + if ret.empty() { + return true } - roots = append(roots, nroot) + copyUpdate(ret) + roots = append(roots, ret.root) } for i := 0; i < len(test.actions); i++ { root := types.EmptyRootHash diff --git a/core/state/stateupdate.go b/core/state/stateupdate.go new file mode 100644 index 0000000000..f3e6af997e --- /dev/null +++ b/core/state/stateupdate.go @@ -0,0 +1,133 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package state + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/trie/trienode" +) + +// contractCode represents a contract code with associated metadata. +type contractCode struct { + hash common.Hash // hash is the cryptographic hash of the contract code. + blob []byte // blob is the binary representation of the contract code. +} + +// accountDelete represents an operation for deleting an Ethereum account. +type accountDelete struct { + address common.Address // address is the unique account identifier + origin []byte // origin is the original value of account data in slim-RLP encoding. + storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. +} + +// accountUpdate represents an operation for updating an Ethereum account. +type accountUpdate struct { + address common.Address // address is the unique account identifier + data []byte // data is the slim-RLP encoded account data. + origin []byte // origin is the original value of account data in slim-RLP encoding. + code *contractCode // code represents mutated contract code; nil means it's not modified. + storages map[common.Hash][]byte // storages stores mutated slots in prefix-zero-trimmed RLP format. + storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format. +} + +// stateUpdate represents the difference between two states resulting from state +// execution. It contains information about mutated contract codes, accounts, +// and storage slots, along with their original values. +type stateUpdate struct { + originRoot common.Hash // hash of the state before applying mutation + root common.Hash // hash of the state after applying mutation + destructs map[common.Hash]struct{} // destructs contains the list of destructed accounts + accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding + accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding + storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format + storagesOrigin map[common.Address]map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in 'prefix-zero-trimmed' RLP format + codes map[common.Address]contractCode // codes contains the set of dirty codes + nodes *trienode.MergedNodeSet // Aggregated dirty nodes caused by state changes +} + +// empty returns a flag indicating the state transition is empty or not. +func (sc *stateUpdate) empty() bool { + return sc.originRoot == sc.root +} + +// newStateUpdate constructs a state update object, representing the differences +// between two states by performing state execution. It aggregates the given +// account deletions and account updates to form a comprehensive state update. +func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate { + var ( + destructs = make(map[common.Hash]struct{}) + accounts = make(map[common.Hash][]byte) + accountsOrigin = make(map[common.Address][]byte) + storages = make(map[common.Hash]map[common.Hash][]byte) + storagesOrigin = make(map[common.Address]map[common.Hash][]byte) + codes = make(map[common.Address]contractCode) + ) + // Due to the fact that some accounts could be destructed and resurrected + // within the same block, the deletions must be aggregated first. + for addrHash, op := range deletes { + addr := op.address + destructs[addrHash] = struct{}{} + accountsOrigin[addr] = op.origin + if len(op.storagesOrigin) > 0 { + storagesOrigin[addr] = op.storagesOrigin + } + } + // Aggregate account updates then. + for addrHash, op := range updates { + // Aggregate dirty contract codes if they are available. + addr := op.address + if op.code != nil { + codes[addr] = *op.code + } + // Aggregate the account changes. The original account value will only + // be tracked if it's not present yet. + accounts[addrHash] = op.data + if _, found := accountsOrigin[addr]; !found { + accountsOrigin[addr] = op.origin + } + // Aggregate the storage changes. The original storage slot value will + // only be tracked if it's not present yet. + if len(op.storages) > 0 { + storages[addrHash] = op.storages + } + if len(op.storagesOrigin) > 0 { + origin := storagesOrigin[addr] + if origin == nil { + storagesOrigin[addr] = op.storagesOrigin + continue + } + for key, slot := range op.storagesOrigin { + if _, found := origin[key]; !found { + origin[key] = slot + } + } + storagesOrigin[addr] = origin + } + } + return &stateUpdate{ + originRoot: types.TrieRootHash(originRoot), + root: types.TrieRootHash(root), + destructs: destructs, + accounts: accounts, + accountsOrigin: accountsOrigin, + storages: storages, + storagesOrigin: storagesOrigin, + codes: codes, + nodes: nodes, + } +} From 50405e29b73140f80cf2008be7827752a430a199 Mon Sep 17 00:00:00 2001 From: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:31:23 +0800 Subject: [PATCH 047/196] cmd/evm/internal/t8ntool: fix a typo (#29887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * i8ntool: fix a typo * cmd/evm/internal/t8ntool: fix typo typo --------- Co-authored-by: Péter Szilágyi --- cmd/evm/internal/t8ntool/transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 9ea94d195e..8fd068b2ea 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -217,7 +217,7 @@ func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { return nil } if env.ParentBaseFee == nil || env.Number == 0 { - return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) + return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'parentBaseFee' in env section")) } env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{ Number: new(big.Int).SetUint64(env.Number - 1), From b36c73813c6101c2cd5dfa227dc8e40b417e23ba Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 3 Jun 2024 19:38:08 +0700 Subject: [PATCH 048/196] beacon/engine: prealloc capacity for map and slice (#29903) * prealloc capacity for map and slice * revert unnecessary change --- beacon/engine/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index a73691ca05..1dfcf5b71a 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -209,7 +209,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) } - var blobHashes []common.Hash + var blobHashes = make([]common.Hash, 0, len(txs)) for _, tx := range txs { blobHashes = append(blobHashes, tx.BlobHashes()...) } From 7270cba25c71d72447a535d0aafcd39892cf8112 Mon Sep 17 00:00:00 2001 From: miles <66052478+miles-six@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:50:24 +0800 Subject: [PATCH 049/196] log: fix a typo (#29883) logger --- log/logger_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/log/logger_test.go b/log/logger_test.go index 6f415eb471..f1a9a93bce 100644 --- a/log/logger_test.go +++ b/log/logger_test.go @@ -26,7 +26,7 @@ func TestLoggingWithVmodule(t *testing.T) { logger.Trace("a message", "foo", "bar") have := out.String() // The timestamp is locale-dependent, so we want to trim that off - // "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..." + // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." have = strings.Split(have, "]")[1] want := " a message foo=bar\n" if have != want { @@ -42,7 +42,7 @@ func TestTerminalHandlerWithAttrs(t *testing.T) { logger.Trace("a message", "foo", "bar") have := out.String() // The timestamp is locale-dependent, so we want to trim that off - // "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..." + // "INFO [01-01|00:00:00.000] a message ..." -> "a message..." have = strings.Split(have, "]")[1] want := " a message baz=bat foo=bar\n" if have != want { From a6751d6fc830b9a1edc963df2c05908f4392e39c Mon Sep 17 00:00:00 2001 From: tianyeyouyou <150894831+tianyeyouyou@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:51:04 +0800 Subject: [PATCH 050/196] core/rawdb,eth/protocols,p2p: prealloc slice size (#29893) chore: prealloc slice size --- eth/protocols/snap/sync.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 53cba5d115..88d7d34dcc 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -3250,9 +3250,9 @@ func (t *healRequestSort) Merge() []TrieNodePathSet { // sortByAccountPath takes hashes and paths, and sorts them. After that, it generates // the TrieNodePaths and merges paths which belongs to the same account path. func sortByAccountPath(paths []string, hashes []common.Hash) ([]string, []common.Hash, []trie.SyncPath, []TrieNodePathSet) { - var syncPaths []trie.SyncPath - for _, path := range paths { - syncPaths = append(syncPaths, trie.NewSyncPath([]byte(path))) + syncPaths := make([]trie.SyncPath, len(paths)) + for i, path := range paths { + syncPaths[i] = trie.NewSyncPath([]byte(path)) } n := &healRequestSort{paths, hashes, syncPaths} sort.Sort(n) From adbbd8cd7b3c0d3e5a8475c3e3557f11ca38a3d1 Mon Sep 17 00:00:00 2001 From: Steven Wang <915337710@qq.com> Date: Tue, 4 Jun 2024 11:12:24 +0800 Subject: [PATCH 051/196] core/state: prefetch account trie while starting a prefetcher (#29919) Always prefetch the account trie while starting the prefetcher. Co-authored-by: steven Co-authored-by: rjl493456442 --- core/state/statedb.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 659c500c3b..bb2a87b172 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -208,6 +208,19 @@ func (s *StateDB) StartPrefetcher(namespace string) { } if s.snap != nil { s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) + + // With the switch to the Proof-of-Stake consensus algorithm, block production + // rewards are now handled at the consensus layer. Consequently, a block may + // have no state transitions if it contains no transactions and no withdrawals. + // In such cases, the account trie won't be scheduled for prefetching, leading + // to unnecessary error logs. + // + // To prevent this, the account trie is always scheduled for prefetching once + // the prefetcher is constructed. For more details, see: + // https://github.com/ethereum/go-ethereum/issues/29880 + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil); err != nil { + log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) + } } } From 68c0ec08158c2e61a40baa4489fd4377f6d1a223 Mon Sep 17 00:00:00 2001 From: Roy Crihfield Date: Tue, 4 Jun 2024 11:17:26 +0800 Subject: [PATCH 052/196] trie: iterate values pre-order and fix seek behavior (#27838) This pull request fixes the pre-order trie traversal by defining a more accurate iterator order and path comparison rule. Co-authored-by: Gary Rong --- trie/iterator.go | 81 ++++++++++++++++++++++++++++++++++--------- trie/iterator_test.go | 18 ++++++---- 2 files changed, 76 insertions(+), 23 deletions(-) diff --git a/trie/iterator.go b/trie/iterator.go index 83ccc0740f..fa01611063 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -135,7 +135,7 @@ type nodeIteratorState struct { node node // Trie node being iterated parent common.Hash // Hash of the first full ancestor node (nil if current is the root) index int // Child to be processed next - pathlen int // Length of the path to this node + pathlen int // Length of the path to the parent node } type nodeIterator struct { @@ -145,7 +145,7 @@ type nodeIterator struct { err error // Failure set in case of an internal error in the iterator resolver NodeResolver // optional node resolver for avoiding disk hits - pool []*nodeIteratorState // local pool for iteratorstates + pool []*nodeIteratorState // local pool for iterator states } // errIteratorEnd is stored in nodeIterator.err when iteration is done. @@ -304,6 +304,7 @@ func (it *nodeIterator) seek(prefix []byte) error { // The path we're looking for is the hex encoded key without terminator. key := keybytesToHex(prefix) key = key[:len(key)-1] + // Move forward until we're just before the closest match to key. for { state, parentIndex, path, err := it.peekSeek(key) @@ -311,7 +312,7 @@ func (it *nodeIterator) seek(prefix []byte) error { return errIteratorEnd } else if err != nil { return seekError{prefix, err} - } else if bytes.Compare(path, key) >= 0 { + } else if reachedPath(path, key) { return nil } it.push(state, parentIndex, path) @@ -339,7 +340,6 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er // If we're skipping children, pop the current node first it.pop() } - // Continue iteration to the next child for len(it.stack) > 0 { parent := it.stack[len(it.stack)-1] @@ -372,7 +372,6 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by // If we're skipping children, pop the current node first it.pop() } - // Continue iteration to the next child for len(it.stack) > 0 { parent := it.stack[len(it.stack)-1] @@ -449,16 +448,18 @@ func (it *nodeIterator) findChild(n *fullNode, index int, ancestor common.Hash) state *nodeIteratorState childPath []byte ) - for ; index < len(n.Children); index++ { + for ; index < len(n.Children); index = nextChildIndex(index) { if n.Children[index] != nil { child = n.Children[index] hash, _ := child.cache() + state = it.getFromPool() state.hash = common.BytesToHash(hash) state.node = child state.parent = ancestor state.index = -1 state.pathlen = len(path) + childPath = append(childPath, path...) childPath = append(childPath, byte(index)) return child, state, childPath, index @@ -471,8 +472,8 @@ func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Has switch node := parent.node.(type) { case *fullNode: // Full node, move to the first non-nil child. - if child, state, path, index := it.findChild(node, parent.index+1, ancestor); child != nil { - parent.index = index - 1 + if child, state, path, index := it.findChild(node, nextChildIndex(parent.index), ancestor); child != nil { + parent.index = prevChildIndex(index) return state, path, true } case *shortNode: @@ -498,23 +499,23 @@ func (it *nodeIterator) nextChildAt(parent *nodeIteratorState, ancestor common.H switch n := parent.node.(type) { case *fullNode: // Full node, move to the first non-nil child before the desired key position - child, state, path, index := it.findChild(n, parent.index+1, ancestor) + child, state, path, index := it.findChild(n, nextChildIndex(parent.index), ancestor) if child == nil { // No more children in this fullnode return parent, it.path, false } // If the child we found is already past the seek position, just return it. - if bytes.Compare(path, key) >= 0 { - parent.index = index - 1 + if reachedPath(path, key) { + parent.index = prevChildIndex(index) return state, path, true } // The child is before the seek position. Try advancing for { - nextChild, nextState, nextPath, nextIndex := it.findChild(n, index+1, ancestor) + nextChild, nextState, nextPath, nextIndex := it.findChild(n, nextChildIndex(index), ancestor) // If we run out of children, or skipped past the target, return the // previous one - if nextChild == nil || bytes.Compare(nextPath, key) >= 0 { - parent.index = index - 1 + if nextChild == nil || reachedPath(nextPath, key) { + parent.index = prevChildIndex(index) return state, path, true } // We found a better child closer to the target @@ -541,7 +542,7 @@ func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path [] it.path = path it.stack = append(it.stack, state) if parentIndex != nil { - *parentIndex++ + *parentIndex = nextChildIndex(*parentIndex) } } @@ -550,8 +551,54 @@ func (it *nodeIterator) pop() { it.path = it.path[:last.pathlen] it.stack[len(it.stack)-1] = nil it.stack = it.stack[:len(it.stack)-1] - // last is now unused - it.putInPool(last) + + it.putInPool(last) // last is now unused +} + +// reachedPath normalizes a path by truncating a terminator if present, and +// returns true if it is greater than or equal to the target. Using this, +// the path of a value node embedded a full node will compare less than the +// full node's children. +func reachedPath(path, target []byte) bool { + if hasTerm(path) { + path = path[:len(path)-1] + } + return bytes.Compare(path, target) >= 0 +} + +// A value embedded in a full node occupies the last slot (16) of the array of +// children. In order to produce a pre-order traversal when iterating children, +// we jump to this last slot first, then go back iterate the child nodes (and +// skip the last slot at the end): + +// prevChildIndex returns the index of a child in a full node which precedes +// the given index when performing a pre-order traversal. +func prevChildIndex(index int) int { + switch index { + case 0: // We jumped back to iterate the children, from the value slot + return 16 + case 16: // We jumped to the embedded value slot at the end, from the placeholder index + return -1 + case 17: // We skipped the value slot after iterating all the children + return 15 + default: // We are iterating the children in sequence + return index - 1 + } +} + +// nextChildIndex returns the index of a child in a full node which follows +// the given index when performing a pre-order traversal. +func nextChildIndex(index int) int { + switch index { + case -1: // Jump from the placeholder index to the embedded value slot + return 16 + case 15: // Skip the value slot after iterating the children + return 17 + case 16: // From the embedded value slot, jump back to iterate the children + return 0 + default: // Iterate children in sequence + return index + 1 + } } func compareNodes(a, b NodeIterator) int { diff --git a/trie/iterator_test.go b/trie/iterator_test.go index 41e83f6cb6..a8f3c4413e 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -182,14 +182,14 @@ func testNodeIteratorCoverage(t *testing.T, scheme string) { type kvs struct{ k, v string } var testdata1 = []kvs{ + {"bar", "b"}, {"barb", "ba"}, {"bard", "bc"}, {"bars", "bb"}, - {"bar", "b"}, {"fab", "z"}, + {"foo", "a"}, {"food", "ab"}, {"foos", "aa"}, - {"foo", "a"}, } var testdata2 = []kvs{ @@ -218,7 +218,7 @@ func TestIteratorSeek(t *testing.T) { // Seek to a non-existent key. it = NewIterator(trie.MustNodeIterator([]byte("barc"))) - if err := checkIteratorOrder(testdata1[1:], it); err != nil { + if err := checkIteratorOrder(testdata1[2:], it); err != nil { t.Fatal(err) } @@ -227,6 +227,12 @@ func TestIteratorSeek(t *testing.T) { if err := checkIteratorOrder(nil, it); err != nil { t.Fatal(err) } + + // Seek to a key for which a prefixing key exists. + it = NewIterator(trie.MustNodeIterator([]byte("food"))) + if err := checkIteratorOrder(testdata1[6:], it); err != nil { + t.Fatal(err) + } } func checkIteratorOrder(want []kvs, it *Iterator) error { @@ -311,16 +317,16 @@ func TestUnionIterator(t *testing.T) { all := []struct{ k, v string }{ {"aardvark", "c"}, + {"bar", "b"}, {"barb", "ba"}, {"barb", "bd"}, {"bard", "bc"}, {"bars", "bb"}, {"bars", "be"}, - {"bar", "b"}, {"fab", "z"}, + {"foo", "a"}, {"food", "ab"}, {"foos", "aa"}, - {"foo", "a"}, {"jars", "d"}, } @@ -512,7 +518,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin rawdb.WriteTrieNode(diskdb, common.Hash{}, barNodePath, barNodeHash, barNodeBlob, triedb.Scheme()) } // Check that iteration produces the right set of values. - if err := checkIteratorOrder(testdata1[2:], NewIterator(it)); err != nil { + if err := checkIteratorOrder(testdata1[3:], NewIterator(it)); err != nil { t.Fatal(err) } } From 682ae838b2312a4ec8e5581069039b567e33c7c2 Mon Sep 17 00:00:00 2001 From: SangIlMo <156392700+SangIlMo@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:59:41 +0900 Subject: [PATCH 053/196] internal/ethapi: recap higher args.Gas with block GasLimit in DoEstimateGas (#29738) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * internal/ethapi: recap higher args.Gas with block GasLimit in DoEstimateGas * internal/ethapi: fix gas estimator capping code * internal/ethapi: fix test * fix goimports lint (remove space) --------- Co-authored-by: Péter Szilágyi --- internal/ethapi/api.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 8866a5b870..f211dcc659 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1199,10 +1199,16 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr State: state, ErrorRatio: estimateGasErrorRatio, } + // Set any required transaction default, but make sure the gas cap itself is not messed with + // if it was not specified in the original argument list. + if args.Gas == nil { + args.Gas = new(hexutil.Uint64) + } if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil { return 0, err } call := args.ToMessage(header.BaseFee) + // Run the gas estimation and wrap any revertals into a custom return estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap) if err != nil { From 125fb1ff5855134b040e295f380eeecff29af375 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 4 Jun 2024 20:51:34 +0800 Subject: [PATCH 054/196] core/state: avoid data race (#29924) --- core/state/statedb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index bb2a87b172..61e76cdd77 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1211,8 +1211,8 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { } lock.Lock() updates[obj.addrHash] = update - lock.Unlock() s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime + lock.Unlock() return nil }) } From 5550d8399f744aca0f50fc20bcd57bf2abeb13e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 5 Jun 2024 11:06:37 +0300 Subject: [PATCH 055/196] params: release Geth v1.14.4 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index a0e2de5a49..62140f05c7 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 4 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From fc40d68e5bd6ffb1651a75f985114de5eabd4e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Wed, 5 Jun 2024 11:20:35 +0300 Subject: [PATCH 056/196] params: begin v1.14.5 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 62140f05c7..5ae1187b82 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 4 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 5 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From e85e21c93267f619c8ce75c0457f4ed52cd9bbf0 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Wed, 5 Jun 2024 17:07:37 +0800 Subject: [PATCH 057/196] core/state, eth/tracers: fix typos (#29932) --- core/state/trie_prefetcher.go | 2 +- eth/tracers/internal/tracetest/supply_test.go | 2 +- eth/tracers/live/supply.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index ce94ab5139..5e5afbbecc 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -82,7 +82,7 @@ func (p *triePrefetcher) terminate(async bool) { return default: } - // Termiante all sub-fetchers, sync or async, depending on the request + // Terminate all sub-fetchers, sync or async, depending on the request for _, fetcher := range p.fetchers { fetcher.terminate(async) } diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go index 2d4f1b0890..d608b1e002 100644 --- a/eth/tracers/internal/tracetest/supply_test.go +++ b/eth/tracers/internal/tracetest/supply_test.go @@ -398,7 +398,7 @@ func TestSupplySelfdestruct(t *testing.T) { } // Tests selfdestructing contract to send its balance to itself (burn). -// It tests both cases of selfdestructing succeding and being reverted. +// It tests both cases of selfdestructing succeeding and being reverted. // - Contract A calls B and D. // - Contract B selfdestructs and sends the eth1 to itself (Burn amount to be counted). // - Contract C selfdestructs and sends the eth1 to itself. diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index 0c9141e99d..936ffb9472 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -205,7 +205,7 @@ func (s *supply) internalTxsHandler(call *supplyTxCallstack) { } if len(call.calls) > 0 { - // Recursivelly handle internal calls + // Recursively handle internal calls for _, call := range call.calls { callCopy := call s.internalTxsHandler(&callCopy) From d09ddac39950645b95eae94894c322fc19f23acb Mon Sep 17 00:00:00 2001 From: Marquis Shanahan <29431502+9547@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:05:00 +0800 Subject: [PATCH 058/196] core/rawdb: remove unused deriveLogFields (#29913) Co-authored-by: Gary Rong Co-authored-by: Martin HS --- core/rawdb/accessors_chain.go | 22 ---------------------- core/rawdb/accessors_chain_test.go | 6 ++---- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 025be7ade7..c4735c850c 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -19,7 +19,6 @@ package rawdb import ( "bytes" "encoding/binary" - "errors" "fmt" "math/big" "slices" @@ -695,27 +694,6 @@ func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error { return nil } -// deriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc. -func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, txs types.Transactions) error { - logIndex := uint(0) - if len(txs) != len(receipts) { - return errors.New("transaction and receipt count mismatch") - } - for i := 0; i < len(receipts); i++ { - txHash := txs[i].Hash() - // The derived log fields can simply be set from the block and transaction - for j := 0; j < len(receipts[i].Logs); j++ { - receipts[i].Logs[j].BlockNumber = number - receipts[i].Logs[j].BlockHash = hash - receipts[i].Logs[j].TxHash = txHash - receipts[i].Logs[j].TxIndex = uint(i) - receipts[i].Logs[j].Index = logIndex - logIndex++ - } - } - return nil -} - // ReadLogs retrieves the logs for all transactions in a block. In case // receipts is not found, a nil is returned. // Note: ReadLogs does not derive unstored log fields. diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index fdc940b57e..2d30af4b3d 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -794,7 +794,7 @@ func TestDeriveLogFields(t *testing.T) { }), } // Create the corresponding receipts - receipts := []*receiptLogs{ + receipts := []*types.Receipt{ { Logs: []*types.Log{ {Address: common.BytesToAddress([]byte{0x11})}, @@ -818,9 +818,7 @@ func TestDeriveLogFields(t *testing.T) { // Derive log metadata fields number := big.NewInt(1) hash := common.BytesToHash([]byte{0x03, 0x14}) - if err := deriveLogFields(receipts, hash, number.Uint64(), txs); err != nil { - t.Fatal(err) - } + types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, number.Uint64(), 0, big.NewInt(0), big.NewInt(0), txs) // Iterate over all the computed fields and check that they're correct logIndex := uint(0) From bc6569462dfd78394599c93fd9e2a21908aca662 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 5 Jun 2024 19:31:04 +0200 Subject: [PATCH 059/196] p2p: use netip.Addr where possible (#29891) enode.Node was recently changed to store a cache of endpoint information. The IP address in the cache is a netip.Addr. I chose that type over net.IP because it is just better. netip.Addr is meant to be used as a value type. Copying it does not allocate, it can be compared with ==, and can be used as a map key. This PR changes most uses of Node.IP() into Node.IPAddr(), which returns the cached value directly without allocating. While there are still some public APIs left where net.IP is used, I have converted all code used internally by p2p/discover to the new types. So this does change some public Go API, but hopefully not APIs any external code actually uses. There weren't supposed to be any semantic differences resulting from this refactoring, however it does introduce one: In package p2p/netutil we treated the 0.0.0.0/8 network (addresses 0.x.y.z) as LAN, but netip.Addr.IsPrivate() doesn't. The treatment of this particular IP address range is controversial, with some software supporting it and others not. IANA lists it as special-purpose and invalid as a destination for a long time, so I don't know why I put it into the LAN list. It has now been marked as special in p2p/netutil as well. --- cmd/devp2p/internal/ethtest/conn.go | 3 +- cmd/devp2p/internal/v4test/framework.go | 6 +- cmd/devp2p/nodesetcmd.go | 6 +- cmd/devp2p/rlpxcmd.go | 6 +- p2p/dial.go | 27 ++-- p2p/discover/table.go | 52 ++++---- p2p/discover/table_test.go | 14 +-- p2p/discover/table_util_test.go | 5 +- p2p/discover/v4_udp.go | 33 ++--- p2p/discover/v4_udp_test.go | 8 +- p2p/discover/v5_udp.go | 12 +- p2p/discover/v5wire/encoding_test.go | 2 +- p2p/enode/localnode.go | 42 ++----- p2p/enode/localnode_test.go | 16 ++- p2p/enode/nodedb.go | 62 +++++---- p2p/enode/nodedb_test.go | 35 +++--- p2p/netutil/addrutil.go | 49 ++++++-- p2p/netutil/iptrack.go | 24 ++-- p2p/netutil/iptrack_test.go | 59 +++++---- p2p/netutil/net.go | 160 +++++++++++++----------- p2p/netutil/net_test.go | 64 +++++++--- p2p/server.go | 15 +-- p2p/server_nat_test.go | 5 +- 23 files changed, 392 insertions(+), 313 deletions(-) diff --git a/cmd/devp2p/internal/ethtest/conn.go b/cmd/devp2p/internal/ethtest/conn.go index ba3c0585fd..757b137aa1 100644 --- a/cmd/devp2p/internal/ethtest/conn.go +++ b/cmd/devp2p/internal/ethtest/conn.go @@ -53,7 +53,8 @@ func (s *Suite) dial() (*Conn, error) { // dialAs attempts to dial a given node and perform a handshake using the given // private key. func (s *Suite) dialAs(key *ecdsa.PrivateKey) (*Conn, error) { - fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP())) + tcpEndpoint, _ := s.Dest.TCPEndpoint() + fd, err := net.Dial("tcp", tcpEndpoint.String()) if err != nil { return nil, err } diff --git a/cmd/devp2p/internal/v4test/framework.go b/cmd/devp2p/internal/v4test/framework.go index df1f1f8aba..958fb71179 100644 --- a/cmd/devp2p/internal/v4test/framework.go +++ b/cmd/devp2p/internal/v4test/framework.go @@ -53,10 +53,12 @@ func newTestEnv(remote string, listen1, listen2 string) *testenv { if err != nil { panic(err) } - if node.IP() == nil || node.UDP() == 0 { + if !node.IPAddr().IsValid() || node.UDP() == 0 { var ip net.IP var tcpPort, udpPort int - if ip = node.IP(); ip == nil { + if node.IPAddr().IsValid() { + ip = node.IPAddr().AsSlice() + } else { ip = net.ParseIP("127.0.0.1") } if tcpPort = node.TCP(); tcpPort == 0 { diff --git a/cmd/devp2p/nodesetcmd.go b/cmd/devp2p/nodesetcmd.go index 6fbc185ad8..f0773edfb8 100644 --- a/cmd/devp2p/nodesetcmd.go +++ b/cmd/devp2p/nodesetcmd.go @@ -19,7 +19,7 @@ package main import ( "errors" "fmt" - "net" + "net/netip" "sort" "strconv" "strings" @@ -205,11 +205,11 @@ func trueFilter(args []string) (nodeFilter, error) { } func ipFilter(args []string) (nodeFilter, error) { - _, cidr, err := net.ParseCIDR(args[0]) + prefix, err := netip.ParsePrefix(args[0]) if err != nil { return nil, err } - f := func(n nodeJSON) bool { return cidr.Contains(n.N.IP()) } + f := func(n nodeJSON) bool { return prefix.Contains(n.N.IPAddr()) } return f, nil } diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index aa7d065818..fb8066ee1a 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -77,7 +77,11 @@ var ( func rlpxPing(ctx *cli.Context) error { n := getNodeArg(ctx) - fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", n.IP(), n.TCP())) + tcpEndpoint, ok := n.TCPEndpoint() + if !ok { + return fmt.Errorf("node has no TCP endpoint") + } + fd, err := net.Dial("tcp", tcpEndpoint.String()) if err != nil { return err } diff --git a/p2p/dial.go b/p2p/dial.go index 08e1db2877..24d4dc2e89 100644 --- a/p2p/dial.go +++ b/p2p/dial.go @@ -65,11 +65,8 @@ type tcpDialer struct { } func (t tcpDialer) Dial(ctx context.Context, dest *enode.Node) (net.Conn, error) { - return t.d.DialContext(ctx, "tcp", nodeAddr(dest).String()) -} - -func nodeAddr(n *enode.Node) net.Addr { - return &net.TCPAddr{IP: n.IP(), Port: n.TCP()} + addr, _ := dest.TCPEndpoint() + return t.d.DialContext(ctx, "tcp", addr.String()) } // checkDial errors: @@ -243,7 +240,7 @@ loop: select { case node := <-nodesCh: if err := d.checkDial(node); err != nil { - d.log.Trace("Discarding dial candidate", "id", node.ID(), "ip", node.IP(), "reason", err) + d.log.Trace("Discarding dial candidate", "id", node.ID(), "ip", node.IPAddr(), "reason", err) } else { d.startDial(newDialTask(node, dynDialedConn)) } @@ -277,7 +274,7 @@ loop: case node := <-d.addStaticCh: id := node.ID() _, exists := d.static[id] - d.log.Trace("Adding static node", "id", id, "ip", node.IP(), "added", !exists) + d.log.Trace("Adding static node", "id", id, "ip", node.IPAddr(), "added", !exists) if exists { continue loop } @@ -376,7 +373,7 @@ func (d *dialScheduler) checkDial(n *enode.Node) error { if n.ID() == d.self { return errSelf } - if n.IP() != nil && n.TCP() == 0 { + if n.IPAddr().IsValid() && n.TCP() == 0 { // This check can trigger if a non-TCP node is found // by discovery. If there is no IP, the node is a static // node and the actual endpoint will be resolved later in dialTask. @@ -388,7 +385,7 @@ func (d *dialScheduler) checkDial(n *enode.Node) error { if _, ok := d.peers[n.ID()]; ok { return errAlreadyConnected } - if d.netRestrict != nil && !d.netRestrict.Contains(n.IP()) { + if d.netRestrict != nil && !d.netRestrict.ContainsAddr(n.IPAddr()) { return errNetRestrict } if d.history.contains(string(n.ID().Bytes())) { @@ -439,7 +436,7 @@ func (d *dialScheduler) removeFromStaticPool(idx int) { // startDial runs the given dial task in a separate goroutine. func (d *dialScheduler) startDial(task *dialTask) { node := task.dest() - d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IP(), "flag", task.flags) + d.log.Trace("Starting p2p dial", "id", node.ID(), "ip", node.IPAddr(), "flag", task.flags) hkey := string(node.ID().Bytes()) d.history.add(hkey, d.clock.Now().Add(dialHistoryExpiration)) d.dialing[node.ID()] = task @@ -492,7 +489,7 @@ func (t *dialTask) run(d *dialScheduler) { } func (t *dialTask) needResolve() bool { - return t.flags&staticDialedConn != 0 && t.dest().IP() == nil + return t.flags&staticDialedConn != 0 && !t.dest().IPAddr().IsValid() } // resolve attempts to find the current endpoint for the destination @@ -526,7 +523,8 @@ func (t *dialTask) resolve(d *dialScheduler) bool { // The node was found. t.resolveDelay = initialResolveDelay t.destPtr.Store(resolved) - d.log.Debug("Resolved node", "id", resolved.ID(), "addr", &net.TCPAddr{IP: resolved.IP(), Port: resolved.TCP()}) + resAddr, _ := resolved.TCPEndpoint() + d.log.Debug("Resolved node", "id", resolved.ID(), "addr", resAddr) return true } @@ -535,7 +533,8 @@ func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { dialMeter.Mark(1) fd, err := d.dialer.Dial(d.ctx, dest) if err != nil { - d.log.Trace("Dial error", "id", dest.ID(), "addr", nodeAddr(dest), "conn", t.flags, "err", cleanupDialErr(err)) + addr, _ := dest.TCPEndpoint() + d.log.Trace("Dial error", "id", dest.ID(), "addr", addr, "conn", t.flags, "err", cleanupDialErr(err)) dialConnectionError.Mark(1) return &dialError{err} } @@ -545,7 +544,7 @@ func (t *dialTask) dial(d *dialScheduler, dest *enode.Node) error { func (t *dialTask) String() string { node := t.dest() id := node.ID() - return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], node.IP(), node.TCP()) + return fmt.Sprintf("%v %x %v:%d", t.flags, id[:8], node.IPAddr(), node.TCP()) } func cleanupDialErr(err error) error { diff --git a/p2p/discover/table.go b/p2p/discover/table.go index bd3c9b4143..bb5ab4f3fc 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -25,7 +25,7 @@ package discover import ( "context" "fmt" - "net" + "net/netip" "slices" "sync" "time" @@ -207,8 +207,8 @@ func (tab *Table) setFallbackNodes(nodes []*enode.Node) error { if err := n.ValidateComplete(); err != nil { return fmt.Errorf("bad bootstrap node %q: %v", n, err) } - if tab.cfg.NetRestrict != nil && !tab.cfg.NetRestrict.Contains(n.IP()) { - tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IP()) + if tab.cfg.NetRestrict != nil && !tab.cfg.NetRestrict.ContainsAddr(n.IPAddr()) { + tab.log.Error("Bootstrap node filtered by netrestrict", "id", n.ID(), "ip", n.IPAddr()) continue } nursery = append(nursery, n) @@ -448,7 +448,7 @@ func (tab *Table) loadSeedNodes() { for i := range seeds { seed := seeds[i] if tab.log.Enabled(context.Background(), log.LevelTrace) { - age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) + age := time.Since(tab.db.LastPongReceived(seed.ID(), seed.IPAddr())) addr, _ := seed.UDPEndpoint() tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age) } @@ -474,31 +474,31 @@ func (tab *Table) bucketAtDistance(d int) *bucket { return tab.buckets[d-bucketMinDistance-1] } -func (tab *Table) addIP(b *bucket, ip net.IP) bool { - if len(ip) == 0 { +func (tab *Table) addIP(b *bucket, ip netip.Addr) bool { + if !ip.IsValid() || ip.IsUnspecified() { return false // Nodes without IP cannot be added. } - if netutil.IsLAN(ip) { + if netutil.AddrIsLAN(ip) { return true } - if !tab.ips.Add(ip) { + if !tab.ips.AddAddr(ip) { tab.log.Debug("IP exceeds table limit", "ip", ip) return false } - if !b.ips.Add(ip) { + if !b.ips.AddAddr(ip) { tab.log.Debug("IP exceeds bucket limit", "ip", ip) - tab.ips.Remove(ip) + tab.ips.RemoveAddr(ip) return false } return true } -func (tab *Table) removeIP(b *bucket, ip net.IP) { - if netutil.IsLAN(ip) { +func (tab *Table) removeIP(b *bucket, ip netip.Addr) { + if netutil.AddrIsLAN(ip) { return } - tab.ips.Remove(ip) - b.ips.Remove(ip) + tab.ips.RemoveAddr(ip) + b.ips.RemoveAddr(ip) } // handleAddNode adds the node in the request to the table, if there is space. @@ -524,7 +524,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { tab.addReplacement(b, req.node) return false } - if !tab.addIP(b, req.node.IP()) { + if !tab.addIP(b, req.node.IPAddr()) { // Can't add: IP limit reached. return false } @@ -547,7 +547,7 @@ func (tab *Table) addReplacement(b *bucket, n *enode.Node) { // TODO: update ENR return } - if !tab.addIP(b, n.IP()) { + if !tab.addIP(b, n.IPAddr()) { return } @@ -555,7 +555,7 @@ func (tab *Table) addReplacement(b *bucket, n *enode.Node) { var removed *tableNode b.replacements, removed = pushNode(b.replacements, wn, maxReplacements) if removed != nil { - tab.removeIP(b, removed.IP()) + tab.removeIP(b, removed.IPAddr()) } } @@ -595,12 +595,12 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *tableNode { // Remove the node. n := b.entries[index] b.entries = slices.Delete(b.entries, index, index+1) - tab.removeIP(b, n.IP()) + tab.removeIP(b, n.IPAddr()) tab.nodeRemoved(b, n) // Add replacement. if len(b.replacements) == 0 { - tab.log.Debug("Removed dead node", "b", b.index, "id", n.ID(), "ip", n.IP()) + tab.log.Debug("Removed dead node", "b", b.index, "id", n.ID(), "ip", n.IPAddr()) return nil } rindex := tab.rand.Intn(len(b.replacements)) @@ -608,7 +608,7 @@ func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *tableNode { b.replacements = slices.Delete(b.replacements, rindex, rindex+1) b.entries = append(b.entries, rep) tab.nodeAdded(b, rep) - tab.log.Debug("Replaced dead node", "b", b.index, "id", n.ID(), "ip", n.IP(), "r", rep.ID(), "rip", rep.IP()) + tab.log.Debug("Replaced dead node", "b", b.index, "id", n.ID(), "ip", n.IPAddr(), "r", rep.ID(), "rip", rep.IPAddr()) return rep } @@ -635,10 +635,10 @@ func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) ipchanged := newRecord.IPAddr() != n.IPAddr() portchanged := newRecord.UDP() != n.UDP() if ipchanged { - tab.removeIP(b, n.IP()) - if !tab.addIP(b, newRecord.IP()) { + tab.removeIP(b, n.IPAddr()) + if !tab.addIP(b, newRecord.IPAddr()) { // It doesn't fit with the limit, put the previous record back. - tab.addIP(b, n.IP()) + tab.addIP(b, n.IPAddr()) return n, false } } @@ -657,11 +657,11 @@ func (tab *Table) handleTrackRequest(op trackRequestOp) { var fails int if op.success { // Reset failure counter because it counts _consecutive_ failures. - tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), 0) + tab.db.UpdateFindFails(op.node.ID(), op.node.IPAddr(), 0) } else { - fails = tab.db.FindFails(op.node.ID(), op.node.IP()) + fails = tab.db.FindFails(op.node.ID(), op.node.IPAddr()) fails++ - tab.db.UpdateFindFails(op.node.ID(), op.node.IP(), fails) + tab.db.UpdateFindFails(op.node.ID(), op.node.IPAddr(), fails) } tab.mutex.Lock() diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 30e7d56f4a..2f1797d1e2 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -188,7 +188,7 @@ func checkIPLimitInvariant(t *testing.T, tab *Table) { tabset := netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit} for _, b := range tab.buckets { for _, n := range b.entries { - tabset.Add(n.IP()) + tabset.AddAddr(n.IPAddr()) } } if tabset.String() != tab.ips.String() { @@ -268,7 +268,7 @@ func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value { } for _, id := range gen([]enode.ID{}, rand).([]enode.ID) { r := new(enr.Record) - r.Set(enr.IP(genIP(rand))) + r.Set(enr.IPv4Addr(netutil.RandomAddr(rand, true))) n := enode.SignNull(r, id) t.All = append(t.All, n) } @@ -385,11 +385,11 @@ func checkBucketContent(t *testing.T, tab *Table, nodes []*enode.Node) { } t.Log("wrong bucket content. have nodes:") for _, n := range b.entries { - t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IPAddr()) } t.Log("want nodes:") for _, n := range nodes { - t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IP()) + t.Logf(" %v (seq=%v, ip=%v)", n.ID(), n.Seq(), n.IPAddr()) } t.FailNow() @@ -483,12 +483,6 @@ func gen(typ interface{}, rand *rand.Rand) interface{} { return v.Interface() } -func genIP(rand *rand.Rand) net.IP { - ip := make(net.IP, 4) - rand.Read(ip) - return ip -} - func quickcfg() *quick.Config { return &quick.Config{ MaxCount: 5000, diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 997ac37799..5b2699d460 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -100,8 +100,9 @@ func idAtDistance(a enode.ID, n int) (b enode.ID) { return b } +// intIP returns a LAN IP address based on i. func intIP(i int) net.IP { - return net.IP{byte(i), 0, 2, byte(i)} + return net.IP{10, 0, byte(i >> 8), byte(i & 0xFF)} } // fillBucket inserts nodes into the given bucket until it is full. @@ -254,7 +255,7 @@ NotEqual: } func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool { - return n1.ID() == n2.ID() && n1.IP().Equal(n2.IP()) + return n1.ID() == n2.ID() && n1.IPAddr() == n2.IPAddr() } func sortByID[N nodeType](nodes []N) { diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 3880ca34a7..6234fd93ca 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -25,7 +25,6 @@ import ( "errors" "fmt" "io" - "net" "net/netip" "sync" "time" @@ -250,8 +249,7 @@ func (t *UDPv4) sendPing(toid enode.ID, toaddr netip.AddrPort, callback func()) return matched, matched }) // Send the packet. - toUDPAddr := &net.UDPAddr{IP: toaddr.Addr().AsSlice()} - t.localNode.UDPContact(toUDPAddr) + t.localNode.UDPContact(toaddr) t.write(toaddr, toid, req.Name(), packet) return rm } @@ -383,7 +381,7 @@ func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { if respN.Seq() < n.Seq() { return n, nil // response record is older } - if err := netutil.CheckRelayIP(addr.Addr().AsSlice(), respN.IP()); err != nil { + if err := netutil.CheckRelayAddr(addr.Addr(), respN.IPAddr()); err != nil { return nil, fmt.Errorf("invalid IP in response record: %v", err) } return respN, nil @@ -578,15 +576,14 @@ func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { // checkBond checks if the given node has a recent enough endpoint proof. func (t *UDPv4) checkBond(id enode.ID, ip netip.AddrPort) bool { - return time.Since(t.db.LastPongReceived(id, ip.Addr().AsSlice())) < bondExpiration + return time.Since(t.db.LastPongReceived(id, ip.Addr())) < bondExpiration } // ensureBond solicits a ping from a node if we haven't seen a ping from it for a while. // This ensures there is a valid endpoint proof on the remote end. func (t *UDPv4) ensureBond(toid enode.ID, toaddr netip.AddrPort) { - ip := toaddr.Addr().AsSlice() - tooOld := time.Since(t.db.LastPingReceived(toid, ip)) > bondExpiration - if tooOld || t.db.FindFails(toid, ip) > maxFindnodeFailures { + tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.Addr())) > bondExpiration + if tooOld || t.db.FindFails(toid, toaddr.Addr()) > maxFindnodeFailures { rm := t.sendPing(toid, toaddr, nil) <-rm.errc // Wait for them to ping back and process our pong. @@ -687,7 +684,7 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode // Ping back if our last pong on file is too far in the past. fromIP := from.Addr().AsSlice() n := enode.NewV4(h.senderKey, fromIP, int(req.From.TCP), int(from.Port())) - if time.Since(t.db.LastPongReceived(n.ID(), fromIP)) > bondExpiration { + if time.Since(t.db.LastPongReceived(n.ID(), from.Addr())) > bondExpiration { t.sendPing(fromID, from, func() { t.tab.addInboundNode(n) }) @@ -696,10 +693,9 @@ func (t *UDPv4) handlePing(h *packetHandlerV4, from netip.AddrPort, fromID enode } // Update node database and endpoint predictor. - t.db.UpdateLastPingReceived(n.ID(), fromIP, time.Now()) - fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} - toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} - t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) + t.db.UpdateLastPingReceived(n.ID(), from.Addr(), time.Now()) + toaddr := netip.AddrPortFrom(netutil.IPToAddr(req.To.IP), req.To.UDP) + t.localNode.UDPEndpointStatement(from, toaddr) } // PONG/v4 @@ -713,11 +709,9 @@ func (t *UDPv4) verifyPong(h *packetHandlerV4, from netip.AddrPort, fromID enode if !t.handleReply(fromID, from.Addr(), req) { return errUnsolicitedReply } - fromIP := from.Addr().AsSlice() - fromUDPAddr := &net.UDPAddr{IP: fromIP, Port: int(from.Port())} - toUDPAddr := &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)} - t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) - t.db.UpdateLastPongReceived(fromID, fromIP, time.Now()) + toaddr := netip.AddrPortFrom(netutil.IPToAddr(req.To.IP), req.To.UDP) + t.localNode.UDPEndpointStatement(from, toaddr) + t.db.UpdateLastPongReceived(fromID, from.Addr(), time.Now()) return nil } @@ -753,8 +747,7 @@ func (t *UDPv4) handleFindnode(h *packetHandlerV4, from netip.AddrPort, fromID e p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} var sent bool for _, n := range closest { - fromIP := from.Addr().AsSlice() - if netutil.CheckRelayIP(fromIP, n.IP()) == nil { + if netutil.CheckRelayAddr(from.Addr(), n.IPAddr()) == nil { p.Nodes = append(p.Nodes, nodeToRPC(n)) } if len(p.Nodes) == v4wire.MaxNeighbors { diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 28a6fb8675..9d6df08ead 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -274,7 +274,7 @@ func TestUDPv4_findnode(t *testing.T) { // ensure there's a bond with the test node, // findnode won't be accepted otherwise. remoteID := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() - test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr().AsSlice(), time.Now()) + test.table.db.UpdateLastPongReceived(remoteID, test.remoteaddr.Addr(), time.Now()) // check that closest neighbors are returned. expected := test.table.findnodeByID(testTarget.ID(), bucketSize, true) @@ -309,7 +309,7 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { defer test.close() rid := enode.PubkeyToIDV4(&test.remotekey.PublicKey) - test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr().AsSlice(), time.Now()) + test.table.db.UpdateLastPingReceived(rid, test.remoteaddr.Addr(), time.Now()) // queue a pending findnode request resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) @@ -437,8 +437,8 @@ func TestUDPv4_successfulPing(t *testing.T) { if n.ID() != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } - if !n.IP().Equal(test.remoteaddr.Addr().AsSlice()) { - t.Errorf("node has wrong IP: got %v, want: %v", n.IP(), test.remoteaddr.Addr()) + if n.IPAddr() != test.remoteaddr.Addr() { + t.Errorf("node has wrong IP: got %v, want: %v", n.IPAddr(), test.remoteaddr.Addr()) } if n.UDP() != int(test.remoteaddr.Port()) { t.Errorf("node has wrong UDP port: got %v, want: %v", n.UDP(), test.remoteaddr.Port()) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 9ba54b3d40..4cc21cd9c5 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -428,10 +428,10 @@ func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, s if err != nil { return nil, err } - if err := netutil.CheckRelayIP(c.addr.Addr().AsSlice(), node.IP()); err != nil { + if err := netutil.CheckRelayAddr(c.addr.Addr(), node.IPAddr()); err != nil { return nil, err } - if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { + if t.netrestrict != nil && !t.netrestrict.ContainsAddr(node.IPAddr()) { return nil, errors.New("not contained in netrestrict list") } if node.UDP() <= 1024 { @@ -754,9 +754,8 @@ func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr netip.AddrPort t.handlePing(p, fromID, fromAddr) case *v5wire.Pong: if t.handleCallResponse(fromID, fromAddr, p) { - fromUDPAddr := &net.UDPAddr{IP: fromAddr.Addr().AsSlice(), Port: int(fromAddr.Port())} - toUDPAddr := &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)} - t.localNode.UDPEndpointStatement(fromUDPAddr, toUDPAddr) + toAddr := netip.AddrPortFrom(netutil.IPToAddr(p.ToIP), p.ToPort) + t.localNode.UDPEndpointStatement(fromAddr, toAddr) } case *v5wire.Findnode: t.handleFindnode(p, fromID, fromAddr) @@ -848,7 +847,6 @@ func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr net // collectTableNodes creates a FINDNODE result set for the given distances. func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) []*enode.Node { - ripSlice := rip.AsSlice() var bn []*enode.Node var nodes []*enode.Node var processed = make(map[uint]struct{}) @@ -863,7 +861,7 @@ func (t *UDPv5) collectTableNodes(rip netip.Addr, distances []uint, limit int) [ for _, n := range t.tab.appendLiveNodes(dist, bn[:0]) { // Apply some pre-checks to avoid sending invalid nodes. // Note liveness is checked by appendLiveNodes. - if netutil.CheckRelayIP(ripSlice, n.IP()) != nil { + if netutil.CheckRelayAddr(rip, n.IPAddr()) != nil { continue } nodes = append(nodes, n) diff --git a/p2p/discover/v5wire/encoding_test.go b/p2p/discover/v5wire/encoding_test.go index 27966f2afc..8dd02620eb 100644 --- a/p2p/discover/v5wire/encoding_test.go +++ b/p2p/discover/v5wire/encoding_test.go @@ -606,7 +606,7 @@ func (n *handshakeTestNode) n() *enode.Node { } func (n *handshakeTestNode) addr() string { - return n.ln.Node().IP().String() + return n.ln.Node().IPAddr().String() } func (n *handshakeTestNode) id() enode.ID { diff --git a/p2p/enode/localnode.go b/p2p/enode/localnode.go index a18204e752..6e79c9cbdc 100644 --- a/p2p/enode/localnode.go +++ b/p2p/enode/localnode.go @@ -20,8 +20,8 @@ import ( "crypto/ecdsa" "fmt" "net" + "net/netip" "reflect" - "strconv" "sync" "sync/atomic" "time" @@ -175,8 +175,8 @@ func (ln *LocalNode) delete(e enr.Entry) { } } -func (ln *LocalNode) endpointForIP(ip net.IP) *lnEndpoint { - if ip.To4() != nil { +func (ln *LocalNode) endpointForIP(ip netip.Addr) *lnEndpoint { + if ip.Is4() { return &ln.endpoint4 } return &ln.endpoint6 @@ -188,7 +188,7 @@ func (ln *LocalNode) SetStaticIP(ip net.IP) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(ip).staticIP = ip + ln.endpointForIP(netutil.IPToAddr(ip)).staticIP = ip ln.updateEndpoints() } @@ -198,7 +198,7 @@ func (ln *LocalNode) SetFallbackIP(ip net.IP) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(ip).fallbackIP = ip + ln.endpointForIP(netutil.IPToAddr(ip)).fallbackIP = ip ln.updateEndpoints() } @@ -215,21 +215,21 @@ func (ln *LocalNode) SetFallbackUDP(port int) { // UDPEndpointStatement should be called whenever a statement about the local node's // UDP endpoint is received. It feeds the local endpoint predictor. -func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint *net.UDPAddr) { +func (ln *LocalNode) UDPEndpointStatement(fromaddr, endpoint netip.AddrPort) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(endpoint.IP).track.AddStatement(fromaddr.String(), endpoint.String()) + ln.endpointForIP(endpoint.Addr()).track.AddStatement(fromaddr.Addr(), endpoint) ln.updateEndpoints() } // UDPContact should be called whenever the local node has announced itself to another node // via UDP. It feeds the local endpoint predictor. -func (ln *LocalNode) UDPContact(toaddr *net.UDPAddr) { +func (ln *LocalNode) UDPContact(toaddr netip.AddrPort) { ln.mu.Lock() defer ln.mu.Unlock() - ln.endpointForIP(toaddr.IP).track.AddContact(toaddr.String()) + ln.endpointForIP(toaddr.Addr()).track.AddContact(toaddr.Addr()) ln.updateEndpoints() } @@ -268,29 +268,13 @@ func (e *lnEndpoint) get() (newIP net.IP, newPort uint16) { } if e.staticIP != nil { newIP = e.staticIP - } else if ip, port := predictAddr(e.track); ip != nil { - newIP = ip - newPort = port + } else if ap := e.track.PredictEndpoint(); ap.IsValid() { + newIP = ap.Addr().AsSlice() + newPort = ap.Port() } return newIP, newPort } -// predictAddr wraps IPTracker.PredictEndpoint, converting from its string-based -// endpoint representation to IP and port types. -func predictAddr(t *netutil.IPTracker) (net.IP, uint16) { - ep := t.PredictEndpoint() - if ep == "" { - return nil, 0 - } - ipString, portString, _ := net.SplitHostPort(ep) - ip := net.ParseIP(ipString) - port, err := strconv.ParseUint(portString, 10, 16) - if err != nil { - return nil, 0 - } - return ip, uint16(port) -} - func (ln *LocalNode) invalidate() { ln.cur.Store((*Node)(nil)) } @@ -314,7 +298,7 @@ func (ln *LocalNode) sign() { panic(fmt.Errorf("enode: can't verify local record: %v", err)) } ln.cur.Store(n) - log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IP(), "udp", n.UDP(), "tcp", n.TCP()) + log.Info("New local node record", "seq", ln.seq, "id", n.ID(), "ip", n.IPAddr(), "udp", n.UDP(), "tcp", n.TCP()) } func (ln *LocalNode) bumpSeq() { diff --git a/p2p/enode/localnode_test.go b/p2p/enode/localnode_test.go index 7f97ad392f..86b962a74e 100644 --- a/p2p/enode/localnode_test.go +++ b/p2p/enode/localnode_test.go @@ -17,12 +17,14 @@ package enode import ( - "crypto/rand" + "math/rand" "net" + "net/netip" "testing" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/p2p/enr" + "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/stretchr/testify/assert" ) @@ -88,6 +90,7 @@ func TestLocalNodeSeqPersist(t *testing.T) { // This test checks behavior of the endpoint predictor. func TestLocalNodeEndpoint(t *testing.T) { var ( + rng = rand.New(rand.NewSource(4)) fallback = &net.UDPAddr{IP: net.IP{127, 0, 0, 1}, Port: 80} predicted = &net.UDPAddr{IP: net.IP{127, 0, 1, 2}, Port: 81} staticIP = net.IP{127, 0, 1, 2} @@ -96,6 +99,7 @@ func TestLocalNodeEndpoint(t *testing.T) { defer db.Close() // Nothing is set initially. + assert.Equal(t, netip.Addr{}, ln.Node().IPAddr()) assert.Equal(t, net.IP(nil), ln.Node().IP()) assert.Equal(t, 0, ln.Node().UDP()) initialSeq := ln.Node().Seq() @@ -103,26 +107,30 @@ func TestLocalNodeEndpoint(t *testing.T) { // Set up fallback address. ln.SetFallbackIP(fallback.IP) ln.SetFallbackUDP(fallback.Port) + assert.Equal(t, netutil.IPToAddr(fallback.IP), ln.Node().IPAddr()) assert.Equal(t, fallback.IP, ln.Node().IP()) assert.Equal(t, fallback.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+1, ln.Node().Seq()) // Add endpoint statements from random hosts. for i := 0; i < iptrackMinStatements; i++ { + assert.Equal(t, netutil.IPToAddr(fallback.IP), ln.Node().IPAddr()) assert.Equal(t, fallback.IP, ln.Node().IP()) assert.Equal(t, fallback.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+1, ln.Node().Seq()) - from := &net.UDPAddr{IP: make(net.IP, 4), Port: 90} - rand.Read(from.IP) - ln.UDPEndpointStatement(from, predicted) + from := netip.AddrPortFrom(netutil.RandomAddr(rng, true), 9000) + endpoint := netip.AddrPortFrom(netutil.IPToAddr(predicted.IP), uint16(predicted.Port)) + ln.UDPEndpointStatement(from, endpoint) } + assert.Equal(t, netutil.IPToAddr(predicted.IP), ln.Node().IPAddr()) assert.Equal(t, predicted.IP, ln.Node().IP()) assert.Equal(t, predicted.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+2, ln.Node().Seq()) // Static IP overrides prediction. ln.SetStaticIP(staticIP) + assert.Equal(t, netutil.IPToAddr(staticIP), ln.Node().IPAddr()) assert.Equal(t, staticIP, ln.Node().IP()) assert.Equal(t, fallback.Port, ln.Node().UDP()) assert.Equal(t, initialSeq+3, ln.Node().Seq()) diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go index 654d71d47b..1f31c98d22 100644 --- a/p2p/enode/nodedb.go +++ b/p2p/enode/nodedb.go @@ -21,7 +21,7 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "net" + "net/netip" "os" "sync" "time" @@ -66,7 +66,7 @@ var ( errInvalidIP = errors.New("invalid IP") ) -var zeroIP = make(net.IP, 16) +var zeroIP = netip.IPv6Unspecified() // DB is the node database, storing previously seen nodes and any collected metadata about // them for QoS purposes. @@ -151,39 +151,37 @@ func splitNodeKey(key []byte) (id ID, rest []byte) { } // nodeItemKey returns the database key for a node metadata field. -func nodeItemKey(id ID, ip net.IP, field string) []byte { - ip16 := ip.To16() - if ip16 == nil { - panic(fmt.Errorf("invalid IP (length %d)", len(ip))) +func nodeItemKey(id ID, ip netip.Addr, field string) []byte { + if !ip.IsValid() { + panic("invalid IP") } - return bytes.Join([][]byte{nodeKey(id), ip16, []byte(field)}, []byte{':'}) + ip16 := ip.As16() + return bytes.Join([][]byte{nodeKey(id), ip16[:], []byte(field)}, []byte{':'}) } // splitNodeItemKey returns the components of a key created by nodeItemKey. -func splitNodeItemKey(key []byte) (id ID, ip net.IP, field string) { +func splitNodeItemKey(key []byte) (id ID, ip netip.Addr, field string) { id, key = splitNodeKey(key) // Skip discover root. if string(key) == dbDiscoverRoot { - return id, nil, "" + return id, netip.Addr{}, "" } key = key[len(dbDiscoverRoot)+1:] // Split out the IP. - ip = key[:16] - if ip4 := ip.To4(); ip4 != nil { - ip = ip4 - } + ip, _ = netip.AddrFromSlice(key[:16]) key = key[16+1:] // Field is the remainder of key. field = string(key) return id, ip, field } -func v5Key(id ID, ip net.IP, field string) []byte { +func v5Key(id ID, ip netip.Addr, field string) []byte { + ip16 := ip.As16() return bytes.Join([][]byte{ []byte(dbNodePrefix), id[:], []byte(dbDiscv5Root), - ip.To16(), + ip16[:], []byte(field), }, []byte{':'}) } @@ -364,24 +362,24 @@ func (db *DB) expireNodes() { // LastPingReceived retrieves the time of the last ping packet received from // a remote node. -func (db *DB) LastPingReceived(id ID, ip net.IP) time.Time { - if ip = ip.To16(); ip == nil { +func (db *DB) LastPingReceived(id ID, ip netip.Addr) time.Time { + if !ip.IsValid() { return time.Time{} } return time.Unix(db.fetchInt64(nodeItemKey(id, ip, dbNodePing)), 0) } // UpdateLastPingReceived updates the last time we tried contacting a remote node. -func (db *DB) UpdateLastPingReceived(id ID, ip net.IP, instance time.Time) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateLastPingReceived(id ID, ip netip.Addr, instance time.Time) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(nodeItemKey(id, ip, dbNodePing), instance.Unix()) } // LastPongReceived retrieves the time of the last successful pong from remote node. -func (db *DB) LastPongReceived(id ID, ip net.IP) time.Time { - if ip = ip.To16(); ip == nil { +func (db *DB) LastPongReceived(id ID, ip netip.Addr) time.Time { + if !ip.IsValid() { return time.Time{} } // Launch expirer @@ -390,40 +388,40 @@ func (db *DB) LastPongReceived(id ID, ip net.IP) time.Time { } // UpdateLastPongReceived updates the last pong time of a node. -func (db *DB) UpdateLastPongReceived(id ID, ip net.IP, instance time.Time) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateLastPongReceived(id ID, ip netip.Addr, instance time.Time) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(nodeItemKey(id, ip, dbNodePong), instance.Unix()) } // FindFails retrieves the number of findnode failures since bonding. -func (db *DB) FindFails(id ID, ip net.IP) int { - if ip = ip.To16(); ip == nil { +func (db *DB) FindFails(id ID, ip netip.Addr) int { + if !ip.IsValid() { return 0 } return int(db.fetchInt64(nodeItemKey(id, ip, dbNodeFindFails))) } // UpdateFindFails updates the number of findnode failures since bonding. -func (db *DB) UpdateFindFails(id ID, ip net.IP, fails int) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateFindFails(id ID, ip netip.Addr, fails int) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(nodeItemKey(id, ip, dbNodeFindFails), int64(fails)) } // FindFailsV5 retrieves the discv5 findnode failure counter. -func (db *DB) FindFailsV5(id ID, ip net.IP) int { - if ip = ip.To16(); ip == nil { +func (db *DB) FindFailsV5(id ID, ip netip.Addr) int { + if !ip.IsValid() { return 0 } return int(db.fetchInt64(v5Key(id, ip, dbNodeFindFails))) } // UpdateFindFailsV5 stores the discv5 findnode failure counter. -func (db *DB) UpdateFindFailsV5(id ID, ip net.IP, fails int) error { - if ip = ip.To16(); ip == nil { +func (db *DB) UpdateFindFailsV5(id ID, ip netip.Addr, fails int) error { + if !ip.IsValid() { return errInvalidIP } return db.storeInt64(v5Key(id, ip, dbNodeFindFails), int64(fails)) @@ -470,7 +468,7 @@ seek: id[0] = 0 continue seek // iterator exhausted } - if now.Sub(db.LastPongReceived(n.ID(), n.IP())) > maxAge { + if now.Sub(db.LastPongReceived(n.ID(), n.IPAddr())) > maxAge { continue seek } for i := range nodes { diff --git a/p2p/enode/nodedb_test.go b/p2p/enode/nodedb_test.go index 38764f31b1..bc0291665d 100644 --- a/p2p/enode/nodedb_test.go +++ b/p2p/enode/nodedb_test.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "net" + "net/netip" "path/filepath" "reflect" "testing" @@ -48,8 +49,10 @@ func TestDBNodeKey(t *testing.T) { } func TestDBNodeItemKey(t *testing.T) { - wantIP := net.IP{127, 0, 0, 3} + wantIP := netip.MustParseAddr("127.0.0.3") + wantIP4in6 := netip.AddrFrom16(wantIP.As16()) wantField := "foobar" + enc := nodeItemKey(keytestID, wantIP, wantField) want := []byte{ 'n', ':', @@ -69,7 +72,7 @@ func TestDBNodeItemKey(t *testing.T) { if id != keytestID { t.Errorf("splitNodeItemKey returned wrong ID: %v", id) } - if !ip.Equal(wantIP) { + if ip != wantIP4in6 { t.Errorf("splitNodeItemKey returned wrong IP: %v", ip) } if field != wantField { @@ -123,33 +126,33 @@ func TestDBFetchStore(t *testing.T) { defer db.Close() // Check fetch/store operations on a node ping object - if stored := db.LastPingReceived(node.ID(), node.IP()); stored.Unix() != 0 { + if stored := db.LastPingReceived(node.ID(), node.IPAddr()); stored.Unix() != 0 { t.Errorf("ping: non-existing object: %v", stored) } - if err := db.UpdateLastPingReceived(node.ID(), node.IP(), inst); err != nil { + if err := db.UpdateLastPingReceived(node.ID(), node.IPAddr(), inst); err != nil { t.Errorf("ping: failed to update: %v", err) } - if stored := db.LastPingReceived(node.ID(), node.IP()); stored.Unix() != inst.Unix() { + if stored := db.LastPingReceived(node.ID(), node.IPAddr()); stored.Unix() != inst.Unix() { t.Errorf("ping: value mismatch: have %v, want %v", stored, inst) } // Check fetch/store operations on a node pong object - if stored := db.LastPongReceived(node.ID(), node.IP()); stored.Unix() != 0 { + if stored := db.LastPongReceived(node.ID(), node.IPAddr()); stored.Unix() != 0 { t.Errorf("pong: non-existing object: %v", stored) } - if err := db.UpdateLastPongReceived(node.ID(), node.IP(), inst); err != nil { + if err := db.UpdateLastPongReceived(node.ID(), node.IPAddr(), inst); err != nil { t.Errorf("pong: failed to update: %v", err) } - if stored := db.LastPongReceived(node.ID(), node.IP()); stored.Unix() != inst.Unix() { + if stored := db.LastPongReceived(node.ID(), node.IPAddr()); stored.Unix() != inst.Unix() { t.Errorf("pong: value mismatch: have %v, want %v", stored, inst) } // Check fetch/store operations on a node findnode-failure object - if stored := db.FindFails(node.ID(), node.IP()); stored != 0 { + if stored := db.FindFails(node.ID(), node.IPAddr()); stored != 0 { t.Errorf("find-node fails: non-existing object: %v", stored) } - if err := db.UpdateFindFails(node.ID(), node.IP(), num); err != nil { + if err := db.UpdateFindFails(node.ID(), node.IPAddr(), num); err != nil { t.Errorf("find-node fails: failed to update: %v", err) } - if stored := db.FindFails(node.ID(), node.IP()); stored != num { + if stored := db.FindFails(node.ID(), node.IPAddr()); stored != num { t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) } // Check fetch/store operations on an actual node object @@ -266,7 +269,7 @@ func testSeedQuery() error { if err := db.UpdateNode(seed.node); err != nil { return fmt.Errorf("node %d: failed to insert: %v", i, err) } - if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IP(), seed.pong); err != nil { + if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IPAddr(), seed.pong); err != nil { return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err) } } @@ -427,7 +430,7 @@ func TestDBExpiration(t *testing.T) { t.Fatalf("node %d: failed to insert: %v", i, err) } } - if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IP(), seed.pong); err != nil { + if err := db.UpdateLastPongReceived(seed.node.ID(), seed.node.IPAddr(), seed.pong); err != nil { t.Fatalf("node %d: failed to update bondTime: %v", i, err) } } @@ -438,13 +441,13 @@ func TestDBExpiration(t *testing.T) { unixZeroTime := time.Unix(0, 0) for i, seed := range nodeDBExpirationNodes { node := db.Node(seed.node.ID()) - pong := db.LastPongReceived(seed.node.ID(), seed.node.IP()) + pong := db.LastPongReceived(seed.node.ID(), seed.node.IPAddr()) if seed.exp { if seed.storeNode && node != nil { t.Errorf("node %d (%s) shouldn't be present after expiration", i, seed.node.ID().TerminalString()) } if !pong.Equal(unixZeroTime) { - t.Errorf("pong time %d (%s %v) shouldn't be present after expiration", i, seed.node.ID().TerminalString(), seed.node.IP()) + t.Errorf("pong time %d (%s %v) shouldn't be present after expiration", i, seed.node.ID().TerminalString(), seed.node.IPAddr()) } } else { if seed.storeNode && node == nil { @@ -463,7 +466,7 @@ func TestDBExpireV5(t *testing.T) { db, _ := OpenDB("") defer db.Close() - ip := net.IP{127, 0, 0, 1} + ip := netip.MustParseAddr("127.0.0.1") db.UpdateFindFailsV5(ID{}, ip, 4) db.expireNodes() } diff --git a/p2p/netutil/addrutil.go b/p2p/netutil/addrutil.go index fb6d8d2731..b8b318571b 100644 --- a/p2p/netutil/addrutil.go +++ b/p2p/netutil/addrutil.go @@ -16,18 +16,53 @@ package netutil -import "net" +import ( + "fmt" + "math/rand" + "net" + "net/netip" +) -// AddrIP gets the IP address contained in addr. It returns nil if no address is present. -func AddrIP(addr net.Addr) net.IP { +// AddrAddr gets the IP address contained in addr. The result will be invalid if the +// address type is unsupported. +func AddrAddr(addr net.Addr) netip.Addr { switch a := addr.(type) { case *net.IPAddr: - return a.IP + return IPToAddr(a.IP) case *net.TCPAddr: - return a.IP + return IPToAddr(a.IP) case *net.UDPAddr: - return a.IP + return IPToAddr(a.IP) default: - return nil + return netip.Addr{} } } + +// IPToAddr converts net.IP to netip.Addr. Note that unlike netip.AddrFromSlice, this +// function will always ensure that the resulting Addr is IPv4 when the input is. +func IPToAddr(ip net.IP) netip.Addr { + if ip4 := ip.To4(); ip4 != nil { + addr, _ := netip.AddrFromSlice(ip4) + return addr + } else if ip6 := ip.To16(); ip6 != nil { + addr, _ := netip.AddrFromSlice(ip6) + return addr + } + return netip.Addr{} +} + +// RandomAddr creates a random IP address. +func RandomAddr(rng *rand.Rand, ipv4 bool) netip.Addr { + var bytes []byte + if ipv4 || rng.Intn(2) == 0 { + bytes = make([]byte, 4) + } else { + bytes = make([]byte, 16) + } + rng.Read(bytes) + addr, ok := netip.AddrFromSlice(bytes) + if !ok { + panic(fmt.Errorf("BUG! invalid IP %v", bytes)) + } + return addr +} diff --git a/p2p/netutil/iptrack.go b/p2p/netutil/iptrack.go index a070499e19..5140ac7539 100644 --- a/p2p/netutil/iptrack.go +++ b/p2p/netutil/iptrack.go @@ -17,6 +17,7 @@ package netutil import ( + "net/netip" "time" "github.com/ethereum/go-ethereum/common/mclock" @@ -29,14 +30,14 @@ type IPTracker struct { contactWindow time.Duration minStatements int clock mclock.Clock - statements map[string]ipStatement - contact map[string]mclock.AbsTime + statements map[netip.Addr]ipStatement + contact map[netip.Addr]mclock.AbsTime lastStatementGC mclock.AbsTime lastContactGC mclock.AbsTime } type ipStatement struct { - endpoint string + endpoint netip.AddrPort time mclock.AbsTime } @@ -51,9 +52,9 @@ func NewIPTracker(window, contactWindow time.Duration, minStatements int) *IPTra return &IPTracker{ window: window, contactWindow: contactWindow, - statements: make(map[string]ipStatement), + statements: make(map[netip.Addr]ipStatement), minStatements: minStatements, - contact: make(map[string]mclock.AbsTime), + contact: make(map[netip.Addr]mclock.AbsTime), clock: mclock.System{}, } } @@ -74,12 +75,15 @@ func (it *IPTracker) PredictFullConeNAT() bool { } // PredictEndpoint returns the current prediction of the external endpoint. -func (it *IPTracker) PredictEndpoint() string { +func (it *IPTracker) PredictEndpoint() netip.AddrPort { it.gcStatements(it.clock.Now()) // The current strategy is simple: find the endpoint with most statements. - counts := make(map[string]int, len(it.statements)) - maxcount, max := 0, "" + var ( + counts = make(map[netip.AddrPort]int, len(it.statements)) + maxcount int + max netip.AddrPort + ) for _, s := range it.statements { c := counts[s.endpoint] + 1 counts[s.endpoint] = c @@ -91,7 +95,7 @@ func (it *IPTracker) PredictEndpoint() string { } // AddStatement records that a certain host thinks our external endpoint is the one given. -func (it *IPTracker) AddStatement(host, endpoint string) { +func (it *IPTracker) AddStatement(host netip.Addr, endpoint netip.AddrPort) { now := it.clock.Now() it.statements[host] = ipStatement{endpoint, now} if time.Duration(now-it.lastStatementGC) >= it.window { @@ -101,7 +105,7 @@ func (it *IPTracker) AddStatement(host, endpoint string) { // AddContact records that a packet containing our endpoint information has been sent to a // certain host. -func (it *IPTracker) AddContact(host string) { +func (it *IPTracker) AddContact(host netip.Addr) { now := it.clock.Now() it.contact[host] = now if time.Duration(now-it.lastContactGC) >= it.contactWindow { diff --git a/p2p/netutil/iptrack_test.go b/p2p/netutil/iptrack_test.go index ee3bba861e..81653a2733 100644 --- a/p2p/netutil/iptrack_test.go +++ b/p2p/netutil/iptrack_test.go @@ -19,6 +19,7 @@ package netutil import ( crand "crypto/rand" "fmt" + "net/netip" "testing" "time" @@ -42,37 +43,37 @@ func TestIPTracker(t *testing.T) { tests := map[string][]iptrackTestEvent{ "minStatements": { {opPredict, 0, "", ""}, - {opStatement, 0, "127.0.0.1", "127.0.0.2"}, + {opStatement, 0, "127.0.0.1:8000", "127.0.0.2"}, {opPredict, 1000, "", ""}, - {opStatement, 1000, "127.0.0.1", "127.0.0.3"}, + {opStatement, 1000, "127.0.0.1:8000", "127.0.0.3"}, {opPredict, 1000, "", ""}, - {opStatement, 1000, "127.0.0.1", "127.0.0.4"}, - {opPredict, 1000, "127.0.0.1", ""}, + {opStatement, 1000, "127.0.0.1:8000", "127.0.0.4"}, + {opPredict, 1000, "127.0.0.1:8000", ""}, }, "window": { - {opStatement, 0, "127.0.0.1", "127.0.0.2"}, - {opStatement, 2000, "127.0.0.1", "127.0.0.3"}, - {opStatement, 3000, "127.0.0.1", "127.0.0.4"}, - {opPredict, 10000, "127.0.0.1", ""}, + {opStatement, 0, "127.0.0.1:8000", "127.0.0.2"}, + {opStatement, 2000, "127.0.0.1:8000", "127.0.0.3"}, + {opStatement, 3000, "127.0.0.1:8000", "127.0.0.4"}, + {opPredict, 10000, "127.0.0.1:8000", ""}, {opPredict, 10001, "", ""}, // first statement expired - {opStatement, 10100, "127.0.0.1", "127.0.0.2"}, - {opPredict, 10200, "127.0.0.1", ""}, + {opStatement, 10100, "127.0.0.1:8000", "127.0.0.2"}, + {opPredict, 10200, "127.0.0.1:8000", ""}, }, "fullcone": { {opContact, 0, "", "127.0.0.2"}, - {opStatement, 10, "127.0.0.1", "127.0.0.2"}, + {opStatement, 10, "127.0.0.1:8000", "127.0.0.2"}, {opContact, 2000, "", "127.0.0.3"}, - {opStatement, 2010, "127.0.0.1", "127.0.0.3"}, + {opStatement, 2010, "127.0.0.1:8000", "127.0.0.3"}, {opContact, 3000, "", "127.0.0.4"}, - {opStatement, 3010, "127.0.0.1", "127.0.0.4"}, + {opStatement, 3010, "127.0.0.1:8000", "127.0.0.4"}, {opCheckFullCone, 3500, "false", ""}, }, "fullcone_2": { {opContact, 0, "", "127.0.0.2"}, - {opStatement, 10, "127.0.0.1", "127.0.0.2"}, + {opStatement, 10, "127.0.0.1:8000", "127.0.0.2"}, {opContact, 2000, "", "127.0.0.3"}, - {opStatement, 2010, "127.0.0.1", "127.0.0.3"}, - {opStatement, 3000, "127.0.0.1", "127.0.0.4"}, + {opStatement, 2010, "127.0.0.1:8000", "127.0.0.3"}, + {opStatement, 3000, "127.0.0.1:8000", "127.0.0.4"}, {opContact, 3010, "", "127.0.0.4"}, {opCheckFullCone, 3500, "true", ""}, }, @@ -93,12 +94,19 @@ func runIPTrackerTest(t *testing.T, evs []iptrackTestEvent) { clock.Run(evtime - time.Duration(clock.Now())) switch ev.op { case opStatement: - it.AddStatement(ev.from, ev.ip) + it.AddStatement(netip.MustParseAddr(ev.from), netip.MustParseAddrPort(ev.ip)) case opContact: - it.AddContact(ev.from) + it.AddContact(netip.MustParseAddr(ev.from)) case opPredict: - if pred := it.PredictEndpoint(); pred != ev.ip { - t.Errorf("op %d: wrong prediction %q, want %q", i, pred, ev.ip) + pred := it.PredictEndpoint() + if ev.ip == "" { + if pred.IsValid() { + t.Errorf("op %d: wrong prediction %v, expected invalid", i, pred) + } + } else { + if pred != netip.MustParseAddrPort(ev.ip) { + t.Errorf("op %d: wrong prediction %v, want %q", i, pred, ev.ip) + } } case opCheckFullCone: pred := fmt.Sprintf("%t", it.PredictFullConeNAT()) @@ -121,12 +129,11 @@ func TestIPTrackerForceGC(t *testing.T) { it.clock = &clock for i := 0; i < 5*max; i++ { - e1 := make([]byte, 4) - e2 := make([]byte, 4) - crand.Read(e1) - crand.Read(e2) - it.AddStatement(string(e1), string(e2)) - it.AddContact(string(e1)) + var e1, e2 [4]byte + crand.Read(e1[:]) + crand.Read(e2[:]) + it.AddStatement(netip.AddrFrom4(e1), netip.AddrPortFrom(netip.AddrFrom4(e2), 9000)) + it.AddContact(netip.AddrFrom4(e1)) clock.Run(rate) } if len(it.contact) > 2*max { diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index d5da3c694f..474912978e 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -22,21 +22,19 @@ import ( "errors" "fmt" "net" - "sort" + "net/netip" + "slices" "strings" + + "golang.org/x/exp/maps" ) -var lan4, lan6, special4, special6 Netlist +var special4, special6 Netlist func init() { // Lists from RFC 5735, RFC 5156, // https://www.iana.org/assignments/iana-ipv4-special-registry/ - lan4.Add("0.0.0.0/8") // "This" network - lan4.Add("10.0.0.0/8") // Private Use - lan4.Add("172.16.0.0/12") // Private Use - lan4.Add("192.168.0.0/16") // Private Use - lan6.Add("fe80::/10") // Link-Local - lan6.Add("fc00::/7") // Unique-Local + special4.Add("0.0.0.0/8") // "This" network. special4.Add("192.0.0.0/29") // IPv4 Service Continuity special4.Add("192.0.0.9/32") // PCP Anycast special4.Add("192.0.0.170/32") // NAT64/DNS64 Discovery @@ -66,7 +64,7 @@ func init() { } // Netlist is a list of IP networks. -type Netlist []net.IPNet +type Netlist []netip.Prefix // ParseNetlist parses a comma-separated list of CIDR masks. // Whitespace and extra commas are ignored. @@ -78,11 +76,11 @@ func ParseNetlist(s string) (*Netlist, error) { if mask == "" { continue } - _, n, err := net.ParseCIDR(mask) + prefix, err := netip.ParsePrefix(mask) if err != nil { return nil, err } - l = append(l, *n) + l = append(l, prefix) } return &l, nil } @@ -103,11 +101,11 @@ func (l *Netlist) UnmarshalTOML(fn func(interface{}) error) error { return err } for _, mask := range masks { - _, n, err := net.ParseCIDR(mask) + prefix, err := netip.ParsePrefix(mask) if err != nil { return err } - *l = append(*l, *n) + *l = append(*l, prefix) } return nil } @@ -115,15 +113,20 @@ func (l *Netlist) UnmarshalTOML(fn func(interface{}) error) error { // Add parses a CIDR mask and appends it to the list. It panics for invalid masks and is // intended to be used for setting up static lists. func (l *Netlist) Add(cidr string) { - _, n, err := net.ParseCIDR(cidr) + prefix, err := netip.ParsePrefix(cidr) if err != nil { panic(err) } - *l = append(*l, *n) + *l = append(*l, prefix) } // Contains reports whether the given IP is contained in the list. func (l *Netlist) Contains(ip net.IP) bool { + return l.ContainsAddr(IPToAddr(ip)) +} + +// ContainsAddr reports whether the given IP is contained in the list. +func (l *Netlist) ContainsAddr(ip netip.Addr) bool { if l == nil { return false } @@ -137,25 +140,39 @@ func (l *Netlist) Contains(ip net.IP) bool { // IsLAN reports whether an IP is a local network address. func IsLAN(ip net.IP) bool { + return AddrIsLAN(IPToAddr(ip)) +} + +// AddrIsLAN reports whether an IP is a local network address. +func AddrIsLAN(ip netip.Addr) bool { + if ip.Is4In6() { + ip = netip.AddrFrom4(ip.As4()) + } if ip.IsLoopback() { return true } - if v4 := ip.To4(); v4 != nil { - return lan4.Contains(v4) - } - return lan6.Contains(ip) + return ip.IsPrivate() || ip.IsLinkLocalUnicast() } // IsSpecialNetwork reports whether an IP is located in a special-use network range // This includes broadcast, multicast and documentation addresses. func IsSpecialNetwork(ip net.IP) bool { + return AddrIsSpecialNetwork(IPToAddr(ip)) +} + +// AddrIsSpecialNetwork reports whether an IP is located in a special-use network range +// This includes broadcast, multicast and documentation addresses. +func AddrIsSpecialNetwork(ip netip.Addr) bool { + if ip.Is4In6() { + ip = netip.AddrFrom4(ip.As4()) + } if ip.IsMulticast() { return true } - if v4 := ip.To4(); v4 != nil { - return special4.Contains(v4) + if ip.Is4() { + return special4.ContainsAddr(ip) } - return special6.Contains(ip) + return special6.ContainsAddr(ip) } var ( @@ -175,19 +192,31 @@ var ( // - LAN addresses are OK if relayed by a LAN host. // - All other addresses are always acceptable. func CheckRelayIP(sender, addr net.IP) error { - if len(addr) != net.IPv4len && len(addr) != net.IPv6len { + return CheckRelayAddr(IPToAddr(sender), IPToAddr(addr)) +} + +// CheckRelayAddr reports whether an IP relayed from the given sender IP +// is a valid connection target. +// +// There are four rules: +// - Special network addresses are never valid. +// - Loopback addresses are OK if relayed by a loopback host. +// - LAN addresses are OK if relayed by a LAN host. +// - All other addresses are always acceptable. +func CheckRelayAddr(sender, addr netip.Addr) error { + if !addr.IsValid() { return errInvalid } if addr.IsUnspecified() { return errUnspecified } - if IsSpecialNetwork(addr) { + if AddrIsSpecialNetwork(addr) { return errSpecial } if addr.IsLoopback() && !sender.IsLoopback() { return errLoopback } - if IsLAN(addr) && !IsLAN(sender) { + if AddrIsLAN(addr) && !AddrIsLAN(sender) { return errLAN } return nil @@ -221,17 +250,22 @@ type DistinctNetSet struct { Subnet uint // number of common prefix bits Limit uint // maximum number of IPs in each subnet - members map[string]uint - buf net.IP + members map[netip.Prefix]uint } // Add adds an IP address to the set. It returns false (and doesn't add the IP) if the // number of existing IPs in the defined range exceeds the limit. func (s *DistinctNetSet) Add(ip net.IP) bool { + return s.AddAddr(IPToAddr(ip)) +} + +// AddAddr adds an IP address to the set. It returns false (and doesn't add the IP) if the +// number of existing IPs in the defined range exceeds the limit. +func (s *DistinctNetSet) AddAddr(ip netip.Addr) bool { key := s.key(ip) - n := s.members[string(key)] + n := s.members[key] if n < s.Limit { - s.members[string(key)] = n + 1 + s.members[key] = n + 1 return true } return false @@ -239,20 +273,30 @@ func (s *DistinctNetSet) Add(ip net.IP) bool { // Remove removes an IP from the set. func (s *DistinctNetSet) Remove(ip net.IP) { + s.RemoveAddr(IPToAddr(ip)) +} + +// RemoveAddr removes an IP from the set. +func (s *DistinctNetSet) RemoveAddr(ip netip.Addr) { key := s.key(ip) - if n, ok := s.members[string(key)]; ok { + if n, ok := s.members[key]; ok { if n == 1 { - delete(s.members, string(key)) + delete(s.members, key) } else { - s.members[string(key)] = n - 1 + s.members[key] = n - 1 } } } // Contains whether the given IP is contained in the set. func (s DistinctNetSet) Contains(ip net.IP) bool { + return s.ContainsAddr(IPToAddr(ip)) +} + +// ContainsAddr whether the given IP is contained in the set. +func (s DistinctNetSet) ContainsAddr(ip netip.Addr) bool { key := s.key(ip) - _, ok := s.members[string(key)] + _, ok := s.members[key] return ok } @@ -265,54 +309,30 @@ func (s DistinctNetSet) Len() int { return int(n) } -// key encodes the map key for an address into a temporary buffer. -// -// The first byte of key is '4' or '6' to distinguish IPv4/IPv6 address types. -// The remainder of the key is the IP, truncated to the number of bits. -func (s *DistinctNetSet) key(ip net.IP) net.IP { +// key returns the map key for ip. +func (s *DistinctNetSet) key(ip netip.Addr) netip.Prefix { // Lazily initialize storage. if s.members == nil { - s.members = make(map[string]uint) - s.buf = make(net.IP, 17) + s.members = make(map[netip.Prefix]uint) } - // Canonicalize ip and bits. - typ := byte('6') - if ip4 := ip.To4(); ip4 != nil { - typ, ip = '4', ip4 + p, err := ip.Prefix(int(s.Subnet)) + if err != nil { + panic(err) } - bits := s.Subnet - if bits > uint(len(ip)*8) { - bits = uint(len(ip) * 8) - } - // Encode the prefix into s.buf. - nb := int(bits / 8) - mask := ^byte(0xFF >> (bits % 8)) - s.buf[0] = typ - buf := append(s.buf[:1], ip[:nb]...) - if nb < len(ip) && mask != 0 { - buf = append(buf, ip[nb]&mask) - } - return buf + return p } // String implements fmt.Stringer func (s DistinctNetSet) String() string { + keys := maps.Keys(s.members) + slices.SortFunc(keys, func(a, b netip.Prefix) int { + return strings.Compare(a.String(), b.String()) + }) + var buf bytes.Buffer buf.WriteString("{") - keys := make([]string, 0, len(s.members)) - for k := range s.members { - keys = append(keys, k) - } - sort.Strings(keys) for i, k := range keys { - var ip net.IP - if k[0] == '4' { - ip = make(net.IP, 4) - } else { - ip = make(net.IP, 16) - } - copy(ip, k[1:]) - fmt.Fprintf(&buf, "%v×%d", ip, s.members[k]) + fmt.Fprintf(&buf, "%v×%d", k, s.members[k]) if i != len(keys)-1 { buf.WriteString(" ") } diff --git a/p2p/netutil/net_test.go b/p2p/netutil/net_test.go index 3a6aa081f2..569c7ac454 100644 --- a/p2p/netutil/net_test.go +++ b/p2p/netutil/net_test.go @@ -18,7 +18,9 @@ package netutil import ( "fmt" + "math/rand" "net" + "net/netip" "reflect" "testing" "testing/quick" @@ -29,7 +31,7 @@ import ( func TestParseNetlist(t *testing.T) { var tests = []struct { input string - wantErr error + wantErr string wantList *Netlist }{ { @@ -38,25 +40,27 @@ func TestParseNetlist(t *testing.T) { }, { input: "127.0.0.0/8", - wantErr: nil, - wantList: &Netlist{{IP: net.IP{127, 0, 0, 0}, Mask: net.CIDRMask(8, 32)}}, + wantList: &Netlist{netip.MustParsePrefix("127.0.0.0/8")}, }, { input: "127.0.0.0/44", - wantErr: &net.ParseError{Type: "CIDR address", Text: "127.0.0.0/44"}, + wantErr: `netip.ParsePrefix("127.0.0.0/44"): prefix length out of range`, }, { input: "127.0.0.0/16, 23.23.23.23/24,", wantList: &Netlist{ - {IP: net.IP{127, 0, 0, 0}, Mask: net.CIDRMask(16, 32)}, - {IP: net.IP{23, 23, 23, 0}, Mask: net.CIDRMask(24, 32)}, + netip.MustParsePrefix("127.0.0.0/16"), + netip.MustParsePrefix("23.23.23.23/24"), }, }, } for _, test := range tests { l, err := ParseNetlist(test.input) - if !reflect.DeepEqual(err, test.wantErr) { + if err == nil && test.wantErr != "" { + t.Errorf("%q: got no error, expected %q", test.input, test.wantErr) + continue + } else if err != nil && err.Error() != test.wantErr { t.Errorf("%q: got error %q, want %q", test.input, err, test.wantErr) continue } @@ -70,14 +74,12 @@ func TestParseNetlist(t *testing.T) { func TestNilNetListContains(t *testing.T) { var list *Netlist - checkContains(t, list.Contains, nil, []string{"1.2.3.4"}) + checkContains(t, list.Contains, list.ContainsAddr, nil, []string{"1.2.3.4"}) } func TestIsLAN(t *testing.T) { - checkContains(t, IsLAN, + checkContains(t, IsLAN, AddrIsLAN, []string{ // included - "0.0.0.0", - "0.2.0.8", "127.0.0.1", "10.0.1.1", "10.22.0.3", @@ -86,25 +88,35 @@ func TestIsLAN(t *testing.T) { "fe80::f4a1:8eff:fec5:9d9d", "febf::ab32:2233", "fc00::4", + // 4-in-6 + "::ffff:127.0.0.1", + "::ffff:10.10.0.2", }, []string{ // excluded "192.0.2.1", "1.0.0.0", "172.32.0.1", "fec0::2233", + // 4-in-6 + "::ffff:88.99.100.2", }, ) } func TestIsSpecialNetwork(t *testing.T) { - checkContains(t, IsSpecialNetwork, + checkContains(t, IsSpecialNetwork, AddrIsSpecialNetwork, []string{ // included + "0.0.0.0", + "0.2.0.8", "192.0.2.1", "192.0.2.44", "2001:db8:85a3:8d3:1319:8a2e:370:7348", "255.255.255.255", "224.0.0.22", // IPv4 multicast "ff05::1:3", // IPv6 multicast + // 4-in-6 + "::ffff:255.255.255.255", + "::ffff:192.0.2.1", }, []string{ // excluded "192.0.3.1", @@ -115,15 +127,21 @@ func TestIsSpecialNetwork(t *testing.T) { ) } -func checkContains(t *testing.T, fn func(net.IP) bool, inc, exc []string) { +func checkContains(t *testing.T, fn func(net.IP) bool, fn2 func(netip.Addr) bool, inc, exc []string) { for _, s := range inc { if !fn(parseIP(s)) { - t.Error("returned false for included address", s) + t.Error("returned false for included net.IP", s) + } + if !fn2(netip.MustParseAddr(s)) { + t.Error("returned false for included netip.Addr", s) } } for _, s := range exc { if fn(parseIP(s)) { - t.Error("returned true for excluded address", s) + t.Error("returned true for excluded net.IP", s) + } + if fn2(netip.MustParseAddr(s)) { + t.Error("returned true for excluded netip.Addr", s) } } } @@ -244,14 +262,22 @@ func TestDistinctNetSet(t *testing.T) { } func TestDistinctNetSetAddRemove(t *testing.T) { - cfg := &quick.Config{} - fn := func(ips []net.IP) bool { + cfg := &quick.Config{ + Values: func(s []reflect.Value, rng *rand.Rand) { + slice := make([]netip.Addr, rng.Intn(20)+1) + for i := range slice { + slice[i] = RandomAddr(rng, false) + } + s[0] = reflect.ValueOf(slice) + }, + } + fn := func(ips []netip.Addr) bool { s := DistinctNetSet{Limit: 3, Subnet: 2} for _, ip := range ips { - s.Add(ip) + s.AddAddr(ip) } for _, ip := range ips { - s.Remove(ip) + s.RemoveAddr(ip) } return s.Len() == 0 } diff --git a/p2p/server.go b/p2p/server.go index 13eebed3f4..22e5f6cb94 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -905,14 +905,14 @@ func (srv *Server) listenLoop() { break } - remoteIP := netutil.AddrIP(fd.RemoteAddr()) + remoteIP := netutil.AddrAddr(fd.RemoteAddr()) if err := srv.checkInboundConn(remoteIP); err != nil { srv.log.Debug("Rejected inbound connection", "addr", fd.RemoteAddr(), "err", err) fd.Close() slots <- struct{}{} continue } - if remoteIP != nil { + if remoteIP.IsValid() { fd = newMeteredConn(fd) serveMeter.Mark(1) srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr()) @@ -924,18 +924,19 @@ func (srv *Server) listenLoop() { } } -func (srv *Server) checkInboundConn(remoteIP net.IP) error { - if remoteIP == nil { +func (srv *Server) checkInboundConn(remoteIP netip.Addr) error { + if !remoteIP.IsValid() { + // This case happens for internal test connections without remote address. return nil } // Reject connections that do not match NetRestrict. - if srv.NetRestrict != nil && !srv.NetRestrict.Contains(remoteIP) { + if srv.NetRestrict != nil && !srv.NetRestrict.ContainsAddr(remoteIP) { return errors.New("not in netrestrict list") } // Reject Internet peers that try too often. now := srv.clock.Now() srv.inboundHistory.expire(now, nil) - if !netutil.IsLAN(remoteIP) && srv.inboundHistory.contains(remoteIP.String()) { + if !netutil.AddrIsLAN(remoteIP) && srv.inboundHistory.contains(remoteIP.String()) { return errors.New("too many attempts") } srv.inboundHistory.add(remoteIP.String(), now.Add(inboundThrottleTime)) @@ -1108,7 +1109,7 @@ func (srv *Server) NodeInfo() *NodeInfo { Name: srv.Name, Enode: node.URLv4(), ID: node.ID().String(), - IP: node.IP().String(), + IP: node.IPAddr().String(), ListenAddr: srv.ListenAddr, Protocols: make(map[string]interface{}), } diff --git a/p2p/server_nat_test.go b/p2p/server_nat_test.go index de935fcfc5..cbb1f37e0a 100644 --- a/p2p/server_nat_test.go +++ b/p2p/server_nat_test.go @@ -18,6 +18,7 @@ package p2p import ( "net" + "net/netip" "sync/atomic" "testing" "time" @@ -64,8 +65,8 @@ func TestServerPortMapping(t *testing.T) { t.Error("wrong request count:", reqCount) } enr := srv.LocalNode().Node() - if enr.IP().String() != "192.0.2.0" { - t.Error("wrong IP in ENR:", enr.IP()) + if enr.IPAddr() != netip.MustParseAddr("192.0.2.0") { + t.Error("wrong IP in ENR:", enr.IPAddr()) } if enr.TCP() != 30000 { t.Error("wrong TCP port in ENR:", enr.TCP()) From 6c518fe6068726679016123d574a0523b2855168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Thu, 6 Jun 2024 09:52:57 +0200 Subject: [PATCH 060/196] build: upgrade -dlgo version to Go 1.22.4 (#29938) --- build/checksums.txt | 89 ++++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 94cac9738c..d099e53156 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,48 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.3 +# version:golang 1.22.4 # https://go.dev/dl/ -80648ef34f903193d72a59c0dff019f5f98ae0c9aa13ade0b0ecbff991a76f68 go1.22.3.src.tar.gz -adc9f5fee89cd53d907eb542d3b269d9d8a08a66bf1ab42175450ffbb58733fb go1.22.3.aix-ppc64.tar.gz -610e48c1df4d2f852de8bc2e7fd2dc1521aac216f0c0026625db12f67f192024 go1.22.3.darwin-amd64.tar.gz -02abeab3f4b8981232237ebd88f0a9bad933bc9621791cd7720a9ca29eacbe9d go1.22.3.darwin-arm64.tar.gz -a5b3d54905f17af2ceaf7fcfe92edee67a5bd4eccd962dd89df719ace3e0894d go1.22.3.dragonfly-amd64.tar.gz -b9989ca87695ae93bacde6f3aa7b13cde5f3825515eb9ed9bbef014273739889 go1.22.3.freebsd-386.tar.gz -7483961fae29d7d768afd5c9c0f229354ca3263ab7119c20bc182761f87cbc74 go1.22.3.freebsd-amd64.tar.gz -edf1f0b8ecf68b14faeedb4f5d868a58c4777a0282bd85e5115c39c010cd0130 go1.22.3.freebsd-arm.tar.gz -572eb70e5e835fbff7d53ebf473f611d7eb458c428f8dbd98a49196883c3309e go1.22.3.freebsd-arm64.tar.gz -ef94eb2b74402e436dce970584222c4e454eb3093908591149bd2ded6862b8af go1.22.3.freebsd-riscv64.tar.gz -3c3f498c68334cbd11f72aadfb6bcb507eb8436cebc50f437a0523cd4c5e03d1 go1.22.3.illumos-amd64.tar.gz -fefba30bb0d3dd1909823ee38c9f1930c3dc5337a2ac4701c2277a329a386b57 go1.22.3.linux-386.tar.gz -8920ea521bad8f6b7bc377b4824982e011c19af27df88a815e3586ea895f1b36 go1.22.3.linux-amd64.tar.gz -6c33e52a5b26e7aa021b94475587fce80043a727a54ceb0eee2f9fc160646434 go1.22.3.linux-arm64.tar.gz -f2bacad20cd2b96f23a86d4826525d42b229fd431cc6d0dec61ff3bc448ef46e go1.22.3.linux-armv6l.tar.gz -41e9328340544893482b2928ae18a9a88ba18b2fdd29ac77f4d33cf1815bbdc2 go1.22.3.linux-loong64.tar.gz -cf4d5faff52e642492729eaf396968f43af179518be769075b90bc1bf650abf6 go1.22.3.linux-mips.tar.gz -3bd009fe2e3d2bfd52433a11cb210d1dfa50b11b4c347a293951efd9e36de945 go1.22.3.linux-mips64.tar.gz -5913b82a042188ef698f7f2dfd0cd0c71f0508a4739de9e41fceff3f4dc769b4 go1.22.3.linux-mips64le.tar.gz -441afebca555be5313867b4577f237c7b5c0fff4386e22e47875b9f805abbec5 go1.22.3.linux-mipsle.tar.gz -f3b53190a76f4a35283501ba6d94cbb72093be0c62ff735c6f9e586a1c983381 go1.22.3.linux-ppc64.tar.gz -04b7b05283de30dd2da20bf3114b2e22cc727938aed3148babaf35cc951051ac go1.22.3.linux-ppc64le.tar.gz -d4992d4a85696e3f1de06cefbfc2fd840c9c6695d77a0f35cfdc4e28b2121c20 go1.22.3.linux-riscv64.tar.gz -2aba796417a69be5f3ed489076bac79c1c02b36e29422712f9f3bf51da9cf2d4 go1.22.3.linux-s390x.tar.gz -d6e6113542dd9f23db899e177fe23772bac114a5ea5e8ee436b9da68628335a8 go1.22.3.netbsd-386.tar.gz -c33cee3075bd18ceefddd75bafa8efb51fbdc17b5ee74275122e7a927a237a4c go1.22.3.netbsd-amd64.tar.gz -1ab251df3c85f3b391a09565ca52fb6e1306527d72852d553e9ab74eabb4ecf8 go1.22.3.netbsd-arm.tar.gz -1d194fe53f5d82f9a612f848950d8af8cab7cb40ccc03f10c4eb1c9808ff1a0c go1.22.3.netbsd-arm64.tar.gz -91d6601727f08506e938640885d3ded784925045e3a4444fd9b4b936efe1b1e0 go1.22.3.openbsd-386.tar.gz -09d0c91ae35a4eea92615426992062ca236cc2f66444fb0b0a24cd3b13bd5297 go1.22.3.openbsd-amd64.tar.gz -338da30cc2c97b9458e0b4caa2509f67bba55d3de16fb7d31775baca82d2e3dc go1.22.3.openbsd-arm.tar.gz -53eadfabd2b7dd09a64941421afee2a2888e2a4f94f353b27919b1dad1171a21 go1.22.3.openbsd-arm64.tar.gz -8a1a2842ae8dcf2374bb05dff58074b368bb698dc9c211c794c1ff119cd9fdc7 go1.22.3.plan9-386.tar.gz -f9816d3dd9e730cad55085ea08c1f0c925720728f9c945fff59cd24d2ac2db7b go1.22.3.plan9-amd64.tar.gz -f4d3d7b17c9e1b1635fcb287b5b5ab5b60acc9db3ba6a27f2b2f5d6537a2ef95 go1.22.3.plan9-arm.tar.gz -46b7999ee94d91b21ad6940b5a3131ff6fe53ef97be9a34e582e2a3ad7263e95 go1.22.3.solaris-amd64.tar.gz -f60f63b8a0885e0d924f39fd284aee5438fe87d8c3d8545a312adf43e0d9edac go1.22.3.windows-386.zip -cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windows-amd64.zip -40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip -59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.windows-arm64.zip +fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz +b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz +7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg +c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz +4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg +242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz +f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz +7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz +88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz +3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz +726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz +5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz +d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz +47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz +ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz +a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz +e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz +e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz +73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz +417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz +7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz +69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz +dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz +a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz +56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz +7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz +ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz +33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz +fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz +c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz +d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz +72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz +1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz +a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz +9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz +a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz +5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz +6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz +e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz +5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi +aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip +3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi +26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip +c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi +5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip +553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi +8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From cbbfa3eac05b816a704ef2e50ab0a7ac8a9c4dcc Mon Sep 17 00:00:00 2001 From: Marquis Shanahan <29431502+9547@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:55:38 +0800 Subject: [PATCH 061/196] rlp: no need to repeat called len method (#29936) rlp: no need to repeat calling len --- rlp/raw.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/rlp/raw.go b/rlp/raw.go index 773aa7e614..879e3bfe5d 100644 --- a/rlp/raw.go +++ b/rlp/raw.go @@ -30,33 +30,33 @@ var rawValueType = reflect.TypeOf(RawValue{}) // StringSize returns the encoded size of a string. func StringSize(s string) uint64 { - switch { - case len(s) == 0: + switch n := len(s); n { + case 0: return 1 - case len(s) == 1: + case 1: if s[0] <= 0x7f { return 1 } else { return 2 } default: - return uint64(headsize(uint64(len(s))) + len(s)) + return uint64(headsize(uint64(n)) + n) } } // BytesSize returns the encoded size of a byte slice. func BytesSize(b []byte) uint64 { - switch { - case len(b) == 0: + switch n := len(b); n { + case 0: return 1 - case len(b) == 1: + case 1: if b[0] <= 0x7f { return 1 } else { return 2 } default: - return uint64(headsize(uint64(len(b))) + len(b)) + return uint64(headsize(uint64(n)) + n) } } @@ -105,18 +105,20 @@ func SplitUint64(b []byte) (x uint64, rest []byte, err error) { if err != nil { return 0, b, err } - switch { - case len(content) == 0: + switch n := len(content); n { + case 0: return 0, rest, nil - case len(content) == 1: + case 1: if content[0] == 0 { return 0, b, ErrCanonInt } return uint64(content[0]), rest, nil - case len(content) > 8: - return 0, b, errUintOverflow default: - x, err = readSize(content, byte(len(content))) + if n > 8 { + return 0, b, errUintOverflow + } + + x, err = readSize(content, byte(n)) if err != nil { return 0, b, ErrCanonInt } From 0750cb0c8f384ade3213ac3eb18dde214fcc1864 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Thu, 6 Jun 2024 15:56:41 +0800 Subject: [PATCH 062/196] p2p/netutil: fix comments (#29942) --- p2p/netutil/net.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/netutil/net.go b/p2p/netutil/net.go index 474912978e..7d8da88670 100644 --- a/p2p/netutil/net.go +++ b/p2p/netutil/net.go @@ -288,12 +288,12 @@ func (s *DistinctNetSet) RemoveAddr(ip netip.Addr) { } } -// Contains whether the given IP is contained in the set. +// Contains reports whether the given IP is contained in the set. func (s DistinctNetSet) Contains(ip net.IP) bool { return s.ContainsAddr(IPToAddr(ip)) } -// ContainsAddr whether the given IP is contained in the set. +// ContainsAddr reports whether the given IP is contained in the set. func (s DistinctNetSet) ContainsAddr(ip netip.Addr) bool { key := s.key(ip) _, ok := s.members[key] From 85459e14395dcd083076ee356358aec961aa35cc Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 6 Jun 2024 15:15:22 +0200 Subject: [PATCH 063/196] p2p/discover: unwrap 4-in-6 UDP source addresses (#29944) Fixes an issue where discovery responses were not recognized. --- p2p/discover/v4_udp.go | 5 +++++ p2p/discover/v5_udp.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index 6234fd93ca..cca01bd3ce 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -557,6 +557,11 @@ func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { } func (t *UDPv4) handlePacket(from netip.AddrPort, buf []byte) error { + // Unwrap IPv4-in-6 source address. + if from.Addr().Is4In6() { + from = netip.AddrPortFrom(netip.AddrFrom4(from.Addr().As4()), from.Port()) + } + rawpacket, fromKey, hash, err := v4wire.Decode(buf) if err != nil { t.log.Debug("Bad discv4 packet", "addr", from, "err", err) diff --git a/p2p/discover/v5_udp.go b/p2p/discover/v5_udp.go index 4cc21cd9c5..81d94812aa 100644 --- a/p2p/discover/v5_udp.go +++ b/p2p/discover/v5_udp.go @@ -674,6 +674,10 @@ func (t *UDPv5) readLoop() { // dispatchReadPacket sends a packet into the dispatch loop. func (t *UDPv5) dispatchReadPacket(from netip.AddrPort, content []byte) bool { + // Unwrap IPv4-in-6 source address. + if from.Addr().Is4In6() { + from = netip.AddrPortFrom(netip.AddrFrom4(from.Addr().As4()), from.Port()) + } select { case t.packetInCh <- ReadPacket{content, from}: return true From 0dd173a727dd2d2409b8e401b22e85d20c25b71f Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 6 Jun 2024 21:17:53 +0800 Subject: [PATCH 064/196] params: release Geth v1.14.5 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 5ae1187b82..f812cc0c1b 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 5 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 4461c1fc17c489f1df86dea1ebde4247c6305ea4 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 6 Jun 2024 21:23:44 +0800 Subject: [PATCH 065/196] params: begin v1.14.6 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index f812cc0c1b..48bca3c5b2 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 5 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 4405f1851953ff75758d4bd570244a6f6c49d32a Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:04:18 +0200 Subject: [PATCH 066/196] cmd/evm/internal/t8ntool: remove unused parameter (#29930) --- cmd/evm/internal/t8ntool/transition.go | 2 +- cmd/evm/internal/t8ntool/tx_iterator.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 8fd068b2ea..fa052f5954 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -181,7 +181,7 @@ func Transition(ctx *cli.Context) error { // Set the chain id chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) - if txIt, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { + if txIt, err = loadTransactions(txStr, inputData, chainConfig); err != nil { return err } if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil { diff --git a/cmd/evm/internal/t8ntool/tx_iterator.go b/cmd/evm/internal/t8ntool/tx_iterator.go index 046f62314d..d4ebb4b399 100644 --- a/cmd/evm/internal/t8ntool/tx_iterator.go +++ b/cmd/evm/internal/t8ntool/tx_iterator.go @@ -112,7 +112,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran return signedTxs, nil } -func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (txIterator, error) { +func loadTransactions(txStr string, inputData *input, chainConfig *params.ChainConfig) (txIterator, error) { var txsWithKeys []*txWithKey if txStr != stdinSelector { data, err := os.ReadFile(txStr) From 6a49d13c13d967dd9fb2190fd110ef6d90fc09cd Mon Sep 17 00:00:00 2001 From: ucwong Date: Thu, 6 Jun 2024 01:48:22 +0800 Subject: [PATCH 067/196] go.mod : tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 8968140fbf..9947df31f3 100644 --- a/go.mod +++ b/go.mod @@ -68,6 +68,7 @@ require ( github.com/urfave/cli/v2 v2.25.7 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.22.0 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/sync v0.7.0 golang.org/x/sys v0.20.0 golang.org/x/text v0.14.0 @@ -139,7 +140,6 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.24.0 // indirect google.golang.org/protobuf v1.33.0 // indirect From deaf10982cc1a6e02c133a8d70982a25b4ae3084 Mon Sep 17 00:00:00 2001 From: kukuru909 Date: Sat, 8 Jun 2024 20:00:53 +0900 Subject: [PATCH 068/196] cmd/clef, cmd/evm: fix markdown issues in README (#29954) --- cmd/clef/README.md | 4 ++-- cmd/evm/README.md | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmd/clef/README.md b/cmd/clef/README.md index cf09265136..b7018a5f41 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -225,8 +225,8 @@ Response - `value` [number:optional]: amount of Wei to send with the transaction - `data` [data:optional]: input data - `nonce` [number]: account nonce - 1. method signature [string:optional] - - The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected. + 2. method signature [string:optional] + - The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected. #### Result diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 25647c18a9..f95b6b4d7b 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -14,15 +14,15 @@ The `evm t8n` tool is a stateless state transition utility. It is a utility which can 1. Take a prestate, including - - Accounts, - - Block context information, - - Previous blockshashes (*optional) + - Accounts, + - Block context information, + - Previous blockshashes (*optional) 2. Apply a set of transactions, 3. Apply a mining-reward (*optional), 4. And generate a post-state, including - - State root, transaction root, receipt root, - - Information about rejected transactions, - - Optionally: a full or partial post-state dump + - State root, transaction root, receipt root, + - Information about rejected transactions, + - Optionally: a full or partial post-state dump ### Specification From 1098d148a51c929fd9829328fe60ca1214f3c7b5 Mon Sep 17 00:00:00 2001 From: Ha DANG Date: Sat, 8 Jun 2024 18:04:16 +0700 Subject: [PATCH 069/196] cmd/geth: remove unused param (#29952) --- cmd/geth/chaincmd.go | 5 ++--- cmd/geth/snapshot.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index d787f340a3..2965b99d94 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -39,7 +39,6 @@ import ( "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" - "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) @@ -516,7 +515,7 @@ func importPreimages(ctx *cli.Context) error { return nil } -func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*state.DumpConfig, common.Hash, error) { +func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, common.Hash, error) { var header *types.Header if ctx.NArg() > 1 { return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg()) @@ -580,7 +579,7 @@ func dump(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - conf, root, err := parseDumpConfig(ctx, stack, db) + conf, root, err := parseDumpConfig(ctx, db) if err != nil { return err } diff --git a/cmd/geth/snapshot.go b/cmd/geth/snapshot.go index cf7093e605..7d713ad110 100644 --- a/cmd/geth/snapshot.go +++ b/cmd/geth/snapshot.go @@ -544,7 +544,7 @@ func dumpState(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - conf, root, err := parseDumpConfig(ctx, stack, db) + conf, root, err := parseDumpConfig(ctx, db) if err != nil { return err } From 349fcdd22d672fedc59a893e6ebb65349c3dfcdf Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:47:51 +0200 Subject: [PATCH 070/196] p2p/discover: add missing lock when calling tab.handleAddNode (#29960) --- p2p/discover/table.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/p2p/discover/table.go b/p2p/discover/table.go index bb5ab4f3fc..8045f1389e 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -452,7 +452,9 @@ func (tab *Table) loadSeedNodes() { addr, _ := seed.UDPEndpoint() tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", addr, "age", age) } + tab.mutex.Lock() tab.handleAddNode(addNodeOp{node: seed, isInbound: false}) + tab.mutex.Unlock() } } From 8bda6429637c6219be5e0965fab15810fed3dced Mon Sep 17 00:00:00 2001 From: Gealber Morales <48373523+Gealber@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:50:22 +0200 Subject: [PATCH 071/196] p2p: use package slices to sort in PeersInfo (#29957) --- p2p/server.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/p2p/server.go b/p2p/server.go index 22e5f6cb94..172f0667eb 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -19,6 +19,7 @@ package p2p import ( "bytes" + "cmp" "crypto/ecdsa" "encoding/hex" "errors" @@ -1140,12 +1141,9 @@ func (srv *Server) PeersInfo() []*PeerInfo { } } // Sort the result array alphabetically by node identifier - for i := 0; i < len(infos); i++ { - for j := i + 1; j < len(infos); j++ { - if infos[i].ID > infos[j].ID { - infos[i], infos[j] = infos[j], infos[i] - } - } - } + slices.SortFunc(infos, func(a, b *PeerInfo) int { + return cmp.Compare(a.ID, b.ID) + }) + return infos } From db273c8733309d415b0c1296aa8630e67930d16d Mon Sep 17 00:00:00 2001 From: jwasinger Date: Sun, 9 Jun 2024 22:58:50 -0700 Subject: [PATCH 072/196] core: initialize developer genesis beacon root contract with 0 balance (#29963) --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index f1b4490f2e..4ca24807fc 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b // Pre-deploy EIP-4788 system contract - params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode}, + params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, }, } if faucet != nil { From 2eb185c92b2655ceee91b730fc5904379fe0ff6f Mon Sep 17 00:00:00 2001 From: TinyFoxy Date: Mon, 10 Jun 2024 20:55:47 +0800 Subject: [PATCH 073/196] core, rlp: remove duplicated words (#29964) --- core/state/snapshot/iterator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/state/snapshot/iterator_test.go b/core/state/snapshot/iterator_test.go index 54614427a5..daa8cdcc54 100644 --- a/core/state/snapshot/iterator_test.go +++ b/core/state/snapshot/iterator_test.go @@ -815,7 +815,7 @@ func TestStorageIteratorDeletions(t *testing.T) { verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage) } -// BenchmarkAccountIteratorTraversal is a bit a bit notorious -- all layers contain the +// BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the // exact same 200 accounts. That means that we need to process 2000 items, but // only spit out 200 values eventually. // From 85587d5ef2da92edc009b85146200e4012f9f6ed Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 11 Jun 2024 01:10:07 -0700 Subject: [PATCH 074/196] cmd, core: prefetch reads too from tries if requested (#29807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cmd/utils, consensus/beacon, core/state: when configured via stub flag: prefetch all reads from account/storage tries, terminate prefetcher synchronously. * cmd, core/state: fix nil panic, fix error handling, prefetch nosnap too * core/state: expand prefetcher metrics for reads and writes separately * cmd/utils, eth: fix noop collect witness flag --------- Co-authored-by: Péter Szilágyi --- cmd/geth/main.go | 1 + cmd/utils/flags.go | 13 ++- core/blockchain.go | 2 +- core/state/state_object.go | 10 +- core/state/statedb.go | 16 ++- core/state/trie_prefetcher.go | 164 ++++++++++++++++++++--------- core/state/trie_prefetcher_test.go | 6 +- core/vm/interpreter.go | 1 + eth/backend.go | 1 + eth/ethconfig/config.go | 3 + 10 files changed, 160 insertions(+), 57 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b7885608bc..f6bb09ee54 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -156,6 +156,7 @@ var ( utils.BeaconGenesisRootFlag, utils.BeaconGenesisTimeFlag, utils.BeaconCheckpointFlag, + utils.CollectWitnessFlag, }, utils.NetworkFlags, utils.DatabaseFlags) rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ecf6acc186..46d380b984 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -604,6 +604,11 @@ var ( Usage: "Disables db compaction after import", Category: flags.LoggingCategory, } + CollectWitnessFlag = &cli.BoolFlag{ + Name: "collectwitness", + Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.", + Category: flags.MiscCategory, + } // MISC settings SyncTargetFlag = &cli.StringFlag{ @@ -1760,6 +1765,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name) } + if ctx.IsSet(CollectWitnessFlag.Name) { + cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name) + } if ctx.IsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name) @@ -2190,7 +2198,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) { cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100 } - vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)} + vmcfg := vm.Config{ + EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name), + EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name), + } if ctx.IsSet(VMTraceFlag.Name) { if name := ctx.String(VMTraceFlag.Name); name != "" { var config json.RawMessage diff --git a/core/blockchain.go b/core/blockchain.go index 7c8ab3abc4..ac4eb1c47e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1809,7 +1809,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // while processing transactions. Before Byzantium the prefetcher is mostly // useless due to the intermediate root hashing after each transaction. if bc.chainConfig.IsByzantium(block.Number()) { - statedb.StartPrefetcher("chain") + statedb.StartPrefetcher("chain", !bc.vmConfig.EnableWitnessCollection) } activeState = statedb diff --git a/core/state/state_object.go b/core/state/state_object.go index b7a215bd17..16a5f3e5e2 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -230,6 +230,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash { } value.SetBytes(val) } + // Independent of where we loaded the data from, add it to the prefetcher. + // Whilst this would be a bit weird if snapshots are disabled, but we still + // want the trie nodes to end up in the prefetcher too, so just push through. + if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash { + if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil { + log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err) + } + } s.originStorage[key] = value return value } @@ -293,7 +301,7 @@ func (s *stateObject) finalise() { s.pendingStorage[key] = value } if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { - if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil { + if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch, false); err != nil { log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err) } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 61e76cdd77..b4ef0a6e47 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -200,14 +200,14 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string) { +func (s *StateDB) StartPrefetcher(namespace string, noreads bool) { if s.prefetcher != nil { s.prefetcher.terminate(false) s.prefetcher.report() s.prefetcher = nil } if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace) + s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, noreads) // With the switch to the Proof-of-Stake consensus algorithm, block production // rewards are now handled at the consensus layer. Consequently, a block may @@ -218,7 +218,7 @@ func (s *StateDB) StartPrefetcher(namespace string) { // To prevent this, the account trie is always scheduled for prefetching once // the prefetcher is constructed. For more details, see: // https://github.com/ethereum/go-ethereum/issues/29880 - if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil); err != nil { + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil { log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err) } } @@ -616,6 +616,14 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { return nil } } + // Independent of where we loaded the data from, add it to the prefetcher. + // Whilst this would be a bit weird if snapshots are disabled, but we still + // want the trie nodes to end up in the prefetcher too, so just push through. + if s.prefetcher != nil { + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil { + log.Error("Failed to prefetch account", "addr", addr, "err", err) + } + } // Insert into the live set obj := newObject(s, addr, data) s.setStateObject(obj) @@ -792,7 +800,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure } if s.prefetcher != nil && len(addressesToPrefetch) > 0 { - if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch); err != nil { + if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch, false); err != nil { log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err) } } diff --git a/core/state/trie_prefetcher.go b/core/state/trie_prefetcher.go index 5e5afbbecc..491b3807c8 100644 --- a/core/state/trie_prefetcher.go +++ b/core/state/trie_prefetcher.go @@ -44,31 +44,49 @@ type triePrefetcher struct { root common.Hash // Root hash of the account trie for metrics fetchers map[string]*subfetcher // Subfetchers for each trie term chan struct{} // Channel to signal interruption + noreads bool // Whether to ignore state-read-only prefetch requests deliveryMissMeter metrics.Meter - accountLoadMeter metrics.Meter - accountDupMeter metrics.Meter - accountWasteMeter metrics.Meter - storageLoadMeter metrics.Meter - storageDupMeter metrics.Meter - storageWasteMeter metrics.Meter + + accountLoadReadMeter metrics.Meter + accountLoadWriteMeter metrics.Meter + accountDupReadMeter metrics.Meter + accountDupWriteMeter metrics.Meter + accountDupCrossMeter metrics.Meter + accountWasteMeter metrics.Meter + + storageLoadReadMeter metrics.Meter + storageLoadWriteMeter metrics.Meter + storageDupReadMeter metrics.Meter + storageDupWriteMeter metrics.Meter + storageDupCrossMeter metrics.Meter + storageWasteMeter metrics.Meter } -func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher { +func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher { prefix := triePrefetchMetricsPrefix + namespace return &triePrefetcher{ db: db, root: root, fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map term: make(chan struct{}), + noreads: noreads, deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil), - accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil), - accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil), - accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), - storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil), - storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil), - storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), + + accountLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/read", nil), + accountLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/write", nil), + accountDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/read", nil), + accountDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/write", nil), + accountDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/cross", nil), + accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil), + + storageLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/read", nil), + storageLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/write", nil), + storageDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/read", nil), + storageDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/write", nil), + storageDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/cross", nil), + storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil), } } @@ -98,19 +116,31 @@ func (p *triePrefetcher) report() { fetcher.wait() // ensure the fetcher's idle before poking in its internals if fetcher.root == p.root { - p.accountLoadMeter.Mark(int64(len(fetcher.seen))) - p.accountDupMeter.Mark(int64(fetcher.dups)) + p.accountLoadReadMeter.Mark(int64(len(fetcher.seenRead))) + p.accountLoadWriteMeter.Mark(int64(len(fetcher.seenWrite))) + + p.accountDupReadMeter.Mark(int64(fetcher.dupsRead)) + p.accountDupWriteMeter.Mark(int64(fetcher.dupsWrite)) + p.accountDupCrossMeter.Mark(int64(fetcher.dupsCross)) + for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) + delete(fetcher.seenRead, string(key)) + delete(fetcher.seenWrite, string(key)) } - p.accountWasteMeter.Mark(int64(len(fetcher.seen))) + p.accountWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite))) } else { - p.storageLoadMeter.Mark(int64(len(fetcher.seen))) - p.storageDupMeter.Mark(int64(fetcher.dups)) + p.storageLoadReadMeter.Mark(int64(len(fetcher.seenRead))) + p.storageLoadWriteMeter.Mark(int64(len(fetcher.seenWrite))) + + p.storageDupReadMeter.Mark(int64(fetcher.dupsRead)) + p.storageDupWriteMeter.Mark(int64(fetcher.dupsWrite)) + p.storageDupCrossMeter.Mark(int64(fetcher.dupsCross)) + for _, key := range fetcher.used { - delete(fetcher.seen, string(key)) + delete(fetcher.seenRead, string(key)) + delete(fetcher.seenWrite, string(key)) } - p.storageWasteMeter.Mark(int64(len(fetcher.seen))) + p.storageWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite))) } } } @@ -126,7 +156,11 @@ func (p *triePrefetcher) report() { // upon the same contract, the parameters invoking this method may be // repeated. // 2. Finalize of the main account trie. This happens only once per block. -func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error { +func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte, read bool) error { + // If the state item is only being read, but reads are disabled, return + if read && p.noreads { + return nil + } // Ensure the subfetcher is still alive select { case <-p.term: @@ -139,7 +173,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm fetcher = newSubfetcher(p.db, p.root, owner, root, addr) p.fetchers[id] = fetcher } - return fetcher.schedule(keys) + return fetcher.schedule(keys, read) } // trie returns the trie matching the root hash, blocking until the fetcher of @@ -186,38 +220,51 @@ type subfetcher struct { addr common.Address // Address of the account that the trie belongs to trie Trie // Trie being populated with nodes - tasks [][]byte // Items queued up for retrieval - lock sync.Mutex // Lock protecting the task queue + tasks []*subfetcherTask // Items queued up for retrieval + lock sync.Mutex // Lock protecting the task queue wake chan struct{} // Wake channel if a new task is scheduled stop chan struct{} // Channel to interrupt processing term chan struct{} // Channel to signal interruption - seen map[string]struct{} // Tracks the entries already loaded - dups int // Number of duplicate preload tasks - used [][]byte // Tracks the entries used in the end + seenRead map[string]struct{} // Tracks the entries already loaded via read operations + seenWrite map[string]struct{} // Tracks the entries already loaded via write operations + + dupsRead int // Number of duplicate preload tasks via reads only + dupsWrite int // Number of duplicate preload tasks via writes only + dupsCross int // Number of duplicate preload tasks via read-write-crosses + + used [][]byte // Tracks the entries used in the end +} + +// subfetcherTask is a trie path to prefetch, tagged with whether it originates +// from a read or a write request. +type subfetcherTask struct { + read bool + key []byte } // newSubfetcher creates a goroutine to prefetch state items belonging to a // particular root hash. func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher { sf := &subfetcher{ - db: db, - state: state, - owner: owner, - root: root, - addr: addr, - wake: make(chan struct{}, 1), - stop: make(chan struct{}), - term: make(chan struct{}), - seen: make(map[string]struct{}), + db: db, + state: state, + owner: owner, + root: root, + addr: addr, + wake: make(chan struct{}, 1), + stop: make(chan struct{}), + term: make(chan struct{}), + seenRead: make(map[string]struct{}), + seenWrite: make(map[string]struct{}), } go sf.loop() return sf } // schedule adds a batch of trie keys to the queue to prefetch. -func (sf *subfetcher) schedule(keys [][]byte) error { +func (sf *subfetcher) schedule(keys [][]byte, read bool) error { // Ensure the subfetcher is still alive select { case <-sf.term: @@ -226,7 +273,10 @@ func (sf *subfetcher) schedule(keys [][]byte) error { } // Append the tasks to the current queue sf.lock.Lock() - sf.tasks = append(sf.tasks, keys...) + for _, key := range keys { + key := key // closure for the append below + sf.tasks = append(sf.tasks, &subfetcherTask{read: read, key: key}) + } sf.lock.Unlock() // Notify the background thread to execute scheduled tasks @@ -303,16 +353,36 @@ func (sf *subfetcher) loop() { sf.lock.Unlock() for _, task := range tasks { - if _, ok := sf.seen[string(task)]; ok { - sf.dups++ - continue - } - if len(task) == common.AddressLength { - sf.trie.GetAccount(common.BytesToAddress(task)) + key := string(task.key) + if task.read { + if _, ok := sf.seenRead[key]; ok { + sf.dupsRead++ + continue + } + if _, ok := sf.seenWrite[key]; ok { + sf.dupsCross++ + continue + } } else { - sf.trie.GetStorage(sf.addr, task) + if _, ok := sf.seenRead[key]; ok { + sf.dupsCross++ + continue + } + if _, ok := sf.seenWrite[key]; ok { + sf.dupsWrite++ + continue + } + } + if len(task.key) == common.AddressLength { + sf.trie.GetAccount(common.BytesToAddress(task.key)) + } else { + sf.trie.GetStorage(sf.addr, task.key) + } + if task.read { + sf.seenRead[key] = struct{}{} + } else { + sf.seenWrite[key] = struct{}{} } - sf.seen[string(task)] = struct{}{} } case <-sf.stop: diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 478407dfbb..8f01acd221 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -47,15 +47,15 @@ func filledStateDB() *StateDB { func TestUseAfterTerminate(t *testing.T) { db := filledStateDB() - prefetcher := newTriePrefetcher(db.db, db.originalRoot, "") + prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", true) skey := common.HexToHash("aaa") - if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err != nil { + if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err != nil { t.Errorf("Prefetch failed before terminate: %v", err) } prefetcher.terminate(false) - if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil { + if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err == nil { t.Errorf("Prefetch succeeded after terminate: %v", err) } if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 66a20f434e..2b1ea38483 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -33,6 +33,7 @@ type Config struct { NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled + EnableWitnessCollection bool // true if witness collection is enabled } // ScopeContext contains the things that are per-call, such as stack and memory, diff --git a/eth/backend.go b/eth/backend.go index 798ffa600b..91a07811f0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -184,6 +184,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { var ( vmConfig = vm.Config{ EnablePreimageRecording: config.EnablePreimageRecording, + EnableWitnessCollection: config.EnableWitnessCollection, } cacheConfig = &core.CacheConfig{ TrieCleanLimit: config.TrieCleanCache, diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index f36f212d9c..7453fb1efd 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -141,6 +141,9 @@ type Config struct { // Enables tracking of SHA3 preimages in the VM EnablePreimageRecording bool + // Enables prefetching trie nodes for read operations too + EnableWitnessCollection bool `toml:"-"` + // Enables VM tracing VMTrace string VMTraceJsonConfig string From 3aa874bed22a82e74fad0d679412d4fb6d9375f2 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 11 Jun 2024 16:24:44 +0800 Subject: [PATCH 075/196] core/state: rename all the AccessList receivers to 'al' (#29921) rename all the receivers to 'al' --- core/state/access_list.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/state/access_list.go b/core/state/access_list.go index b0effbeadc..90e5590748 100644 --- a/core/state/access_list.go +++ b/core/state/access_list.go @@ -60,11 +60,11 @@ func newAccessList() *accessList { } // Copy creates an independent copy of an accessList. -func (a *accessList) Copy() *accessList { +func (al *accessList) Copy() *accessList { cp := newAccessList() - cp.addresses = maps.Clone(a.addresses) - cp.slots = make([]map[common.Hash]struct{}, len(a.slots)) - for i, slotMap := range a.slots { + cp.addresses = maps.Clone(al.addresses) + cp.slots = make([]map[common.Hash]struct{}, len(al.slots)) + for i, slotMap := range al.slots { cp.slots[i] = maps.Clone(slotMap) } return cp From ffb29be7d4b32256f6becb603feced0dec661c89 Mon Sep 17 00:00:00 2001 From: ucwong Date: Tue, 11 Jun 2024 13:34:56 +0100 Subject: [PATCH 076/196] ethconfig: regenerate config (#29970) --- eth/ethconfig/gen_config.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index b8b9eee294..147a559984 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -50,6 +50,7 @@ func (c Config) MarshalTOML() (interface{}, error) { BlobPool blobpool.Config GPO gasprice.Config EnablePreimageRecording bool + EnableWitnessCollection bool `toml:"-"` VMTrace string VMTraceJsonConfig string DocRoot string `toml:"-"` @@ -93,6 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.BlobPool = c.BlobPool enc.GPO = c.GPO enc.EnablePreimageRecording = c.EnablePreimageRecording + enc.EnableWitnessCollection = c.EnableWitnessCollection enc.VMTrace = c.VMTrace enc.VMTraceJsonConfig = c.VMTraceJsonConfig enc.DocRoot = c.DocRoot @@ -140,6 +142,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { BlobPool *blobpool.Config GPO *gasprice.Config EnablePreimageRecording *bool + EnableWitnessCollection *bool `toml:"-"` VMTrace *string VMTraceJsonConfig *string DocRoot *string `toml:"-"` @@ -252,6 +255,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.EnablePreimageRecording != nil { c.EnablePreimageRecording = *dec.EnablePreimageRecording } + if dec.EnableWitnessCollection != nil { + c.EnableWitnessCollection = *dec.EnableWitnessCollection + } if dec.VMTrace != nil { c.VMTrace = *dec.VMTrace } From caa066dcb0dcb250d32f0861f996fefd1373082c Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:27:35 +0800 Subject: [PATCH 077/196] cmd/devp2p: fix log output (#29972) --- cmd/devp2p/rlpxcmd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index fb8066ee1a..77f09e6b85 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -109,7 +109,7 @@ func rlpxPing(ctx *cli.Context) error { } return fmt.Errorf("received disconnect message: %v", msg[0]) default: - return fmt.Errorf("invalid message code %d, expected handshake (code zero)", code) + return fmt.Errorf("invalid message code %d, expected handshake (code zero) or disconnect (code one)", code) } return nil } From c732039a3442c6724054b0d9f4ec96a8639cce47 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:57:41 +0200 Subject: [PATCH 078/196] .github: disable cache in actions run (#29926) --- .github/workflows/go.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 41e9631f15..844cfb5d24 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -16,6 +16,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: 1.21.4 + cache: false - name: Run tests run: go test -short ./... env: From b6f2bbd4172cbb56cf879358b1d378564dd09d93 Mon Sep 17 00:00:00 2001 From: bugmaker9371 <167614621+bugmaker9371@users.noreply.github.com> Date: Wed, 12 Jun 2024 01:41:17 +0800 Subject: [PATCH 079/196] p2p/simulations: update doc of HTTP endpoints (#29894) --- p2p/simulations/README.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/p2p/simulations/README.md b/p2p/simulations/README.md index 023f73a098..1f9f72dcda 100644 --- a/p2p/simulations/README.md +++ b/p2p/simulations/README.md @@ -123,20 +123,25 @@ The API is initialised with a particular node adapter and has the following endpoints: ``` -GET / Get network information -POST /start Start all nodes in the network -POST /stop Stop all nodes in the network -GET /events Stream network events -GET /snapshot Take a network snapshot -POST /snapshot Load a network snapshot -POST /nodes Create a node -GET /nodes Get all nodes in the network -GET /nodes/:nodeid Get node information -POST /nodes/:nodeid/start Start a node -POST /nodes/:nodeid/stop Stop a node -POST /nodes/:nodeid/conn/:peerid Connect two nodes -DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes -GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket +OPTIONS / Response 200 with "Access-Control-Allow-Headers"" header set to "Content-Type"" +GET / Get network information +POST /start Start all nodes in the network +POST /stop Stop all nodes in the network +POST /mocker/start Start the mocker node simulation +POST /mocker/stop Stop the mocker node simulation +GET /mocker Get a list of available mockers +POST /reset Reset all properties of a network to initial (empty) state +GET /events Stream network events +GET /snapshot Take a network snapshot +POST /snapshot Load a network snapshot +POST /nodes Create a node +GET /nodes Get all nodes in the network +GET /nodes/:nodeid Get node information +POST /nodes/:nodeid/start Start a node +POST /nodes/:nodeid/stop Stop a node +POST /nodes/:nodeid/conn/:peerid Connect two nodes +DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes +GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket ``` For convenience, `nodeid` in the URL can be the name of a node rather than its From 1e97148249e027b68c2ff71fe14db4b1d36cf216 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 12 Jun 2024 09:45:42 +0200 Subject: [PATCH 080/196] all: fix inconsistent receiver name and add lint rule for it (#29974) * .golangci.yml: enable check for consistent receiver name * beacon/light/sync: fix receiver name * core/txpool/blobpool: fix receiver name * core/types: fix receiver name * internal/ethapi: use consistent receiver name 'api' for handler object * signer/core/apitypes: fix receiver name * signer/core: use consistent receiver name 'api' for handler object * log: fix receiver name --- .golangci.yml | 13 + beacon/light/sync/test_helpers.go | 20 +- core/txpool/blobpool/blobpool_test.go | 2 +- core/types/transaction_signing.go | 8 +- internal/ethapi/api.go | 373 +++++++++++++------------- log/handler.go | 8 +- signer/core/apitypes/types.go | 4 +- signer/core/uiapi.go | 34 +-- 8 files changed, 237 insertions(+), 225 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 46844d1e90..2132f5403a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -23,6 +23,7 @@ linters: - durationcheck - exportloopref - whitespace + - revive # only certain checks enabled ### linters we tried and will not be using: ### @@ -38,6 +39,15 @@ linters: linters-settings: gofmt: simplify: true + revive: + enable-all-rules: false + # here we enable specific useful rules + # see https://golangci-lint.run/usage/linters/#revive for supported rules + rules: + - name: receiver-naming + severity: warning + disabled: false + exclude: [""] issues: exclude-files: @@ -47,6 +57,9 @@ issues: linters: - deadcode - staticcheck + - path: crypto/bn256/ + linters: + - revive - path: internal/build/pgp.go text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go diff --git a/beacon/light/sync/test_helpers.go b/beacon/light/sync/test_helpers.go index cfca8ad8a4..b331bf7110 100644 --- a/beacon/light/sync/test_helpers.go +++ b/beacon/light/sync/test_helpers.go @@ -173,24 +173,24 @@ type TestCommitteeChain struct { init bool } -func (t *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { - t.fsp, t.nsp, t.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true +func (tc *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error { + tc.fsp, tc.nsp, tc.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true return nil } -func (t *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error { +func (tc *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error { period := update.AttestedHeader.Header.SyncPeriod() - if period < t.fsp || period > t.nsp || !t.init { + if period < tc.fsp || period > tc.nsp || !tc.init { return light.ErrInvalidPeriod } - if period == t.nsp { - t.nsp++ + if period == tc.nsp { + tc.nsp++ } return nil } -func (t *TestCommitteeChain) NextSyncPeriod() (uint64, bool) { - return t.nsp, t.init +func (tc *TestCommitteeChain) NextSyncPeriod() (uint64, bool) { + return tc.nsp, tc.init } func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) { @@ -199,8 +199,8 @@ func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) { } } -func (t *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) { - t.init, t.nsp = true, nsp +func (tc *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) { + tc.init, tc.nsp = true, nsp } func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) { diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 85e13980be..d658a6daf4 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -143,7 +143,7 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header { } } -func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { +func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { return nil } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 6e5f6712f8..2ae38661f3 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -459,11 +459,11 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash { // homestead rules. type HomesteadSigner struct{ FrontierSigner } -func (s HomesteadSigner) ChainID() *big.Int { +func (hs HomesteadSigner) ChainID() *big.Int { return nil } -func (s HomesteadSigner) Equal(s2 Signer) bool { +func (hs HomesteadSigner) Equal(s2 Signer) bool { _, ok := s2.(HomesteadSigner) return ok } @@ -486,11 +486,11 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) { // frontier rules. type FrontierSigner struct{} -func (s FrontierSigner) ChainID() *big.Int { +func (fs FrontierSigner) ChainID() *big.Int { return nil } -func (s FrontierSigner) Equal(s2 Signer) bool { +func (fs FrontierSigner) Equal(s2 Signer) bool { _, ok := s2.(FrontierSigner) return ok } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f211dcc659..1c209fb5a4 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -26,9 +26,6 @@ import ( "time" "github.com/davecgh/go-spew/spew" - "github.com/holiman/uint256" - "github.com/tyler-smith/go-bip39" - "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" @@ -51,6 +48,8 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" + "github.com/holiman/uint256" + "github.com/tyler-smith/go-bip39" ) // estimateGasErrorRatio is the amount of overestimation eth_estimateGas is @@ -70,20 +69,20 @@ func NewEthereumAPI(b Backend) *EthereumAPI { } // GasPrice returns a suggestion for a gas price for legacy transactions. -func (s *EthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { - tipcap, err := s.b.SuggestGasTipCap(ctx) +func (api *EthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) { + tipcap, err := api.b.SuggestGasTipCap(ctx) if err != nil { return nil, err } - if head := s.b.CurrentHeader(); head.BaseFee != nil { + if head := api.b.CurrentHeader(); head.BaseFee != nil { tipcap.Add(tipcap, head.BaseFee) } return (*hexutil.Big)(tipcap), err } // MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. -func (s *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { - tipcap, err := s.b.SuggestGasTipCap(ctx) +func (api *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) { + tipcap, err := api.b.SuggestGasTipCap(ctx) if err != nil { return nil, err } @@ -100,8 +99,8 @@ type feeHistoryResult struct { } // FeeHistory returns the fee market history. -func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { - oldest, reward, baseFee, gasUsed, blobBaseFee, blobGasUsed, err := s.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) +func (api *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { + oldest, reward, baseFee, gasUsed, blobBaseFee, blobGasUsed, err := api.b.FeeHistory(ctx, uint64(blockCount), lastBlock, rewardPercentiles) if err != nil { return nil, err } @@ -137,8 +136,8 @@ func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecim } // BlobBaseFee returns the base fee for blob gas at the current head. -func (s *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { - return (*hexutil.Big)(s.b.BlobBaseFee(ctx)) +func (api *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { + return (*hexutil.Big)(api.b.BlobBaseFee(ctx)) } // Syncing returns false in case the node is currently not syncing with the network. It can be up-to-date or has not @@ -148,8 +147,8 @@ func (s *EthereumAPI) BlobBaseFee(ctx context.Context) *hexutil.Big { // - highestBlock: block number of the highest block header this node has received from peers // - pulledStates: number of state entries processed until now // - knownStates: number of known state entries that still need to be pulled -func (s *EthereumAPI) Syncing() (interface{}, error) { - progress := s.b.SyncProgress() +func (api *EthereumAPI) Syncing() (interface{}, error) { + progress := api.b.SyncProgress() // Return not syncing if the synchronisation already completed if progress.Done() { @@ -188,18 +187,18 @@ func NewTxPoolAPI(b Backend) *TxPoolAPI { } // Content returns the transactions contained within the transaction pool. -func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { +func (api *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { content := map[string]map[string]map[string]*RPCTransaction{ "pending": make(map[string]map[string]*RPCTransaction), "queued": make(map[string]map[string]*RPCTransaction), } - pending, queue := s.b.TxPoolContent() - curHeader := s.b.CurrentHeader() + pending, queue := api.b.TxPoolContent() + curHeader := api.b.CurrentHeader() // Flatten the pending transactions for account, txs := range pending { dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["pending"][account.Hex()] = dump } @@ -207,7 +206,7 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { for account, txs := range queue { dump := make(map[string]*RPCTransaction) for _, tx := range txs { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["queued"][account.Hex()] = dump } @@ -215,22 +214,22 @@ func (s *TxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction { } // ContentFrom returns the transactions contained within the transaction pool. -func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction { +func (api *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction { content := make(map[string]map[string]*RPCTransaction, 2) - pending, queue := s.b.TxPoolContentFrom(addr) - curHeader := s.b.CurrentHeader() + pending, queue := api.b.TxPoolContentFrom(addr) + curHeader := api.b.CurrentHeader() // Build the pending transactions dump := make(map[string]*RPCTransaction, len(pending)) for _, tx := range pending { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["pending"] = dump // Build the queued transactions dump = make(map[string]*RPCTransaction, len(queue)) for _, tx := range queue { - dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()) + dump[fmt.Sprintf("%d", tx.Nonce())] = NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig()) } content["queued"] = dump @@ -238,8 +237,8 @@ func (s *TxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCT } // Status returns the number of pending and queued transaction in the pool. -func (s *TxPoolAPI) Status() map[string]hexutil.Uint { - pending, queue := s.b.Stats() +func (api *TxPoolAPI) Status() map[string]hexutil.Uint { + pending, queue := api.b.Stats() return map[string]hexutil.Uint{ "pending": hexutil.Uint(pending), "queued": hexutil.Uint(queue), @@ -248,12 +247,12 @@ func (s *TxPoolAPI) Status() map[string]hexutil.Uint { // Inspect retrieves the content of the transaction pool and flattens it into an // easily inspectable list. -func (s *TxPoolAPI) Inspect() map[string]map[string]map[string]string { +func (api *TxPoolAPI) Inspect() map[string]map[string]map[string]string { content := map[string]map[string]map[string]string{ "pending": make(map[string]map[string]string), "queued": make(map[string]map[string]string), } - pending, queue := s.b.TxPoolContent() + pending, queue := api.b.TxPoolContent() // Define a formatter to flatten a transaction into a string var format = func(tx *types.Transaction) string { @@ -293,8 +292,8 @@ func NewEthereumAccountAPI(am *accounts.Manager) *EthereumAccountAPI { } // Accounts returns the collection of accounts this node manages. -func (s *EthereumAccountAPI) Accounts() []common.Address { - return s.am.Accounts() +func (api *EthereumAccountAPI) Accounts() []common.Address { + return api.am.Accounts() } // PersonalAccountAPI provides an API to access accounts managed by this node. @@ -316,8 +315,8 @@ func NewPersonalAccountAPI(b Backend, nonceLock *AddrLocker) *PersonalAccountAPI } // ListAccounts will return a list of addresses for accounts this node manages. -func (s *PersonalAccountAPI) ListAccounts() []common.Address { - return s.am.Accounts() +func (api *PersonalAccountAPI) ListAccounts() []common.Address { + return api.am.Accounts() } // rawWallet is a JSON representation of an accounts.Wallet interface, with its @@ -330,9 +329,9 @@ type rawWallet struct { } // ListWallets will return a list of wallets this node manages. -func (s *PersonalAccountAPI) ListWallets() []rawWallet { +func (api *PersonalAccountAPI) ListWallets() []rawWallet { wallets := make([]rawWallet, 0) // return [] instead of nil if empty - for _, wallet := range s.am.Wallets() { + for _, wallet := range api.am.Wallets() { status, failure := wallet.Status() raw := rawWallet{ @@ -352,8 +351,8 @@ func (s *PersonalAccountAPI) ListWallets() []rawWallet { // connection and attempting to authenticate via the provided passphrase. Note, // the method may return an extra challenge requiring a second open (e.g. the // Trezor PIN matrix challenge). -func (s *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { + wallet, err := api.am.Wallet(url) if err != nil { return err } @@ -366,8 +365,8 @@ func (s *PersonalAccountAPI) OpenWallet(url string, passphrase *string) error { // DeriveAccount requests an HD wallet to derive a new account, optionally pinning // it for later reuse. -func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { + wallet, err := api.am.Wallet(url) if err != nil { return accounts.Account{}, err } @@ -382,8 +381,8 @@ func (s *PersonalAccountAPI) DeriveAccount(url string, path string, pin *bool) ( } // NewAccount will create a new account and returns the address for the new account. -func (s *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { - ks, err := fetchKeystore(s.am) +func (api *PersonalAccountAPI) NewAccount(password string) (common.AddressEIP55, error) { + ks, err := fetchKeystore(api.am) if err != nil { return common.AddressEIP55{}, err } @@ -408,12 +407,12 @@ func fetchKeystore(am *accounts.Manager) (*keystore.KeyStore, error) { // ImportRawKey stores the given hex encoded ECDSA key into the key directory, // encrypting it with the passphrase. -func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { +func (api *PersonalAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) { key, err := crypto.HexToECDSA(privkey) if err != nil { return common.Address{}, err } - ks, err := fetchKeystore(s.am) + ks, err := fetchKeystore(api.am) if err != nil { return common.Address{}, err } @@ -424,11 +423,11 @@ func (s *PersonalAccountAPI) ImportRawKey(privkey string, password string) (comm // UnlockAccount will unlock the account associated with the given address with // the given password for duration seconds. If duration is nil it will use a // default of 300 seconds. It returns an indication if the account was unlocked. -func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) { +func (api *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) { // When the API is exposed by external RPC(http, ws etc), unless the user // explicitly specifies to allow the insecure account unlocking, otherwise // it is disabled. - if s.b.ExtRPCEnabled() && !s.b.AccountManager().Config().InsecureUnlockAllowed { + if api.b.ExtRPCEnabled() && !api.b.AccountManager().Config().InsecureUnlockAllowed { return false, errors.New("account unlock with HTTP access is forbidden") } @@ -441,7 +440,7 @@ func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Addr } else { d = time.Duration(*duration) * time.Second } - ks, err := fetchKeystore(s.am) + ks, err := fetchKeystore(api.am) if err != nil { return false, err } @@ -453,8 +452,8 @@ func (s *PersonalAccountAPI) UnlockAccount(ctx context.Context, addr common.Addr } // LockAccount will lock the account associated with the given address when it's unlocked. -func (s *PersonalAccountAPI) LockAccount(addr common.Address) bool { - if ks, err := fetchKeystore(s.am); err == nil { +func (api *PersonalAccountAPI) LockAccount(addr common.Address) bool { + if ks, err := fetchKeystore(api.am); err == nil { return ks.Lock(addr) == nil } return false @@ -463,49 +462,49 @@ func (s *PersonalAccountAPI) LockAccount(addr common.Address) bool { // signTransaction sets defaults and signs the given transaction // NOTE: the caller needs to ensure that the nonceLock is held, if applicable, // and release it after the transaction has been submitted to the tx pool -func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { +func (api *PersonalAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.from()} - wallet, err := s.am.Find(account) + wallet, err := api.am.Find(account) if err != nil { return nil, err } // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return nil, err } // Assemble the transaction and sign with the wallet tx := args.ToTransaction() - return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) + return wallet.SignTxWithPassphrase(account, passwd, tx, api.b.ChainConfig().ChainID) } // SendTransaction will create a transaction from the given arguments and // tries to sign it with the key associated with args.From. If the given // passwd isn't able to decrypt the key it fails. -func (s *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { +func (api *PersonalAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, passwd string) (common.Hash, error) { if args.Nonce == nil { // Hold the mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. - s.nonceLock.LockAddr(args.from()) - defer s.nonceLock.UnlockAddr(args.from()) + api.nonceLock.LockAddr(args.from()) + defer api.nonceLock.UnlockAddr(args.from()) } if args.IsEIP4844() { return common.Hash{}, errBlobTxNotSupported } - signed, err := s.signTransaction(ctx, &args, passwd) + signed, err := api.signTransaction(ctx, &args, passwd) if err != nil { log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) return common.Hash{}, err } - return SubmitTransaction(ctx, s.b, signed) + return SubmitTransaction(ctx, api.b, signed) } // SignTransaction will create a transaction from the given arguments and // tries to sign it with the key associated with args.From. If the given passwd isn't // able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast // to other nodes -func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { +func (api *PersonalAccountAPI) SignTransaction(ctx context.Context, args TransactionArgs, passwd string) (*SignTransactionResult, error) { // No need to obtain the noncelock mutex, since we won't be sending this // tx into the transaction pool, but right back to the user if args.From == nil { @@ -525,10 +524,10 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti } // Before actually signing the transaction, ensure the transaction fee is reasonable. tx := args.ToTransaction() - if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { + if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil { return nil, err } - signed, err := s.signTransaction(ctx, &args, passwd) + signed, err := api.signTransaction(ctx, &args, passwd) if err != nil { log.Warn("Failed transaction sign attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err) return nil, err @@ -549,11 +548,11 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti // The key used to calculate the signature is decrypted with the given password. // // https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal#personal-sign -func (s *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { +func (api *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return nil, err } @@ -577,7 +576,7 @@ func (s *PersonalAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr // the V value must be 27 or 28 for legacy reasons. // // https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal#personal-ecrecover -func (s *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { +func (api *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) { if len(sig) != crypto.SignatureLength { return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength) } @@ -594,8 +593,8 @@ func (s *PersonalAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.By } // InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. -func (s *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { + wallet, err := api.am.Wallet(url) if err != nil { return "", err } @@ -621,8 +620,8 @@ func (s *PersonalAccountAPI) InitializeWallet(ctx context.Context, url string) ( } // Unpair deletes a pairing between wallet and geth. -func (s *PersonalAccountAPI) Unpair(ctx context.Context, url string, pin string) error { - wallet, err := s.am.Wallet(url) +func (api *PersonalAccountAPI) Unpair(ctx context.Context, url string, pin string) error { + wallet, err := api.am.Wallet(url) if err != nil { return err } @@ -656,16 +655,16 @@ func (api *BlockChainAPI) ChainId() *hexutil.Big { } // BlockNumber returns the block number of the chain head. -func (s *BlockChainAPI) BlockNumber() hexutil.Uint64 { - header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available +func (api *BlockChainAPI) BlockNumber() hexutil.Uint64 { + header, _ := api.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available return hexutil.Uint64(header.Number.Uint64()) } // GetBalance returns the amount of wei for the given address in the state of the // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // block numbers are also allowed. -func (s *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -704,7 +703,7 @@ func (n *proofList) Delete(key []byte) error { } // GetProof returns the Merkle-proof for a given account and optionally some storage keys. -func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { +func (api *BlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { var ( keys = make([]common.Hash, len(storageKeys)) keyLengths = make([]int, len(storageKeys)) @@ -718,7 +717,7 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st return nil, err } } - statedb, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + statedb, header, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if statedb == nil || err != nil { return nil, err } @@ -804,10 +803,10 @@ func decodeHash(s string) (h common.Hash, inputLength int, err error) { // - When blockNr is -2 the chain latest header is returned. // - When blockNr is -3 the chain finalized header is returned. // - When blockNr is -4 the chain safe header is returned. -func (s *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { - header, err := s.b.HeaderByNumber(ctx, number) +func (api *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { + header, err := api.b.HeaderByNumber(ctx, number) if header != nil && err == nil { - response := s.rpcMarshalHeader(ctx, header) + response := api.rpcMarshalHeader(ctx, header) if number == rpc.PendingBlockNumber { // Pending header need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -820,10 +819,10 @@ func (s *BlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockN } // GetHeaderByHash returns the requested header by hash. -func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { - header, _ := s.b.HeaderByHash(ctx, hash) +func (api *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} { + header, _ := api.b.HeaderByHash(ctx, hash) if header != nil { - return s.rpcMarshalHeader(ctx, header) + return api.rpcMarshalHeader(ctx, header) } return nil } @@ -835,10 +834,10 @@ func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) m // - When blockNr is -4 the chain safe block is returned. // - When fullTx is true all transactions in the block are returned, otherwise // only the transaction hash is returned. -func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, number) +func (api *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + block, err := api.b.BlockByNumber(ctx, number) if block != nil && err == nil { - response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) + response, err := api.rpcMarshalBlock(ctx, block, true, fullTx) if err == nil && number == rpc.PendingBlockNumber { // Pending blocks need to nil out a few fields for _, field := range []string{"hash", "nonce", "miner"} { @@ -852,17 +851,17 @@ func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNu // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // detail, otherwise only the transaction hash is returned. -func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByHash(ctx, hash) +func (api *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { + block, err := api.b.BlockByHash(ctx, hash) if block != nil { - return s.rpcMarshalBlock(ctx, block, true, fullTx) + return api.rpcMarshalBlock(ctx, block, true, fullTx) } return nil, err } // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. -func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, blockNr) +func (api *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { + block, err := api.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() if index >= hexutil.Uint(len(uncles)) { @@ -870,14 +869,14 @@ func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, block return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcMarshalBlock(ctx, block, false, false) + return api.rpcMarshalBlock(ctx, block, false, false) } return nil, err } // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. -func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { - block, err := s.b.BlockByHash(ctx, blockHash) +func (api *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { + block, err := api.b.BlockByHash(ctx, blockHash) if block != nil { uncles := block.Uncles() if index >= hexutil.Uint(len(uncles)) { @@ -885,14 +884,14 @@ func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHa return nil, nil } block = types.NewBlockWithHeader(uncles[index]) - return s.rpcMarshalBlock(ctx, block, false, false) + return api.rpcMarshalBlock(ctx, block, false, false) } return nil, err } // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number -func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n } @@ -900,8 +899,8 @@ func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr } // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash -func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { +func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n } @@ -909,8 +908,8 @@ func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash } // GetCode returns the code stored at the given address in the state for the given block number. -func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -921,8 +920,8 @@ func (s *BlockChainAPI) GetCode(ctx context.Context, address common.Address, blo // GetStorageAt returns the storage from the state at the given address, key and // block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block // numbers are also allowed. -func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -935,14 +934,14 @@ func (s *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Address } // GetBlockReceipts returns the block receipts for the given block hash or number or tag. -func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { - block, err := s.b.BlockByNumberOrHash(ctx, blockNrOrHash) +func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) { + block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash) if block == nil || err != nil { // When the block doesn't exist, the RPC method should return JSON null // as per specification. return nil, nil } - receipts, err := s.b.GetReceipts(ctx, block.Hash()) + receipts, err := api.b.GetReceipts(ctx, block.Hash()) if err != nil { return nil, err } @@ -952,7 +951,7 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc. } // Derive the sender. - signer := types.MakeSigner(s.b.ChainConfig(), block.Number(), block.Time()) + signer := types.MakeSigner(api.b.ChainConfig(), block.Number(), block.Time()) result := make([]map[string]interface{}, len(receipts)) for i, receipt := range receipts { @@ -1162,12 +1161,12 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash // // Note, this function doesn't make and changes in the state/blockchain and is // useful to execute and retrieve values. -func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { +func (api *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Bytes, error) { if blockNrOrHash == nil { latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) blockNrOrHash = &latest } - result, err := DoCall(ctx, s.b, args, *blockNrOrHash, overrides, blockOverrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap()) + result, err := DoCall(ctx, api.b, args, *blockNrOrHash, overrides, blockOverrides, api.b.RPCEVMTimeout(), api.b.RPCGasCap()) if err != nil { return nil, err } @@ -1226,12 +1225,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap // configuration (if non-zero). // Note: Required blob gas is not computed in this method. -func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { +func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, s.b.RPCGasCap()) + return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.b.RPCGasCap()) } // RPCMarshalHeader converts the given header to the RPC output . @@ -1309,18 +1308,18 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param // rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires // a `BlockchainAPI`. -func (s *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { +func (api *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { fields := RPCMarshalHeader(header) - fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash())) + fields["totalDifficulty"] = (*hexutil.Big)(api.b.GetTd(ctx, header.Hash())) return fields } // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `BlockchainAPI`. -func (s *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) +func (api *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields := RPCMarshalBlock(b, inclTx, fullTx, api.b.ChainConfig()) if inclTx { - fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, b.Hash())) + fields["totalDifficulty"] = (*hexutil.Big)(api.b.GetTd(ctx, b.Hash())) } return fields, nil } @@ -1484,12 +1483,12 @@ type accessListResult struct { // CreateAccessList creates an EIP-2930 type AccessList for the given transaction. // Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state. -func (s *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { +func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - acl, gasUsed, vmerr, err := AccessList(ctx, s.b, bNrOrHash, args) + acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args) if err != nil { return nil, err } @@ -1574,8 +1573,8 @@ func NewTransactionAPI(b Backend, nonceLock *AddrLocker) *TransactionAPI { } // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. -func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n } @@ -1583,8 +1582,8 @@ func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, b } // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. -func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { +func (api *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n } @@ -1592,49 +1591,49 @@ func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blo } // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. -func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) +func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()) } return nil } // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. -func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { - return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) +func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()) } return nil } // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. -func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { +func (api *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { + if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. -func (s *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { +func (api *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { + if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil } // GetTransactionCount returns the number of transactions the given address has sent for the given block number -func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { +func (api *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { // Ask transaction pool for the nonce which includes pending transactions if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber { - nonce, err := s.b.GetPoolNonce(ctx, address) + nonce, err := api.b.GetPoolNonce(ctx, address) if err != nil { return nil, err } return (*hexutil.Uint64)(&nonce), nil } // Resolve block number and use its state to ask for the nonce - state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + state, _, err := api.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) if state == nil || err != nil { return nil, err } @@ -1643,32 +1642,32 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common } // GetTransactionByHash returns the transaction for the given hash -func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { +func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { // Try to return an already finalized transaction - found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) + found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) if !found { // No finalized transaction, try to retrieve it from the pool - if tx := s.b.GetPoolTransaction(hash); tx != nil { - return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil + if tx := api.b.GetPoolTransaction(hash); tx != nil { + return NewRPCPendingTransaction(tx, api.b.CurrentHeader(), api.b.ChainConfig()), nil } if err == nil { return nil, nil } return nil, NewTxIndexingError() } - header, err := s.b.HeaderByHash(ctx, blockHash) + header, err := api.b.HeaderByHash(ctx, blockHash) if err != nil { return nil, err } - return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil + return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, api.b.ChainConfig()), nil } // GetRawTransactionByHash returns the bytes of the transaction for the given hash. -func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { +func (api *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash) + found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) if !found { - if tx = s.b.GetPoolTransaction(hash); tx != nil { + if tx = api.b.GetPoolTransaction(hash); tx != nil { return tx.MarshalBinary() } if err == nil { @@ -1680,19 +1679,19 @@ func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash commo } // GetTransactionReceipt returns the transaction receipt for the given transaction hash. -func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { - found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) +func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { + found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) if err != nil { return nil, NewTxIndexingError() // transaction is not fully indexed } if !found { return nil, nil // transaction is not existent or reachable } - header, err := s.b.HeaderByHash(ctx, blockHash) + header, err := api.b.HeaderByHash(ctx, blockHash) if err != nil { return nil, err } - receipts, err := s.b.GetReceipts(ctx, blockHash) + receipts, err := api.b.GetReceipts(ctx, blockHash) if err != nil { return nil, err } @@ -1702,7 +1701,7 @@ func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common. receipt := receipts[index] // Derive the sender. - signer := types.MakeSigner(s.b.ChainConfig(), header.Number, header.Time) + signer := types.MakeSigner(api.b.ChainConfig(), header.Number, header.Time) return marshalReceipt(receipt, blockHash, blockNumber, signer, tx, int(index)), nil } @@ -1749,16 +1748,16 @@ func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber u } // sign is a helper function that signs a transaction with the private key of the given address. -func (s *TransactionAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { +func (api *TransactionAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return nil, err } // Request the wallet to sign the transaction - return wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) + return wallet.SignTx(account, tx, api.b.ChainConfig().ChainID) } // SubmitTransaction is a helper function that submits tx to txPool and logs a message. @@ -1794,11 +1793,11 @@ func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (c // SendTransaction creates a transaction for the given argument, sign it and submit it to the // transaction pool. -func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { +func (api *TransactionAPI) SendTransaction(ctx context.Context, args TransactionArgs) (common.Hash, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: args.from()} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return common.Hash{}, err } @@ -1806,35 +1805,35 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr if args.Nonce == nil { // Hold the mutex around signing to prevent concurrent assignment of // the same nonce to multiple accounts. - s.nonceLock.LockAddr(args.from()) - defer s.nonceLock.UnlockAddr(args.from()) + api.nonceLock.LockAddr(args.from()) + defer api.nonceLock.UnlockAddr(args.from()) } if args.IsEIP4844() { return common.Hash{}, errBlobTxNotSupported } // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return common.Hash{}, err } // Assemble the transaction and sign with the wallet tx := args.ToTransaction() - signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) + signed, err := wallet.SignTx(account, tx, api.b.ChainConfig().ChainID) if err != nil { return common.Hash{}, err } - return SubmitTransaction(ctx, s.b, signed) + return SubmitTransaction(ctx, api.b, signed) } // FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields) // on a given unsigned transaction, and returns it to the caller for further // processing (signing + broadcast). -func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (api *TransactionAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { args.blobSidecarAllowed = true // Set some sanity defaults and terminate on failure - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return nil, err } // Assemble the transaction and obtain rlp @@ -1848,12 +1847,12 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. -func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { +func (api *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { tx := new(types.Transaction) if err := tx.UnmarshalBinary(input); err != nil { return common.Hash{}, err } - return SubmitTransaction(ctx, s.b, tx) + return SubmitTransaction(ctx, api.b, tx) } // Sign calculates an ECDSA signature for: @@ -1865,11 +1864,11 @@ func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.B // The account associated with addr must be unlocked. // // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign -func (s *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { +func (api *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { // Look up the wallet containing the requested signer account := accounts.Account{Address: addr} - wallet, err := s.b.AccountManager().Find(account) + wallet, err := api.b.AccountManager().Find(account) if err != nil { return nil, err } @@ -1890,7 +1889,7 @@ type SignTransactionResult struct { // SignTransaction will sign the given transaction with the from account. // The node needs to have the private key of the account corresponding with // the given from address and it needs to be unlocked. -func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { +func (api *TransactionAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) { args.blobSidecarAllowed = true if args.Gas == nil { @@ -1902,15 +1901,15 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr if args.Nonce == nil { return nil, errors.New("nonce not specified") } - if err := args.setDefaults(ctx, s.b, false); err != nil { + if err := args.setDefaults(ctx, api.b, false); err != nil { return nil, err } // Before actually sign the transaction, ensure the transaction fee is reasonable. tx := args.ToTransaction() - if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil { + if err := checkTxFee(tx.GasPrice(), tx.Gas(), api.b.RPCTxFeeCap()); err != nil { return nil, err } - signed, err := s.sign(args.from(), tx) + signed, err := api.sign(args.from(), tx) if err != nil { return nil, err } @@ -1933,23 +1932,23 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { - pending, err := s.b.GetPoolTransactions() +func (api *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { + pending, err := api.b.GetPoolTransactions() if err != nil { return nil, err } accounts := make(map[common.Address]struct{}) - for _, wallet := range s.b.AccountManager().Wallets() { + for _, wallet := range api.b.AccountManager().Wallets() { for _, account := range wallet.Accounts() { accounts[account.Address] = struct{}{} } } - curHeader := s.b.CurrentHeader() + curHeader := api.b.CurrentHeader() transactions := make([]*RPCTransaction, 0, len(pending)) for _, tx := range pending { - from, _ := types.Sender(s.signer, tx) + from, _ := types.Sender(api.signer, tx) if _, exists := accounts[from]; exists { - transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())) + transactions = append(transactions, NewRPCPendingTransaction(tx, curHeader, api.b.ChainConfig())) } } return transactions, nil @@ -1957,11 +1956,11 @@ func (s *TransactionAPI) PendingTransactions() ([]*RPCTransaction, error) { // Resend accepts an existing transaction and a new gas price and limit. It will remove // the given transaction from the pool and reinsert it with the new gas price and limit. -func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { +func (api *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { if sendArgs.Nonce == nil { return common.Hash{}, errors.New("missing transaction nonce in transaction spec") } - if err := sendArgs.setDefaults(ctx, s.b, false); err != nil { + if err := sendArgs.setDefaults(ctx, api.b, false); err != nil { return common.Hash{}, err } matchTx := sendArgs.ToTransaction() @@ -1975,18 +1974,18 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if gasLimit != nil { gas = uint64(*gasLimit) } - if err := checkTxFee(price, gas, s.b.RPCTxFeeCap()); err != nil { + if err := checkTxFee(price, gas, api.b.RPCTxFeeCap()); err != nil { return common.Hash{}, err } // Iterate the pending list for replacement - pending, err := s.b.GetPoolTransactions() + pending, err := api.b.GetPoolTransactions() if err != nil { return common.Hash{}, err } for _, p := range pending { - wantSigHash := s.signer.Hash(matchTx) - pFrom, err := types.Sender(s.signer, p) - if err == nil && pFrom == sendArgs.from() && s.signer.Hash(p) == wantSigHash { + wantSigHash := api.signer.Hash(matchTx) + pFrom, err := types.Sender(api.signer, p) + if err == nil && pFrom == sendArgs.from() && api.signer.Hash(p) == wantSigHash { // Match. Re-sign and send the transaction. if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 { sendArgs.GasPrice = gasPrice @@ -1994,11 +1993,11 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g if gasLimit != nil && *gasLimit != 0 { sendArgs.Gas = gasLimit } - signedTx, err := s.sign(sendArgs.from(), sendArgs.ToTransaction()) + signedTx, err := api.sign(sendArgs.from(), sendArgs.ToTransaction()) if err != nil { return common.Hash{}, err } - if err = s.b.SendTx(ctx, signedTx); err != nil { + if err = api.b.SendTx(ctx, signedTx); err != nil { return common.Hash{}, err } return signedTx.Hash(), nil @@ -2084,11 +2083,11 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block } // GetRawTransaction returns the bytes of the transaction for the given hash. -func (s *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { +func (api *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { // Retrieve a finalized transaction, or a pooled otherwise - found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash) + found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) if !found { - if tx = s.b.GetPoolTransaction(hash); tx != nil { + if tx = api.b.GetPoolTransaction(hash); tx != nil { return tx.MarshalBinary() } if err == nil { @@ -2151,18 +2150,18 @@ func NewNetAPI(net *p2p.Server, networkVersion uint64) *NetAPI { } // Listening returns an indication if the node is listening for network connections. -func (s *NetAPI) Listening() bool { +func (api *NetAPI) Listening() bool { return true // always listening } // PeerCount returns the number of connected peers -func (s *NetAPI) PeerCount() hexutil.Uint { - return hexutil.Uint(s.net.PeerCount()) +func (api *NetAPI) PeerCount() hexutil.Uint { + return hexutil.Uint(api.net.PeerCount()) } // Version returns the current ethereum protocol version. -func (s *NetAPI) Version() string { - return fmt.Sprintf("%d", s.networkVersion) +func (api *NetAPI) Version() string { + return fmt.Sprintf("%d", api.networkVersion) } // checkTxFee is an internal function used to check whether the fee of diff --git a/log/handler.go b/log/handler.go index c604a62301..56eff6671f 100644 --- a/log/handler.go +++ b/log/handler.go @@ -101,10 +101,10 @@ func (h *TerminalHandler) WithAttrs(attrs []slog.Attr) slog.Handler { } // ResetFieldPadding zeroes the field-padding for all attribute pairs. -func (t *TerminalHandler) ResetFieldPadding() { - t.mu.Lock() - t.fieldPadding = make(map[string]int) - t.mu.Unlock() +func (h *TerminalHandler) ResetFieldPadding() { + h.mu.Lock() + h.fieldPadding = make(map[string]int) + h.mu.Unlock() } type leveler struct{ minLevel slog.Level } diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 9113c091c5..73243b16a1 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -67,9 +67,9 @@ func (vs *ValidationMessages) Info(msg string) { } // GetWarnings returns an error with all messages of type WARN of above, or nil if no warnings were present -func (v *ValidationMessages) GetWarnings() error { +func (vs *ValidationMessages) GetWarnings() error { var messages []string - for _, msg := range v.Messages { + for _, msg := range vs.Messages { if msg.Typ == WARN || msg.Typ == CRIT { messages = append(messages, msg.Message) } diff --git a/signer/core/uiapi.go b/signer/core/uiapi.go index b8c3acfb4d..43edfe7d97 100644 --- a/signer/core/uiapi.go +++ b/signer/core/uiapi.go @@ -52,9 +52,9 @@ func NewUIServerAPI(extapi *SignerAPI) *UIServerAPI { // the full Account object and not only Address. // Example call // {"jsonrpc":"2.0","method":"clef_listAccounts","params":[], "id":4} -func (s *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) { +func (api *UIServerAPI) ListAccounts(ctx context.Context) ([]accounts.Account, error) { var accs []accounts.Account - for _, wallet := range s.am.Wallets() { + for _, wallet := range api.am.Wallets() { accs = append(accs, wallet.Accounts()...) } return accs, nil @@ -72,9 +72,9 @@ type rawWallet struct { // ListWallets will return a list of wallets that clef manages // Example call // {"jsonrpc":"2.0","method":"clef_listWallets","params":[], "id":5} -func (s *UIServerAPI) ListWallets() []rawWallet { +func (api *UIServerAPI) ListWallets() []rawWallet { wallets := make([]rawWallet, 0) // return [] instead of nil if empty - for _, wallet := range s.am.Wallets() { + for _, wallet := range api.am.Wallets() { status, failure := wallet.Status() raw := rawWallet{ @@ -94,8 +94,8 @@ func (s *UIServerAPI) ListWallets() []rawWallet { // it for later reuse. // Example call // {"jsonrpc":"2.0","method":"clef_deriveAccount","params":["ledger://","m/44'/60'/0'", false], "id":6} -func (s *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { - wallet, err := s.am.Wallet(url) +func (api *UIServerAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) { + wallet, err := api.am.Wallet(url) if err != nil { return accounts.Account{}, err } @@ -122,7 +122,7 @@ func fetchKeystore(am *accounts.Manager) *keystore.KeyStore { // encrypting it with the passphrase. // Example call (should fail on password too short) // {"jsonrpc":"2.0","method":"clef_importRawKey","params":["1111111111111111111111111111111111111111111111111111111111111111","test"], "id":6} -func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) { +func (api *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Account, error) { key, err := crypto.HexToECDSA(privkey) if err != nil { return accounts.Account{}, err @@ -131,7 +131,7 @@ func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Ac return accounts.Account{}, fmt.Errorf("password requirements not met: %v", err) } // No error - return fetchKeystore(s.am).ImportECDSA(key, password) + return fetchKeystore(api.am).ImportECDSA(key, password) } // OpenWallet initiates a hardware wallet opening procedure, establishing a USB @@ -140,8 +140,8 @@ func (s *UIServerAPI) ImportRawKey(privkey string, password string) (accounts.Ac // Trezor PIN matrix challenge). // Example // {"jsonrpc":"2.0","method":"clef_openWallet","params":["ledger://",""], "id":6} -func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error { - wallet, err := s.am.Wallet(url) +func (api *UIServerAPI) OpenWallet(url string, passphrase *string) error { + wallet, err := api.am.Wallet(url) if err != nil { return err } @@ -155,24 +155,24 @@ func (s *UIServerAPI) OpenWallet(url string, passphrase *string) error { // ChainId returns the chainid in use for Eip-155 replay protection // Example call // {"jsonrpc":"2.0","method":"clef_chainId","params":[], "id":8} -func (s *UIServerAPI) ChainId() math.HexOrDecimal64 { - return (math.HexOrDecimal64)(s.extApi.chainID.Uint64()) +func (api *UIServerAPI) ChainId() math.HexOrDecimal64 { + return (math.HexOrDecimal64)(api.extApi.chainID.Uint64()) } // SetChainId sets the chain id to use when signing transactions. // Example call to set Ropsten: // {"jsonrpc":"2.0","method":"clef_setChainId","params":["3"], "id":8} -func (s *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 { - s.extApi.chainID = new(big.Int).SetUint64(uint64(id)) - return s.ChainId() +func (api *UIServerAPI) SetChainId(id math.HexOrDecimal64) math.HexOrDecimal64 { + api.extApi.chainID = new(big.Int).SetUint64(uint64(id)) + return api.ChainId() } // Export returns encrypted private key associated with the given address in web3 keystore format. // Example // {"jsonrpc":"2.0","method":"clef_export","params":["0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a"], "id":4} -func (s *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { +func (api *UIServerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) { // Look up the wallet containing the requested signer - wallet, err := s.am.Find(accounts.Account{Address: addr}) + wallet, err := api.am.Find(accounts.Account{Address: addr}) if err != nil { return nil, err } From 3687c34cfc9eba1b2c29209d27d272a72c4de3af Mon Sep 17 00:00:00 2001 From: jackyin <648588267@qq.com> Date: Wed, 12 Jun 2024 15:46:36 +0800 Subject: [PATCH 081/196] accounts: avoid duplicate regex compilation (#29943) * fix: Optimize regular initialization * modify var name * variable change to private types --- accounts/abi/type.go | 6 ++++-- accounts/scwallet/wallet.go | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/accounts/abi/type.go b/accounts/abi/type.go index 3839826633..d57fa3d4e6 100644 --- a/accounts/abi/type.go +++ b/accounts/abi/type.go @@ -64,6 +64,9 @@ type Type struct { var ( // typeRegex parses the abi sub types typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?") + + // sliceSizeRegex grab the slice size + sliceSizeRegex = regexp.MustCompile("[0-9]+") ) // NewType creates a new reflection type of abi type given in t. @@ -91,8 +94,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty // grab the last cell and create a type from there sliced := t[i:] // grab the slice size with regexp - re := regexp.MustCompile("[0-9]+") - intz := re.FindAllString(sliced, -1) + intz := sliceSizeRegex.FindAllString(sliced, -1) if len(intz) == 0 { // is a slice diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index f0ca9085b6..58cfc88301 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -73,6 +73,14 @@ var ( DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes()) ) +var ( + // PinRegexp is the regular expression used to validate PIN codes. + pinRegexp = regexp.MustCompile(`^[0-9]{6,}$`) + + // PukRegexp is the regular expression used to validate PUK codes. + pukRegexp = regexp.MustCompile(`^[0-9]{12,}$`) +) + // List of APDU command-related constants const ( claISO7816 = 0 @@ -380,7 +388,7 @@ func (w *Wallet) Open(passphrase string) error { case passphrase == "": return ErrPINUnblockNeeded case status.PinRetryCount > 0: - if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) { + if !pinRegexp.MatchString(passphrase) { w.log.Error("PIN needs to be at least 6 digits") return ErrPINNeeded } @@ -388,7 +396,7 @@ func (w *Wallet) Open(passphrase string) error { return err } default: - if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) { + if !pukRegexp.MatchString(passphrase) { w.log.Error("PUK needs to be at least 12 digits") return ErrPINUnblockNeeded } From 69351e8b0fcbcfb5b7dd8f3dc85d4c7d0217c848 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Wed, 12 Jun 2024 02:23:16 -0700 Subject: [PATCH 082/196] core/state, eth/protocols, trie, triedb/pathdb: remove unused error from trie Commit (#29869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core/state, eth/protocols, trie, triedb/pathdb: remove unused error return from trie Commit * move set back to account-trie-update block scoping for easier readability * address review * undo tests submodule change * trie: panic if BatchSerialize returns an error in Verkle trie Commit * trie: verkle comment nitpicks --------- Co-authored-by: Péter Szilágyi --- core/state/database.go | 2 +- core/state/snapshot/generate.go | 5 +---- core/state/snapshot/generate_test.go | 4 ++-- core/state/state_object.go | 5 +---- core/state/statedb.go | 5 +---- eth/protocols/snap/sync_test.go | 14 +++++++------- trie/iterator_test.go | 16 ++++++++-------- trie/secure_trie.go | 2 +- trie/secure_trie_test.go | 2 +- trie/stacktrie_fuzzer_test.go | 5 +---- trie/sync_test.go | 18 +++++++++--------- trie/tracer_test.go | 18 +++++++++--------- trie/trie.go | 10 +++++----- trie/trie_test.go | 22 +++++++++++----------- trie/triestate/state.go | 17 ++++------------- trie/verkle.go | 15 +++++++-------- triedb/pathdb/database_test.go | 6 +----- triedb/pathdb/testutils.go | 4 ++-- 18 files changed, 72 insertions(+), 98 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 04d7c06687..d71f8f34b6 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -123,7 +123,7 @@ type Trie interface { // The returned nodeset can be nil if the trie is clean(nothing to commit). // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. And error will be returned diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 8de4b134d3..d81a628c91 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -360,10 +360,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi for i, key := range result.keys { snapTrie.Update(key, result.vals[i]) } - root, nodes, err := snapTrie.Commit(false) - if err != nil { - return false, nil, err - } + root, nodes := snapTrie.Commit(false) if nodes != nil { tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) tdb.Commit(root, false) diff --git a/core/state/snapshot/generate_test.go b/core/state/snapshot/generate_test.go index da93ebc875..891111973a 100644 --- a/core/state/snapshot/generate_test.go +++ b/core/state/snapshot/generate_test.go @@ -210,7 +210,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st if !commit { return stTrie.Hash() } - root, nodes, _ := stTrie.Commit(false) + root, nodes := stTrie.Commit(false) if nodes != nil { t.nodes.Merge(nodes) } @@ -218,7 +218,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st } func (t *testHelper) Commit() common.Hash { - root, nodes, _ := t.accTrie.Commit(true) + root, nodes := t.accTrie.Commit(true) if nodes != nil { t.nodes.Merge(nodes) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 16a5f3e5e2..5c1dab53dc 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -470,10 +470,7 @@ func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) { s.origin = s.data.Copy() return op, nil, nil } - root, nodes, err := s.trie.Commit(false) - if err != nil { - return nil, nil, err - } + root, nodes := s.trie.Commit(false) s.data.Root = root s.origin = s.data.Copy() return op, nodes, nil diff --git a/core/state/statedb.go b/core/state/statedb.go index b4ef0a6e47..4f84d93d63 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1179,10 +1179,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // code didn't anticipate for. workers.Go(func() error { // Write the account trie changes, measuring the amount of wasted time - newroot, set, err := s.trie.Commit(true) - if err != nil { - return err - } + newroot, set := s.trie.Commit(true) root = newroot if err := merge(set); err != nil { diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 5f6826373a..82360ae0e3 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -1525,7 +1525,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv) // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes, _ := accTrie.Commit(false) + root, nodes := accTrie.Commit(false) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1587,7 +1587,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) { // Commit the state changes into db and re-create the trie // for accessing later. - root, nodes, _ := accTrie.Commit(false) + root, nodes := accTrie.Commit(false) db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil) accTrie, _ = trie.New(trie.StateTrieID(root), db) @@ -1633,7 +1633,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots slices.SortFunc(entries, (*kv).cmp) // Commit account trie - root, set, _ := accTrie.Commit(true) + root, set := accTrie.Commit(true) nodes.Merge(set) // Commit gathered dirty nodes into database @@ -1700,7 +1700,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda slices.SortFunc(entries, (*kv).cmp) // Commit account trie - root, set, _ := accTrie.Commit(true) + root, set := accTrie.Commit(true) nodes.Merge(set) // Commit gathered dirty nodes into database @@ -1742,7 +1742,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *triedb.Datab entries = append(entries, elem) } slices.SortFunc(entries, (*kv).cmp) - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) return root, nodes, entries } @@ -1793,7 +1793,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *triedb.Database) (com entries = append(entries, elem) } slices.SortFunc(entries, (*kv).cmp) - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) return root, nodes, entries } @@ -1825,7 +1825,7 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c } } slices.SortFunc(entries, (*kv).cmp) - root, nodes, _ := tr.Commit(false) + root, nodes := tr.Commit(false) return root, nodes, entries } diff --git a/trie/iterator_test.go b/trie/iterator_test.go index a8f3c4413e..b463294b09 100644 --- a/trie/iterator_test.go +++ b/trie/iterator_test.go @@ -59,7 +59,7 @@ func TestIterator(t *testing.T) { all[val.k] = val.v trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -257,7 +257,7 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata1 { triea.MustUpdate([]byte(val.k), []byte(val.v)) } - rootA, nodesA, _ := triea.Commit(false) + rootA, nodesA := triea.Commit(false) dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) @@ -266,7 +266,7 @@ func TestDifferenceIterator(t *testing.T) { for _, val := range testdata2 { trieb.MustUpdate([]byte(val.k), []byte(val.v)) } - rootB, nodesB, _ := trieb.Commit(false) + rootB, nodesB := trieb.Commit(false) dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) @@ -299,7 +299,7 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata1 { triea.MustUpdate([]byte(val.k), []byte(val.v)) } - rootA, nodesA, _ := triea.Commit(false) + rootA, nodesA := triea.Commit(false) dba.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)) triea, _ = New(TrieID(rootA), dba) @@ -308,7 +308,7 @@ func TestUnionIterator(t *testing.T) { for _, val := range testdata2 { trieb.MustUpdate([]byte(val.k), []byte(val.v)) } - rootB, nodesB, _ := trieb.Commit(false) + rootB, nodesB := trieb.Commit(false) dbb.Update(rootB, types.EmptyRootHash, trienode.NewWithNodeSet(nodesB)) trieb, _ = New(TrieID(rootB), dbb) @@ -371,7 +371,7 @@ func testIteratorContinueAfterError(t *testing.T, memonly bool, scheme string) { for _, val := range testdata1 { tr.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := tr.Commit(false) + root, nodes := tr.Commit(false) tdb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) if !memonly { tdb.Commit(root) @@ -481,7 +481,7 @@ func testIteratorContinueAfterSeekError(t *testing.T, memonly bool, scheme strin for _, val := range testdata1 { ctr.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := ctr.Commit(false) + root, nodes := ctr.Commit(false) for path, n := range nodes.Nodes { if n.Hash == barNodeHash { barNodePath = []byte(path) @@ -561,7 +561,7 @@ func testIteratorNodeBlob(t *testing.T, scheme string) { all[val.k] = val.v trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) triedb.Commit(root) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index e38d5ac4dc..fb39a80609 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -221,7 +221,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { // All cached preimages will be also flushed if preimages recording is enabled. // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage -func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { preimages := make(map[common.Hash][]byte) diff --git a/trie/secure_trie_test.go b/trie/secure_trie_test.go index 0a6fd688b7..59958d33f4 100644 --- a/trie/secure_trie_test.go +++ b/trie/secure_trie_test.go @@ -60,7 +60,7 @@ func makeTestStateTrie() (*testDb, *StateTrie, map[string][]byte) { trie.MustUpdate(key, val) } } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } diff --git a/trie/stacktrie_fuzzer_test.go b/trie/stacktrie_fuzzer_test.go index 418b941d94..df487d16bf 100644 --- a/trie/stacktrie_fuzzer_test.go +++ b/trie/stacktrie_fuzzer_test.go @@ -79,10 +79,7 @@ func fuzz(data []byte, debugging bool) { return } // Flush trie -> database - rootA, nodes, err := trieA.Commit(false) - if err != nil { - panic(err) - } + rootA, nodes := trieA.Commit(false) if nodes != nil { dbA.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) } diff --git a/trie/sync_test.go b/trie/sync_test.go index 7221b06f59..ccdee7d014 100644 --- a/trie/sync_test.go +++ b/trie/sync_test.go @@ -58,7 +58,7 @@ func makeTestTrie(scheme string) (ethdb.Database, *testDb, *StateTrie, map[strin trie.MustUpdate(key, val) } } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) if err := triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)); err != nil { panic(fmt.Errorf("failed to commit db %v", err)) } @@ -771,7 +771,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) { srcTrie.MustUpdate(key, val) diff[string(key)] = val } - root, nodes, _ := srcTrie.Commit(false) + root, nodes := srcTrie.Commit(false) if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { panic(err) } @@ -796,7 +796,7 @@ func testSyncMovingTarget(t *testing.T, scheme string) { srcTrie.MustUpdate([]byte(k), val) reverted[k] = val } - root, nodes, _ = srcTrie.Commit(false) + root, nodes = srcTrie.Commit(false) if err := srcDb.Update(root, preRoot, trienode.NewWithNodeSet(nodes)); err != nil { panic(err) } @@ -847,7 +847,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateA) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateA) - rootA, nodesA, _ := srcTrie.Commit(false) + rootA, nodesA := srcTrie.Commit(false) if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { panic(err) } @@ -866,7 +866,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { deleteFn([]byte{0x13, 0x44}, srcTrie, stateB) writeFn([]byte{0x01, 0x24}, nil, srcTrie, stateB) - rootB, nodesB, _ := srcTrie.Commit(false) + rootB, nodesB := srcTrie.Commit(false) if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { panic(err) } @@ -884,7 +884,7 @@ func testPivotMove(t *testing.T, scheme string, tiny bool) { writeFn([]byte{0x02, 0x34}, nil, srcTrie, stateC) writeFn([]byte{0x13, 0x44}, nil, srcTrie, stateC) - rootC, nodesC, _ := srcTrie.Commit(false) + rootC, nodesC := srcTrie.Commit(false) if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { panic(err) } @@ -946,7 +946,7 @@ func testSyncAbort(t *testing.T, scheme string) { } writeFn(key, val, srcTrie, stateA) - rootA, nodesA, _ := srcTrie.Commit(false) + rootA, nodesA := srcTrie.Commit(false) if err := srcTrieDB.Update(rootA, types.EmptyRootHash, trienode.NewWithNodeSet(nodesA)); err != nil { panic(err) } @@ -963,7 +963,7 @@ func testSyncAbort(t *testing.T, scheme string) { srcTrie, _ = New(TrieID(rootA), srcTrieDB) deleteFn(key, srcTrie, stateB) - rootB, nodesB, _ := srcTrie.Commit(false) + rootB, nodesB := srcTrie.Commit(false) if err := srcTrieDB.Update(rootB, rootA, trienode.NewWithNodeSet(nodesB)); err != nil { panic(err) } @@ -990,7 +990,7 @@ func testSyncAbort(t *testing.T, scheme string) { srcTrie, _ = New(TrieID(rootB), srcTrieDB) writeFn(key, val, srcTrie, stateC) - rootC, nodesC, _ := srcTrie.Commit(false) + rootC, nodesC := srcTrie.Commit(false) if err := srcTrieDB.Update(rootC, rootB, trienode.NewWithNodeSet(nodesC)); err != nil { panic(err) } diff --git a/trie/tracer_test.go b/trie/tracer_test.go index 27e42d497a..852a706021 100644 --- a/trie/tracer_test.go +++ b/trie/tracer_test.go @@ -70,7 +70,7 @@ func testTrieTracer(t *testing.T, vals []struct{ k, v string }) { } insertSet := copySet(trie.tracer.inserts) // copy before commit deleteSet := copySet(trie.tracer.deletes) // copy before commit - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) seen := setKeys(iterNodes(db, root)) @@ -137,7 +137,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -152,7 +152,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), randBytes(32)) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -170,7 +170,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { keys = append(keys, string(key)) trie.MustUpdate(key, randBytes(32)) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -185,7 +185,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, key := range keys { trie.MustUpdate([]byte(key), nil) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -200,7 +200,7 @@ func testAccessList(t *testing.T, vals []struct{ k, v string }) { for _, val := range vals { trie.MustUpdate([]byte(val.k), nil) } - root, nodes, _ = trie.Commit(false) + root, nodes = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) @@ -219,7 +219,7 @@ func TestAccessListLeak(t *testing.T) { for _, val := range standard { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) var cases = []struct { @@ -269,7 +269,7 @@ func TestTinyTree(t *testing.T) { for _, val := range tiny { trie.MustUpdate([]byte(val.k), randBytes(32)) } - root, set, _ := trie.Commit(false) + root, set := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(set)) parent := root @@ -278,7 +278,7 @@ func TestTinyTree(t *testing.T) { for _, val := range tiny { trie.MustUpdate([]byte(val.k), []byte(val.v)) } - root, set, _ = trie.Commit(false) + root, set = trie.Commit(false) db.Update(root, parent, trienode.NewWithNodeSet(set)) trie, _ = New(TrieID(root), db) diff --git a/trie/trie.go b/trie/trie.go index 12764e18d1..935f81fc7d 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -608,7 +608,7 @@ func (t *Trie) Hash() common.Hash { // The returned nodeset can be nil if the trie is clean (nothing to commit). // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage -func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { defer t.tracer.reset() defer func() { t.committed = true @@ -620,13 +620,13 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) if t.root == nil { paths := t.tracer.deletedNodes() if len(paths) == 0 { - return types.EmptyRootHash, nil, nil // case (a) + return types.EmptyRootHash, nil // case (a) } nodes := trienode.NewNodeSet(t.owner) for _, path := range paths { nodes.AddNode([]byte(path), trienode.NewDeleted()) } - return types.EmptyRootHash, nodes, nil // case (b) + return types.EmptyRootHash, nodes // case (b) } // Derive the hash for all dirty nodes first. We hold the assumption // in the following procedure that all nodes are hashed. @@ -638,14 +638,14 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) // Replace the root node with the origin hash in order to // ensure all resolved nodes are dropped after the commit. t.root = hashedNode - return rootHash, nil, nil + return rootHash, nil } nodes := trienode.NewNodeSet(t.owner) for _, path := range t.tracer.deletedNodes() { nodes.AddNode([]byte(path), trienode.NewDeleted()) } t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) - return rootHash, nodes, nil + return rootHash, nodes } // hashRoot calculates the root hash of the given trie diff --git a/trie/trie_test.go b/trie/trie_test.go index da60a7423d..f31fd393f5 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -95,7 +95,7 @@ func testMissingNode(t *testing.T, memonly bool, scheme string) { trie := NewEmpty(triedb) updateString(trie, "120000", "qwerqwerqwerqwerqwerqwerqwerqwer") updateString(trie, "123456", "asdfasdfasdfasdfasdfasdfasdfasdf") - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) triedb.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) if !memonly { @@ -184,7 +184,7 @@ func TestInsert(t *testing.T) { updateString(trie, "A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") exp = common.HexToHash("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab") - root, _, _ = trie.Commit(false) + root, _ = trie.Commit(false) if root != exp { t.Errorf("case 2: exp %x got %x", exp, root) } @@ -209,7 +209,7 @@ func TestGet(t *testing.T) { if i == 1 { return } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) trie, _ = New(TrieID(root), db) } @@ -282,7 +282,7 @@ func TestReplication(t *testing.T) { for _, val := range vals { updateString(trie, val.k, val.v) } - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // create a new trie on top of the database and check that lookups work. @@ -295,7 +295,7 @@ func TestReplication(t *testing.T) { t.Errorf("trie2 doesn't have %q => %q", kv.k, kv.v) } } - hash, nodes, _ := trie2.Commit(false) + hash, nodes := trie2.Commit(false) if hash != root { t.Errorf("root failure. expected %x got %x", root, hash) } @@ -531,7 +531,7 @@ func runRandTest(rt randTest) error { case opHash: tr.Hash() case opCommit: - root, nodes, _ := tr.Commit(true) + root, nodes := tr.Commit(true) if nodes != nil { triedb.Update(root, origin, trienode.NewWithNodeSet(nodes)) } @@ -768,7 +768,7 @@ func TestCommitAfterHash(t *testing.T) { if exp != root { t.Errorf("got %x, exp %x", root, exp) } - root, _, _ = trie.Commit(false) + root, _ = trie.Commit(false) if exp != root { t.Errorf("got %x, exp %x", root, exp) } @@ -894,7 +894,7 @@ func TestCommitSequence(t *testing.T) { trie.MustUpdate(crypto.Keccak256(addresses[i][:]), accounts[i]) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root) @@ -935,7 +935,7 @@ func TestCommitSequenceRandomBlobs(t *testing.T) { trie.MustUpdate(key, val) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) // Flush memdb -> disk (sponge) db.Commit(root) @@ -984,7 +984,7 @@ func TestCommitSequenceStackTrie(t *testing.T) { stTrie.Update(key, val) } // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root) @@ -1042,7 +1042,7 @@ func TestCommitSequenceSmallRoot(t *testing.T) { stTrie.Update(key, []byte{0x1}) // Flush trie -> database - root, nodes, _ := trie.Commit(false) + root, nodes := trie.Commit(false) // Flush memdb -> disk (sponge) db.Update(root, types.EmptyRootHash, trienode.NewWithNodeSet(nodes)) db.Commit(root) diff --git a/trie/triestate/state.go b/trie/triestate/state.go index 9db9211e8c..7508da5d60 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -42,7 +42,7 @@ type Trie interface { // Commit the trie and returns a set of dirty nodes generated along with // the new root hash. - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) + Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) } // TrieLoader wraps functions to load tries. @@ -125,10 +125,7 @@ func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Addre return nil, fmt.Errorf("failed to revert state, err: %w", err) } } - root, result, err := tr.Commit(false) - if err != nil { - return nil, err - } + root, result := tr.Commit(false) if root != prevRoot { return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) } @@ -180,10 +177,7 @@ func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { return err } } - root, result, err := st.Commit(false) - if err != nil { - return err - } + root, result := st.Commit(false) if root != prev.Root { return errors.New("failed to reset storage trie") } @@ -234,10 +228,7 @@ func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { return err } } - root, result, err := st.Commit(false) - if err != nil { - return err - } + root, result := st.Commit(false) if root != types.EmptyRootHash { return errors.New("failed to clear storage trie") } diff --git a/trie/verkle.go b/trie/verkle.go index bb0c54857f..1ea23186f9 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -217,22 +217,21 @@ func (t *VerkleTrie) Hash() common.Hash { } // Commit writes all nodes to the tree's memory database. -func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) { - root, ok := t.root.(*verkle.InternalNode) - if !ok { - return common.Hash{}, nil, errors.New("unexpected root node type") - } +func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) { + root := t.root.(*verkle.InternalNode) nodes, err := root.BatchSerialize() if err != nil { - return common.Hash{}, nil, fmt.Errorf("serializing tree nodes: %s", err) + // Error return from this function indicates error in the code logic + // of BatchSerialize, and we fail catastrophically if this is the case. + panic(fmt.Errorf("BatchSerialize failed: %v", err)) } nodeset := trienode.NewNodeSet(common.Hash{}) for _, node := range nodes { - // hash parameter is not used in pathdb + // Hash parameter is not used in pathdb nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes)) } // Serialize root commitment form - return t.Hash(), nodeset, nil + return t.Hash(), nodeset } // NodeIterator implements state.Trie, returning an iterator that returns diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 7b24082315..04c8af415f 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -46,11 +46,7 @@ func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[comm h.Update(key.Bytes(), val) } } - root, nodes, err := h.Commit(false) - if err != nil { - panic(fmt.Errorf("failed to commit hasher, err: %w", err)) - } - return root, nodes + return h.Commit(false) } func generateAccount(storageRoot common.Hash) types.StateAccount { diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go index 0c99565b8e..af832bc59c 100644 --- a/triedb/pathdb/testutils.go +++ b/triedb/pathdb/testutils.go @@ -80,7 +80,7 @@ func (h *testHasher) Delete(key []byte) error { // Commit computes the new hash of the states and returns the set with all // state changes. -func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { +func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { var ( nodes = make(map[common.Hash][]byte) set = trienode.NewNodeSet(h.owner) @@ -111,7 +111,7 @@ func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, e if root == types.EmptyRootHash && h.root != types.EmptyRootHash { set.AddNode(nil, trienode.NewDeleted()) } - return root, set, nil + return root, set } // hash performs the hash computation upon the provided states. From 86150af2e5deb33130660a5a5d62ed819a2b0e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felf=C3=B6ldi=20Zsolt?= Date: Wed, 12 Jun 2024 16:38:19 +0200 Subject: [PATCH 083/196] beacon/light: fix shutdown issues (#29946) * beacon/light/request: add server test for event after unsubscribe * beacon/light/api: fixed double stream.Close() * beacon/light/request: add checks for nil event callback function * beacon/light/request: unlock server mutex while unsubscribing from parent --- beacon/light/api/light_api.go | 3 --- beacon/light/request/server.go | 31 +++++++++++++++++------------ beacon/light/request/server_test.go | 31 +++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 903db57344..6f60fc0cc6 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -494,9 +494,6 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() for { select { - case <-ctx.Done(): - stream.Close() - case event, ok := <-stream.Events: if !ok { log.Trace("Event stream closed") diff --git a/beacon/light/request/server.go b/beacon/light/request/server.go index 9f3b09b81e..a06dec99ae 100644 --- a/beacon/light/request/server.go +++ b/beacon/light/request/server.go @@ -186,10 +186,14 @@ func (s *serverWithTimeout) eventCallback(event Event) { // call will just do nothing timer.Stop() delete(s.timeouts, id) - s.childEventCb(event) + if s.childEventCb != nil { + s.childEventCb(event) + } } default: - s.childEventCb(event) + if s.childEventCb != nil { + s.childEventCb(event) + } } } @@ -211,25 +215,27 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) { delete(s.timeouts, id) childEventCb := s.childEventCb s.lock.Unlock() - childEventCb(Event{Type: EvFail, Data: reqData}) + if childEventCb != nil { + childEventCb(Event{Type: EvFail, Data: reqData}) + } }) childEventCb := s.childEventCb s.lock.Unlock() - childEventCb(Event{Type: EvTimeout, Data: reqData}) + if childEventCb != nil { + childEventCb(Event{Type: EvTimeout, Data: reqData}) + } }) } // unsubscribe stops all goroutines associated with the server. func (s *serverWithTimeout) unsubscribe() { s.lock.Lock() - defer s.lock.Unlock() - for _, timer := range s.timeouts { if timer != nil { timer.Stop() } } - s.childEventCb = nil + s.lock.Unlock() s.parent.Unsubscribe() } @@ -328,10 +334,10 @@ func (s *serverWithLimits) eventCallback(event Event) { } childEventCb := s.childEventCb s.lock.Unlock() - if passEvent { + if passEvent && childEventCb != nil { childEventCb(event) } - if sendCanRequestAgain { + if sendCanRequestAgain && childEventCb != nil { childEventCb(Event{Type: EvCanRequestAgain}) } } @@ -347,13 +353,12 @@ func (s *serverWithLimits) sendRequest(request Request) (reqId ID) { // unsubscribe stops all goroutines associated with the server. func (s *serverWithLimits) unsubscribe() { s.lock.Lock() - defer s.lock.Unlock() - if s.delayTimer != nil { s.delayTimer.Stop() s.delayTimer = nil } s.childEventCb = nil + s.lock.Unlock() s.serverWithTimeout.unsubscribe() } @@ -383,7 +388,7 @@ func (s *serverWithLimits) canRequestNow() bool { } childEventCb := s.childEventCb s.lock.Unlock() - if sendCanRequestAgain { + if sendCanRequestAgain && childEventCb != nil { childEventCb(Event{Type: EvCanRequestAgain}) } return canRequest @@ -415,7 +420,7 @@ func (s *serverWithLimits) delay(delay time.Duration) { } childEventCb := s.childEventCb s.lock.Unlock() - if sendCanRequestAgain { + if sendCanRequestAgain && childEventCb != nil { childEventCb(Event{Type: EvCanRequestAgain}) } }) diff --git a/beacon/light/request/server_test.go b/beacon/light/request/server_test.go index 38629cb8c4..fef5d062ea 100644 --- a/beacon/light/request/server_test.go +++ b/beacon/light/request/server_test.go @@ -51,6 +51,7 @@ func TestServerEvents(t *testing.T) { expEvent(EvFail) rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}}) expEvent(nil) + srv.unsubscribe() } func TestServerParallel(t *testing.T) { @@ -129,9 +130,7 @@ func TestServerEventRateLimit(t *testing.T) { srv := NewServer(rs, clock) var eventCount int srv.subscribe(func(event Event) { - if !event.IsRequestEvent() { - eventCount++ - } + eventCount++ }) expEvents := func(send, expAllowed int) { eventCount = 0 @@ -147,6 +146,30 @@ func TestServerEventRateLimit(t *testing.T) { expEvents(5, 1) clock.Run(maxServerEventRate * maxServerEventBuffer * 2) expEvents(maxServerEventBuffer+5, maxServerEventBuffer) + srv.unsubscribe() +} + +func TestServerUnsubscribe(t *testing.T) { + rs := &testRequestServer{} + clock := &mclock.Simulated{} + srv := NewServer(rs, clock) + var eventCount int + srv.subscribe(func(event Event) { + eventCount++ + }) + eventCb := rs.eventCb + eventCb(Event{Type: testEventType}) + if eventCount != 1 { + t.Errorf("Server event callback not called before unsubscribe") + } + srv.unsubscribe() + if rs.eventCb != nil { + t.Errorf("Server event callback not removed after unsubscribe") + } + eventCb(Event{Type: testEventType}) + if eventCount != 1 { + t.Errorf("Server event callback called after unsubscribe") + } } type testRequestServer struct { @@ -156,4 +179,4 @@ type testRequestServer struct { func (rs *testRequestServer) Name() string { return "" } func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb } func (rs *testRequestServer) SendRequest(ID, Request) {} -func (rs *testRequestServer) Unsubscribe() {} +func (rs *testRequestServer) Unsubscribe() { rs.eventCb = nil } From fd5078c779f2aab50ea759bd3dcd3c5d4f2556f8 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 13 Jun 2024 23:52:46 -0700 Subject: [PATCH 084/196] trie/triedb: add Reader to backend interface (#29988) --- triedb/database.go | 12 +++++------- triedb/hashdb/database.go | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/triedb/database.go b/triedb/database.go index 10f77982f3..ef757e7f5b 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -74,6 +74,10 @@ type backend interface { // Close closes the trie database backend and releases all held resources. Close() error + + // Reader returns a reader for accessing all trie nodes with provided state + // root. An error will be returned if the requested state is not available. + Reader(root common.Hash) (database.Reader, error) } // Database is the wrapper of the underlying backend which is shared by different @@ -123,13 +127,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { // Reader returns a reader for accessing all trie nodes with provided state root. // An error will be returned if the requested state is not available. func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) { - switch b := db.backend.(type) { - case *hashdb.Database: - return b.Reader(blockRoot) - case *pathdb.Database: - return b.Reader(blockRoot) - } - return nil, errors.New("unknown backend") + return db.backend.Reader(blockRoot) } // Update performs a state transition by committing dirty nodes contained in the diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index ebb5d72057..bb0deca9a7 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/triestate" + "github.com/ethereum/go-ethereum/triedb/database" ) var ( @@ -625,7 +626,7 @@ func (db *Database) Close() error { // Reader retrieves a node reader belonging to the given state root. // An error will be returned if the requested state is not available. -func (db *Database) Reader(root common.Hash) (*reader, error) { +func (db *Database) Reader(root common.Hash) (database.Reader, error) { if _, err := db.node(root); err != nil { return nil, fmt.Errorf("state %#x is not available, %v", root, err) } From 34b46a2f756da71595ac84eb7f25441f2a5b6ebb Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jun 2024 15:42:39 +0800 Subject: [PATCH 085/196] core/state/snapshot: add a missing lock (#30001) * upgrade lock usage * revert unnecessary change --- core/state/snapshot/snapshot.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 89a4c16c20..7c76765417 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -829,6 +829,8 @@ func (t *Tree) disklayer() *diskLayer { case *diskLayer: return layer case *diffLayer: + layer.lock.RLock() + defer layer.lock.RUnlock() return layer.origin default: panic(fmt.Sprintf("%T: undefined layer", snap)) @@ -860,7 +862,7 @@ func (t *Tree) generating() (bool, error) { return layer.genMarker != nil, nil } -// DiskRoot is a external helper function to return the disk layer root. +// DiskRoot is an external helper function to return the disk layer root. func (t *Tree) DiskRoot() common.Hash { t.lock.Lock() defer t.lock.Unlock() From a58e4f06747b287af6d5befaddaae66c4494f431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 17 Jun 2024 11:15:27 +0300 Subject: [PATCH 086/196] go.mod: update Pebble to sort out a deleted upstream dependency (#30010) --- go.mod | 11 ++++++----- go.sum | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 9947df31f3..b578ec07b5 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.2.0 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.79.0 - github.com/cockroachdb/pebble v1.1.0 + github.com/cockroachdb/pebble v1.1.1 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 @@ -61,7 +61,7 @@ require ( github.com/rs/cors v1.7.0 github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible github.com/status-im/keycard-go v0.2.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/supranational/blst v0.3.11 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.1.0 @@ -95,7 +95,8 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/cockroachdb/errors v1.11.1 // indirect + github.com/cockroachdb/errors v1.11.3 // indirect + github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect @@ -105,7 +106,7 @@ require ( github.com/deepmap/oapi-codegen v1.6.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61 // indirect - github.com/getsentry/sentry-go v0.18.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -116,7 +117,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect + github.com/klauspost/compress v1.16.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect diff --git a/go.sum b/go.sum index 5e4b38e9a6..168637b0ad 100644 --- a/go.sum +++ b/go.sum @@ -116,12 +116,14 @@ github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= -github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= -github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= +github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= +github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= @@ -187,8 +189,8 @@ github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILD github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0= -github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -347,8 +349,8 @@ github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4 github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= -github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -494,8 +496,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= From b78d2352ef55b727ed57d1abe612af09c67be29a Mon Sep 17 00:00:00 2001 From: Zoro <40222601+BabyHalimao@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:03:27 +0800 Subject: [PATCH 087/196] log: fix some functions comments (#29907) updates some docstrings --------- Co-authored-by: rjl493456442 --- log/handler_glog.go | 12 ++++++++++-- log/logger.go | 6 +++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/log/handler_glog.go b/log/handler_glog.go index 625a036403..739f8c5b42 100644 --- a/log/handler_glog.go +++ b/log/handler_glog.go @@ -139,11 +139,15 @@ func (h *GlogHandler) Vmodule(ruleset string) error { return nil } +// Enabled implements slog.Handler, reporting whether the handler handles records +// at the given level. func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool { // fast-track skipping logging if override not enabled and the provided verbosity is above configured return h.override.Load() || slog.Level(h.level.Load()) <= lvl } +// WithAttrs implements slog.Handler, returning a new Handler whose attributes +// consist of both the receiver's attributes and the arguments. func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { h.lock.RLock() siteCache := maps.Clone(h.siteCache) @@ -164,12 +168,16 @@ func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return &res } +// WithGroup implements slog.Handler, returning a new Handler with the given +// group appended to the receiver's existing groups. +// +// Note, this function is not implemented. func (h *GlogHandler) WithGroup(name string) slog.Handler { panic("not implemented") } -// Log implements Handler.Log, filtering a log record through the global, local -// and backtrace filters, finally emitting it if either allow it through. +// Handle implements slog.Handler, filtering a log record through the global, +// local and backtrace filters, finally emitting it if either allow it through. func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error { // If the global log level allows, fast track logging if slog.Level(h.level.Load()) <= r.Level { diff --git a/log/logger.go b/log/logger.go index 8b03b68fc8..016856c834 100644 --- a/log/logger.go +++ b/log/logger.go @@ -35,7 +35,7 @@ const ( LvlDebug = LevelDebug ) -// convert from old Geth verbosity level constants +// FromLegacyLevel converts from old Geth verbosity level constants // to levels defined by slog func FromLegacyLevel(lvl int) slog.Level { switch lvl { @@ -107,7 +107,7 @@ type Logger interface { // With returns a new Logger that has this logger's attributes plus the given attributes With(ctx ...interface{}) Logger - // With returns a new Logger that has this logger's attributes plus the given attributes. Identical to 'With'. + // New returns a new Logger that has this logger's attributes plus the given attributes. Identical to 'With'. New(ctx ...interface{}) Logger // Log logs a message at the specified level with context key/value pairs @@ -156,7 +156,7 @@ func (l *logger) Handler() slog.Handler { return l.inner.Handler() } -// Write logs a message at the specified level: +// Write logs a message at the specified level. func (l *logger) Write(level slog.Level, msg string, attrs ...any) { if !l.inner.Enabled(context.Background(), level) { return From 115d154392dc47eedbdfe9e598f2f4d9ae421976 Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jun 2024 17:42:41 +0800 Subject: [PATCH 088/196] trie, triedb/pathdb: prealloc capacity for map and slice (#29986) --- trie/secure_trie.go | 2 +- trie/trienode/node.go | 2 +- triedb/pathdb/history.go | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/trie/secure_trie.go b/trie/secure_trie.go index fb39a80609..cfa7f0bddb 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -224,7 +224,7 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { // Write all the pre-images to the actual disk database if len(t.getSecKeyCache()) > 0 { - preimages := make(map[common.Hash][]byte) + preimages := make(map[common.Hash][]byte, len(t.secKeyCache)) for hk, key := range t.secKeyCache { preimages[common.BytesToHash([]byte(hk))] = key } diff --git a/trie/trienode/node.go b/trie/trienode/node.go index aa8a0f6d99..fa7bebe4f9 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -186,7 +186,7 @@ func (set *MergedNodeSet) Merge(other *NodeSet) error { // Flatten returns a two-dimensional map for internal nodes. func (set *MergedNodeSet) Flatten() map[common.Hash]map[string]*Node { - nodes := make(map[common.Hash]map[string]*Node) + nodes := make(map[common.Hash]map[string]*Node, len(set.Sets)) for owner, set := range set.Sets { nodes[owner] = set.Nodes } diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 3663cbbdb9..60ce3dc2bc 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -384,10 +384,11 @@ func (r *decoder) readAccount(pos int) (accountIndex, []byte, error) { func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common.Hash][]byte, error) { var ( last common.Hash - list []common.Hash - storage = make(map[common.Hash][]byte) + count = int(accIndex.storageSlots) + list = make([]common.Hash, 0, count) + storage = make(map[common.Hash][]byte, count) ) - for j := 0; j < int(accIndex.storageSlots); j++ { + for j := 0; j < count; j++ { var ( index slotIndex start = (accIndex.storageOffset + uint32(j)) * uint32(slotIndexSize) @@ -430,9 +431,10 @@ func (r *decoder) readStorage(accIndex accountIndex) ([]common.Hash, map[common. // decode deserializes the account and storage data from the provided byte stream. func (h *history) decode(accountData, storageData, accountIndexes, storageIndexes []byte) error { var ( - accounts = make(map[common.Address][]byte) + count = len(accountIndexes) / accountIndexSize + accounts = make(map[common.Address][]byte, count) storages = make(map[common.Address]map[common.Hash][]byte) - accountList []common.Address + accountList = make([]common.Address, 0, count) storageList = make(map[common.Address][]common.Hash) r = &decoder{ @@ -445,7 +447,7 @@ func (h *history) decode(accountData, storageData, accountIndexes, storageIndexe if err := r.verify(); err != nil { return err } - for i := 0; i < len(accountIndexes)/accountIndexSize; i++ { + for i := 0; i < count; i++ { // Resolve account first accIndex, accData, err := r.readAccount(i) if err != nil { From c736b04d9b3bec8d9281146490b05075a91e7eea Mon Sep 17 00:00:00 2001 From: maskpp Date: Mon, 17 Jun 2024 23:09:29 +0800 Subject: [PATCH 089/196] triedb/pathdb: use maps.Clone and maps.Keys (#29985) --- triedb/pathdb/history.go | 11 +++-------- triedb/pathdb/nodebuffer.go | 5 ++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 60ce3dc2bc..d77f7aa04d 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie/triestate" + "golang.org/x/exp/maps" ) // State history records the state changes involved in executing a block. The @@ -244,19 +245,13 @@ type history struct { // newHistory constructs the state history object with provided state change set. func newHistory(root common.Hash, parent common.Hash, block uint64, states *triestate.Set) *history { var ( - accountList []common.Address + accountList = maps.Keys(states.Accounts) storageList = make(map[common.Address][]common.Hash) ) - for addr := range states.Accounts { - accountList = append(accountList, addr) - } slices.SortFunc(accountList, common.Address.Cmp) for addr, slots := range states.Storages { - slist := make([]common.Hash, 0, len(slots)) - for slotHash := range slots { - slist = append(slist, slotHash) - } + slist := maps.Keys(slots) slices.SortFunc(slist, common.Hash.Cmp) storageList[addr] = slist } diff --git a/triedb/pathdb/nodebuffer.go b/triedb/pathdb/nodebuffer.go index ff09484100..d3492602c8 100644 --- a/triedb/pathdb/nodebuffer.go +++ b/triedb/pathdb/nodebuffer.go @@ -19,6 +19,7 @@ package pathdb import ( "bytes" "fmt" + "maps" "time" "github.com/VictoriaMetrics/fastcache" @@ -90,12 +91,10 @@ func (b *nodebuffer) commit(nodes map[common.Hash]map[string]*trienode.Node) *no // The nodes belong to original diff layer are still accessible even // after merging, thus the ownership of nodes map should still belong // to original layer and any mutation on it should be prevented. - current = make(map[string]*trienode.Node, len(subset)) for path, n := range subset { - current[path] = n delta += int64(len(n.Blob) + len(path)) } - b.nodes[owner] = current + b.nodes[owner] = maps.Clone(subset) continue } for path, n := range subset { From d8664490da47bfff1854869826268c486e6487d7 Mon Sep 17 00:00:00 2001 From: Dean Eigenmann <7621705+decanus@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:53:00 +0200 Subject: [PATCH 090/196] common/math: fix out of bounds access in json unmarshalling (#30014) Co-authored-by: Martin Holst Swende --- common/math/big.go | 2 +- common/math/integer.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/math/big.go b/common/math/big.go index 721b297c9c..d9748d01a3 100644 --- a/common/math/big.go +++ b/common/math/big.go @@ -54,7 +54,7 @@ func NewHexOrDecimal256(x int64) *HexOrDecimal256 { // It is similar to UnmarshalText, but allows parsing real decimals too, not just // quoted decimal strings. func (i *HexOrDecimal256) UnmarshalJSON(input []byte) error { - if len(input) > 0 && input[0] == '"' { + if len(input) > 1 && input[0] == '"' { input = input[1 : len(input)-1] } return i.UnmarshalText(input) diff --git a/common/math/integer.go b/common/math/integer.go index 080fba8fea..82de96f927 100644 --- a/common/math/integer.go +++ b/common/math/integer.go @@ -46,7 +46,7 @@ type HexOrDecimal64 uint64 // It is similar to UnmarshalText, but allows parsing real decimals too, not just // quoted decimal strings. func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error { - if len(input) > 0 && input[0] == '"' { + if len(input) > 1 && input[0] == '"' { input = input[1 : len(input)-1] } return i.UnmarshalText(input) From 7cf6a63687da2d9300fec495ff4bc978c4b70b65 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Tue, 18 Jun 2024 04:52:49 +0200 Subject: [PATCH 091/196] core/state/snapshot: acquire the lock on Release (#30011) * core/state/snapshot: acquire the lock on release * core/state/snapshot: only acquire read-lock when iterating --- core/state/snapshot/snapshot.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 7c76765417..752f4359fb 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -666,6 +666,9 @@ func diffToDisk(bottom *diffLayer) *diskLayer { // Release releases resources func (t *Tree) Release() { + t.lock.RLock() + defer t.lock.RUnlock() + if dl := t.disklayer(); dl != nil { dl.Release() } @@ -850,8 +853,8 @@ func (t *Tree) diskRoot() common.Hash { // generating is an internal helper function which reports whether the snapshot // is still under the construction. func (t *Tree) generating() (bool, error) { - t.lock.Lock() - defer t.lock.Unlock() + t.lock.RLock() + defer t.lock.RUnlock() layer := t.disklayer() if layer == nil { @@ -864,8 +867,8 @@ func (t *Tree) generating() (bool, error) { // DiskRoot is an external helper function to return the disk layer root. func (t *Tree) DiskRoot() common.Hash { - t.lock.Lock() - defer t.lock.Unlock() + t.lock.RLock() + defer t.lock.RUnlock() return t.diskRoot() } From 67a862db9de372cd9c53fb3d7f44252d6b535c28 Mon Sep 17 00:00:00 2001 From: Ha DANG Date: Wed, 19 Jun 2024 13:47:17 +0700 Subject: [PATCH 092/196] cmd/geth, ethdb/pebble: improve database statistic (#29948) * cmd/geth, ethdb/pebble: polish method naming and code comment * implement db stat for pebble * cmd, core, ethdb, internal, trie: remove db property selector * cmd, core, ethdb: fix function description --------- Co-authored-by: prpeh Co-authored-by: Gary Rong --- cmd/geth/chaincmd.go | 4 +-- cmd/geth/dbcmd.go | 20 ++++++-------- core/rawdb/table.go | 6 ++--- ethdb/database.go | 4 +-- ethdb/leveldb/leveldb.go | 54 +++++++++++++++++++++++++++++++------ ethdb/memorydb/memorydb.go | 6 ++--- ethdb/pebble/pebble.go | 6 ++--- ethdb/remotedb/remotedb.go | 4 +-- internal/ethapi/api.go | 4 +-- internal/web3ext/web3ext.go | 1 - trie/trie_test.go | 2 +- 11 files changed, 71 insertions(+), 40 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 2965b99d94..9450c09e7e 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -336,7 +336,7 @@ func importChain(ctx *cli.Context) error { fmt.Printf("Import done in %v.\n\n", time.Since(start)) // Output pre-compaction stats mostly to see the import trashing - showLeveldbStats(db) + showDBStats(db) // Print the memory statistics used by the importing mem := new(runtime.MemStats) @@ -359,7 +359,7 @@ func importChain(ctx *cli.Context) error { } fmt.Printf("Compaction done in %v.\n\n", time.Since(start)) - showLeveldbStats(db) + showDBStats(db) return importErr } diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 742eadd5f3..4b683569a4 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -407,17 +407,13 @@ func checkStateContent(ctx *cli.Context) error { return nil } -func showLeveldbStats(db ethdb.KeyValueStater) { - if stats, err := db.Stat("leveldb.stats"); err != nil { +func showDBStats(db ethdb.KeyValueStater) { + stats, err := db.Stat() + if err != nil { log.Warn("Failed to read database stats", "error", err) - } else { - fmt.Println(stats) - } - if ioStats, err := db.Stat("leveldb.iostats"); err != nil { - log.Warn("Failed to read database iostats", "error", err) - } else { - fmt.Println(ioStats) + return } + fmt.Println(stats) } func dbStats(ctx *cli.Context) error { @@ -427,7 +423,7 @@ func dbStats(ctx *cli.Context) error { db := utils.MakeChainDatabase(ctx, stack, true) defer db.Close() - showLeveldbStats(db) + showDBStats(db) return nil } @@ -439,7 +435,7 @@ func dbCompact(ctx *cli.Context) error { defer db.Close() log.Info("Stats before compaction") - showLeveldbStats(db) + showDBStats(db) log.Info("Triggering compaction") if err := db.Compact(nil, nil); err != nil { @@ -447,7 +443,7 @@ func dbCompact(ctx *cli.Context) error { return err } log.Info("Stats after compaction") - showLeveldbStats(db) + showDBStats(db) return nil } diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 19e4ed5b5c..90849fe9d9 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -147,9 +147,9 @@ func (t *table) NewIterator(prefix []byte, start []byte) ethdb.Iterator { } } -// Stat returns a particular internal stat of the database. -func (t *table) Stat(property string) (string, error) { - return t.db.Stat(property) +// Stat returns the statistic data of the database. +func (t *table) Stat() (string, error) { + return t.db.Stat() } // Compact flattens the underlying data store for the given key range. In essence, diff --git a/ethdb/database.go b/ethdb/database.go index 3ec1f70e3b..9ef5942a13 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -39,8 +39,8 @@ type KeyValueWriter interface { // KeyValueStater wraps the Stat method of a backing data store. type KeyValueStater interface { - // Stat returns a particular internal stat of the database. - Stat(property string) (string, error) + // Stat returns the statistic data of the database. + Stat() (string, error) } // Compacter wraps the Compact method of a backing data store. diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 64f51cf217..92838ad7ab 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -22,7 +22,6 @@ package leveldb import ( "fmt" - "strings" "sync" "time" @@ -244,14 +243,53 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { return &snapshot{db: snap}, nil } -// Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - if property == "" { - property = "leveldb.stats" - } else if !strings.HasPrefix(property, "leveldb.") { - property = "leveldb." + property +// Stat returns the statistic data of the database. +func (db *Database) Stat() (string, error) { + var stats leveldb.DBStats + if err := db.db.Stats(&stats); err != nil { + return "", err } - return db.db.GetProperty(property) + var ( + message string + totalRead int64 + totalWrite int64 + totalSize int64 + totalTables int + totalDuration time.Duration + ) + if len(stats.LevelSizes) > 0 { + message += " Level | Tables | Size(MB) | Time(sec) | Read(MB) | Write(MB)\n" + + "-------+------------+---------------+---------------+---------------+---------------\n" + for level, size := range stats.LevelSizes { + read := stats.LevelRead[level] + write := stats.LevelWrite[level] + duration := stats.LevelDurations[level] + tables := stats.LevelTablesCounts[level] + + if tables == 0 && duration == 0 { + continue + } + totalTables += tables + totalSize += size + totalRead += read + totalWrite += write + totalDuration += duration + message += fmt.Sprintf(" %3d | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + level, tables, float64(size)/1048576.0, duration.Seconds(), + float64(read)/1048576.0, float64(write)/1048576.0) + } + message += "-------+------------+---------------+---------------+---------------+---------------\n" + message += fmt.Sprintf(" Total | %10d | %13.5f | %13.5f | %13.5f | %13.5f\n", + totalTables, float64(totalSize)/1048576.0, totalDuration.Seconds(), + float64(totalRead)/1048576.0, float64(totalWrite)/1048576.0) + message += "-------+------------+---------------+---------------+---------------+---------------\n\n" + } + message += fmt.Sprintf("Read(MB):%.5f Write(MB):%.5f\n", float64(stats.IORead)/1048576.0, float64(stats.IOWrite)/1048576.0) + message += fmt.Sprintf("BlockCache(MB):%.5f FileCache:%d\n", float64(stats.BlockCacheSize)/1048576.0, stats.OpenedTablesCount) + message += fmt.Sprintf("MemoryCompaction:%d Level0Compaction:%d NonLevel0Compaction:%d SeekCompaction:%d\n", stats.MemComp, stats.Level0Comp, stats.NonLevel0Comp, stats.SeekComp) + message += fmt.Sprintf("WriteDelayCount:%d WriteDelayDuration:%s Paused:%t\n", stats.WriteDelayCount, common.PrettyDuration(stats.WriteDelayDuration), stats.WritePaused) + message += fmt.Sprintf("Snapshots:%d Iterators:%d\n", stats.AliveSnapshots, stats.AliveIterators) + return message, nil } // Compact flattens the underlying data store for the given key range. In essence, diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index d1233acb21..9b0872f89a 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -182,9 +182,9 @@ func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { return newSnapshot(db), nil } -// Stat returns a particular internal stat of the database. -func (db *Database) Stat(property string) (string, error) { - return "", errors.New("unknown property") +// Stat returns the statistic data of the database. +func (db *Database) Stat() (string, error) { + return "", nil } // Compact is not supported on a memory database, but there's no need either as diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 0fac07c960..130d6617b5 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -416,10 +416,8 @@ func upperBound(prefix []byte) (limit []byte) { } // Stat returns the internal metrics of Pebble in a text format. It's a developer -// method to read everything there is to read independent of Pebble version. -// -// The property is unused in Pebble as there's only one thing to retrieve. -func (d *Database) Stat(property string) (string, error) { +// method to read everything there is to read, independent of Pebble version. +func (d *Database) Stat() (string, error) { return d.db.Metrics().String(), nil } diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index c1c803caf2..bfecde4a32 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -126,8 +126,8 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { panic("not supported") } -func (db *Database) Stat(property string) (string, error) { - panic("not supported") +func (db *Database) Stat() (string, error) { + return "", nil } func (db *Database) AncientDatadir() (string, error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1c209fb5a4..0ecedf1130 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -2108,8 +2108,8 @@ func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, err } // ChaindbProperty returns leveldb properties of the key-value database. -func (api *DebugAPI) ChaindbProperty(property string) (string, error) { - return api.b.ChainDb().Stat(property) +func (api *DebugAPI) ChaindbProperty() (string, error) { + return api.b.ChainDb().Stat() } // ChaindbCompact flattens the entire key-value database into a single level, diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 1da7d737dd..4a1a37d722 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -263,7 +263,6 @@ web3._extend({ new web3._extend.Method({ name: 'chaindbProperty', call: 'debug_chaindbProperty', - params: 1, outputFormatter: console.log }), new web3._extend.Method({ diff --git a/trie/trie_test.go b/trie/trie_test.go index f31fd393f5..5f706a28be 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -820,7 +820,7 @@ func (s *spongeDb) Delete(key []byte) error { panic("implement func (s *spongeDb) NewBatch() 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(property string) (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) Close() error { return nil } func (s *spongeDb) Put(key []byte, value []byte) error { From 0e3a0a693ce99cca1f928c913108237d4be8c233 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Wed, 19 Jun 2024 00:58:22 -0700 Subject: [PATCH 093/196] trie: don't reset tracer at the end of Commit (#30024) * trie: don't reset tracer at the end of Commit * Update trie.go --------- Co-authored-by: rjl493456442 --- trie/trie.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/trie/trie.go b/trie/trie.go index 935f81fc7d..e1a9201108 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -53,7 +53,6 @@ type Trie struct { reader *trieReader // tracer is the tool to track the trie changes. - // It will be reset after each commit operation. tracer *tracer } @@ -609,7 +608,6 @@ func (t *Trie) Hash() common.Hash { // Once the trie is committed, it's not usable anymore. A new trie must // be created with new root and updated trie database for following usage func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { - defer t.tracer.reset() defer func() { t.committed = true }() From c11aac249ddca275a12a1da0e66d1f4c6c21f4f6 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Wed, 19 Jun 2024 17:06:52 +0800 Subject: [PATCH 094/196] common: using `ParseUint` instead of `ParseInt` (#30020) Since Decimal is defined as unsiged `uint64`, we should use `strconv.ParseUint` instead of `strconv.ParseInt` during unmarshalling. --------- Co-authored-by: Martin Holst Swende --- common/types.go | 2 +- common/types_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/common/types.go b/common/types.go index b914787d13..fdb25f1b34 100644 --- a/common/types.go +++ b/common/types.go @@ -468,7 +468,7 @@ func (d *Decimal) UnmarshalJSON(input []byte) error { if !isString(input) { return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))} } - if i, err := strconv.ParseInt(string(input[1:len(input)-1]), 10, 64); err == nil { + if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil { *d = Decimal(i) return nil } else { diff --git a/common/types_test.go b/common/types_test.go index cec689ea39..11247b117b 100644 --- a/common/types_test.go +++ b/common/types_test.go @@ -21,6 +21,7 @@ import ( "database/sql/driver" "encoding/json" "fmt" + "math" "math/big" "reflect" "strings" @@ -595,3 +596,29 @@ func BenchmarkPrettyDuration(b *testing.B) { } b.Logf("Post %s", a) } + +func TestDecimalUnmarshalJSON(t *testing.T) { + // These should error + for _, tc := range []string{``, `"`, `""`, `"-1"`} { + if err := new(Decimal).UnmarshalJSON([]byte(tc)); err == nil { + t.Errorf("input %s should cause error", tc) + } + } + // These should succeed + for _, tc := range []struct { + input string + want uint64 + }{ + {`"0"`, 0}, + {`"9223372036854775807"`, math.MaxInt64}, + {`"18446744073709551615"`, math.MaxUint64}, + } { + have := new(Decimal) + if err := have.UnmarshalJSON([]byte(tc.input)); err != nil { + t.Errorf("input %q triggered error: %v", tc.input, err) + } + if uint64(*have) != tc.want { + t.Errorf("input %q, have %d want %d", tc.input, *have, tc.want) + } + } +} From 27008408a57c77e55d3630adb50c72b0a36abb32 Mon Sep 17 00:00:00 2001 From: psogv0308 Date: Wed, 19 Jun 2024 21:46:57 +0900 Subject: [PATCH 095/196] core/txpool/blobpool: change rw-lock to r-lock (#29989) --- core/txpool/blobpool/blobpool.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index f1c2c10fc9..69423731ee 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1598,8 +1598,8 @@ func (p *BlobPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool // Nonce returns the next nonce of an account, with all transactions executable // by the pool already applied on top. func (p *BlobPool) Nonce(addr common.Address) uint64 { - p.lock.Lock() - defer p.lock.Unlock() + p.lock.RLock() + defer p.lock.RUnlock() if txs, ok := p.index[addr]; ok { return txs[len(txs)-1].nonce + 1 @@ -1610,8 +1610,8 @@ func (p *BlobPool) Nonce(addr common.Address) uint64 { // Stats retrieves the current pool stats, namely the number of pending and the // number of queued (non-executable) transactions. func (p *BlobPool) Stats() (int, int) { - p.lock.Lock() - defer p.lock.Unlock() + p.lock.RLock() + defer p.lock.RUnlock() var pending int for _, txs := range p.index { From 00675c5876d84bffd44f3b18db9db7892fa3f87e Mon Sep 17 00:00:00 2001 From: maskpp Date: Thu, 20 Jun 2024 11:47:29 +0800 Subject: [PATCH 096/196] trie/trienode: avoid unnecessary copy (#30019) * avoid unnecessary copy * delete the never used function ProofList * eth/protocols/snap, trie/trienode: polish the code --------- Co-authored-by: Gary Rong --- eth/protocols/snap/handler.go | 10 ++-------- eth/protocols/snap/sync_test.go | 23 ++++++----------------- trie/trienode/proof.go | 10 +++++----- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index bd7ce9e715..5cbe9d1270 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -332,11 +332,7 @@ func ServiceGetAccountRangeQuery(chain *core.BlockChain, req *GetAccountRangePac return nil, nil } } - var proofs [][]byte - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } - return accounts, proofs + return accounts, proof.List() } func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesPacket) ([][]*StorageData, [][]byte) { @@ -438,9 +434,7 @@ func ServiceGetStorageRangesQuery(chain *core.BlockChain, req *GetStorageRangesP return nil, nil } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } + proofs = append(proofs, proof.List()...) // Proof terminates the reply as proofs are only added if a node // refuses to serve more data (exception when a contract fetch is // finishing, but that's that). diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 82360ae0e3..c97c3b99b3 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -286,10 +286,7 @@ func createAccountRequestResponse(t *testPeer, root common.Hash, origin common.H t.logger.Error("Could not prove last item", "error", err) } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } - return keys, vals, proofs + return keys, vals, proof.List() } // defaultStorageRequestHandler is a well-behaving storage request handler @@ -371,9 +368,7 @@ func createStorageRequestResponse(t *testPeer, root common.Hash, accounts []comm t.logger.Error("Could not prove last item", "error", err) } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } + proofs = append(proofs, proof.List()...) break } } @@ -430,9 +425,7 @@ func createStorageRequestResponseAlwaysProve(t *testPeer, root common.Hash, acco t.logger.Error("Could not prove last item", "error", err) } } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } + proofs = append(proofs, proof.List()...) break } } @@ -586,9 +579,8 @@ func testSyncBloatedProof(t *testing.T, scheme string) { source.accountRequestHandler = func(t *testPeer, requestId uint64, root common.Hash, origin common.Hash, limit common.Hash, cap uint64) error { var ( - proofs [][]byte - keys []common.Hash - vals [][]byte + keys []common.Hash + vals [][]byte ) // The values for _, entry := range t.accountValues { @@ -618,10 +610,7 @@ func testSyncBloatedProof(t *testing.T, scheme string) { keys = append(keys[:1], keys[2:]...) vals = append(vals[:1], vals[2:]...) } - for _, blob := range proof.List() { - proofs = append(proofs, blob) - } - if err := t.remote.OnAccounts(t, requestId, keys, vals, proofs); err != nil { + if err := t.remote.OnAccounts(t, requestId, keys, vals, proof.List()); err != nil { t.logger.Info("remote error on delivery (as expected)", "error", err) t.term() // This is actually correct, signal to exit the test successfully diff --git a/trie/trienode/proof.go b/trie/trienode/proof.go index 012f0087dd..d3075ecccf 100644 --- a/trie/trienode/proof.go +++ b/trie/trienode/proof.go @@ -102,14 +102,14 @@ func (db *ProofSet) DataSize() int { return db.dataSize } -// List converts the node set to a ProofList -func (db *ProofSet) List() ProofList { +// List converts the node set to a slice of bytes. +func (db *ProofSet) List() [][]byte { db.lock.RLock() defer db.lock.RUnlock() - var values ProofList - for _, key := range db.order { - values = append(values, db.nodes[key]) + values := make([][]byte, len(db.order)) + for i, key := range db.order { + values[i] = db.nodes[key] } return values } From 27654d30228f9de2c15e351948103ae619364f36 Mon Sep 17 00:00:00 2001 From: David Theodore <29786815+infosecual@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:08:54 -0500 Subject: [PATCH 097/196] p2p/rlpx: 2KB maximum size for handshake messages (#30029) Co-authored-by: Felix Lange --- p2p/rlpx/rlpx.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/p2p/rlpx/rlpx.go b/p2p/rlpx/rlpx.go index a338490e62..dd14822dee 100644 --- a/p2p/rlpx/rlpx.go +++ b/p2p/rlpx/rlpx.go @@ -604,6 +604,11 @@ func (h *handshakeState) readMsg(msg interface{}, prv *ecdsa.PrivateKey, r io.Re } size := binary.BigEndian.Uint16(prefix) + // baseProtocolMaxMsgSize = 2 * 1024 + if size > 2048 { + return nil, errors.New("message too big") + } + // Read the handshake packet. packet, err := h.rbuf.read(r, int(size)) if err != nil { From e0e45dbc32501d7917edb07083aa1c34ab7b0fb4 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 21 Jun 2024 09:51:03 +0800 Subject: [PATCH 098/196] core/state/snapshot: tiny fixes (#29995) --- core/state/snapshot/generate.go | 9 +-------- core/state/snapshot/snapshot.go | 10 ++-------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index d81a628c91..6d9e163075 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -631,16 +631,10 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er accMarker = nil return nil } - // Always reset the initial account range as 1 whenever recover from the - // interruption. TODO(rjl493456442) can we remove it? - var accountRange = accountCheckRange - if len(accMarker) > 0 { - accountRange = 1 - } origin := common.CopyBytes(accMarker) for { id := trie.StateTrieID(dl.root) - exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP) + exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -652,7 +646,6 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er ctx.removeStorageLeft() break } - accountRange = accountCheckRange } return nil } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 752f4359fb..e319c8e4e0 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -258,14 +258,6 @@ func (t *Tree) Disable() { for _, layer := range t.layers { switch layer := layer.(type) { case *diskLayer: - - layer.lock.RLock() - generating := layer.genMarker != nil - layer.lock.RUnlock() - if !generating { - // Generator is already aborted or finished - break - } // If the base layer is generating, abort it if layer.genAbort != nil { abort := make(chan *generatorStats) @@ -276,6 +268,7 @@ func (t *Tree) Disable() { layer.lock.Lock() layer.stale = true layer.lock.Unlock() + layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale @@ -740,6 +733,7 @@ func (t *Tree) Rebuild(root common.Hash) { layer.lock.Lock() layer.stale = true layer.lock.Unlock() + layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale From c10ac4f48fb9c985390be0f46115aaa40a4ef16d Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 21 Jun 2024 15:42:43 +0800 Subject: [PATCH 099/196] Revert "core/state/snapshot: tiny fixes" (#30039) Revert "core/state/snapshot: tiny fixes (#29995)" This reverts commit e0e45dbc32501d7917edb07083aa1c34ab7b0fb4. --- core/state/snapshot/generate.go | 9 ++++++++- core/state/snapshot/snapshot.go | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/core/state/snapshot/generate.go b/core/state/snapshot/generate.go index 6d9e163075..d81a628c91 100644 --- a/core/state/snapshot/generate.go +++ b/core/state/snapshot/generate.go @@ -631,10 +631,16 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er accMarker = nil return nil } + // Always reset the initial account range as 1 whenever recover from the + // interruption. TODO(rjl493456442) can we remove it? + var accountRange = accountCheckRange + if len(accMarker) > 0 { + accountRange = 1 + } origin := common.CopyBytes(accMarker) for { id := trie.StateTrieID(dl.root) - exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP) + exhausted, last, err := dl.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountRange, onAccount, types.FullAccountRLP) if err != nil { return err // The procedure it aborted, either by external signal or internal error. } @@ -646,6 +652,7 @@ func generateAccounts(ctx *generatorContext, dl *diskLayer, accMarker []byte) er ctx.removeStorageLeft() break } + accountRange = accountCheckRange } return nil } diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index e319c8e4e0..752f4359fb 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -258,6 +258,14 @@ func (t *Tree) Disable() { for _, layer := range t.layers { switch layer := layer.(type) { case *diskLayer: + + layer.lock.RLock() + generating := layer.genMarker != nil + layer.lock.RUnlock() + if !generating { + // Generator is already aborted or finished + break + } // If the base layer is generating, abort it if layer.genAbort != nil { abort := make(chan *generatorStats) @@ -268,7 +276,6 @@ func (t *Tree) Disable() { layer.lock.Lock() layer.stale = true layer.lock.Unlock() - layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale @@ -733,7 +740,6 @@ func (t *Tree) Rebuild(root common.Hash) { layer.lock.Lock() layer.stale = true layer.lock.Unlock() - layer.Release() case *diffLayer: // If the layer is a simple diff, simply mark as stale From a71f6f91fdb2fcccdd0c1e336267951d45932f26 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Fri, 21 Jun 2024 21:29:07 +0800 Subject: [PATCH 100/196] p2p/discover: improve flaky revalidation tests (#30023) --- p2p/discover/table_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/discover/table_test.go b/p2p/discover/table_test.go index 2f1797d1e2..8cc4ae33b2 100644 --- a/p2p/discover/table_test.go +++ b/p2p/discover/table_test.go @@ -135,7 +135,7 @@ func waitForRevalidationPing(t *testing.T, transport *pingRecorder, tab *Table, simclock.Run(tab.cfg.PingInterval * slowRevalidationFactor) p := transport.waitPing(2 * time.Second) if p == nil { - t.Fatal("Table did not send revalidation ping") + continue } if id == (enode.ID{}) || p.ID() == id { return p From d8ea7ac2b056f94ed77e18493d5d17f90f1c7747 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 25 Jun 2024 03:14:12 -0600 Subject: [PATCH 101/196] cmd/blsync: use debug.Setup for logging configuration (#30065) --- cmd/blsync/main.go | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/cmd/blsync/main.go b/cmd/blsync/main.go index 2aa3d9a24e..854c99703c 100644 --- a/cmd/blsync/main.go +++ b/cmd/blsync/main.go @@ -19,39 +19,21 @@ package main import ( "context" "fmt" - "io" "os" "github.com/ethereum/go-ethereum/beacon/blsync" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rpc" - "github.com/mattn/go-colorable" - "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" ) -var ( - verbosityFlag = &cli.IntFlag{ - Name: "verbosity", - Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail", - Value: 3, - Category: flags.LoggingCategory, - } - vmoduleFlag = &cli.StringFlag{ - Name: "vmodule", - Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", - Value: "", - Hidden: true, - Category: flags.LoggingCategory, - } -) - func main() { app := flags.NewApp("beacon light syncer tool") - app.Flags = []cli.Flag{ + app.Flags = flags.Merge([]cli.Flag{ utils.BeaconApiFlag, utils.BeaconApiHeaderFlag, utils.BeaconThresholdFlag, @@ -66,8 +48,16 @@ func main() { utils.GoerliFlag, utils.BlsyncApiFlag, utils.BlsyncJWTSecretFlag, - verbosityFlag, - vmoduleFlag, + }, + debug.Flags, + ) + app.Before = func(ctx *cli.Context) error { + flags.MigrateGlobalFlags(ctx) + return debug.Setup(ctx) + } + app.After = func(ctx *cli.Context) error { + debug.Exit() + return nil } app.Action = sync @@ -78,14 +68,6 @@ func main() { } func sync(ctx *cli.Context) error { - usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" - output := io.Writer(os.Stderr) - if usecolor { - output = colorable.NewColorable(os.Stderr) - } - verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name)) - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor))) - // set up blsync client := blsync.NewClient(ctx) client.SetEngineRPC(makeRPCClient(ctx)) From 0a651f8972392943b22120d2444adcfe8a480d14 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 25 Jun 2024 03:16:27 -0600 Subject: [PATCH 102/196] .github: add lightclient as codeowner to relevant packages (#30062) --- .github/CODEOWNERS | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0dabaf4df5..ec2efb10e3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,14 +4,18 @@ accounts/usbwallet @karalabe accounts/scwallet @gballet accounts/abi @gballet @MariusVanDerWijden +beacon/engine @lightclient cmd/clef @holiman +cmd/evm @holiman @MariusVanDerWijden @lightclient consensus @karalabe core/ @karalabe @holiman @rjl493456442 eth/ @karalabe @holiman @rjl493456442 -eth/catalyst/ @gballet +eth/catalyst/ @gballet @lightclient eth/tracers/ @s1na core/tracing/ @s1na graphql/ @s1na +internal/ethapi @lightclient +internal/era @lightclient les/ @zsfelfoldi @rjl493456442 light/ @zsfelfoldi @rjl493456442 node/ @fjl From fe0c0b04fee6d7fbaad77540ceaed4df84939ba7 Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Tue, 25 Jun 2024 17:24:33 +0800 Subject: [PATCH 103/196] accounts/keystore: use t.TempDir in test (#30052) --- accounts/keystore/account_cache_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 6bc14f5bb6..41a3002248 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -325,11 +325,7 @@ func TestUpdatedKeyfileContents(t *testing.T) { t.Parallel() // Create a temporary keystore to test with - dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int())) - - // Create the directory - os.MkdirAll(dir, 0700) - defer os.RemoveAll(dir) + dir := t.TempDir() ks := NewKeyStore(dir, LightScryptN, LightScryptP) From 73f7e7c0878b61eceb11923187a34660a7218f47 Mon Sep 17 00:00:00 2001 From: AMIR <31338382+amiremohamadi@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:00:58 +0330 Subject: [PATCH 104/196] internal/debug: remove unnecessary log level assignment (#30044) Log level is specified in L259 so it's unnecessary to specify it for handlers (L234, L236). --- internal/debug/flags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 361dc6fcca..19222c8325 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -231,9 +231,9 @@ func Setup(ctx *cli.Context) error { case ctx.Bool(logjsonFlag.Name): // Retain backwards compatibility with `--log.json` flag if `--log.format` not set defer log.Warn("The flag '--log.json' is deprecated, please use '--log.format=json' instead") - handler = log.JSONHandlerWithLevel(output, log.LevelInfo) + handler = log.JSONHandler(output) case logFmtFlag == "json": - handler = log.JSONHandlerWithLevel(output, log.LevelInfo) + handler = log.JSONHandler(output) case logFmtFlag == "logfmt": handler = log.LogfmtHandler(output) case logFmtFlag == "", logFmtFlag == "terminal": From ed8fd0ac0919ee954cfa621d16a5d0cfbf30c96d Mon Sep 17 00:00:00 2001 From: jwasinger Date: Tue, 25 Jun 2024 04:48:08 -0700 Subject: [PATCH 105/196] all: stateless witness builder and (self-)cross validator (#29719) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * all: add stateless verifications * all: simplify witness and integrate it into live geth --------- Co-authored-by: Péter Szilágyi --- cmd/evm/blockrunner.go | 2 +- core/block_validator.go | 37 ++++++- core/blockchain.go | 33 ++++-- core/blockchain_test.go | 3 +- core/state/database.go | 4 + core/state/state_object.go | 16 ++- core/state/statedb.go | 85 +++++++++++++-- core/state_prefetcher.go | 11 +- core/state_processor.go | 16 ++- core/stateless.go | 73 +++++++++++++ core/stateless/database.go | 60 +++++++++++ core/stateless/encoding.go | 129 ++++++++++++++++++++++ core/stateless/gen_encoding_json.go | 74 +++++++++++++ core/stateless/witness.go | 159 ++++++++++++++++++++++++++++ core/types.go | 7 +- core/vm/evm.go | 12 +++ core/vm/instructions.go | 16 ++- core/vm/interface.go | 3 + tests/block_test.go | 52 ++++----- tests/block_test_util.go | 5 +- trie/secure_trie.go | 5 + trie/trie.go | 12 +++ trie/verkle.go | 5 + 23 files changed, 738 insertions(+), 81 deletions(-) create mode 100644 core/stateless.go create mode 100644 core/stateless/database.go create mode 100644 core/stateless/encoding.go create mode 100644 core/stateless/gen_encoding_json.go create mode 100644 core/stateless/witness.go diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go index 0275c019bc..d5cd8d8e3d 100644 --- a/cmd/evm/blockrunner.go +++ b/cmd/evm/blockrunner.go @@ -86,7 +86,7 @@ func blockTestCmd(ctx *cli.Context) error { continue } test := tests[name] - if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) { + if err := test.Run(false, rawdb.HashScheme, false, tracer, func(res error, chain *core.BlockChain) { if ctx.Bool(DumpFlag.Name) { if state, _ := chain.State(); state != nil { fmt.Println(string(state.Dump(nil))) diff --git a/core/block_validator.go b/core/block_validator.go index 3d49f4e6a3..75f7f8a94b 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -20,8 +20,10 @@ import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" @@ -34,14 +36,12 @@ import ( type BlockValidator struct { config *params.ChainConfig // Chain configuration options bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for validating } // NewBlockValidator returns a new block validator which is safe for re-use -func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator { +func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *BlockValidator { validator := &BlockValidator{ config: config, - engine: engine, bc: blockchain, } return validator @@ -59,7 +59,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // Header validity is known at this point. Here we verify that uncles, transactions // and withdrawals given in the block body match the header. header := block.Header() - if err := v.engine.VerifyUncles(v.bc, block); err != nil { + if err := v.bc.engine.VerifyUncles(v.bc, block); err != nil { return err } if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash { @@ -121,7 +121,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // ValidateState validates the various changes that happen after a state transition, // such as amount of used gas, the receipt roots and the state root itself. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) @@ -132,6 +132,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if rbloom != header.Bloom { return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) } + // In stateless mode, return early because the receipt and state root are not + // provided through the witness, rather the cross validator needs to return it. + if stateless { + return nil + } // The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]])) receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) if receiptSha != header.ReceiptHash { @@ -145,6 +150,28 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil } +// ValidateWitness cross validates a block execution with stateless remote clients. +// +// Normally we'd distribute the block witness to remote cross validators, wait +// for them to respond and then merge the results. For now, however, it's only +// Geth, so do an internal stateless run. +func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error { + // Run the cross client stateless execution + // TODO(karalabe): Self-stateless for now, swap with other clients + crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness) + if err != nil { + return fmt.Errorf("stateless execution failed: %v", err) + } + // Stateless cross execution suceeeded, validate the withheld computed fields + if crossReceiptRoot != receiptRoot { + return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot) + } + if crossStateRoot != stateRoot { + return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot) + } + return nil +} + // CalcGasLimit computes the gas limit of the next block after parent. It aims // to keep the baseline gas close to the provided target, and increase it towards // the target if the baseline gas is lower. diff --git a/core/blockchain.go b/core/blockchain.go index ac4eb1c47e..05ebfd18b8 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -302,18 +303,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis vmConfig: vmConfig, logger: vmConfig.Tracer, } - bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) - bc.forker = NewForkChoice(bc, shouldPreserve) - bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) - bc.validator = NewBlockValidator(chainConfig, bc, engine) - bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) - bc.processor = NewStateProcessor(chainConfig, bc, engine) - var err error bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped) if err != nil { return nil, err } + bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit)) + bc.forker = NewForkChoice(bc, shouldPreserve) + bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb) + bc.validator = NewBlockValidator(chainConfig, bc) + bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc) + bc.processor = NewStateProcessor(chainConfig, bc.hc) + bc.genesisBlock = bc.GetBlockByNumber(0) if bc.genesisBlock == nil { return nil, ErrNoGenesis @@ -1809,7 +1810,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error) // while processing transactions. Before Byzantium the prefetcher is mostly // useless due to the intermediate root hashing after each transaction. if bc.chainConfig.IsByzantium(block.Number()) { - statedb.StartPrefetcher("chain", !bc.vmConfig.EnableWitnessCollection) + var witness *stateless.Witness + if bc.vmConfig.EnableWitnessCollection { + witness, err = stateless.NewWitness(bc, block) + if err != nil { + return it.index, err + } + } + statedb.StartPrefetcher("chain", witness) } activeState = statedb @@ -1924,11 +1932,18 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s ptime := time.Since(pstart) vstart := time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { bc.reportBlock(block, receipts, err) return nil, err } vtime := time.Since(vstart) + + if witness := statedb.Witness(); witness != nil { + if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil { + bc.reportBlock(block, receipts, err) + return nil, fmt.Errorf("cross verification failed: %v", err) + } + } proctime := time.Since(start) // processing + validation // Update the metrics touched during block processing and validation diff --git a/core/blockchain_test.go b/core/blockchain_test.go index e4bc3e09a6..4f28c6f5e6 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -168,8 +168,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) - if err != nil { + if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil { blockchain.reportBlock(block, receipts, err) return err } diff --git a/core/state/database.go b/core/state/database.go index d71f8f34b6..d54417d2f9 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -125,6 +125,10 @@ type Trie interface { // be created with new root and updated trie database for following usage Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) + // Witness returns a set containing all trie nodes that have been accessed. + // The returned map could be nil if the witness is empty. + Witness() map[string]struct{} + // NodeIterator returns an iterator that returns nodes of the trie. Iteration // starts at the key after the given start key. And error will be returned // if fails to create node iterator. diff --git a/core/state/state_object.go b/core/state/state_object.go index 5c1dab53dc..880b715b4b 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -323,11 +323,17 @@ func (s *stateObject) finalise() { // // It assumes all the dirty storage slots have been finalized before. func (s *stateObject) updateTrie() (Trie, error) { - // Short circuit if nothing changed, don't bother with hashing anything + // Short circuit if nothing was accessed, don't trigger a prefetcher warning if len(s.uncommittedStorage) == 0 { - return s.trie, nil + // Nothing was written, so we could stop early. Unless we have both reads + // and witness collection enabled, in which case we need to fetch the trie. + if s.db.witness == nil || len(s.originStorage) == 0 { + return s.trie, nil + } } - // Retrieve a pretecher populated trie, or fall back to the database + // Retrieve a pretecher populated trie, or fall back to the database. This will + // block until all prefetch tasks are done, which are needed for witnesses even + // for unmodified state objects. tr := s.getPrefetchedTrie() if tr != nil { // Prefetcher returned a live trie, swap it out for the current one @@ -341,6 +347,10 @@ func (s *stateObject) updateTrie() (Trie, error) { return nil, err } } + // Short circuit if nothing changed, don't bother with hashing anything + if len(s.uncommittedStorage) == 0 { + return s.trie, nil + } // Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes // in circumstances similar to the following: // diff --git a/core/state/statedb.go b/core/state/statedb.go index 4f84d93d63..ac82a8e3e3 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -105,7 +106,7 @@ type StateDB struct { // resurrection. The account value is tracked as the original value // before the transition. This map is populated at the transaction // boundaries. - stateObjectsDestruct map[common.Address]*types.StateAccount + stateObjectsDestruct map[common.Address]*stateObject // This map tracks the account mutations that occurred during the // transition. Uncommitted mutations belonging to the same account @@ -146,6 +147,9 @@ type StateDB struct { validRevisions []revision nextRevisionId int + // State witness if cross validation is needed + witness *stateless.Witness + // Measurements gathered during execution for debugging purposes AccountReads time.Duration AccountHashes time.Duration @@ -177,7 +181,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) originalRoot: root, snaps: snaps, stateObjects: make(map[common.Address]*stateObject), - stateObjectsDestruct: make(map[common.Address]*types.StateAccount), + stateObjectsDestruct: make(map[common.Address]*stateObject), mutations: make(map[common.Address]*mutation), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), @@ -200,14 +204,19 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) { // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. -func (s *StateDB) StartPrefetcher(namespace string, noreads bool) { +func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) { + // Terminate any previously running prefetcher if s.prefetcher != nil { s.prefetcher.terminate(false) s.prefetcher.report() s.prefetcher = nil } + // Enable witness collection if requested + s.witness = witness + + // If snapshots are enabled, start prefethers explicitly if s.snap != nil { - s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, noreads) + s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, witness == nil) // With the switch to the Proof-of-Stake consensus algorithm, block production // rewards are now handled at the consensus layer. Consequently, a block may @@ -582,7 +591,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject { start := time.Now() acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())) s.SnapshotAccountReads += time.Since(start) - if err == nil { if acc == nil { return nil @@ -683,7 +691,7 @@ func (s *StateDB) Copy() *StateDB { hasher: crypto.NewKeccakState(), originalRoot: s.originalRoot, stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)), - stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct), + stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)), mutations: make(map[common.Address]*mutation, len(s.mutations)), dbErr: s.dbErr, refund: s.refund, @@ -703,10 +711,17 @@ func (s *StateDB) Copy() *StateDB { snaps: s.snaps, snap: s.snap, } + if s.witness != nil { + state.witness = s.witness.Copy() + } // Deep copy cached state objects. for addr, obj := range s.stateObjects { state.stateObjects[addr] = obj.deepCopy(state) } + // Deep copy destructed state objects. + for addr, obj := range s.stateObjectsDestruct { + state.stateObjectsDestruct[addr] = obj.deepCopy(state) + } // Deep copy the object state markers. for addr, op := range s.mutations { state.mutations[addr] = op.copy() @@ -788,7 +803,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // set indefinitely). Note only the first occurred self-destruct // event is tracked. if _, ok := s.stateObjectsDestruct[obj.address]; !ok { - s.stateObjectsDestruct[obj.address] = obj.origin + s.stateObjectsDestruct[obj.address] = obj } } else { obj.finalise() @@ -846,9 +861,46 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { obj := s.stateObjects[addr] // closure for the task runner below workers.Go(func() error { obj.updateRoot() + + // If witness building is enabled and the state object has a trie, + // gather the witnesses for its specific storage trie + if s.witness != nil && obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } return nil }) } + // If witness building is enabled, gather all the read-only accesses + if s.witness != nil { + // Pull in anything that has been accessed before destruction + for _, obj := range s.stateObjectsDestruct { + // Skip any objects that haven't touched their storage + if len(obj.originStorage) == 0 { + continue + } + if trie := obj.getPrefetchedTrie(); trie != nil { + s.witness.AddState(trie.Witness()) + } else if obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } + } + // Pull in only-read and non-destructed trie witnesses + for _, obj := range s.stateObjects { + // Skip any objects that have been updated + if _, ok := s.mutations[obj.address]; ok { + continue + } + // Skip any objects that haven't touched their storage + if len(obj.originStorage) == 0 { + continue + } + if trie := obj.getPrefetchedTrie(); trie != nil { + s.witness.AddState(trie.Witness()) + } else if obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } + } + } workers.Wait() s.StorageUpdates += time.Since(start) @@ -904,7 +956,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { // Track the amount of time wasted on hashing the account trie defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now()) - return s.trie.Hash() + hash := s.trie.Hash() + + // If witness building is enabled, gather the account trie witness + if s.witness != nil { + s.witness.AddState(s.trie.Witness()) + } + return hash } // SetTxContext sets the current transaction hash and index which are @@ -1060,7 +1118,9 @@ func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trieno buf = crypto.NewKeccakState() deletes = make(map[common.Hash]*accountDelete) ) - for addr, prev := range s.stateObjectsDestruct { + for addr, prevObj := range s.stateObjectsDestruct { + prev := prevObj.origin + // The account was non-existent, and it's marked as destructed in the scope // of block. It can be either case (a) or (b) and will be interpreted as // null->null state transition. @@ -1239,7 +1299,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // Clear all internal flags and update state root at the end. s.mutations = make(map[common.Address]*mutation) - s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount) + s.stateObjectsDestruct = make(map[common.Address]*stateObject) origin := s.originalRoot s.originalRoot = root @@ -1412,3 +1472,8 @@ func (s *StateDB) markUpdate(addr common.Address) { func (s *StateDB) PointCache() *utils.PointCache { return s.db.PointCache() } + +// Witness retrieves the current state witness being collected. +func (s *StateDB) Witness() *stateless.Witness { + return s.witness +} diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index ff867309de..31405fa078 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -19,7 +19,6 @@ package core import ( "sync/atomic" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -31,16 +30,14 @@ import ( // data from disk before the main block processor start executing. type statePrefetcher struct { config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for block rewards + chain *HeaderChain // Canonical block chain } // newStatePrefetcher initialises a new statePrefetcher. -func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *statePrefetcher { +func newStatePrefetcher(config *params.ChainConfig, chain *HeaderChain) *statePrefetcher { return &statePrefetcher{ config: config, - bc: bc, - engine: engine, + chain: chain, } } @@ -51,7 +48,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) - blockContext = NewEVMBlockContext(header, p.bc, nil) + blockContext = NewEVMBlockContext(header, p.chain, nil) evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) signer = types.MakeSigner(p.config, header.Number, header.Time) ) diff --git a/core/state_processor.go b/core/state_processor.go index 7166ed8bd8..c21f644f98 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -22,7 +22,6 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -37,16 +36,14 @@ import ( // StateProcessor implements Processor. type StateProcessor struct { config *params.ChainConfig // Chain configuration options - bc *BlockChain // Canonical block chain - engine consensus.Engine // Consensus engine used for block rewards + chain *HeaderChain // Canonical header chain } // NewStateProcessor initialises a new StateProcessor. -func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { +func NewStateProcessor(config *params.ChainConfig, chain *HeaderChain) *StateProcessor { return &StateProcessor{ config: config, - bc: bc, - engine: engine, + chain: chain, } } @@ -73,10 +70,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg misc.ApplyDAOHardFork(statedb) } var ( - context = NewEVMBlockContext(header, p.bc, nil) - vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) + context vm.BlockContext signer = types.MakeSigner(p.config, header.Number, header.Time) ) + context = NewEVMBlockContext(header, p.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } @@ -101,7 +99,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, errors.New("withdrawals before shanghai") } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.engine.Finalize(p.bc, header, statedb, block.Body()) + p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) return receipts, allLogs, *usedGas, nil } diff --git a/core/stateless.go b/core/stateless.go new file mode 100644 index 0000000000..4c7e6f3102 --- /dev/null +++ b/core/stateless.go @@ -0,0 +1,73 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package core + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/lru" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" +) + +// ExecuteStateless runs a stateless execution based on a witness, verifies +// everything it can locally and returns the two computed fields that need the +// other side to explicitly check. +// +// This method is a bit of a sore thumb here, but: +// - It cannot be placed in core/stateless, because state.New prodces a circular dep +// - It cannot be placed outside of core, because it needs to construct a dud headerchain +// +// TODO(karalabe): Would be nice to resolve both issues above somehow and move it. +func ExecuteStateless(config *params.ChainConfig, witness *stateless.Witness) (common.Hash, common.Hash, error) { + // Create and populate the state database to serve as the stateless backend + memdb := witness.MakeHashDB() + + db, err := state.New(witness.Root(), state.NewDatabaseWithConfig(memdb, triedb.HashDefaults), nil) + if err != nil { + return common.Hash{}, common.Hash{}, err + } + // Create a blockchain that is idle, but can be used to access headers through + chain := &HeaderChain{ + config: config, + chainDb: memdb, + headerCache: lru.NewCache[common.Hash, *types.Header](256), + engine: beacon.New(ethash.NewFaker()), + } + processor := NewStateProcessor(config, chain) + validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block + + // Run the stateless blocks processing and self-validate certain fields + receipts, _, usedGas, err := processor.Process(witness.Block, db, vm.Config{}) + if err != nil { + return common.Hash{}, common.Hash{}, err + } + if err = validator.ValidateState(witness.Block, db, receipts, usedGas, true); err != nil { + return common.Hash{}, common.Hash{}, err + } + // Almost everything validated, but receipt and state root needs to be returned + receiptRoot := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + stateRoot := db.IntermediateRoot(config.IsEIP158(witness.Block.Number())) + + return receiptRoot, stateRoot, nil +} diff --git a/core/stateless/database.go b/core/stateless/database.go new file mode 100644 index 0000000000..135da62193 --- /dev/null +++ b/core/stateless/database.go @@ -0,0 +1,60 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package stateless + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" +) + +// MakeHashDB imports tries, codes and block hashes from a witness into a new +// hash-based memory db. We could eventually rewrite this into a pathdb, but +// simple is better for now. +func (w *Witness) MakeHashDB() ethdb.Database { + var ( + memdb = rawdb.NewMemoryDatabase() + hasher = crypto.NewKeccakState() + hash = make([]byte, 32) + ) + // Inject all the "block hashes" (i.e. headers) into the ephemeral database + for _, header := range w.Headers { + rawdb.WriteHeader(memdb, header) + } + // Inject all the bytecodes into the ephemeral database + for code := range w.Codes { + blob := []byte(code) + + hasher.Reset() + hasher.Write(blob) + hasher.Read(hash) + + rawdb.WriteCode(memdb, common.BytesToHash(hash), blob) + } + // Inject all the MPT trie nodes into the ephemeral database + for node := range w.State { + blob := []byte(node) + + hasher.Reset() + hasher.Write(blob) + hasher.Read(hash) + + rawdb.WriteLegacyTrieNode(memdb, common.BytesToHash(hash), blob) + } + return memdb +} diff --git a/core/stateless/encoding.go b/core/stateless/encoding.go new file mode 100644 index 0000000000..2b7245d377 --- /dev/null +++ b/core/stateless/encoding.go @@ -0,0 +1,129 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package stateless + +import ( + "bytes" + "errors" + "fmt" + "io" + "slices" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +//go:generate go run github.com/fjl/gencodec -type extWitness -field-override extWitnessMarshalling -out gen_encoding_json.go + +// toExtWitness converts our internal witness representation to the consensus one. +func (w *Witness) toExtWitness() *extWitness { + ext := &extWitness{ + Block: w.Block, + Headers: w.Headers, + } + ext.Codes = make([][]byte, 0, len(w.Codes)) + for code := range w.Codes { + ext.Codes = append(ext.Codes, []byte(code)) + } + slices.SortFunc(ext.Codes, bytes.Compare) + + ext.State = make([][]byte, 0, len(w.State)) + for node := range w.State { + ext.State = append(ext.State, []byte(node)) + } + slices.SortFunc(ext.State, bytes.Compare) + return ext +} + +// fromExtWitness converts the consensus witness format into our internal one. +func (w *Witness) fromExtWitness(ext *extWitness) error { + w.Block, w.Headers = ext.Block, ext.Headers + + w.Codes = make(map[string]struct{}, len(ext.Codes)) + for _, code := range ext.Codes { + w.Codes[string(code)] = struct{}{} + } + w.State = make(map[string]struct{}, len(ext.State)) + for _, node := range ext.State { + w.State[string(node)] = struct{}{} + } + return w.sanitize() +} + +// MarshalJSON marshals a witness as JSON. +func (w *Witness) MarshalJSON() ([]byte, error) { + return w.toExtWitness().MarshalJSON() +} + +// EncodeRLP serializes a witness as RLP. +func (w *Witness) EncodeRLP(wr io.Writer) error { + return rlp.Encode(wr, w.toExtWitness()) +} + +// UnmarshalJSON unmarshals from JSON. +func (w *Witness) UnmarshalJSON(input []byte) error { + var ext extWitness + if err := ext.UnmarshalJSON(input); err != nil { + return err + } + return w.fromExtWitness(&ext) +} + +// DecodeRLP decodes a witness from RLP. +func (w *Witness) DecodeRLP(s *rlp.Stream) error { + var ext extWitness + if err := s.Decode(&ext); err != nil { + return err + } + return w.fromExtWitness(&ext) +} + +// sanitize checks for some mandatory fields in the witness after decoding so +// the rest of the code can assume invariants and doesn't have to deal with +// corrupted data. +func (w *Witness) sanitize() error { + // Verify that the "parent" header (i.e. index 0) is available, and is the + // true parent of the block-to-be executed, since we use that to link the + // current block to the pre-state. + if len(w.Headers) == 0 { + return errors.New("parent header (for pre-root hash) missing") + } + for i, header := range w.Headers { + if header == nil { + return fmt.Errorf("witness header nil at position %d", i) + } + } + if w.Headers[0].Hash() != w.Block.ParentHash() { + return fmt.Errorf("parent hash different: witness %v, block parent %v", w.Headers[0].Hash(), w.Block.ParentHash()) + } + return nil +} + +// extWitness is a witness RLP encoding for transferring across clients. +type extWitness struct { + Block *types.Block `json:"block" gencodec:"required"` + Headers []*types.Header `json:"headers" gencodec:"required"` + Codes [][]byte `json:"codes"` + State [][]byte `json:"state"` +} + +// extWitnessMarshalling defines the hex marshalling types for a witness. +type extWitnessMarshalling struct { + Codes []hexutil.Bytes + State []hexutil.Bytes +} diff --git a/core/stateless/gen_encoding_json.go b/core/stateless/gen_encoding_json.go new file mode 100644 index 0000000000..1d0497976e --- /dev/null +++ b/core/stateless/gen_encoding_json.go @@ -0,0 +1,74 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package stateless + +import ( + "encoding/json" + "errors" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" +) + +var _ = (*extWitnessMarshalling)(nil) + +// MarshalJSON marshals as JSON. +func (e extWitness) MarshalJSON() ([]byte, error) { + type extWitness struct { + Block *types.Block `json:"block" gencodec:"required"` + Headers []*types.Header `json:"headers" gencodec:"required"` + Codes []hexutil.Bytes `json:"codes"` + State []hexutil.Bytes `json:"state"` + } + var enc extWitness + enc.Block = e.Block + enc.Headers = e.Headers + if e.Codes != nil { + enc.Codes = make([]hexutil.Bytes, len(e.Codes)) + for k, v := range e.Codes { + enc.Codes[k] = v + } + } + if e.State != nil { + enc.State = make([]hexutil.Bytes, len(e.State)) + for k, v := range e.State { + enc.State[k] = v + } + } + return json.Marshal(&enc) +} + +// UnmarshalJSON unmarshals from JSON. +func (e *extWitness) UnmarshalJSON(input []byte) error { + type extWitness struct { + Block *types.Block `json:"block" gencodec:"required"` + Headers []*types.Header `json:"headers" gencodec:"required"` + Codes []hexutil.Bytes `json:"codes"` + State []hexutil.Bytes `json:"state"` + } + var dec extWitness + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Block == nil { + return errors.New("missing required field 'block' for extWitness") + } + e.Block = dec.Block + if dec.Headers == nil { + return errors.New("missing required field 'headers' for extWitness") + } + e.Headers = dec.Headers + if dec.Codes != nil { + e.Codes = make([][]byte, len(dec.Codes)) + for k, v := range dec.Codes { + e.Codes[k] = v + } + } + if dec.State != nil { + e.State = make([][]byte, len(dec.State)) + for k, v := range dec.State { + e.State[k] = v + } + } + return nil +} diff --git a/core/stateless/witness.go b/core/stateless/witness.go new file mode 100644 index 0000000000..7622c5eb61 --- /dev/null +++ b/core/stateless/witness.go @@ -0,0 +1,159 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package stateless + +import ( + "bytes" + "errors" + "fmt" + "maps" + "slices" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +// HeaderReader is an interface to pull in headers in place of block hashes for +// the witness. +type HeaderReader interface { + // GetHeader retrieves a block header from the database by hash and number, + GetHeader(hash common.Hash, number uint64) *types.Header +} + +// Witness encompasses a block, state and any other chain data required to apply +// a set of transactions and derive a post state/receipt root. +type Witness struct { + Block *types.Block // Current block with rootHash and receiptHash zeroed out + Headers []*types.Header // Past headers in reverse order (0=parent, 1=parent's-parent, etc). First *must* be set. + Codes map[string]struct{} // Set of bytecodes ran or accessed + State map[string]struct{} // Set of MPT state trie nodes (account and storage together) + + chain HeaderReader // Chain reader to convert block hash ops to header proofs + lock sync.Mutex // Lock to allow concurrent state insertions +} + +// NewWitness creates an empty witness ready for population. +func NewWitness(chain HeaderReader, block *types.Block) (*Witness, error) { + // Zero out the result fields to avoid accidentally sending them to the verifier + header := block.Header() + header.Root = common.Hash{} + header.ReceiptHash = common.Hash{} + + // Retrieve the parent header, which will *always* be included to act as a + // trustless pre-root hash container + parent := chain.GetHeader(block.ParentHash(), block.NumberU64()-1) + if parent == nil { + return nil, errors.New("failed to retrieve parent header") + } + // Create the wtness with a reconstructed gutted out block + return &Witness{ + Block: types.NewBlockWithHeader(header).WithBody(*block.Body()), + Codes: make(map[string]struct{}), + State: make(map[string]struct{}), + Headers: []*types.Header{parent}, + chain: chain, + }, nil +} + +// AddBlockHash adds a "blockhash" to the witness with the designated offset from +// chain head. Under the hood, this method actually pulls in enough headers from +// the chain to cover the block being added. +func (w *Witness) AddBlockHash(number uint64) { + // Keep pulling in headers until this hash is populated + for int(w.Block.NumberU64()-number) > len(w.Headers) { + tail := w.Block.Header() + if len(w.Headers) > 0 { + tail = w.Headers[len(w.Headers)-1] + } + w.Headers = append(w.Headers, w.chain.GetHeader(tail.ParentHash, tail.Number.Uint64()-1)) + } +} + +// AddCode adds a bytecode blob to the witness. +func (w *Witness) AddCode(code []byte) { + if len(code) == 0 { + return + } + w.Codes[string(code)] = struct{}{} +} + +// AddState inserts a batch of MPT trie nodes into the witness. +func (w *Witness) AddState(nodes map[string]struct{}) { + if len(nodes) == 0 { + return + } + w.lock.Lock() + defer w.lock.Unlock() + + for node := range nodes { + w.State[node] = struct{}{} + } +} + +// Copy deep-copies the witness object. Witness.Block isn't deep-copied as it +// is never mutated by Witness +func (w *Witness) Copy() *Witness { + return &Witness{ + Block: w.Block, + Headers: slices.Clone(w.Headers), + Codes: maps.Clone(w.Codes), + State: maps.Clone(w.State), + } +} + +// String prints a human-readable summary containing the total size of the +// witness and the sizes of the underlying components +func (w *Witness) String() string { + blob, _ := rlp.EncodeToBytes(w) + bytesTotal := len(blob) + + blob, _ = rlp.EncodeToBytes(w.Block) + bytesBlock := len(blob) + + bytesHeaders := 0 + for _, header := range w.Headers { + blob, _ = rlp.EncodeToBytes(header) + bytesHeaders += len(blob) + } + bytesCodes := 0 + for code := range w.Codes { + bytesCodes += len(code) + } + bytesState := 0 + for node := range w.State { + bytesState += len(node) + } + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "Witness #%d: %v\n", w.Block.Number(), common.StorageSize(bytesTotal)) + fmt.Fprintf(buf, " block (%4d txs): %10v\n", len(w.Block.Transactions()), common.StorageSize(bytesBlock)) + fmt.Fprintf(buf, "%4d headers: %10v\n", len(w.Headers), common.StorageSize(bytesHeaders)) + fmt.Fprintf(buf, "%4d trie nodes: %10v\n", len(w.State), common.StorageSize(bytesState)) + fmt.Fprintf(buf, "%4d codes: %10v\n", len(w.Codes), common.StorageSize(bytesCodes)) + + return buf.String() +} + +// Root returns the pre-state root from the first header. +// +// Note, this method will panic in case of a bad witness (but RLP decoding will +// sanitize it and fail before that). +func (w *Witness) Root() common.Hash { + return w.Headers[0].Root +} diff --git a/core/types.go b/core/types.go index 36eb0d1ded..dc13de52ce 100644 --- a/core/types.go +++ b/core/types.go @@ -19,7 +19,9 @@ package core import ( "sync/atomic" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" ) @@ -33,7 +35,10 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error + + // ValidateWitness cross validates a block execution with stateless remote clients. + ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error } // Prefetcher is an interface for pre-caching transaction signatures and state. diff --git a/core/vm/evm.go b/core/vm/evm.go index 26af0ea041..1944189b5d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -231,6 +231,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. code := evm.StateDB.GetCode(addr) + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(code) + } if len(code) == 0 { ret, err = nil, nil // gas is unchanged } else { @@ -298,6 +301,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(caller.Address()), value, gas) + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(evm.StateDB.GetCode(addrCopy)) + } contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas @@ -345,6 +351,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by addrCopy := addr // Initialise a new contract and make initialise the delegate values contract := NewContract(caller, AccountRef(caller.Address()), nil, gas).AsDelegate() + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(evm.StateDB.GetCode(addrCopy)) + } contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) ret, err = evm.interpreter.Run(contract, input, false) gas = contract.Gas @@ -400,6 +409,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. contract := NewContract(caller, AccountRef(addrCopy), new(uint256.Int), gas) + if witness := evm.StateDB.Witness(); witness != nil { + witness.AddCode(evm.StateDB.GetCode(addrCopy)) + } contract.SetCallCode(&addrCopy, evm.StateDB.GetCodeHash(addrCopy), evm.StateDB.GetCode(addrCopy)) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 10cdd72e0c..9ec4544643 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -340,6 +340,10 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { slot := scope.Stack.peek() + address := slot.Bytes20() + if witness := interpreter.evm.StateDB.Witness(); witness != nil { + witness.AddCode(interpreter.evm.StateDB.GetCode(address)) + } slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(slot.Bytes20()))) return nil, nil } @@ -378,7 +382,11 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) uint64CodeOffset = math.MaxUint64 } addr := common.Address(a.Bytes20()) - codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64()) + code := interpreter.evm.StateDB.GetCode(addr) + if witness := interpreter.evm.StateDB.Witness(); witness != nil { + witness.AddCode(code) + } + codeCopy := getData(code, uint64CodeOffset, length.Uint64()) scope.Memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) return nil, nil @@ -443,7 +451,11 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( lower = upper - 256 } if num64 >= lower && num64 < upper { - num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) + res := interpreter.evm.Context.GetHash(num64) + if witness := interpreter.evm.StateDB.Witness(); witness != nil { + witness.AddBlockHash(num64) + } + num.SetBytes(res[:]) } else { num.Clear() } diff --git a/core/vm/interface.go b/core/vm/interface.go index 8b2c58898e..5f42643565 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -87,6 +88,8 @@ type StateDB interface { AddLog(*types.Log) AddPreimage(common.Hash, []byte) + + Witness() *stateless.Witness } // CallContext provides a basic interface for the EVM calling conventions. The EVM diff --git a/tests/block_test.go b/tests/block_test.go index 1ba84f5f24..52184eb274 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -26,11 +26,11 @@ import ( func TestBlockchain(t *testing.T) { bt := new(testMatcher) - // General state tests are 'exported' as blockchain tests, but we can run them natively. - // For speedier CI-runs, the line below can be uncommented, so those are skipped. - // For now, in hardfork-times (Berlin), we run the tests both as StateTests and - // as blockchain tests, since the latter also covers things like receipt root - bt.skipLoad(`^GeneralStateTests/`) + + // We are running most of GeneralStatetests to tests witness support, even + // though they are ran as state tests too. Still, the performance tests are + // less about state andmore about EVM number crunching, so skip those. + bt.skipLoad(`^GeneralStateTests/VMTests/vmPerformance`) // Skip random failures due to selfish mining test bt.skipLoad(`.*bcForgedTest/bcForkUncle\.json`) @@ -70,33 +70,25 @@ func TestExecutionSpecBlocktests(t *testing.T) { } func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { - // If -short flag is used, we don't execute all four permutations, only one. - executionMask := 0xf + // Define all the different flag combinations we should run the tests with, + // picking only one for short tests. + // + // Note, witness building and self-testing is always enabled as it's a very + // good test to ensure that we don't break it. + var ( + snapshotConf = []bool{false, true} + dbschemeConf = []string{rawdb.HashScheme, rawdb.PathScheme} + ) if testing.Short() { - executionMask = (1 << (rand.Int63() & 4)) + snapshotConf = []bool{snapshotConf[rand.Int()%2]} + dbschemeConf = []string{dbschemeConf[rand.Int()%2]} } - if executionMask&0x1 != 0 { - if err := bt.checkFailure(t, test.Run(false, rawdb.HashScheme, nil, nil)); err != nil { - t.Errorf("test in hash mode without snapshotter failed: %v", err) - return - } - } - if executionMask&0x2 != 0 { - if err := bt.checkFailure(t, test.Run(true, rawdb.HashScheme, nil, nil)); err != nil { - t.Errorf("test in hash mode with snapshotter failed: %v", err) - return - } - } - if executionMask&0x4 != 0 { - if err := bt.checkFailure(t, test.Run(false, rawdb.PathScheme, nil, nil)); err != nil { - t.Errorf("test in path mode without snapshotter failed: %v", err) - return - } - } - if executionMask&0x8 != 0 { - if err := bt.checkFailure(t, test.Run(true, rawdb.PathScheme, nil, nil)); err != nil { - t.Errorf("test in path mode with snapshotter failed: %v", err) - return + for _, snapshot := range snapshotConf { + for _, dbscheme := range dbschemeConf { + if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, nil, nil)); err != nil { + t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err) + return + } } } } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 04a04fdc28..62aa582c82 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -110,7 +110,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { +func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} @@ -151,7 +151,8 @@ func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, cache.SnapshotWait = true } chain, err := core.NewBlockChain(db, cache, gspec, nil, engine, vm.Config{ - Tracer: tracer, + Tracer: tracer, + EnableWitnessCollection: witness, }, nil, nil) if err != nil { return err diff --git a/trie/secure_trie.go b/trie/secure_trie.go index cfa7f0bddb..3572117e03 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -214,6 +214,11 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { return t.db.Preimage(common.BytesToHash(shaKey)) } +// Witness returns a set containing all trie nodes that have been accessed. +func (t *StateTrie) Witness() map[string]struct{} { + return t.trie.Witness() +} + // Commit collects all dirty nodes in the trie and replaces them with the // corresponding node hash. All collected nodes (including dirty leaves if // collectLeaf is true) will be encapsulated into a nodeset for return. diff --git a/trie/trie.go b/trie/trie.go index e1a9201108..f44e10b918 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -661,6 +661,18 @@ func (t *Trie) hashRoot() (node, node) { return hashed, cached } +// Witness returns a set containing all trie nodes that have been accessed. +func (t *Trie) Witness() map[string]struct{} { + if len(t.tracer.accessList) == 0 { + return nil + } + witness := make(map[string]struct{}) + for _, node := range t.tracer.accessList { + witness[string(node)] = struct{}{} + } + return witness +} + // Reset drops the referenced root node and cleans all internal state. func (t *Trie) Reset() { t.root = nil diff --git a/trie/verkle.go b/trie/verkle.go index 1ea23186f9..94a5ca9a2c 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -369,3 +369,8 @@ func (t *VerkleTrie) ToDot() string { func (t *VerkleTrie) nodeResolver(path []byte) ([]byte, error) { return t.reader.node(path, common.Hash{}) } + +// Witness returns a set containing all trie nodes that have been accessed. +func (t *VerkleTrie) Witness() map[string]struct{} { + panic("not implemented") +} From 98b5930d2d780fe13895633ffcc6b84c9beb4450 Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 25 Jun 2024 20:19:04 +0800 Subject: [PATCH 106/196] core/txpool/blobpool: avoid use *map as parameter. (#30048) --- core/txpool/blobpool/blobpool.go | 2 +- core/txpool/blobpool/evictheap.go | 12 ++++++------ core/txpool/blobpool/evictheap_test.go | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 69423731ee..2fca5c7b3e 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -407,7 +407,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres if p.head.ExcessBlobGas != nil { blobfee = uint256.MustFromBig(eip4844.CalcBlobFee(*p.head.ExcessBlobGas)) } - p.evict = newPriceHeap(basefee, blobfee, &p.index) + p.evict = newPriceHeap(basefee, blobfee, p.index) // Pool initialized, attach the blob limbo to it to track blobs included // recently but not yet finalized diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go index bc4543a352..701eb405cf 100644 --- a/core/txpool/blobpool/evictheap.go +++ b/core/txpool/blobpool/evictheap.go @@ -35,7 +35,7 @@ import ( // The goal of the heap is to decide which account has the worst bottleneck to // evict transactions from. type evictHeap struct { - metas *map[common.Address][]*blobTxMeta // Pointer to the blob pool's index for price retrievals + metas map[common.Address][]*blobTxMeta // Pointer to the blob pool's index for price retrievals basefeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the base fee blobfeeJumps float64 // Pre-calculated absolute dynamic fee jumps for the blob fee @@ -46,7 +46,7 @@ type evictHeap struct { // newPriceHeap creates a new heap of cheapest accounts in the blob pool to evict // from in case of over saturation. -func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index *map[common.Address][]*blobTxMeta) *evictHeap { +func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index map[common.Address][]*blobTxMeta) *evictHeap { heap := &evictHeap{ metas: index, index: make(map[common.Address]int), @@ -54,8 +54,8 @@ func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index *map[common. // Populate the heap in account sort order. Not really needed in practice, // but it makes the heap initialization deterministic and less annoying to // test in unit tests. - addrs := make([]common.Address, 0, len(*index)) - for addr := range *index { + addrs := make([]common.Address, 0, len(index)) + for addr := range index { addrs = append(addrs, addr) } sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i][:], addrs[j][:]) < 0 }) @@ -94,8 +94,8 @@ func (h *evictHeap) Len() int { // Less implements sort.Interface as part of heap.Interface, returning which of // the two requested accounts has a cheaper bottleneck. func (h *evictHeap) Less(i, j int) bool { - txsI := (*(h.metas))[h.addrs[i]] - txsJ := (*(h.metas))[h.addrs[j]] + txsI := h.metas[h.addrs[i]] + txsJ := h.metas[h.addrs[j]] lastI := txsI[len(txsI)-1] lastJ := txsJ[len(txsJ)-1] diff --git a/core/txpool/blobpool/evictheap_test.go b/core/txpool/blobpool/evictheap_test.go index 01b136551c..1cf577cb00 100644 --- a/core/txpool/blobpool/evictheap_test.go +++ b/core/txpool/blobpool/evictheap_test.go @@ -37,17 +37,17 @@ func verifyHeapInternals(t *testing.T, evict *evictHeap) { seen := make(map[common.Address]struct{}) for i, addr := range evict.addrs { seen[addr] = struct{}{} - if _, ok := (*evict.metas)[addr]; !ok { + if _, ok := evict.metas[addr]; !ok { t.Errorf("heap contains unexpected address at slot %d: %v", i, addr) } } - for addr := range *evict.metas { + for addr := range evict.metas { if _, ok := seen[addr]; !ok { t.Errorf("heap is missing required address %v", addr) } } - if len(evict.addrs) != len(*evict.metas) { - t.Errorf("heap size %d mismatches metadata size %d", len(evict.addrs), len(*evict.metas)) + if len(evict.addrs) != len(evict.metas) { + t.Errorf("heap size %d mismatches metadata size %d", len(evict.addrs), len(evict.metas)) } // Ensure that all accounts are present in the heap order index and no extras have := make([]common.Address, len(evict.index)) @@ -159,7 +159,7 @@ func TestPriceHeapSorting(t *testing.T) { }} } // Create a price heap and check the pop order - priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), &index) + priceheap := newPriceHeap(uint256.NewInt(tt.basefee), uint256.NewInt(tt.blobfee), index) verifyHeapInternals(t, priceheap) for j := 0; j < len(tt.order); j++ { @@ -218,7 +218,7 @@ func benchmarkPriceHeapReinit(b *testing.B, datacap uint64) { }} } // Create a price heap and reinit it over and over - heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index) + heap := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index) basefees := make([]*uint256.Int, b.N) blobfees := make([]*uint256.Int, b.N) @@ -278,7 +278,7 @@ func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) { }} } // Create a price heap and overflow it over and over - evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), &index) + evict := newPriceHeap(uint256.NewInt(rand.Uint64()), uint256.NewInt(rand.Uint64()), index) var ( addrs = make([]common.Address, b.N) metas = make([]*blobTxMeta, b.N) From 9298d2db884c4e3f9474880e3dcfd080ef9eacfa Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 25 Jun 2024 21:45:33 +0800 Subject: [PATCH 107/196] trie/trienode: remove unnecessary check in Summary (#30047) --- trie/trienode/node.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/trie/trienode/node.go b/trie/trienode/node.go index fa7bebe4f9..09f355f3b5 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -139,16 +139,14 @@ func (set *NodeSet) Size() (int, int) { func (set *NodeSet) Summary() string { var out = new(strings.Builder) fmt.Fprintf(out, "nodeset owner: %v\n", set.Owner) - if set.Nodes != nil { - for path, n := range set.Nodes { - // Deletion - if n.IsDeleted() { - fmt.Fprintf(out, " [-]: %x\n", path) - continue - } - // Insertion or update - fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash) + for path, n := range set.Nodes { + // Deletion + if n.IsDeleted() { + fmt.Fprintf(out, " [-]: %x\n", path) + continue } + // Insertion or update + fmt.Fprintf(out, " [+/*]: %x -> %v \n", path, n.Hash) } for _, n := range set.Leaves { fmt.Fprintf(out, "[leaf]: %v\n", n) From 269e80b07ed8b8300372c44ebb5d7ac2328bf84c Mon Sep 17 00:00:00 2001 From: Halimao <1065621723@qq.com> Date: Thu, 27 Jun 2024 17:29:50 +0800 Subject: [PATCH 108/196] eth/tracers,trie: remove unnecessary check (#30071) --- eth/tracers/live/supply.go | 10 ++++------ eth/tracers/native/call_flat.go | 16 +++++++--------- trie/verkle.go | 6 ++---- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index 936ffb9472..96f7059454 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -204,12 +204,10 @@ func (s *supply) internalTxsHandler(call *supplyTxCallstack) { s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn) } - if len(call.calls) > 0 { - // Recursively handle internal calls - for _, call := range call.calls { - callCopy := call - s.internalTxsHandler(&callCopy) - } + // Recursively handle internal calls + for _, call := range call.calls { + callCopy := call + s.internalTxsHandler(&callCopy) } } diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index ce0fb08114..a47b79f8df 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -274,16 +274,14 @@ func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx } output = append(output, *frame) - if len(input.Calls) > 0 { - for i, childCall := range input.Calls { - childAddr := childTraceAddress(traceAddress, i) - childCallCopy := childCall - flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx) - if err != nil { - return nil, err - } - output = append(output, flat...) + for i, childCall := range input.Calls { + childAddr := childTraceAddress(traceAddress, i) + childCallCopy := childCall + flat, err := flatFromNested(&childCallCopy, childAddr, convertErrs, ctx) + if err != nil { + return nil, err } + output = append(output, flat...) } return output, nil diff --git a/trie/verkle.go b/trie/verkle.go index 94a5ca9a2c..a457097e95 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -144,10 +144,8 @@ func (t *VerkleTrie) UpdateAccount(addr common.Address, acc *types.StateAccount) // Encode balance in little-endian bytes := acc.Balance.Bytes() - if len(bytes) > 0 { - for i, b := range bytes { - balance[len(bytes)-i-1] = b - } + for i, b := range bytes { + balance[len(bytes)-i-1] = b } values[utils.BalanceLeafKey] = balance[:] From 045b9718d512d24af71331cbe4d8e3e1a7afba12 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 27 Jun 2024 20:30:39 +0800 Subject: [PATCH 109/196] trie: relocate state execution logic into pathdb package (#29861) --- trie/secure_trie.go | 29 ++++- trie/trie_reader.go | 21 ---- trie/triestate/state.go | 212 +-------------------------------- triedb/database.go | 9 +- triedb/database/database.go | 16 +-- triedb/pathdb/database.go | 4 +- triedb/pathdb/database_test.go | 64 ++++++---- triedb/pathdb/disklayer.go | 4 +- triedb/pathdb/execute.go | 186 +++++++++++++++++++++++++++++ triedb/pathdb/testutils.go | 159 ------------------------- 10 files changed, 259 insertions(+), 445 deletions(-) create mode 100644 triedb/pathdb/execute.go delete mode 100644 triedb/pathdb/testutils.go diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 3572117e03..6eb6defa45 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -24,6 +24,16 @@ import ( "github.com/ethereum/go-ethereum/triedb/database" ) +// preimageStore wraps the methods of a backing store for reading and writing +// trie node preimages. +type preimageStore interface { + // Preimage retrieves the preimage of the specified hash. + Preimage(hash common.Hash) []byte + + // InsertPreimage commits a set of preimages along with their hashes. + InsertPreimage(preimages map[common.Hash][]byte) +} + // SecureTrie is the old name of StateTrie. // Deprecated: use StateTrie. type SecureTrie = StateTrie @@ -52,6 +62,7 @@ func NewSecure(stateRoot common.Hash, owner common.Hash, root common.Hash, db da type StateTrie struct { trie Trie db database.Database + preimages preimageStore hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte secKeyCacheOwner *StateTrie // Pointer to self, replace the key cache on mismatch @@ -70,7 +81,14 @@ func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) { if err != nil { return nil, err } - return &StateTrie{trie: *trie, db: db}, nil + tr := &StateTrie{trie: *trie, db: db} + + // link the preimage store if it's supported + preimages, ok := db.(preimageStore) + if ok { + tr.preimages = preimages + } + return tr, nil } // MustGet returns the value for key stored in the trie. @@ -211,7 +229,10 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { return key } - return t.db.Preimage(common.BytesToHash(shaKey)) + if t.preimages == nil { + return nil + } + return t.preimages.Preimage(common.BytesToHash(shaKey)) } // Witness returns a set containing all trie nodes that have been accessed. @@ -233,7 +254,9 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { for hk, key := range t.secKeyCache { preimages[common.BytesToHash([]byte(hk))] = key } - t.db.InsertPreimage(preimages) + if t.preimages != nil { + t.preimages.InsertPreimage(preimages) + } t.secKeyCache = make(map[string][]byte) } // Commit the trie and return its modified nodeset. diff --git a/trie/trie_reader.go b/trie/trie_reader.go index 42bc4316fe..adbf43d287 100644 --- a/trie/trie_reader.go +++ b/trie/trie_reader.go @@ -20,7 +20,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/triedb/database" ) @@ -72,23 +71,3 @@ func (r *trieReader) node(path []byte, hash common.Hash) ([]byte, error) { } return blob, nil } - -// MerkleLoader implements triestate.TrieLoader for constructing tries. -type MerkleLoader struct { - db database.Database -} - -// NewMerkleLoader creates the merkle trie loader. -func NewMerkleLoader(db database.Database) *MerkleLoader { - return &MerkleLoader{db: db} -} - -// OpenTrie opens the main account trie. -func (l *MerkleLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { - return New(TrieID(root), l.db) -} - -// OpenStorageTrie opens the storage trie of an account. -func (l *MerkleLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { - return New(StorageTrieID(stateRoot, addrHash, root), l.db) -} diff --git a/trie/triestate/state.go b/trie/triestate/state.go index 7508da5d60..62a9043873 100644 --- a/trie/triestate/state.go +++ b/trie/triestate/state.go @@ -16,43 +16,7 @@ package triestate -import ( - "errors" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/trie/trienode" -) - -// Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia -// tree or Verkle tree. -type Trie interface { - // Get returns the value for key stored in the trie. - Get(key []byte) ([]byte, error) - - // Update associates key with value in the trie. - Update(key, value []byte) error - - // Delete removes any existing value for key from the trie. - Delete(key []byte) error - - // Commit the trie and returns a set of dirty nodes generated along with - // the new root hash. - Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) -} - -// TrieLoader wraps functions to load tries. -type TrieLoader interface { - // OpenTrie opens the main account trie. - OpenTrie(root common.Hash) (Trie, error) - - // OpenStorageTrie opens the storage trie of an account. - OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) -} +import "github.com/ethereum/go-ethereum/common" // Set represents a collection of mutated states during a state transition. // The value refers to the original content of state before the transition @@ -87,177 +51,3 @@ func (s *Set) Size() common.StorageSize { } return s.size } - -// context wraps all fields for executing state diffs. -type context struct { - prevRoot common.Hash - postRoot common.Hash - accounts map[common.Address][]byte - storages map[common.Address]map[common.Hash][]byte - accountTrie Trie - nodes *trienode.MergedNodeSet -} - -// Apply traverses the provided state diffs, apply them in the associated -// post-state and return the generated dirty trie nodes. The state can be -// loaded via the provided trie loader. -func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) { - tr, err := loader.OpenTrie(postRoot) - if err != nil { - return nil, err - } - ctx := &context{ - prevRoot: prevRoot, - postRoot: postRoot, - accounts: accounts, - storages: storages, - accountTrie: tr, - nodes: trienode.NewMergedNodeSet(), - } - for addr, account := range accounts { - var err error - if len(account) == 0 { - err = deleteAccount(ctx, loader, addr) - } else { - err = updateAccount(ctx, loader, addr) - } - if err != nil { - return nil, fmt.Errorf("failed to revert state, err: %w", err) - } - } - root, result := tr.Commit(false) - if root != prevRoot { - return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) - } - if err := ctx.nodes.Merge(result); err != nil { - return nil, err - } - return ctx.nodes.Flatten(), nil -} - -// updateAccount the account was present in prev-state, and may or may not -// existent in post-state. Apply the reverse diff and verify if the storage -// root matches the one in prev-state account. -func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { - // The account was present in prev-state, decode it from the - // 'slim-rlp' format bytes. - h := newHasher() - defer h.release() - - addrHash := h.hash(addr.Bytes()) - prev, err := types.FullAccount(ctx.accounts[addr]) - if err != nil { - return err - } - // The account may or may not existent in post-state, try to - // load it and decode if it's found. - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) - if err != nil { - return err - } - post := types.NewEmptyStateAccount() - if len(blob) != 0 { - if err := rlp.DecodeBytes(blob, &post); err != nil { - return err - } - } - // Apply all storage changes into the post-state storage trie. - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) - if err != nil { - return err - } - for key, val := range ctx.storages[addr] { - var err error - if len(val) == 0 { - err = st.Delete(key.Bytes()) - } else { - err = st.Update(key.Bytes(), val) - } - if err != nil { - return err - } - } - root, result := st.Commit(false) - if root != prev.Root { - return errors.New("failed to reset storage trie") - } - // The returned set can be nil if storage trie is not changed - // at all. - if result != nil { - if err := ctx.nodes.Merge(result); err != nil { - return err - } - } - // Write the prev-state account into the main trie - full, err := rlp.EncodeToBytes(prev) - if err != nil { - return err - } - return ctx.accountTrie.Update(addrHash.Bytes(), full) -} - -// deleteAccount the account was not present in prev-state, and is expected -// to be existent in post-state. Apply the reverse diff and verify if the -// account and storage is wiped out correctly. -func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { - // The account must be existent in post-state, load the account. - h := newHasher() - defer h.release() - - addrHash := h.hash(addr.Bytes()) - blob, err := ctx.accountTrie.Get(addrHash.Bytes()) - if err != nil { - return err - } - if len(blob) == 0 { - return fmt.Errorf("account is non-existent %#x", addrHash) - } - var post types.StateAccount - if err := rlp.DecodeBytes(blob, &post); err != nil { - return err - } - st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) - if err != nil { - return err - } - for key, val := range ctx.storages[addr] { - if len(val) != 0 { - return errors.New("expect storage deletion") - } - if err := st.Delete(key.Bytes()); err != nil { - return err - } - } - root, result := st.Commit(false) - if root != types.EmptyRootHash { - return errors.New("failed to clear storage trie") - } - // The returned set can be nil if storage trie is not changed - // at all. - if result != nil { - if err := ctx.nodes.Merge(result); err != nil { - return err - } - } - // Delete the post-state account from the main trie. - return ctx.accountTrie.Delete(addrHash.Bytes()) -} - -// hasher is used to compute the sha256 hash of the provided data. -type hasher struct{ sha crypto.KeccakState } - -var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, -} - -func newHasher() *hasher { - return hasherPool.Get().(*hasher) -} - -func (h *hasher) hash(data []byte) common.Hash { - return crypto.HashData(h.sha, data) -} - -func (h *hasher) release() { - hasherPool.Put(h) -} diff --git a/triedb/database.go b/triedb/database.go index ef757e7f5b..91386a9dbc 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -264,14 +264,7 @@ func (db *Database) Recover(target common.Hash) error { if !ok { return errors.New("not supported") } - var loader triestate.TrieLoader - if db.config.IsVerkle { - // TODO define verkle loader - log.Crit("Verkle loader is not defined") - } else { - loader = trie.NewMerkleLoader(db) - } - return pdb.Recover(target, loader) + return pdb.Recover(target) } // Recoverable returns the indicator if the specified state is enabled to be diff --git a/triedb/database/database.go b/triedb/database/database.go index f11c7e9bbd..9bd5da08d1 100644 --- a/triedb/database/database.go +++ b/triedb/database/database.go @@ -16,9 +16,7 @@ package database -import ( - "github.com/ethereum/go-ethereum/common" -) +import "github.com/ethereum/go-ethereum/common" // Reader wraps the Node method of a backing trie reader. type Reader interface { @@ -31,20 +29,8 @@ type Reader interface { Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) } -// PreimageStore wraps the methods of a backing store for reading and writing -// trie node preimages. -type PreimageStore interface { - // Preimage retrieves the preimage of the specified hash. - Preimage(hash common.Hash) []byte - - // InsertPreimage commits a set of preimages along with their hashes. - InsertPreimage(preimages map[common.Hash][]byte) -} - // Database wraps the methods of a backing trie store. type Database interface { - PreimageStore - // Reader returns a node reader associated with the specific state. // An error will be returned if the specified state is not available. Reader(stateRoot common.Hash) (Reader, error) diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index bd6aeaa6ab..450c3a8f4f 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -345,7 +345,7 @@ func (db *Database) Enable(root common.Hash) error { // Recover rollbacks the database to a specified historical point. // The state is supported as the rollback destination only if it's // canonical state and the corresponding trie histories are existent. -func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error { +func (db *Database) Recover(root common.Hash) error { db.lock.Lock() defer db.lock.Unlock() @@ -371,7 +371,7 @@ func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error if err != nil { return err } - dl, err = dl.revert(h, loader) + dl, err = dl.revert(h) if err != nil { return err } diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 04c8af415f..8870bfe95b 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -29,24 +29,31 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/testrand" "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/triestate" "github.com/holiman/uint256" ) -func updateTrie(addrHash common.Hash, root common.Hash, dirties, cleans map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) { - h, err := newTestHasher(addrHash, root, cleans) +func updateTrie(db *Database, stateRoot common.Hash, addrHash common.Hash, root common.Hash, dirties map[common.Hash][]byte) (common.Hash, *trienode.NodeSet) { + var id *trie.ID + if addrHash == (common.Hash{}) { + id = trie.StateTrieID(stateRoot) + } else { + id = trie.StorageTrieID(stateRoot, addrHash, root) + } + tr, err := trie.New(id, db) if err != nil { - panic(fmt.Errorf("failed to create hasher, err: %w", err)) + panic(fmt.Errorf("failed to load trie, err: %w", err)) } for key, val := range dirties { if len(val) == 0 { - h.Delete(key.Bytes()) + tr.Delete(key.Bytes()) } else { - h.Update(key.Bytes(), val) + tr.Update(key.Bytes(), val) } } - return h.Commit(false) + return tr.Commit(false) } func generateAccount(storageRoot common.Hash) types.StateAccount { @@ -66,6 +73,7 @@ const ( ) type genctx struct { + stateRoot common.Hash accounts map[common.Hash][]byte storages map[common.Hash]map[common.Hash][]byte accountOrigin map[common.Address][]byte @@ -73,8 +81,9 @@ type genctx struct { nodes *trienode.MergedNodeSet } -func newCtx() *genctx { +func newCtx(stateRoot common.Hash) *genctx { return &genctx{ + stateRoot: stateRoot, accounts: make(map[common.Hash][]byte), storages: make(map[common.Hash]map[common.Hash][]byte), accountOrigin: make(map[common.Address][]byte), @@ -151,7 +160,7 @@ func (t *tester) generateStorage(ctx *genctx, addr common.Address) common.Hash { storage[hash] = v origin[hash] = nil } - root, set := updateTrie(addrHash, types.EmptyRootHash, storage, nil) + root, set := updateTrie(t.db, ctx.stateRoot, addrHash, types.EmptyRootHash, storage) ctx.storages[addrHash] = storage ctx.storageOrigin[addr] = origin @@ -180,7 +189,7 @@ func (t *tester) mutateStorage(ctx *genctx, addr common.Address, root common.Has storage[hash] = v origin[hash] = nil } - root, set := updateTrie(crypto.Keccak256Hash(addr.Bytes()), root, storage, t.storages[addrHash]) + root, set := updateTrie(t.db, ctx.stateRoot, crypto.Keccak256Hash(addr.Bytes()), root, storage) ctx.storages[addrHash] = storage ctx.storageOrigin[addr] = origin @@ -198,7 +207,7 @@ func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash origin[hash] = val storage[hash] = nil } - root, set := updateTrie(addrHash, root, storage, t.storages[addrHash]) + root, set := updateTrie(t.db, ctx.stateRoot, addrHash, root, storage) if root != types.EmptyRootHash { panic("failed to clear storage trie") } @@ -210,7 +219,7 @@ func (t *tester) clearStorage(ctx *genctx, addr common.Address, root common.Hash func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNodeSet, *triestate.Set) { var ( - ctx = newCtx() + ctx = newCtx(parent) dirties = make(map[common.Hash]struct{}) ) for i := 0; i < 20; i++ { @@ -271,7 +280,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode ctx.accountOrigin[addr] = account } } - root, set := updateTrie(common.Hash{}, parent, ctx.accounts, t.accounts) + root, set := updateTrie(t.db, parent, common.Hash{}, parent, ctx.accounts) ctx.nodes.Merge(set) // Save state snapshot before commit @@ -297,6 +306,9 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode t.storages[addrHash][sHash] = slot } } + if len(t.storages[addrHash]) == 0 { + delete(t.storages, addrHash) + } } return root, ctx.nodes, triestate.New(ctx.accountOrigin, ctx.storageOrigin) } @@ -310,25 +322,31 @@ func (t *tester) lastHash() common.Hash { } func (t *tester) verifyState(root common.Hash) error { - reader, err := t.db.Reader(root) + tr, err := trie.New(trie.StateTrieID(root), t.db) if err != nil { return err } - _, err = reader.Node(common.Hash{}, nil, root) - if err != nil { - return errors.New("root node is not available") - } for addrHash, account := range t.snapAccounts[root] { - path := crypto.Keccak256(addrHash.Bytes()) - blob, err := reader.Node(common.Hash{}, path, crypto.Keccak256Hash(account)) + blob, err := tr.Get(addrHash.Bytes()) if err != nil || !bytes.Equal(blob, account) { return fmt.Errorf("account is mismatched: %w", err) } } for addrHash, slots := range t.snapStorages[root] { + blob := t.snapAccounts[root][addrHash] + if len(blob) == 0 { + return fmt.Errorf("account %x is missing", addrHash) + } + account := new(types.StateAccount) + if err := rlp.DecodeBytes(blob, account); err != nil { + return err + } + storageIt, err := trie.New(trie.StorageTrieID(root, addrHash, account.Root), t.db) + if err != nil { + return err + } for hash, slot := range slots { - path := crypto.Keccak256(hash.Bytes()) - blob, err := reader.Node(addrHash, path, crypto.Keccak256Hash(slot)) + blob, err := storageIt.Get(hash.Bytes()) if err != nil || !bytes.Equal(blob, slot) { return fmt.Errorf("slot is mismatched: %w", err) } @@ -395,13 +413,11 @@ func TestDatabaseRollback(t *testing.T) { } // Revert database from top to bottom for i := tester.bottomIndex(); i >= 0; i-- { - root := tester.roots[i] parent := types.EmptyRootHash if i > 0 { parent = tester.roots[i-1] } - loader := newHashLoader(tester.snapAccounts[root], tester.snapStorages[root]) - if err := tester.db.Recover(parent, loader); err != nil { + if err := tester.db.Recover(parent); err != nil { t.Fatalf("Failed to revert db, err: %v", err) } if i > 0 { diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 964ad2ef77..e538a79280 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -219,7 +219,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) { } // revert applies the given state history and return a reverted disk layer. -func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer, error) { +func (dl *diskLayer) revert(h *history) (*diskLayer, error) { if h.meta.root != dl.rootHash() { return nil, errUnexpectedHistory } @@ -229,7 +229,7 @@ func (dl *diskLayer) revert(h *history, loader triestate.TrieLoader) (*diskLayer // Apply the reverse state changes upon the current state. This must // be done before holding the lock in order to access state in "this" // layer. - nodes, err := triestate.Apply(h.meta.parent, h.meta.root, h.accounts, h.storages, loader) + nodes, err := apply(dl.db, h.meta.parent, h.meta.root, h.accounts, h.storages) if err != nil { return nil, err } diff --git a/triedb/pathdb/execute.go b/triedb/pathdb/execute.go new file mode 100644 index 0000000000..9074e4debf --- /dev/null +++ b/triedb/pathdb/execute.go @@ -0,0 +1,186 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see + +package pathdb + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" + "github.com/ethereum/go-ethereum/triedb/database" +) + +// context wraps all fields for executing state diffs. +type context struct { + prevRoot common.Hash + postRoot common.Hash + accounts map[common.Address][]byte + storages map[common.Address]map[common.Hash][]byte + nodes *trienode.MergedNodeSet + + // TODO (rjl493456442) abstract out the state hasher + // for supporting verkle tree. + accountTrie *trie.Trie +} + +// apply processes the given state diffs, updates the corresponding post-state +// and returns the trie nodes that have been modified. +func apply(db database.Database, prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte) (map[common.Hash]map[string]*trienode.Node, error) { + tr, err := trie.New(trie.TrieID(postRoot), db) + if err != nil { + return nil, err + } + ctx := &context{ + prevRoot: prevRoot, + postRoot: postRoot, + accounts: accounts, + storages: storages, + accountTrie: tr, + nodes: trienode.NewMergedNodeSet(), + } + for addr, account := range accounts { + var err error + if len(account) == 0 { + err = deleteAccount(ctx, db, addr) + } else { + err = updateAccount(ctx, db, addr) + } + if err != nil { + return nil, fmt.Errorf("failed to revert state, err: %w", err) + } + } + root, result := tr.Commit(false) + if root != prevRoot { + return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) + } + if err := ctx.nodes.Merge(result); err != nil { + return nil, err + } + return ctx.nodes.Flatten(), nil +} + +// updateAccount the account was present in prev-state, and may or may not +// existent in post-state. Apply the reverse diff and verify if the storage +// root matches the one in prev-state account. +func updateAccount(ctx *context, db database.Database, addr common.Address) error { + // The account was present in prev-state, decode it from the + // 'slim-rlp' format bytes. + h := newHasher() + defer h.release() + + addrHash := h.hash(addr.Bytes()) + prev, err := types.FullAccount(ctx.accounts[addr]) + if err != nil { + return err + } + // The account may or may not existent in post-state, try to + // load it and decode if it's found. + blob, err := ctx.accountTrie.Get(addrHash.Bytes()) + if err != nil { + return err + } + post := types.NewEmptyStateAccount() + if len(blob) != 0 { + if err := rlp.DecodeBytes(blob, &post); err != nil { + return err + } + } + // Apply all storage changes into the post-state storage trie. + st, err := trie.New(trie.StorageTrieID(ctx.postRoot, addrHash, post.Root), db) + if err != nil { + return err + } + for key, val := range ctx.storages[addr] { + var err error + if len(val) == 0 { + err = st.Delete(key.Bytes()) + } else { + err = st.Update(key.Bytes(), val) + } + if err != nil { + return err + } + } + root, result := st.Commit(false) + if root != prev.Root { + return errors.New("failed to reset storage trie") + } + // The returned set can be nil if storage trie is not changed + // at all. + if result != nil { + if err := ctx.nodes.Merge(result); err != nil { + return err + } + } + // Write the prev-state account into the main trie + full, err := rlp.EncodeToBytes(prev) + if err != nil { + return err + } + return ctx.accountTrie.Update(addrHash.Bytes(), full) +} + +// deleteAccount the account was not present in prev-state, and is expected +// to be existent in post-state. Apply the reverse diff and verify if the +// account and storage is wiped out correctly. +func deleteAccount(ctx *context, db database.Database, addr common.Address) error { + // The account must be existent in post-state, load the account. + h := newHasher() + defer h.release() + + addrHash := h.hash(addr.Bytes()) + blob, err := ctx.accountTrie.Get(addrHash.Bytes()) + if err != nil { + return err + } + if len(blob) == 0 { + return fmt.Errorf("account is non-existent %#x", addrHash) + } + var post types.StateAccount + if err := rlp.DecodeBytes(blob, &post); err != nil { + return err + } + st, err := trie.New(trie.StorageTrieID(ctx.postRoot, addrHash, post.Root), db) + if err != nil { + return err + } + for key, val := range ctx.storages[addr] { + if len(val) != 0 { + return errors.New("expect storage deletion") + } + if err := st.Delete(key.Bytes()); err != nil { + return err + } + } + root, result := st.Commit(false) + if root != types.EmptyRootHash { + return errors.New("failed to clear storage trie") + } + // The returned set can be nil if storage trie is not changed + // at all. + if result != nil { + if err := ctx.nodes.Merge(result); err != nil { + return err + } + } + // Delete the post-state account from the main trie. + return ctx.accountTrie.Delete(addrHash.Bytes()) +} diff --git a/triedb/pathdb/testutils.go b/triedb/pathdb/testutils.go deleted file mode 100644 index af832bc59c..0000000000 --- a/triedb/pathdb/testutils.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2023 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 . - -package pathdb - -import ( - "bytes" - "fmt" - "slices" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/trie/trienode" - "github.com/ethereum/go-ethereum/trie/triestate" -) - -// testHasher is a test utility for computing root hash of a batch of state -// elements. The hash algorithm is to sort all the elements in lexicographical -// order, concat the key and value in turn, and perform hash calculation on -// the concatenated bytes. Except the root hash, a nodeset will be returned -// once Commit is called, which contains all the changes made to hasher. -type testHasher struct { - owner common.Hash // owner identifier - root common.Hash // original root - dirties map[common.Hash][]byte // dirty states - cleans map[common.Hash][]byte // clean states -} - -// newTestHasher constructs a hasher object with provided states. -func newTestHasher(owner common.Hash, root common.Hash, cleans map[common.Hash][]byte) (*testHasher, error) { - if cleans == nil { - cleans = make(map[common.Hash][]byte) - } - if got, _ := hash(cleans); got != root { - return nil, fmt.Errorf("state root mismatched, want: %x, got: %x", root, got) - } - return &testHasher{ - owner: owner, - root: root, - dirties: make(map[common.Hash][]byte), - cleans: cleans, - }, nil -} - -// Get returns the value for key stored in the trie. -func (h *testHasher) Get(key []byte) ([]byte, error) { - hash := common.BytesToHash(key) - val, ok := h.dirties[hash] - if ok { - return val, nil - } - return h.cleans[hash], nil -} - -// Update associates key with value in the trie. -func (h *testHasher) Update(key, value []byte) error { - h.dirties[common.BytesToHash(key)] = common.CopyBytes(value) - return nil -} - -// Delete removes any existing value for key from the trie. -func (h *testHasher) Delete(key []byte) error { - h.dirties[common.BytesToHash(key)] = nil - return nil -} - -// Commit computes the new hash of the states and returns the set with all -// state changes. -func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { - var ( - nodes = make(map[common.Hash][]byte) - set = trienode.NewNodeSet(h.owner) - ) - for hash, val := range h.cleans { - nodes[hash] = val - } - for hash, val := range h.dirties { - nodes[hash] = val - if bytes.Equal(val, h.cleans[hash]) { - continue - } - // Utilize the hash of the state key as the node path to mitigate - // potential collisions within the path. - path := crypto.Keccak256(hash.Bytes()) - if len(val) == 0 { - set.AddNode(path, trienode.NewDeleted()) - } else { - set.AddNode(path, trienode.New(crypto.Keccak256Hash(val), val)) - } - } - root, blob := hash(nodes) - - // Include the dirty root node as well. - if root != types.EmptyRootHash && root != h.root { - set.AddNode(nil, trienode.New(root, blob)) - } - if root == types.EmptyRootHash && h.root != types.EmptyRootHash { - set.AddNode(nil, trienode.NewDeleted()) - } - return root, set -} - -// hash performs the hash computation upon the provided states. -func hash(states map[common.Hash][]byte) (common.Hash, []byte) { - var hs []common.Hash - for hash := range states { - hs = append(hs, hash) - } - slices.SortFunc(hs, common.Hash.Cmp) - - var input []byte - for _, hash := range hs { - if len(states[hash]) == 0 { - continue - } - input = append(input, hash.Bytes()...) - input = append(input, states[hash]...) - } - if len(input) == 0 { - return types.EmptyRootHash, nil - } - return crypto.Keccak256Hash(input), input -} - -type hashLoader struct { - accounts map[common.Hash][]byte - storages map[common.Hash]map[common.Hash][]byte -} - -func newHashLoader(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *hashLoader { - return &hashLoader{ - accounts: accounts, - storages: storages, - } -} - -// OpenTrie opens the main account trie. -func (l *hashLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { - return newTestHasher(common.Hash{}, root, l.accounts) -} - -// OpenStorageTrie opens the storage trie of an account. -func (l *hashLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { - return newTestHasher(addrHash, root, l.storages[addrHash]) -} From 19c3c1e20560ff85205dbad9c5c0c698d1854bf6 Mon Sep 17 00:00:00 2001 From: lilasxie Date: Fri, 28 Jun 2024 21:15:54 +0800 Subject: [PATCH 110/196] triedb/pathdb: fix flaky test in pathdb (#29901) --- triedb/pathdb/database_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 8870bfe95b..f667944784 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -121,7 +121,7 @@ func newTester(t *testing.T, historyLimit uint64) *tester { snapStorages: make(map[common.Hash]map[common.Hash]map[common.Hash][]byte), } ) - for i := 0; i < 8; i++ { + for i := 0; i < 12; i++ { var parent = types.EmptyRootHash if len(obj.roots) != 0 { parent = obj.roots[len(obj.roots)-1] From 36d67be41be59fc92118a6a8cdebdf52e1037eb3 Mon Sep 17 00:00:00 2001 From: maskpp Date: Fri, 28 Jun 2024 21:51:27 +0800 Subject: [PATCH 111/196] core/txpool/blobpool: improve newPriceHeap function (#30050) Co-authored-by: Felix Lange --- core/txpool/blobpool/evictheap.go | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/core/txpool/blobpool/evictheap.go b/core/txpool/blobpool/evictheap.go index 701eb405cf..5e285e6c53 100644 --- a/core/txpool/blobpool/evictheap.go +++ b/core/txpool/blobpool/evictheap.go @@ -17,13 +17,13 @@ package blobpool import ( - "bytes" "container/heap" "math" - "sort" + "slices" "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" + "golang.org/x/exp/maps" ) // evictHeap is a helper data structure to keep track of the cheapest bottleneck @@ -49,20 +49,15 @@ type evictHeap struct { func newPriceHeap(basefee *uint256.Int, blobfee *uint256.Int, index map[common.Address][]*blobTxMeta) *evictHeap { heap := &evictHeap{ metas: index, - index: make(map[common.Address]int), + index: make(map[common.Address]int, len(index)), } // Populate the heap in account sort order. Not really needed in practice, // but it makes the heap initialization deterministic and less annoying to // test in unit tests. - addrs := make([]common.Address, 0, len(index)) - for addr := range index { - addrs = append(addrs, addr) - } - sort.Slice(addrs, func(i, j int) bool { return bytes.Compare(addrs[i][:], addrs[j][:]) < 0 }) - - for _, addr := range addrs { - heap.index[addr] = len(heap.addrs) - heap.addrs = append(heap.addrs, addr) + heap.addrs = maps.Keys(index) + slices.SortFunc(heap.addrs, common.Address.Cmp) + for i, addr := range heap.addrs { + heap.index[addr] = i } heap.reinit(basefee, blobfee, true) return heap From 4939c253411c3a02fff84df6f9506f998b9762de Mon Sep 17 00:00:00 2001 From: maskpp Date: Sat, 29 Jun 2024 00:05:57 +0800 Subject: [PATCH 112/196] cmd/evm/internal/t8ntool: log writeTraceResult error message (#30038) --- cmd/evm/internal/t8ntool/execution.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 3c09229e1c..9537d6d974 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -306,7 +306,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, if tracer.Hooks.OnTxEnd != nil { tracer.Hooks.OnTxEnd(receipt, nil) } - writeTraceResult(tracer, traceOutput) + if err = writeTraceResult(tracer, traceOutput); err != nil { + log.Warn("Error writing tracer output", "err", err) + } } } From 06f1d077d382b457ba28497d1a7bcfb3d0ea5645 Mon Sep 17 00:00:00 2001 From: gitglorythegreat Date: Sat, 29 Jun 2024 00:08:31 +0800 Subject: [PATCH 113/196] all: replace division with right shift if possible (#29911) --- cmd/evm/internal/t8ntool/execution.go | 4 ++-- consensus/ethash/consensus.go | 10 ++-------- core/types/transaction_signing.go | 4 ++-- core/vm/contracts.go | 13 +++++-------- 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 9537d6d974..a4c5f6efcb 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -325,7 +325,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, var ( blockReward = big.NewInt(miningReward) minerReward = new(big.Int).Set(blockReward) - perOmmer = new(big.Int).Div(blockReward, big.NewInt(32)) + perOmmer = new(big.Int).Rsh(blockReward, 5) ) for _, ommer := range pre.Env.Ommers { // Add 1/32th for each ommer included @@ -334,7 +334,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, reward := big.NewInt(8) reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) reward.Mul(reward, blockReward) - reward.Div(reward, big.NewInt(8)) + reward.Rsh(reward, 3) statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), tracing.BalanceIncreaseRewardMineUncle) } statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), tracing.BalanceIncreaseRewardMineBlock) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index b5e2754c2d..0bd1a56bce 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -562,12 +562,6 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { return hash } -// Some weird constants to avoid constant memory allocs for them. -var ( - u256_8 = uint256.NewInt(8) - u256_32 = uint256.NewInt(32) -) - // accumulateRewards credits the coinbase of the given block with the mining // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. @@ -589,10 +583,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade r.AddUint64(uNum, 8) r.Sub(r, hNum) r.Mul(r, blockReward) - r.Div(r, u256_8) + r.Rsh(r, 3) stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle) - r.Div(blockReward, u256_32) + r.Rsh(blockReward, 5) reward.Add(reward, r) } stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 2ae38661f3..339fee6f97 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int { } return new(big.Int).SetUint64((v - 35) / 2) } - v = new(big.Int).Sub(v, big.NewInt(35)) - return v.Div(v, big.NewInt(2)) + v.Sub(v, big.NewInt(35)) + return v.Rsh(v, 1) } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 8e0f846775..dd71a9729f 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -296,10 +296,7 @@ type bigModExp struct { var ( big1 = big.NewInt(1) big3 = big.NewInt(3) - big4 = big.NewInt(4) big7 = big.NewInt(7) - big8 = big.NewInt(8) - big16 = big.NewInt(16) big20 = big.NewInt(20) big32 = big.NewInt(32) big64 = big.NewInt(64) @@ -325,13 +322,13 @@ func modexpMultComplexity(x *big.Int) *big.Int { case x.Cmp(big1024) <= 0: // (x ** 2 // 4 ) + ( 96 * x - 3072) x = new(big.Int).Add( - new(big.Int).Div(new(big.Int).Mul(x, x), big4), + new(big.Int).Rsh(new(big.Int).Mul(x, x), 2), new(big.Int).Sub(new(big.Int).Mul(big96, x), big3072), ) default: // (x ** 2 // 16) + (480 * x - 199680) x = new(big.Int).Add( - new(big.Int).Div(new(big.Int).Mul(x, x), big16), + new(big.Int).Rsh(new(big.Int).Mul(x, x), 4), new(big.Int).Sub(new(big.Int).Mul(big480, x), big199680), ) } @@ -369,7 +366,7 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { adjExpLen := new(big.Int) if expLen.Cmp(big32) > 0 { adjExpLen.Sub(expLen, big32) - adjExpLen.Mul(big8, adjExpLen) + adjExpLen.Lsh(adjExpLen, 3) } adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) // Calculate the gas cost of the operation @@ -383,8 +380,8 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { // ceiling(x/8)^2 // //where is x is max(length_of_MODULUS, length_of_BASE) - gas = gas.Add(gas, big7) - gas = gas.Div(gas, big8) + gas.Add(gas, big7) + gas.Rsh(gas, 3) gas.Mul(gas, gas) gas.Mul(gas, math.BigMax(adjExpLen, big1)) From 7cfff30ba3a67de767a9b2a7405b91f120873d10 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Fri, 28 Jun 2024 21:37:58 +0300 Subject: [PATCH 114/196] rpc: truncate call error data logs (#30028) Co-authored-by: Felix Lange --- rpc/handler.go | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/rpc/handler.go b/rpc/handler.go index 7b8f64aa7b..f23b544b58 100644 --- a/rpc/handler.go +++ b/rpc/handler.go @@ -17,8 +17,11 @@ package rpc import ( + "bytes" "context" "encoding/json" + "errors" + "fmt" "reflect" "strconv" "strings" @@ -468,16 +471,16 @@ func (h *handler) handleCallMsg(ctx *callProc, msg *jsonrpcMessage) *jsonrpcMess case msg.isCall(): resp := h.handleCall(ctx, msg) - var ctx []interface{} - ctx = append(ctx, "reqid", idForLog{msg.ID}, "duration", time.Since(start)) + var logctx []any + logctx = append(logctx, "reqid", idForLog{msg.ID}, "duration", time.Since(start)) if resp.Error != nil { - ctx = append(ctx, "err", resp.Error.Message) + logctx = append(logctx, "err", resp.Error.Message) if resp.Error.Data != nil { - ctx = append(ctx, "errdata", resp.Error.Data) + logctx = append(logctx, "errdata", formatErrorData(resp.Error.Data)) } - h.log.Warn("Served "+msg.Method, ctx...) + h.log.Warn("Served "+msg.Method, logctx...) } else { - h.log.Debug("Served "+msg.Method, ctx...) + h.log.Debug("Served "+msg.Method, logctx...) } return resp @@ -591,3 +594,33 @@ func (id idForLog) String() string { } return string(id.RawMessage) } + +var errTruncatedOutput = errors.New("truncated output") + +type limitedBuffer struct { + output []byte + limit int +} + +func (buf *limitedBuffer) Write(data []byte) (int, error) { + avail := max(buf.limit, len(buf.output)) + if len(data) < avail { + buf.output = append(buf.output, data...) + return len(data), nil + } + buf.output = append(buf.output, data[:avail]...) + return avail, errTruncatedOutput +} + +func formatErrorData(v any) string { + buf := limitedBuffer{limit: 1024} + err := json.NewEncoder(&buf).Encode(v) + switch { + case err == nil: + return string(bytes.TrimRight(buf.output, "\n")) + case errors.Is(err, errTruncatedOutput): + return fmt.Sprintf("%s... (truncated)", buf.output) + default: + return fmt.Sprintf("bad error data (err=%v)", err) + } +} From a4e338f05e1e38b752a50c0fb2d66d93501a4a3f Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 1 Jul 2024 07:18:38 -0700 Subject: [PATCH 115/196] accounts/usbwallet/trezor: upgrade to generate with protoc 27.1 (#30058) --- .../usbwallet/trezor/messages-common.pb.go | 1427 +++++---- .../usbwallet/trezor/messages-common.proto | 2 + .../usbwallet/trezor/messages-ethereum.pb.go | 1200 +++++--- .../usbwallet/trezor/messages-ethereum.proto | 2 + .../trezor/messages-management.pb.go | 2667 ++++++++++------- .../trezor/messages-management.proto | 2 + accounts/usbwallet/trezor/messages.pb.go | 1743 +++++++---- accounts/usbwallet/trezor/messages.proto | 3 + accounts/usbwallet/trezor/trezor.go | 2 +- 9 files changed, 4440 insertions(+), 2608 deletions(-) diff --git a/accounts/usbwallet/trezor/messages-common.pb.go b/accounts/usbwallet/trezor/messages-common.pb.go index b396c6d8b5..c5e305960b 100644 --- a/accounts/usbwallet/trezor/messages-common.pb.go +++ b/accounts/usbwallet/trezor/messages-common.pb.go @@ -1,25 +1,28 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages-common.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages-common.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) type Failure_FailureType int32 @@ -39,37 +42,39 @@ const ( Failure_Failure_FirmwareError Failure_FailureType = 99 ) -var Failure_FailureType_name = map[int32]string{ - 1: "Failure_UnexpectedMessage", - 2: "Failure_ButtonExpected", - 3: "Failure_DataError", - 4: "Failure_ActionCancelled", - 5: "Failure_PinExpected", - 6: "Failure_PinCancelled", - 7: "Failure_PinInvalid", - 8: "Failure_InvalidSignature", - 9: "Failure_ProcessError", - 10: "Failure_NotEnoughFunds", - 11: "Failure_NotInitialized", - 12: "Failure_PinMismatch", - 99: "Failure_FirmwareError", -} - -var Failure_FailureType_value = map[string]int32{ - "Failure_UnexpectedMessage": 1, - "Failure_ButtonExpected": 2, - "Failure_DataError": 3, - "Failure_ActionCancelled": 4, - "Failure_PinExpected": 5, - "Failure_PinCancelled": 6, - "Failure_PinInvalid": 7, - "Failure_InvalidSignature": 8, - "Failure_ProcessError": 9, - "Failure_NotEnoughFunds": 10, - "Failure_NotInitialized": 11, - "Failure_PinMismatch": 12, - "Failure_FirmwareError": 99, -} +// Enum value maps for Failure_FailureType. +var ( + Failure_FailureType_name = map[int32]string{ + 1: "Failure_UnexpectedMessage", + 2: "Failure_ButtonExpected", + 3: "Failure_DataError", + 4: "Failure_ActionCancelled", + 5: "Failure_PinExpected", + 6: "Failure_PinCancelled", + 7: "Failure_PinInvalid", + 8: "Failure_InvalidSignature", + 9: "Failure_ProcessError", + 10: "Failure_NotEnoughFunds", + 11: "Failure_NotInitialized", + 12: "Failure_PinMismatch", + 99: "Failure_FirmwareError", + } + Failure_FailureType_value = map[string]int32{ + "Failure_UnexpectedMessage": 1, + "Failure_ButtonExpected": 2, + "Failure_DataError": 3, + "Failure_ActionCancelled": 4, + "Failure_PinExpected": 5, + "Failure_PinCancelled": 6, + "Failure_PinInvalid": 7, + "Failure_InvalidSignature": 8, + "Failure_ProcessError": 9, + "Failure_NotEnoughFunds": 10, + "Failure_NotInitialized": 11, + "Failure_PinMismatch": 12, + "Failure_FirmwareError": 99, + } +) func (x Failure_FailureType) Enum() *Failure_FailureType { p := new(Failure_FailureType) @@ -78,20 +83,34 @@ func (x Failure_FailureType) Enum() *Failure_FailureType { } func (x Failure_FailureType) String() string { - return proto.EnumName(Failure_FailureType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *Failure_FailureType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Failure_FailureType_value, data, "Failure_FailureType") +func (Failure_FailureType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_common_proto_enumTypes[0].Descriptor() +} + +func (Failure_FailureType) Type() protoreflect.EnumType { + return &file_messages_common_proto_enumTypes[0] +} + +func (x Failure_FailureType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *Failure_FailureType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = Failure_FailureType(value) + *x = Failure_FailureType(num) return nil } +// Deprecated: Use Failure_FailureType.Descriptor instead. func (Failure_FailureType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{1, 0} + return file_messages_common_proto_rawDescGZIP(), []int{1, 0} } // * @@ -116,41 +135,43 @@ const ( ButtonRequest_ButtonRequest_UnknownDerivationPath ButtonRequest_ButtonRequestType = 15 ) -var ButtonRequest_ButtonRequestType_name = map[int32]string{ - 1: "ButtonRequest_Other", - 2: "ButtonRequest_FeeOverThreshold", - 3: "ButtonRequest_ConfirmOutput", - 4: "ButtonRequest_ResetDevice", - 5: "ButtonRequest_ConfirmWord", - 6: "ButtonRequest_WipeDevice", - 7: "ButtonRequest_ProtectCall", - 8: "ButtonRequest_SignTx", - 9: "ButtonRequest_FirmwareCheck", - 10: "ButtonRequest_Address", - 11: "ButtonRequest_PublicKey", - 12: "ButtonRequest_MnemonicWordCount", - 13: "ButtonRequest_MnemonicInput", - 14: "ButtonRequest_PassphraseType", - 15: "ButtonRequest_UnknownDerivationPath", -} - -var ButtonRequest_ButtonRequestType_value = map[string]int32{ - "ButtonRequest_Other": 1, - "ButtonRequest_FeeOverThreshold": 2, - "ButtonRequest_ConfirmOutput": 3, - "ButtonRequest_ResetDevice": 4, - "ButtonRequest_ConfirmWord": 5, - "ButtonRequest_WipeDevice": 6, - "ButtonRequest_ProtectCall": 7, - "ButtonRequest_SignTx": 8, - "ButtonRequest_FirmwareCheck": 9, - "ButtonRequest_Address": 10, - "ButtonRequest_PublicKey": 11, - "ButtonRequest_MnemonicWordCount": 12, - "ButtonRequest_MnemonicInput": 13, - "ButtonRequest_PassphraseType": 14, - "ButtonRequest_UnknownDerivationPath": 15, -} +// Enum value maps for ButtonRequest_ButtonRequestType. +var ( + ButtonRequest_ButtonRequestType_name = map[int32]string{ + 1: "ButtonRequest_Other", + 2: "ButtonRequest_FeeOverThreshold", + 3: "ButtonRequest_ConfirmOutput", + 4: "ButtonRequest_ResetDevice", + 5: "ButtonRequest_ConfirmWord", + 6: "ButtonRequest_WipeDevice", + 7: "ButtonRequest_ProtectCall", + 8: "ButtonRequest_SignTx", + 9: "ButtonRequest_FirmwareCheck", + 10: "ButtonRequest_Address", + 11: "ButtonRequest_PublicKey", + 12: "ButtonRequest_MnemonicWordCount", + 13: "ButtonRequest_MnemonicInput", + 14: "ButtonRequest_PassphraseType", + 15: "ButtonRequest_UnknownDerivationPath", + } + ButtonRequest_ButtonRequestType_value = map[string]int32{ + "ButtonRequest_Other": 1, + "ButtonRequest_FeeOverThreshold": 2, + "ButtonRequest_ConfirmOutput": 3, + "ButtonRequest_ResetDevice": 4, + "ButtonRequest_ConfirmWord": 5, + "ButtonRequest_WipeDevice": 6, + "ButtonRequest_ProtectCall": 7, + "ButtonRequest_SignTx": 8, + "ButtonRequest_FirmwareCheck": 9, + "ButtonRequest_Address": 10, + "ButtonRequest_PublicKey": 11, + "ButtonRequest_MnemonicWordCount": 12, + "ButtonRequest_MnemonicInput": 13, + "ButtonRequest_PassphraseType": 14, + "ButtonRequest_UnknownDerivationPath": 15, + } +) func (x ButtonRequest_ButtonRequestType) Enum() *ButtonRequest_ButtonRequestType { p := new(ButtonRequest_ButtonRequestType) @@ -159,20 +180,34 @@ func (x ButtonRequest_ButtonRequestType) Enum() *ButtonRequest_ButtonRequestType } func (x ButtonRequest_ButtonRequestType) String() string { - return proto.EnumName(ButtonRequest_ButtonRequestType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *ButtonRequest_ButtonRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(ButtonRequest_ButtonRequestType_value, data, "ButtonRequest_ButtonRequestType") +func (ButtonRequest_ButtonRequestType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_common_proto_enumTypes[1].Descriptor() +} + +func (ButtonRequest_ButtonRequestType) Type() protoreflect.EnumType { + return &file_messages_common_proto_enumTypes[1] +} + +func (x ButtonRequest_ButtonRequestType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *ButtonRequest_ButtonRequestType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = ButtonRequest_ButtonRequestType(value) + *x = ButtonRequest_ButtonRequestType(num) return nil } +// Deprecated: Use ButtonRequest_ButtonRequestType.Descriptor instead. func (ButtonRequest_ButtonRequestType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{2, 0} + return file_messages_common_proto_rawDescGZIP(), []int{2, 0} } // * @@ -185,17 +220,19 @@ const ( PinMatrixRequest_PinMatrixRequestType_NewSecond PinMatrixRequest_PinMatrixRequestType = 3 ) -var PinMatrixRequest_PinMatrixRequestType_name = map[int32]string{ - 1: "PinMatrixRequestType_Current", - 2: "PinMatrixRequestType_NewFirst", - 3: "PinMatrixRequestType_NewSecond", -} - -var PinMatrixRequest_PinMatrixRequestType_value = map[string]int32{ - "PinMatrixRequestType_Current": 1, - "PinMatrixRequestType_NewFirst": 2, - "PinMatrixRequestType_NewSecond": 3, -} +// Enum value maps for PinMatrixRequest_PinMatrixRequestType. +var ( + PinMatrixRequest_PinMatrixRequestType_name = map[int32]string{ + 1: "PinMatrixRequestType_Current", + 2: "PinMatrixRequestType_NewFirst", + 3: "PinMatrixRequestType_NewSecond", + } + PinMatrixRequest_PinMatrixRequestType_value = map[string]int32{ + "PinMatrixRequestType_Current": 1, + "PinMatrixRequestType_NewFirst": 2, + "PinMatrixRequestType_NewSecond": 3, + } +) func (x PinMatrixRequest_PinMatrixRequestType) Enum() *PinMatrixRequest_PinMatrixRequestType { p := new(PinMatrixRequest_PinMatrixRequestType) @@ -204,60 +241,82 @@ func (x PinMatrixRequest_PinMatrixRequestType) Enum() *PinMatrixRequest_PinMatri } func (x PinMatrixRequest_PinMatrixRequestType) String() string { - return proto.EnumName(PinMatrixRequest_PinMatrixRequestType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *PinMatrixRequest_PinMatrixRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(PinMatrixRequest_PinMatrixRequestType_value, data, "PinMatrixRequest_PinMatrixRequestType") +func (PinMatrixRequest_PinMatrixRequestType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_common_proto_enumTypes[2].Descriptor() +} + +func (PinMatrixRequest_PinMatrixRequestType) Type() protoreflect.EnumType { + return &file_messages_common_proto_enumTypes[2] +} + +func (x PinMatrixRequest_PinMatrixRequestType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *PinMatrixRequest_PinMatrixRequestType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = PinMatrixRequest_PinMatrixRequestType(value) + *x = PinMatrixRequest_PinMatrixRequestType(num) return nil } +// Deprecated: Use PinMatrixRequest_PinMatrixRequestType.Descriptor instead. func (PinMatrixRequest_PinMatrixRequestType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{4, 0} + return file_messages_common_proto_rawDescGZIP(), []int{4, 0} } // * // Response: Success of the previous request // @end type Success struct { - Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` // human readable description of action or request-specific payload } -func (m *Success) Reset() { *m = Success{} } -func (m *Success) String() string { return proto.CompactTextString(m) } -func (*Success) ProtoMessage() {} +func (x *Success) Reset() { + *x = Success{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Success) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Success) ProtoMessage() {} + +func (x *Success) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Success.ProtoReflect.Descriptor instead. func (*Success) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{0} + return file_messages_common_proto_rawDescGZIP(), []int{0} } -func (m *Success) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Success.Unmarshal(m, b) -} -func (m *Success) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Success.Marshal(b, m, deterministic) -} -func (m *Success) XXX_Merge(src proto.Message) { - xxx_messageInfo_Success.Merge(m, src) -} -func (m *Success) XXX_Size() int { - return xxx_messageInfo_Success.Size(m) -} -func (m *Success) XXX_DiscardUnknown() { - xxx_messageInfo_Success.DiscardUnknown(m) -} - -var xxx_messageInfo_Success proto.InternalMessageInfo - -func (m *Success) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message +func (x *Success) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message } return "" } @@ -266,48 +325,56 @@ func (m *Success) GetMessage() string { // Response: Failure of the previous request // @end type Failure struct { - Code *Failure_FailureType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.Failure_FailureType" json:"code,omitempty"` - Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code *Failure_FailureType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.Failure_FailureType" json:"code,omitempty"` // computer-readable definition of the error state + Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` // human-readable message of the error state } -func (m *Failure) Reset() { *m = Failure{} } -func (m *Failure) String() string { return proto.CompactTextString(m) } -func (*Failure) ProtoMessage() {} +func (x *Failure) Reset() { + *x = Failure{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Failure) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Failure) ProtoMessage() {} + +func (x *Failure) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Failure.ProtoReflect.Descriptor instead. func (*Failure) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{1} + return file_messages_common_proto_rawDescGZIP(), []int{1} } -func (m *Failure) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Failure.Unmarshal(m, b) -} -func (m *Failure) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Failure.Marshal(b, m, deterministic) -} -func (m *Failure) XXX_Merge(src proto.Message) { - xxx_messageInfo_Failure.Merge(m, src) -} -func (m *Failure) XXX_Size() int { - return xxx_messageInfo_Failure.Size(m) -} -func (m *Failure) XXX_DiscardUnknown() { - xxx_messageInfo_Failure.DiscardUnknown(m) -} - -var xxx_messageInfo_Failure proto.InternalMessageInfo - -func (m *Failure) GetCode() Failure_FailureType { - if m != nil && m.Code != nil { - return *m.Code +func (x *Failure) GetCode() Failure_FailureType { + if x != nil && x.Code != nil { + return *x.Code } return Failure_Failure_UnexpectedMessage } -func (m *Failure) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message +func (x *Failure) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message } return "" } @@ -317,48 +384,56 @@ func (m *Failure) GetMessage() string { // @auxstart // @next ButtonAck type ButtonRequest struct { - Code *ButtonRequest_ButtonRequestType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.ButtonRequest_ButtonRequestType" json:"code,omitempty"` - Data *string `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code *ButtonRequest_ButtonRequestType `protobuf:"varint,1,opt,name=code,enum=hw.trezor.messages.common.ButtonRequest_ButtonRequestType" json:"code,omitempty"` + Data *string `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"` } -func (m *ButtonRequest) Reset() { *m = ButtonRequest{} } -func (m *ButtonRequest) String() string { return proto.CompactTextString(m) } -func (*ButtonRequest) ProtoMessage() {} +func (x *ButtonRequest) Reset() { + *x = ButtonRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ButtonRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ButtonRequest) ProtoMessage() {} + +func (x *ButtonRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ButtonRequest.ProtoReflect.Descriptor instead. func (*ButtonRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{2} + return file_messages_common_proto_rawDescGZIP(), []int{2} } -func (m *ButtonRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ButtonRequest.Unmarshal(m, b) -} -func (m *ButtonRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ButtonRequest.Marshal(b, m, deterministic) -} -func (m *ButtonRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ButtonRequest.Merge(m, src) -} -func (m *ButtonRequest) XXX_Size() int { - return xxx_messageInfo_ButtonRequest.Size(m) -} -func (m *ButtonRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ButtonRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_ButtonRequest proto.InternalMessageInfo - -func (m *ButtonRequest) GetCode() ButtonRequest_ButtonRequestType { - if m != nil && m.Code != nil { - return *m.Code +func (x *ButtonRequest) GetCode() ButtonRequest_ButtonRequestType { + if x != nil && x.Code != nil { + return *x.Code } return ButtonRequest_ButtonRequest_Other } -func (m *ButtonRequest) GetData() string { - if m != nil && m.Data != nil { - return *m.Data +func (x *ButtonRequest) GetData() string { + if x != nil && x.Data != nil { + return *x.Data } return "" } @@ -367,75 +442,90 @@ func (m *ButtonRequest) GetData() string { // Request: Computer agrees to wait for HW button press // @auxend type ButtonAck struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *ButtonAck) Reset() { *m = ButtonAck{} } -func (m *ButtonAck) String() string { return proto.CompactTextString(m) } -func (*ButtonAck) ProtoMessage() {} +func (x *ButtonAck) Reset() { + *x = ButtonAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ButtonAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ButtonAck) ProtoMessage() {} + +func (x *ButtonAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ButtonAck.ProtoReflect.Descriptor instead. func (*ButtonAck) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{3} + return file_messages_common_proto_rawDescGZIP(), []int{3} } -func (m *ButtonAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ButtonAck.Unmarshal(m, b) -} -func (m *ButtonAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ButtonAck.Marshal(b, m, deterministic) -} -func (m *ButtonAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_ButtonAck.Merge(m, src) -} -func (m *ButtonAck) XXX_Size() int { - return xxx_messageInfo_ButtonAck.Size(m) -} -func (m *ButtonAck) XXX_DiscardUnknown() { - xxx_messageInfo_ButtonAck.DiscardUnknown(m) -} - -var xxx_messageInfo_ButtonAck proto.InternalMessageInfo - // * // Response: Device is asking computer to show PIN matrix and awaits PIN encoded using this matrix scheme // @auxstart // @next PinMatrixAck type PinMatrixRequest struct { - Type *PinMatrixRequest_PinMatrixRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.common.PinMatrixRequest_PinMatrixRequestType" json:"type,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type *PinMatrixRequest_PinMatrixRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.common.PinMatrixRequest_PinMatrixRequestType" json:"type,omitempty"` } -func (m *PinMatrixRequest) Reset() { *m = PinMatrixRequest{} } -func (m *PinMatrixRequest) String() string { return proto.CompactTextString(m) } -func (*PinMatrixRequest) ProtoMessage() {} +func (x *PinMatrixRequest) Reset() { + *x = PinMatrixRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PinMatrixRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PinMatrixRequest) ProtoMessage() {} + +func (x *PinMatrixRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PinMatrixRequest.ProtoReflect.Descriptor instead. func (*PinMatrixRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{4} + return file_messages_common_proto_rawDescGZIP(), []int{4} } -func (m *PinMatrixRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PinMatrixRequest.Unmarshal(m, b) -} -func (m *PinMatrixRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PinMatrixRequest.Marshal(b, m, deterministic) -} -func (m *PinMatrixRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PinMatrixRequest.Merge(m, src) -} -func (m *PinMatrixRequest) XXX_Size() int { - return xxx_messageInfo_PinMatrixRequest.Size(m) -} -func (m *PinMatrixRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PinMatrixRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_PinMatrixRequest proto.InternalMessageInfo - -func (m *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { - if m != nil && m.Type != nil { - return *m.Type +func (x *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { + if x != nil && x.Type != nil { + return *x.Type } return PinMatrixRequest_PinMatrixRequestType_Current } @@ -444,40 +534,48 @@ func (m *PinMatrixRequest) GetType() PinMatrixRequest_PinMatrixRequestType { // Request: Computer responds with encoded PIN // @auxend type PinMatrixAck struct { - Pin *string `protobuf:"bytes,1,req,name=pin" json:"pin,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Pin *string `protobuf:"bytes,1,req,name=pin" json:"pin,omitempty"` // matrix encoded PIN entered by user } -func (m *PinMatrixAck) Reset() { *m = PinMatrixAck{} } -func (m *PinMatrixAck) String() string { return proto.CompactTextString(m) } -func (*PinMatrixAck) ProtoMessage() {} +func (x *PinMatrixAck) Reset() { + *x = PinMatrixAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PinMatrixAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PinMatrixAck) ProtoMessage() {} + +func (x *PinMatrixAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PinMatrixAck.ProtoReflect.Descriptor instead. func (*PinMatrixAck) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{5} + return file_messages_common_proto_rawDescGZIP(), []int{5} } -func (m *PinMatrixAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PinMatrixAck.Unmarshal(m, b) -} -func (m *PinMatrixAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PinMatrixAck.Marshal(b, m, deterministic) -} -func (m *PinMatrixAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_PinMatrixAck.Merge(m, src) -} -func (m *PinMatrixAck) XXX_Size() int { - return xxx_messageInfo_PinMatrixAck.Size(m) -} -func (m *PinMatrixAck) XXX_DiscardUnknown() { - xxx_messageInfo_PinMatrixAck.DiscardUnknown(m) -} - -var xxx_messageInfo_PinMatrixAck proto.InternalMessageInfo - -func (m *PinMatrixAck) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin +func (x *PinMatrixAck) GetPin() string { + if x != nil && x.Pin != nil { + return *x.Pin } return "" } @@ -487,40 +585,48 @@ func (m *PinMatrixAck) GetPin() string { // @auxstart // @next PassphraseAck type PassphraseRequest struct { - OnDevice *bool `protobuf:"varint,1,opt,name=on_device,json=onDevice" json:"on_device,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OnDevice *bool `protobuf:"varint,1,opt,name=on_device,json=onDevice" json:"on_device,omitempty"` // passphrase is being entered on the device } -func (m *PassphraseRequest) Reset() { *m = PassphraseRequest{} } -func (m *PassphraseRequest) String() string { return proto.CompactTextString(m) } -func (*PassphraseRequest) ProtoMessage() {} +func (x *PassphraseRequest) Reset() { + *x = PassphraseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PassphraseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PassphraseRequest) ProtoMessage() {} + +func (x *PassphraseRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PassphraseRequest.ProtoReflect.Descriptor instead. func (*PassphraseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{6} + return file_messages_common_proto_rawDescGZIP(), []int{6} } -func (m *PassphraseRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PassphraseRequest.Unmarshal(m, b) -} -func (m *PassphraseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PassphraseRequest.Marshal(b, m, deterministic) -} -func (m *PassphraseRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PassphraseRequest.Merge(m, src) -} -func (m *PassphraseRequest) XXX_Size() int { - return xxx_messageInfo_PassphraseRequest.Size(m) -} -func (m *PassphraseRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_PassphraseRequest proto.InternalMessageInfo - -func (m *PassphraseRequest) GetOnDevice() bool { - if m != nil && m.OnDevice != nil { - return *m.OnDevice +func (x *PassphraseRequest) GetOnDevice() bool { + if x != nil && x.OnDevice != nil { + return *x.OnDevice } return false } @@ -529,48 +635,56 @@ func (m *PassphraseRequest) GetOnDevice() bool { // Request: Send passphrase back // @next PassphraseStateRequest type PassphraseAck struct { - Passphrase *string `protobuf:"bytes,1,opt,name=passphrase" json:"passphrase,omitempty"` - State []byte `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Passphrase *string `protobuf:"bytes,1,opt,name=passphrase" json:"passphrase,omitempty"` + State []byte `protobuf:"bytes,2,opt,name=state" json:"state,omitempty"` // expected device state } -func (m *PassphraseAck) Reset() { *m = PassphraseAck{} } -func (m *PassphraseAck) String() string { return proto.CompactTextString(m) } -func (*PassphraseAck) ProtoMessage() {} +func (x *PassphraseAck) Reset() { + *x = PassphraseAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PassphraseAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PassphraseAck) ProtoMessage() {} + +func (x *PassphraseAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PassphraseAck.ProtoReflect.Descriptor instead. func (*PassphraseAck) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{7} + return file_messages_common_proto_rawDescGZIP(), []int{7} } -func (m *PassphraseAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PassphraseAck.Unmarshal(m, b) -} -func (m *PassphraseAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PassphraseAck.Marshal(b, m, deterministic) -} -func (m *PassphraseAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_PassphraseAck.Merge(m, src) -} -func (m *PassphraseAck) XXX_Size() int { - return xxx_messageInfo_PassphraseAck.Size(m) -} -func (m *PassphraseAck) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseAck.DiscardUnknown(m) -} - -var xxx_messageInfo_PassphraseAck proto.InternalMessageInfo - -func (m *PassphraseAck) GetPassphrase() string { - if m != nil && m.Passphrase != nil { - return *m.Passphrase +func (x *PassphraseAck) GetPassphrase() string { + if x != nil && x.Passphrase != nil { + return *x.Passphrase } return "" } -func (m *PassphraseAck) GetState() []byte { - if m != nil { - return m.State +func (x *PassphraseAck) GetState() []byte { + if x != nil { + return x.State } return nil } @@ -579,40 +693,48 @@ func (m *PassphraseAck) GetState() []byte { // Response: Device awaits passphrase state // @next PassphraseStateAck type PassphraseStateRequest struct { - State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` // actual device state } -func (m *PassphraseStateRequest) Reset() { *m = PassphraseStateRequest{} } -func (m *PassphraseStateRequest) String() string { return proto.CompactTextString(m) } -func (*PassphraseStateRequest) ProtoMessage() {} +func (x *PassphraseStateRequest) Reset() { + *x = PassphraseStateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PassphraseStateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PassphraseStateRequest) ProtoMessage() {} + +func (x *PassphraseStateRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PassphraseStateRequest.ProtoReflect.Descriptor instead. func (*PassphraseStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{8} + return file_messages_common_proto_rawDescGZIP(), []int{8} } -func (m *PassphraseStateRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PassphraseStateRequest.Unmarshal(m, b) -} -func (m *PassphraseStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PassphraseStateRequest.Marshal(b, m, deterministic) -} -func (m *PassphraseStateRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PassphraseStateRequest.Merge(m, src) -} -func (m *PassphraseStateRequest) XXX_Size() int { - return xxx_messageInfo_PassphraseStateRequest.Size(m) -} -func (m *PassphraseStateRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseStateRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_PassphraseStateRequest proto.InternalMessageInfo - -func (m *PassphraseStateRequest) GetState() []byte { - if m != nil { - return m.State +func (x *PassphraseStateRequest) GetState() []byte { + if x != nil { + return x.State } return nil } @@ -621,191 +743,456 @@ func (m *PassphraseStateRequest) GetState() []byte { // Request: Send passphrase state back // @auxend type PassphraseStateAck struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *PassphraseStateAck) Reset() { *m = PassphraseStateAck{} } -func (m *PassphraseStateAck) String() string { return proto.CompactTextString(m) } -func (*PassphraseStateAck) ProtoMessage() {} +func (x *PassphraseStateAck) Reset() { + *x = PassphraseStateAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PassphraseStateAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PassphraseStateAck) ProtoMessage() {} + +func (x *PassphraseStateAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PassphraseStateAck.ProtoReflect.Descriptor instead. func (*PassphraseStateAck) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{9} + return file_messages_common_proto_rawDescGZIP(), []int{9} } -func (m *PassphraseStateAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PassphraseStateAck.Unmarshal(m, b) -} -func (m *PassphraseStateAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PassphraseStateAck.Marshal(b, m, deterministic) -} -func (m *PassphraseStateAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_PassphraseStateAck.Merge(m, src) -} -func (m *PassphraseStateAck) XXX_Size() int { - return xxx_messageInfo_PassphraseStateAck.Size(m) -} -func (m *PassphraseStateAck) XXX_DiscardUnknown() { - xxx_messageInfo_PassphraseStateAck.DiscardUnknown(m) -} - -var xxx_messageInfo_PassphraseStateAck proto.InternalMessageInfo - // * // Structure representing BIP32 (hierarchical deterministic) node // Used for imports of private key into the device and exporting public key out of device // @embed type HDNodeType struct { - Depth *uint32 `protobuf:"varint,1,req,name=depth" json:"depth,omitempty"` - Fingerprint *uint32 `protobuf:"varint,2,req,name=fingerprint" json:"fingerprint,omitempty"` - ChildNum *uint32 `protobuf:"varint,3,req,name=child_num,json=childNum" json:"child_num,omitempty"` - ChainCode []byte `protobuf:"bytes,4,req,name=chain_code,json=chainCode" json:"chain_code,omitempty"` - PrivateKey []byte `protobuf:"bytes,5,opt,name=private_key,json=privateKey" json:"private_key,omitempty"` - PublicKey []byte `protobuf:"bytes,6,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Depth *uint32 `protobuf:"varint,1,req,name=depth" json:"depth,omitempty"` + Fingerprint *uint32 `protobuf:"varint,2,req,name=fingerprint" json:"fingerprint,omitempty"` + ChildNum *uint32 `protobuf:"varint,3,req,name=child_num,json=childNum" json:"child_num,omitempty"` + ChainCode []byte `protobuf:"bytes,4,req,name=chain_code,json=chainCode" json:"chain_code,omitempty"` + PrivateKey []byte `protobuf:"bytes,5,opt,name=private_key,json=privateKey" json:"private_key,omitempty"` + PublicKey []byte `protobuf:"bytes,6,opt,name=public_key,json=publicKey" json:"public_key,omitempty"` } -func (m *HDNodeType) Reset() { *m = HDNodeType{} } -func (m *HDNodeType) String() string { return proto.CompactTextString(m) } -func (*HDNodeType) ProtoMessage() {} +func (x *HDNodeType) Reset() { + *x = HDNodeType{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_common_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HDNodeType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HDNodeType) ProtoMessage() {} + +func (x *HDNodeType) ProtoReflect() protoreflect.Message { + mi := &file_messages_common_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HDNodeType.ProtoReflect.Descriptor instead. func (*HDNodeType) Descriptor() ([]byte, []int) { - return fileDescriptor_aaf30d059fdbc38d, []int{10} + return file_messages_common_proto_rawDescGZIP(), []int{10} } -func (m *HDNodeType) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_HDNodeType.Unmarshal(m, b) -} -func (m *HDNodeType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_HDNodeType.Marshal(b, m, deterministic) -} -func (m *HDNodeType) XXX_Merge(src proto.Message) { - xxx_messageInfo_HDNodeType.Merge(m, src) -} -func (m *HDNodeType) XXX_Size() int { - return xxx_messageInfo_HDNodeType.Size(m) -} -func (m *HDNodeType) XXX_DiscardUnknown() { - xxx_messageInfo_HDNodeType.DiscardUnknown(m) -} - -var xxx_messageInfo_HDNodeType proto.InternalMessageInfo - -func (m *HDNodeType) GetDepth() uint32 { - if m != nil && m.Depth != nil { - return *m.Depth +func (x *HDNodeType) GetDepth() uint32 { + if x != nil && x.Depth != nil { + return *x.Depth } return 0 } -func (m *HDNodeType) GetFingerprint() uint32 { - if m != nil && m.Fingerprint != nil { - return *m.Fingerprint +func (x *HDNodeType) GetFingerprint() uint32 { + if x != nil && x.Fingerprint != nil { + return *x.Fingerprint } return 0 } -func (m *HDNodeType) GetChildNum() uint32 { - if m != nil && m.ChildNum != nil { - return *m.ChildNum +func (x *HDNodeType) GetChildNum() uint32 { + if x != nil && x.ChildNum != nil { + return *x.ChildNum } return 0 } -func (m *HDNodeType) GetChainCode() []byte { - if m != nil { - return m.ChainCode +func (x *HDNodeType) GetChainCode() []byte { + if x != nil { + return x.ChainCode } return nil } -func (m *HDNodeType) GetPrivateKey() []byte { - if m != nil { - return m.PrivateKey +func (x *HDNodeType) GetPrivateKey() []byte { + if x != nil { + return x.PrivateKey } return nil } -func (m *HDNodeType) GetPublicKey() []byte { - if m != nil { - return m.PublicKey +func (x *HDNodeType) GetPublicKey() []byte { + if x != nil { + return x.PublicKey } return nil } -func init() { - proto.RegisterEnum("hw.trezor.messages.common.Failure_FailureType", Failure_FailureType_name, Failure_FailureType_value) - proto.RegisterEnum("hw.trezor.messages.common.ButtonRequest_ButtonRequestType", ButtonRequest_ButtonRequestType_name, ButtonRequest_ButtonRequestType_value) - proto.RegisterEnum("hw.trezor.messages.common.PinMatrixRequest_PinMatrixRequestType", PinMatrixRequest_PinMatrixRequestType_name, PinMatrixRequest_PinMatrixRequestType_value) - proto.RegisterType((*Success)(nil), "hw.trezor.messages.common.Success") - proto.RegisterType((*Failure)(nil), "hw.trezor.messages.common.Failure") - proto.RegisterType((*ButtonRequest)(nil), "hw.trezor.messages.common.ButtonRequest") - proto.RegisterType((*ButtonAck)(nil), "hw.trezor.messages.common.ButtonAck") - proto.RegisterType((*PinMatrixRequest)(nil), "hw.trezor.messages.common.PinMatrixRequest") - proto.RegisterType((*PinMatrixAck)(nil), "hw.trezor.messages.common.PinMatrixAck") - proto.RegisterType((*PassphraseRequest)(nil), "hw.trezor.messages.common.PassphraseRequest") - proto.RegisterType((*PassphraseAck)(nil), "hw.trezor.messages.common.PassphraseAck") - proto.RegisterType((*PassphraseStateRequest)(nil), "hw.trezor.messages.common.PassphraseStateRequest") - proto.RegisterType((*PassphraseStateAck)(nil), "hw.trezor.messages.common.PassphraseStateAck") - proto.RegisterType((*HDNodeType)(nil), "hw.trezor.messages.common.HDNodeType") +var File_messages_common_proto protoreflect.FileDescriptor + +var file_messages_common_proto_rawDesc = []byte{ + 0x0a, 0x15, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, + 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x22, 0x23, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd5, 0x03, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x12, 0x42, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x2e, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x46, 0x61, + 0x69, 0x6c, 0x75, 0x72, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0xeb, 0x02, 0x0a, 0x0b, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x55, 0x6e, 0x65, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x01, + 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, + 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x44, 0x61, 0x74, 0x61, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x10, 0x03, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x10, 0x04, + 0x12, 0x17, 0x0a, 0x13, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x45, + 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x10, 0x05, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, + 0x64, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, + 0x69, 0x6e, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x08, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x10, 0x09, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x4e, + 0x6f, 0x74, 0x45, 0x6e, 0x6f, 0x75, 0x67, 0x68, 0x46, 0x75, 0x6e, 0x64, 0x73, 0x10, 0x0a, 0x12, + 0x1a, 0x0a, 0x16, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x4e, 0x6f, 0x74, 0x49, 0x6e, + 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x10, 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x4d, 0x69, 0x73, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x10, 0x0c, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x5f, + 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x10, 0x63, 0x22, + 0xe6, 0x04, 0x0a, 0x0d, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x4e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x3a, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf0, 0x03, 0x0a, 0x11, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x42, + 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x4f, 0x74, 0x68, + 0x65, 0x72, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x46, 0x65, 0x65, 0x4f, 0x76, 0x65, 0x72, 0x54, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x10, 0x02, 0x12, 0x1f, 0x0a, 0x1b, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x75, 0x74, + 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x52, 0x65, 0x73, 0x65, 0x74, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x04, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, + 0x6d, 0x57, 0x6f, 0x72, 0x64, 0x10, 0x05, 0x12, 0x1c, 0x0a, 0x18, 0x42, 0x75, 0x74, 0x74, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x57, 0x69, 0x70, 0x65, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x10, 0x06, 0x12, 0x1d, 0x0a, 0x19, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x43, 0x61, + 0x6c, 0x6c, 0x10, 0x07, 0x12, 0x18, 0x0a, 0x14, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0x08, 0x12, 0x1f, + 0x0a, 0x1b, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x10, 0x09, 0x12, + 0x19, 0x0a, 0x15, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x0a, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x75, + 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x0b, 0x12, 0x23, 0x0a, 0x1f, 0x42, 0x75, 0x74, 0x74, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, + 0x63, 0x57, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0x0c, 0x12, 0x1f, 0x0a, 0x1b, + 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x4d, 0x6e, + 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x10, 0x0d, 0x12, 0x20, 0x0a, + 0x1c, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x50, + 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x10, 0x0e, 0x12, + 0x27, 0x0a, 0x23, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x44, 0x65, 0x72, 0x69, 0x76, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x10, 0x0f, 0x22, 0x0b, 0x0a, 0x09, 0x42, 0x75, 0x74, 0x74, + 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x22, 0xe9, 0x01, 0x0a, 0x10, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, + 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x40, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x7f, 0x0a, 0x14, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x50, 0x69, 0x6e, 0x4d, + 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x50, 0x69, + 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4e, 0x65, 0x77, 0x46, 0x69, 0x72, 0x73, 0x74, 0x10, 0x02, 0x12, 0x22, 0x0a, + 0x1e, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x65, 0x77, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x10, + 0x03, 0x22, 0x20, 0x0a, 0x0c, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x41, 0x63, + 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x03, + 0x70, 0x69, 0x6e, 0x22, 0x30, 0x0a, 0x11, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6f, 0x6e, 0x5f, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6f, 0x6e, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x45, 0x0a, 0x0d, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, + 0x61, 0x73, 0x65, 0x41, 0x63, 0x6b, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x73, 0x73, + 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x2e, 0x0a, 0x16, + 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x14, 0x0a, 0x12, + 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, + 0x63, 0x6b, 0x22, 0xc0, 0x01, 0x0a, 0x0a, 0x48, 0x44, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0d, + 0x52, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, + 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0d, 0x52, 0x0b, 0x66, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0d, 0x52, 0x08, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x02, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, 0x65, 0x7a, + 0x6f, 0x72, } -func init() { proto.RegisterFile("messages-common.proto", fileDescriptor_aaf30d059fdbc38d) } +var ( + file_messages_common_proto_rawDescOnce sync.Once + file_messages_common_proto_rawDescData = file_messages_common_proto_rawDesc +) -var fileDescriptor_aaf30d059fdbc38d = []byte{ - // 846 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xcd, 0x52, 0x23, 0x37, - 0x10, 0x2e, 0xff, 0x80, 0xed, 0xb6, 0xd9, 0x08, 0xc5, 0x80, 0x09, 0xb0, 0x38, 0xc3, 0x21, 0x5c, - 0xe2, 0x4a, 0xe5, 0x98, 0x53, 0x58, 0x83, 0x2b, 0xd4, 0x16, 0x86, 0x1a, 0xd8, 0xda, 0xa3, 0x4b, - 0xd1, 0xf4, 0x32, 0x2a, 0xcf, 0x48, 0x13, 0x8d, 0x06, 0xf0, 0x5e, 0xf2, 0x6a, 0x79, 0x89, 0xbc, - 0x42, 0xaa, 0x52, 0xb9, 0xe4, 0x11, 0xb6, 0x34, 0x3f, 0x78, 0xc6, 0x66, 0x39, 0xcd, 0xe8, 0xfb, - 0xbe, 0xee, 0x96, 0xba, 0x3f, 0x09, 0x76, 0x42, 0x8c, 0x63, 0x76, 0x8f, 0xf1, 0x8f, 0x5c, 0x85, - 0xa1, 0x92, 0xa3, 0x48, 0x2b, 0xa3, 0xe8, 0xbe, 0xff, 0x38, 0x32, 0x1a, 0x3f, 0x2b, 0x3d, 0x2a, - 0x04, 0xa3, 0x4c, 0xe0, 0x9c, 0x40, 0xeb, 0x36, 0xe1, 0x1c, 0xe3, 0x98, 0x0e, 0xa0, 0x95, 0xb3, - 0x83, 0xda, 0xb0, 0x76, 0xda, 0x71, 0x8b, 0xa5, 0xf3, 0x77, 0x03, 0x5a, 0x13, 0x26, 0x82, 0x44, - 0x23, 0x7d, 0x07, 0x4d, 0xae, 0xbc, 0x4c, 0xf2, 0xe6, 0xe7, 0xd1, 0xe8, 0xab, 0xa9, 0x47, 0x79, - 0x44, 0xf1, 0xbd, 0x5b, 0x44, 0xe8, 0xa6, 0xb1, 0xe5, 0x4a, 0xf5, 0x6a, 0xa5, 0xff, 0xea, 0xd0, - 0x2d, 0xe9, 0xe9, 0x11, 0xec, 0xe7, 0xcb, 0xd9, 0x07, 0x89, 0x4f, 0x11, 0x72, 0x83, 0xde, 0x55, - 0x26, 0x26, 0x35, 0xfa, 0x1d, 0xec, 0x16, 0xf4, 0xbb, 0xc4, 0x18, 0x25, 0x2f, 0x72, 0x09, 0xa9, - 0xd3, 0x1d, 0xd8, 0x2e, 0xb8, 0x73, 0x66, 0xd8, 0x85, 0xd6, 0x4a, 0x93, 0x06, 0x3d, 0x80, 0xbd, - 0x02, 0x3e, 0xe3, 0x46, 0x28, 0x39, 0x66, 0x92, 0x63, 0x10, 0xa0, 0x47, 0x9a, 0x74, 0x0f, 0xbe, - 0x2d, 0xc8, 0x1b, 0xb1, 0x4c, 0xb6, 0x41, 0x07, 0xd0, 0x2f, 0x11, 0xcb, 0x90, 0x4d, 0xba, 0x0b, - 0xb4, 0xc4, 0x5c, 0xca, 0x07, 0x16, 0x08, 0x8f, 0xb4, 0xe8, 0x21, 0x0c, 0x0a, 0x3c, 0x07, 0x6f, - 0xc5, 0xbd, 0x64, 0x26, 0xd1, 0x48, 0xda, 0x95, 0x7c, 0x5a, 0xd9, 0xf6, 0x67, 0xfb, 0xeb, 0x94, - 0x8f, 0x34, 0x55, 0xe6, 0x42, 0xaa, 0xe4, 0xde, 0x9f, 0x24, 0xd2, 0x8b, 0x09, 0xac, 0x70, 0x97, - 0x52, 0x18, 0xc1, 0x02, 0xf1, 0x19, 0x3d, 0xd2, 0x5d, 0xd9, 0xfa, 0x95, 0x88, 0x43, 0x66, 0xb8, - 0x4f, 0x7a, 0x74, 0x1f, 0x76, 0x0a, 0x62, 0x22, 0x74, 0xf8, 0xc8, 0x34, 0x66, 0xb5, 0xb8, 0xf3, - 0x4f, 0x13, 0xb6, 0xb2, 0xbe, 0xb9, 0xf8, 0x47, 0x82, 0xb1, 0xa1, 0xd3, 0xca, 0x74, 0x7f, 0x79, - 0x65, 0xba, 0x95, 0xb8, 0xea, 0xaa, 0x34, 0x69, 0x0a, 0x4d, 0x8f, 0x19, 0x96, 0x8f, 0x39, 0xfd, - 0x77, 0xfe, 0x6f, 0xc0, 0xf6, 0x9a, 0xde, 0xee, 0xbf, 0x02, 0xce, 0xae, 0x8d, 0x8f, 0x9a, 0xd4, - 0xa8, 0x03, 0x6f, 0xab, 0xc4, 0x04, 0xf1, 0xfa, 0x01, 0xf5, 0x9d, 0xaf, 0x31, 0xf6, 0x55, 0x60, - 0x67, 0x7d, 0x0c, 0x07, 0x55, 0xcd, 0x58, 0xc9, 0x4f, 0x42, 0x87, 0xd7, 0x89, 0x89, 0x12, 0x43, - 0x1a, 0xd6, 0x47, 0x55, 0x81, 0x8b, 0x31, 0x9a, 0x73, 0x7c, 0x10, 0x1c, 0x49, 0x73, 0x9d, 0xce, - 0xe3, 0x3f, 0x2a, 0x6d, 0xa7, 0x7f, 0x08, 0x83, 0x2a, 0xfd, 0x51, 0x44, 0x98, 0x07, 0x6f, 0xae, - 0x07, 0xdf, 0x68, 0x65, 0x90, 0x9b, 0x31, 0x0b, 0x02, 0xd2, 0xb2, 0xa3, 0xae, 0xd2, 0xd6, 0x07, - 0x77, 0x4f, 0xa4, 0xbd, 0xbe, 0xeb, 0x62, 0x3e, 0x63, 0x1f, 0xf9, 0x9c, 0x74, 0xec, 0xe8, 0xaa, - 0x82, 0x33, 0xcf, 0xd3, 0x18, 0x5b, 0x2b, 0x1c, 0xc0, 0xde, 0x4a, 0xd1, 0xe4, 0xf7, 0x40, 0xf0, - 0xf7, 0xb8, 0x20, 0x5d, 0x7a, 0x02, 0xc7, 0x55, 0xf2, 0x4a, 0x62, 0xa8, 0xa4, 0xe0, 0xf6, 0x3c, - 0x63, 0x95, 0x48, 0x43, 0x7a, 0xeb, 0xd5, 0x0b, 0xd1, 0xa5, 0xb4, 0x3d, 0xdb, 0xa2, 0x43, 0x38, - 0x5c, 0x29, 0xc1, 0xe2, 0x38, 0xf2, 0x35, 0x8b, 0xd3, 0xbb, 0x49, 0xde, 0xd0, 0x1f, 0xe0, 0xa4, - 0xaa, 0xf8, 0x20, 0xe7, 0x52, 0x3d, 0xca, 0x73, 0xd4, 0xe2, 0x81, 0xd9, 0xcb, 0x75, 0xc3, 0x8c, - 0x4f, 0xbe, 0x71, 0xba, 0xd0, 0xc9, 0x84, 0x67, 0x7c, 0xee, 0xfc, 0x5b, 0x03, 0x62, 0x2d, 0xca, - 0x8c, 0x16, 0x4f, 0x85, 0xf1, 0xee, 0xa0, 0x69, 0x16, 0x51, 0x61, 0xbc, 0x5f, 0x5f, 0x31, 0xde, - 0x6a, 0xe8, 0x1a, 0x90, 0xd9, 0xcf, 0x66, 0x73, 0xfe, 0x84, 0xfe, 0x4b, 0xac, 0x3d, 0xda, 0x4b, - 0xf8, 0x6c, 0x9c, 0x68, 0x8d, 0xd2, 0x90, 0x1a, 0xfd, 0x1e, 0x8e, 0x5e, 0x54, 0x4c, 0xf1, 0x71, - 0x22, 0x74, 0x6c, 0x48, 0xdd, 0x1a, 0xf3, 0x6b, 0x92, 0x5b, 0xe4, 0x4a, 0x7a, 0xa4, 0xe1, 0x0c, - 0xa1, 0xf7, 0xac, 0x39, 0xe3, 0x73, 0x4a, 0xa0, 0x11, 0x09, 0x39, 0xa8, 0x0d, 0xeb, 0xa7, 0x1d, - 0xd7, 0xfe, 0x3a, 0x3f, 0xc1, 0xf6, 0xb2, 0xaf, 0x45, 0x37, 0x0e, 0xa0, 0xa3, 0xe4, 0xcc, 0x4b, - 0x1d, 0x96, 0xb6, 0xa4, 0xed, 0xb6, 0x95, 0xcc, 0x1c, 0xe7, 0x5c, 0xc0, 0xd6, 0x32, 0xc2, 0x26, - 0x7d, 0x0b, 0x10, 0x3d, 0x03, 0xf9, 0xdb, 0x5d, 0x42, 0x68, 0x1f, 0x36, 0x62, 0xc3, 0x4c, 0xf6, - 0xd8, 0xf6, 0xdc, 0x6c, 0xe1, 0x8c, 0x60, 0x77, 0x99, 0xe6, 0xd6, 0x42, 0x45, 0xf5, 0x67, 0x7d, - 0xad, 0xac, 0xef, 0x03, 0x5d, 0xd1, 0xdb, 0x61, 0xfe, 0x55, 0x03, 0xf8, 0xed, 0x7c, 0xaa, 0xbc, - 0xec, 0xbd, 0xee, 0xc3, 0x86, 0x87, 0x91, 0xf1, 0xd3, 0x13, 0x6e, 0xb9, 0xd9, 0x82, 0x0e, 0xa1, - 0xfb, 0x49, 0xc8, 0x7b, 0xd4, 0x91, 0x16, 0xd2, 0x0c, 0xea, 0x29, 0x57, 0x86, 0xec, 0x81, 0xb9, - 0x2f, 0x02, 0x6f, 0x26, 0x93, 0x70, 0xd0, 0x48, 0xf9, 0x76, 0x0a, 0x4c, 0x93, 0x90, 0x1e, 0x01, - 0x70, 0x9f, 0x09, 0x39, 0x4b, 0x9f, 0xa6, 0xe6, 0xb0, 0x7e, 0xda, 0x73, 0x3b, 0x29, 0x32, 0xb6, - 0x6f, 0xcc, 0x31, 0x74, 0xa3, 0xd4, 0x6f, 0x38, 0x9b, 0xe3, 0x62, 0xb0, 0x91, 0x6e, 0x1a, 0x72, - 0xe8, 0x3d, 0x2e, 0x6c, 0x7c, 0x94, 0xde, 0x8e, 0x94, 0xdf, 0x4c, 0xf9, 0x4e, 0x54, 0xdc, 0x97, - 0x2f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb2, 0x7d, 0x20, 0xa6, 0x35, 0x07, 0x00, 0x00, +func file_messages_common_proto_rawDescGZIP() []byte { + file_messages_common_proto_rawDescOnce.Do(func() { + file_messages_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_common_proto_rawDescData) + }) + return file_messages_common_proto_rawDescData +} + +var file_messages_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_messages_common_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_messages_common_proto_goTypes = []interface{}{ + (Failure_FailureType)(0), // 0: hw.trezor.messages.common.Failure.FailureType + (ButtonRequest_ButtonRequestType)(0), // 1: hw.trezor.messages.common.ButtonRequest.ButtonRequestType + (PinMatrixRequest_PinMatrixRequestType)(0), // 2: hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequestType + (*Success)(nil), // 3: hw.trezor.messages.common.Success + (*Failure)(nil), // 4: hw.trezor.messages.common.Failure + (*ButtonRequest)(nil), // 5: hw.trezor.messages.common.ButtonRequest + (*ButtonAck)(nil), // 6: hw.trezor.messages.common.ButtonAck + (*PinMatrixRequest)(nil), // 7: hw.trezor.messages.common.PinMatrixRequest + (*PinMatrixAck)(nil), // 8: hw.trezor.messages.common.PinMatrixAck + (*PassphraseRequest)(nil), // 9: hw.trezor.messages.common.PassphraseRequest + (*PassphraseAck)(nil), // 10: hw.trezor.messages.common.PassphraseAck + (*PassphraseStateRequest)(nil), // 11: hw.trezor.messages.common.PassphraseStateRequest + (*PassphraseStateAck)(nil), // 12: hw.trezor.messages.common.PassphraseStateAck + (*HDNodeType)(nil), // 13: hw.trezor.messages.common.HDNodeType +} +var file_messages_common_proto_depIdxs = []int32{ + 0, // 0: hw.trezor.messages.common.Failure.code:type_name -> hw.trezor.messages.common.Failure.FailureType + 1, // 1: hw.trezor.messages.common.ButtonRequest.code:type_name -> hw.trezor.messages.common.ButtonRequest.ButtonRequestType + 2, // 2: hw.trezor.messages.common.PinMatrixRequest.type:type_name -> hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequestType + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_messages_common_proto_init() } +func file_messages_common_proto_init() { + if File_messages_common_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_messages_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Success); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Failure); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ButtonRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ButtonAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinMatrixRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PinMatrixAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseStateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PassphraseStateAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_common_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HDNodeType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_common_proto_rawDesc, + NumEnums: 3, + NumMessages: 11, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_common_proto_goTypes, + DependencyIndexes: file_messages_common_proto_depIdxs, + EnumInfos: file_messages_common_proto_enumTypes, + MessageInfos: file_messages_common_proto_msgTypes, + }.Build() + File_messages_common_proto = out.File + file_messages_common_proto_rawDesc = nil + file_messages_common_proto_goTypes = nil + file_messages_common_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages-common.proto b/accounts/usbwallet/trezor/messages-common.proto index 75a983b0a3..1f524e25d7 100644 --- a/accounts/usbwallet/trezor/messages-common.proto +++ b/accounts/usbwallet/trezor/messages-common.proto @@ -5,6 +5,8 @@ syntax = "proto2"; package hw.trezor.messages.common; +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + /** * Response: Success of the previous request * @end diff --git a/accounts/usbwallet/trezor/messages-ethereum.pb.go b/accounts/usbwallet/trezor/messages-ethereum.pb.go index 230a48279d..a080a1c3fe 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.pb.go +++ b/accounts/usbwallet/trezor/messages-ethereum.pb.go @@ -1,25 +1,28 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages-ethereum.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) // * // Request: Ask device for public key corresponding to address_n path @@ -27,48 +30,56 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // @next EthereumPublicKey // @next Failure type EthereumGetPublicKey struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` // optionally show on display before sending the result } -func (m *EthereumGetPublicKey) Reset() { *m = EthereumGetPublicKey{} } -func (m *EthereumGetPublicKey) String() string { return proto.CompactTextString(m) } -func (*EthereumGetPublicKey) ProtoMessage() {} +func (x *EthereumGetPublicKey) Reset() { + *x = EthereumGetPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumGetPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumGetPublicKey) ProtoMessage() {} + +func (x *EthereumGetPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumGetPublicKey.ProtoReflect.Descriptor instead. func (*EthereumGetPublicKey) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{0} + return file_messages_ethereum_proto_rawDescGZIP(), []int{0} } -func (m *EthereumGetPublicKey) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumGetPublicKey.Unmarshal(m, b) -} -func (m *EthereumGetPublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumGetPublicKey.Marshal(b, m, deterministic) -} -func (m *EthereumGetPublicKey) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumGetPublicKey.Merge(m, src) -} -func (m *EthereumGetPublicKey) XXX_Size() int { - return xxx_messageInfo_EthereumGetPublicKey.Size(m) -} -func (m *EthereumGetPublicKey) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumGetPublicKey.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumGetPublicKey proto.InternalMessageInfo - -func (m *EthereumGetPublicKey) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumGetPublicKey) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumGetPublicKey) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay +func (x *EthereumGetPublicKey) GetShowDisplay() bool { + if x != nil && x.ShowDisplay != nil { + return *x.ShowDisplay } return false } @@ -77,48 +88,56 @@ func (m *EthereumGetPublicKey) GetShowDisplay() bool { // Response: Contains public key derived from device private seed // @end type EthereumPublicKey struct { - Node *HDNodeType `protobuf:"bytes,1,opt,name=node" json:"node,omitempty"` - Xpub *string `protobuf:"bytes,2,opt,name=xpub" json:"xpub,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Node *HDNodeType `protobuf:"bytes,1,opt,name=node" json:"node,omitempty"` // BIP32 public node + Xpub *string `protobuf:"bytes,2,opt,name=xpub" json:"xpub,omitempty"` // serialized form of public node } -func (m *EthereumPublicKey) Reset() { *m = EthereumPublicKey{} } -func (m *EthereumPublicKey) String() string { return proto.CompactTextString(m) } -func (*EthereumPublicKey) ProtoMessage() {} +func (x *EthereumPublicKey) Reset() { + *x = EthereumPublicKey{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumPublicKey) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumPublicKey) ProtoMessage() {} + +func (x *EthereumPublicKey) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumPublicKey.ProtoReflect.Descriptor instead. func (*EthereumPublicKey) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{1} + return file_messages_ethereum_proto_rawDescGZIP(), []int{1} } -func (m *EthereumPublicKey) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumPublicKey.Unmarshal(m, b) -} -func (m *EthereumPublicKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumPublicKey.Marshal(b, m, deterministic) -} -func (m *EthereumPublicKey) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumPublicKey.Merge(m, src) -} -func (m *EthereumPublicKey) XXX_Size() int { - return xxx_messageInfo_EthereumPublicKey.Size(m) -} -func (m *EthereumPublicKey) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumPublicKey.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumPublicKey proto.InternalMessageInfo - -func (m *EthereumPublicKey) GetNode() *HDNodeType { - if m != nil { - return m.Node +func (x *EthereumPublicKey) GetNode() *HDNodeType { + if x != nil { + return x.Node } return nil } -func (m *EthereumPublicKey) GetXpub() string { - if m != nil && m.Xpub != nil { - return *m.Xpub +func (x *EthereumPublicKey) GetXpub() string { + if x != nil && x.Xpub != nil { + return *x.Xpub } return "" } @@ -129,48 +148,56 @@ func (m *EthereumPublicKey) GetXpub() string { // @next EthereumAddress // @next Failure type EthereumGetAddress struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + ShowDisplay *bool `protobuf:"varint,2,opt,name=show_display,json=showDisplay" json:"show_display,omitempty"` // optionally show on display before sending the result } -func (m *EthereumGetAddress) Reset() { *m = EthereumGetAddress{} } -func (m *EthereumGetAddress) String() string { return proto.CompactTextString(m) } -func (*EthereumGetAddress) ProtoMessage() {} +func (x *EthereumGetAddress) Reset() { + *x = EthereumGetAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumGetAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumGetAddress) ProtoMessage() {} + +func (x *EthereumGetAddress) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumGetAddress.ProtoReflect.Descriptor instead. func (*EthereumGetAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{2} + return file_messages_ethereum_proto_rawDescGZIP(), []int{2} } -func (m *EthereumGetAddress) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumGetAddress.Unmarshal(m, b) -} -func (m *EthereumGetAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumGetAddress.Marshal(b, m, deterministic) -} -func (m *EthereumGetAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumGetAddress.Merge(m, src) -} -func (m *EthereumGetAddress) XXX_Size() int { - return xxx_messageInfo_EthereumGetAddress.Size(m) -} -func (m *EthereumGetAddress) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumGetAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumGetAddress proto.InternalMessageInfo - -func (m *EthereumGetAddress) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumGetAddress) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumGetAddress) GetShowDisplay() bool { - if m != nil && m.ShowDisplay != nil { - return *m.ShowDisplay +func (x *EthereumGetAddress) GetShowDisplay() bool { + if x != nil && x.ShowDisplay != nil { + return *x.ShowDisplay } return false } @@ -179,48 +206,56 @@ func (m *EthereumGetAddress) GetShowDisplay() bool { // Response: Contains an Ethereum address derived from device private seed // @end type EthereumAddress struct { - AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` - AddressHex *string `protobuf:"bytes,2,opt,name=addressHex" json:"addressHex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` // Ethereum address as 20 bytes (legacy firmwares) + AddressHex *string `protobuf:"bytes,2,opt,name=addressHex" json:"addressHex,omitempty"` // Ethereum address as hex string (newer firmwares) } -func (m *EthereumAddress) Reset() { *m = EthereumAddress{} } -func (m *EthereumAddress) String() string { return proto.CompactTextString(m) } -func (*EthereumAddress) ProtoMessage() {} +func (x *EthereumAddress) Reset() { + *x = EthereumAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumAddress) ProtoMessage() {} + +func (x *EthereumAddress) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumAddress.ProtoReflect.Descriptor instead. func (*EthereumAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{3} + return file_messages_ethereum_proto_rawDescGZIP(), []int{3} } -func (m *EthereumAddress) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumAddress.Unmarshal(m, b) -} -func (m *EthereumAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumAddress.Marshal(b, m, deterministic) -} -func (m *EthereumAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumAddress.Merge(m, src) -} -func (m *EthereumAddress) XXX_Size() int { - return xxx_messageInfo_EthereumAddress.Size(m) -} -func (m *EthereumAddress) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumAddress proto.InternalMessageInfo - -func (m *EthereumAddress) GetAddressBin() []byte { - if m != nil { - return m.AddressBin +func (x *EthereumAddress) GetAddressBin() []byte { + if x != nil { + return x.AddressBin } return nil } -func (m *EthereumAddress) GetAddressHex() string { - if m != nil && m.AddressHex != nil { - return *m.AddressHex +func (x *EthereumAddress) GetAddressHex() string { + if x != nil && x.AddressHex != nil { + return *x.AddressHex } return "" } @@ -233,120 +268,128 @@ func (m *EthereumAddress) GetAddressHex() string { // @next EthereumTxRequest // @next Failure type EthereumSignTx struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` - GasPrice []byte `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice" json:"gas_price,omitempty"` - GasLimit []byte `protobuf:"bytes,4,opt,name=gas_limit,json=gasLimit" json:"gas_limit,omitempty"` - ToBin []byte `protobuf:"bytes,5,opt,name=toBin" json:"toBin,omitempty"` - ToHex *string `protobuf:"bytes,11,opt,name=toHex" json:"toHex,omitempty"` - Value []byte `protobuf:"bytes,6,opt,name=value" json:"value,omitempty"` - DataInitialChunk []byte `protobuf:"bytes,7,opt,name=data_initial_chunk,json=dataInitialChunk" json:"data_initial_chunk,omitempty"` - DataLength *uint32 `protobuf:"varint,8,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` - ChainId *uint32 `protobuf:"varint,9,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"` - TxType *uint32 `protobuf:"varint,10,opt,name=tx_type,json=txType" json:"tx_type,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + Nonce []byte `protobuf:"bytes,2,opt,name=nonce" json:"nonce,omitempty"` // <=256 bit unsigned big endian + GasPrice []byte `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice" json:"gas_price,omitempty"` // <=256 bit unsigned big endian (in wei) + GasLimit []byte `protobuf:"bytes,4,opt,name=gas_limit,json=gasLimit" json:"gas_limit,omitempty"` // <=256 bit unsigned big endian + ToBin []byte `protobuf:"bytes,5,opt,name=toBin" json:"toBin,omitempty"` // recipient address (20 bytes, legacy firmware) + ToHex *string `protobuf:"bytes,11,opt,name=toHex" json:"toHex,omitempty"` // recipient address (hex string, newer firmware) + Value []byte `protobuf:"bytes,6,opt,name=value" json:"value,omitempty"` // <=256 bit unsigned big endian (in wei) + DataInitialChunk []byte `protobuf:"bytes,7,opt,name=data_initial_chunk,json=dataInitialChunk" json:"data_initial_chunk,omitempty"` // The initial data chunk (<= 1024 bytes) + DataLength *uint32 `protobuf:"varint,8,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` // Length of transaction payload + ChainId *uint32 `protobuf:"varint,9,opt,name=chain_id,json=chainId" json:"chain_id,omitempty"` // Chain Id for EIP 155 + TxType *uint32 `protobuf:"varint,10,opt,name=tx_type,json=txType" json:"tx_type,omitempty"` // (only for Wanchain) } -func (m *EthereumSignTx) Reset() { *m = EthereumSignTx{} } -func (m *EthereumSignTx) String() string { return proto.CompactTextString(m) } -func (*EthereumSignTx) ProtoMessage() {} +func (x *EthereumSignTx) Reset() { + *x = EthereumSignTx{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumSignTx) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumSignTx) ProtoMessage() {} + +func (x *EthereumSignTx) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumSignTx.ProtoReflect.Descriptor instead. func (*EthereumSignTx) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{4} + return file_messages_ethereum_proto_rawDescGZIP(), []int{4} } -func (m *EthereumSignTx) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumSignTx.Unmarshal(m, b) -} -func (m *EthereumSignTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumSignTx.Marshal(b, m, deterministic) -} -func (m *EthereumSignTx) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumSignTx.Merge(m, src) -} -func (m *EthereumSignTx) XXX_Size() int { - return xxx_messageInfo_EthereumSignTx.Size(m) -} -func (m *EthereumSignTx) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumSignTx.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumSignTx proto.InternalMessageInfo - -func (m *EthereumSignTx) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumSignTx) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumSignTx) GetNonce() []byte { - if m != nil { - return m.Nonce +func (x *EthereumSignTx) GetNonce() []byte { + if x != nil { + return x.Nonce } return nil } -func (m *EthereumSignTx) GetGasPrice() []byte { - if m != nil { - return m.GasPrice +func (x *EthereumSignTx) GetGasPrice() []byte { + if x != nil { + return x.GasPrice } return nil } -func (m *EthereumSignTx) GetGasLimit() []byte { - if m != nil { - return m.GasLimit +func (x *EthereumSignTx) GetGasLimit() []byte { + if x != nil { + return x.GasLimit } return nil } -func (m *EthereumSignTx) GetToBin() []byte { - if m != nil { - return m.ToBin +func (x *EthereumSignTx) GetToBin() []byte { + if x != nil { + return x.ToBin } return nil } -func (m *EthereumSignTx) GetToHex() string { - if m != nil && m.ToHex != nil { - return *m.ToHex +func (x *EthereumSignTx) GetToHex() string { + if x != nil && x.ToHex != nil { + return *x.ToHex } return "" } -func (m *EthereumSignTx) GetValue() []byte { - if m != nil { - return m.Value +func (x *EthereumSignTx) GetValue() []byte { + if x != nil { + return x.Value } return nil } -func (m *EthereumSignTx) GetDataInitialChunk() []byte { - if m != nil { - return m.DataInitialChunk +func (x *EthereumSignTx) GetDataInitialChunk() []byte { + if x != nil { + return x.DataInitialChunk } return nil } -func (m *EthereumSignTx) GetDataLength() uint32 { - if m != nil && m.DataLength != nil { - return *m.DataLength +func (x *EthereumSignTx) GetDataLength() uint32 { + if x != nil && x.DataLength != nil { + return *x.DataLength } return 0 } -func (m *EthereumSignTx) GetChainId() uint32 { - if m != nil && m.ChainId != nil { - return *m.ChainId +func (x *EthereumSignTx) GetChainId() uint32 { + if x != nil && x.ChainId != nil { + return *x.ChainId } return 0 } -func (m *EthereumSignTx) GetTxType() uint32 { - if m != nil && m.TxType != nil { - return *m.TxType +func (x *EthereumSignTx) GetTxType() uint32 { + if x != nil && x.TxType != nil { + return *x.TxType } return 0 } @@ -358,64 +401,72 @@ func (m *EthereumSignTx) GetTxType() uint32 { // @end // @next EthereumTxAck type EthereumTxRequest struct { - DataLength *uint32 `protobuf:"varint,1,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` - SignatureV *uint32 `protobuf:"varint,2,opt,name=signature_v,json=signatureV" json:"signature_v,omitempty"` - SignatureR []byte `protobuf:"bytes,3,opt,name=signature_r,json=signatureR" json:"signature_r,omitempty"` - SignatureS []byte `protobuf:"bytes,4,opt,name=signature_s,json=signatureS" json:"signature_s,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataLength *uint32 `protobuf:"varint,1,opt,name=data_length,json=dataLength" json:"data_length,omitempty"` // Number of bytes being requested (<= 1024) + SignatureV *uint32 `protobuf:"varint,2,opt,name=signature_v,json=signatureV" json:"signature_v,omitempty"` // Computed signature (recovery parameter, limited to 27 or 28) + SignatureR []byte `protobuf:"bytes,3,opt,name=signature_r,json=signatureR" json:"signature_r,omitempty"` // Computed signature R component (256 bit) + SignatureS []byte `protobuf:"bytes,4,opt,name=signature_s,json=signatureS" json:"signature_s,omitempty"` // Computed signature S component (256 bit) } -func (m *EthereumTxRequest) Reset() { *m = EthereumTxRequest{} } -func (m *EthereumTxRequest) String() string { return proto.CompactTextString(m) } -func (*EthereumTxRequest) ProtoMessage() {} +func (x *EthereumTxRequest) Reset() { + *x = EthereumTxRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumTxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumTxRequest) ProtoMessage() {} + +func (x *EthereumTxRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumTxRequest.ProtoReflect.Descriptor instead. func (*EthereumTxRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{5} + return file_messages_ethereum_proto_rawDescGZIP(), []int{5} } -func (m *EthereumTxRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumTxRequest.Unmarshal(m, b) -} -func (m *EthereumTxRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumTxRequest.Marshal(b, m, deterministic) -} -func (m *EthereumTxRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumTxRequest.Merge(m, src) -} -func (m *EthereumTxRequest) XXX_Size() int { - return xxx_messageInfo_EthereumTxRequest.Size(m) -} -func (m *EthereumTxRequest) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumTxRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumTxRequest proto.InternalMessageInfo - -func (m *EthereumTxRequest) GetDataLength() uint32 { - if m != nil && m.DataLength != nil { - return *m.DataLength +func (x *EthereumTxRequest) GetDataLength() uint32 { + if x != nil && x.DataLength != nil { + return *x.DataLength } return 0 } -func (m *EthereumTxRequest) GetSignatureV() uint32 { - if m != nil && m.SignatureV != nil { - return *m.SignatureV +func (x *EthereumTxRequest) GetSignatureV() uint32 { + if x != nil && x.SignatureV != nil { + return *x.SignatureV } return 0 } -func (m *EthereumTxRequest) GetSignatureR() []byte { - if m != nil { - return m.SignatureR +func (x *EthereumTxRequest) GetSignatureR() []byte { + if x != nil { + return x.SignatureR } return nil } -func (m *EthereumTxRequest) GetSignatureS() []byte { - if m != nil { - return m.SignatureS +func (x *EthereumTxRequest) GetSignatureS() []byte { + if x != nil { + return x.SignatureS } return nil } @@ -424,40 +475,48 @@ func (m *EthereumTxRequest) GetSignatureS() []byte { // Request: Transaction payload data. // @next EthereumTxRequest type EthereumTxAck struct { - DataChunk []byte `protobuf:"bytes,1,opt,name=data_chunk,json=dataChunk" json:"data_chunk,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DataChunk []byte `protobuf:"bytes,1,opt,name=data_chunk,json=dataChunk" json:"data_chunk,omitempty"` // Bytes from transaction payload (<= 1024 bytes) } -func (m *EthereumTxAck) Reset() { *m = EthereumTxAck{} } -func (m *EthereumTxAck) String() string { return proto.CompactTextString(m) } -func (*EthereumTxAck) ProtoMessage() {} +func (x *EthereumTxAck) Reset() { + *x = EthereumTxAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumTxAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumTxAck) ProtoMessage() {} + +func (x *EthereumTxAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumTxAck.ProtoReflect.Descriptor instead. func (*EthereumTxAck) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{6} + return file_messages_ethereum_proto_rawDescGZIP(), []int{6} } -func (m *EthereumTxAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumTxAck.Unmarshal(m, b) -} -func (m *EthereumTxAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumTxAck.Marshal(b, m, deterministic) -} -func (m *EthereumTxAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumTxAck.Merge(m, src) -} -func (m *EthereumTxAck) XXX_Size() int { - return xxx_messageInfo_EthereumTxAck.Size(m) -} -func (m *EthereumTxAck) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumTxAck.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumTxAck proto.InternalMessageInfo - -func (m *EthereumTxAck) GetDataChunk() []byte { - if m != nil { - return m.DataChunk +func (x *EthereumTxAck) GetDataChunk() []byte { + if x != nil { + return x.DataChunk } return nil } @@ -468,48 +527,56 @@ func (m *EthereumTxAck) GetDataChunk() []byte { // @next EthereumMessageSignature // @next Failure type EthereumSignMessage struct { - AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` - Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node + Message []byte `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"` // message to be signed } -func (m *EthereumSignMessage) Reset() { *m = EthereumSignMessage{} } -func (m *EthereumSignMessage) String() string { return proto.CompactTextString(m) } -func (*EthereumSignMessage) ProtoMessage() {} +func (x *EthereumSignMessage) Reset() { + *x = EthereumSignMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumSignMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumSignMessage) ProtoMessage() {} + +func (x *EthereumSignMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumSignMessage.ProtoReflect.Descriptor instead. func (*EthereumSignMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{7} + return file_messages_ethereum_proto_rawDescGZIP(), []int{7} } -func (m *EthereumSignMessage) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumSignMessage.Unmarshal(m, b) -} -func (m *EthereumSignMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumSignMessage.Marshal(b, m, deterministic) -} -func (m *EthereumSignMessage) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumSignMessage.Merge(m, src) -} -func (m *EthereumSignMessage) XXX_Size() int { - return xxx_messageInfo_EthereumSignMessage.Size(m) -} -func (m *EthereumSignMessage) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumSignMessage.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumSignMessage proto.InternalMessageInfo - -func (m *EthereumSignMessage) GetAddressN() []uint32 { - if m != nil { - return m.AddressN +func (x *EthereumSignMessage) GetAddressN() []uint32 { + if x != nil { + return x.AddressN } return nil } -func (m *EthereumSignMessage) GetMessage() []byte { - if m != nil { - return m.Message +func (x *EthereumSignMessage) GetMessage() []byte { + if x != nil { + return x.Message } return nil } @@ -518,56 +585,64 @@ func (m *EthereumSignMessage) GetMessage() []byte { // Response: Signed message // @end type EthereumMessageSignature struct { - AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - AddressHex *string `protobuf:"bytes,3,opt,name=addressHex" json:"addressHex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` // address used to sign the message (20 bytes, legacy firmware) + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` // signature of the message + AddressHex *string `protobuf:"bytes,3,opt,name=addressHex" json:"addressHex,omitempty"` // address used to sign the message (hex string, newer firmware) } -func (m *EthereumMessageSignature) Reset() { *m = EthereumMessageSignature{} } -func (m *EthereumMessageSignature) String() string { return proto.CompactTextString(m) } -func (*EthereumMessageSignature) ProtoMessage() {} +func (x *EthereumMessageSignature) Reset() { + *x = EthereumMessageSignature{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumMessageSignature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumMessageSignature) ProtoMessage() {} + +func (x *EthereumMessageSignature) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumMessageSignature.ProtoReflect.Descriptor instead. func (*EthereumMessageSignature) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{8} + return file_messages_ethereum_proto_rawDescGZIP(), []int{8} } -func (m *EthereumMessageSignature) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumMessageSignature.Unmarshal(m, b) -} -func (m *EthereumMessageSignature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumMessageSignature.Marshal(b, m, deterministic) -} -func (m *EthereumMessageSignature) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumMessageSignature.Merge(m, src) -} -func (m *EthereumMessageSignature) XXX_Size() int { - return xxx_messageInfo_EthereumMessageSignature.Size(m) -} -func (m *EthereumMessageSignature) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumMessageSignature.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumMessageSignature proto.InternalMessageInfo - -func (m *EthereumMessageSignature) GetAddressBin() []byte { - if m != nil { - return m.AddressBin +func (x *EthereumMessageSignature) GetAddressBin() []byte { + if x != nil { + return x.AddressBin } return nil } -func (m *EthereumMessageSignature) GetSignature() []byte { - if m != nil { - return m.Signature +func (x *EthereumMessageSignature) GetSignature() []byte { + if x != nil { + return x.Signature } return nil } -func (m *EthereumMessageSignature) GetAddressHex() string { - if m != nil && m.AddressHex != nil { - return *m.AddressHex +func (x *EthereumMessageSignature) GetAddressHex() string { + if x != nil && x.AddressHex != nil { + return *x.AddressHex } return "" } @@ -578,121 +653,350 @@ func (m *EthereumMessageSignature) GetAddressHex() string { // @next Success // @next Failure type EthereumVerifyMessage struct { - AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` - AddressHex *string `protobuf:"bytes,4,opt,name=addressHex" json:"addressHex,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AddressBin []byte `protobuf:"bytes,1,opt,name=addressBin" json:"addressBin,omitempty"` // address to verify (20 bytes, legacy firmware) + Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` // signature to verify + Message []byte `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"` // message to verify + AddressHex *string `protobuf:"bytes,4,opt,name=addressHex" json:"addressHex,omitempty"` // address to verify (hex string, newer firmware) } -func (m *EthereumVerifyMessage) Reset() { *m = EthereumVerifyMessage{} } -func (m *EthereumVerifyMessage) String() string { return proto.CompactTextString(m) } -func (*EthereumVerifyMessage) ProtoMessage() {} +func (x *EthereumVerifyMessage) Reset() { + *x = EthereumVerifyMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_ethereum_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EthereumVerifyMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EthereumVerifyMessage) ProtoMessage() {} + +func (x *EthereumVerifyMessage) ProtoReflect() protoreflect.Message { + mi := &file_messages_ethereum_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EthereumVerifyMessage.ProtoReflect.Descriptor instead. func (*EthereumVerifyMessage) Descriptor() ([]byte, []int) { - return fileDescriptor_cb33f46ba915f15c, []int{9} + return file_messages_ethereum_proto_rawDescGZIP(), []int{9} } -func (m *EthereumVerifyMessage) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EthereumVerifyMessage.Unmarshal(m, b) -} -func (m *EthereumVerifyMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EthereumVerifyMessage.Marshal(b, m, deterministic) -} -func (m *EthereumVerifyMessage) XXX_Merge(src proto.Message) { - xxx_messageInfo_EthereumVerifyMessage.Merge(m, src) -} -func (m *EthereumVerifyMessage) XXX_Size() int { - return xxx_messageInfo_EthereumVerifyMessage.Size(m) -} -func (m *EthereumVerifyMessage) XXX_DiscardUnknown() { - xxx_messageInfo_EthereumVerifyMessage.DiscardUnknown(m) -} - -var xxx_messageInfo_EthereumVerifyMessage proto.InternalMessageInfo - -func (m *EthereumVerifyMessage) GetAddressBin() []byte { - if m != nil { - return m.AddressBin +func (x *EthereumVerifyMessage) GetAddressBin() []byte { + if x != nil { + return x.AddressBin } return nil } -func (m *EthereumVerifyMessage) GetSignature() []byte { - if m != nil { - return m.Signature +func (x *EthereumVerifyMessage) GetSignature() []byte { + if x != nil { + return x.Signature } return nil } -func (m *EthereumVerifyMessage) GetMessage() []byte { - if m != nil { - return m.Message +func (x *EthereumVerifyMessage) GetMessage() []byte { + if x != nil { + return x.Message } return nil } -func (m *EthereumVerifyMessage) GetAddressHex() string { - if m != nil && m.AddressHex != nil { - return *m.AddressHex +func (x *EthereumVerifyMessage) GetAddressHex() string { + if x != nil && x.AddressHex != nil { + return *x.AddressHex } return "" } -func init() { - proto.RegisterType((*EthereumGetPublicKey)(nil), "hw.trezor.messages.ethereum.EthereumGetPublicKey") - proto.RegisterType((*EthereumPublicKey)(nil), "hw.trezor.messages.ethereum.EthereumPublicKey") - proto.RegisterType((*EthereumGetAddress)(nil), "hw.trezor.messages.ethereum.EthereumGetAddress") - proto.RegisterType((*EthereumAddress)(nil), "hw.trezor.messages.ethereum.EthereumAddress") - proto.RegisterType((*EthereumSignTx)(nil), "hw.trezor.messages.ethereum.EthereumSignTx") - proto.RegisterType((*EthereumTxRequest)(nil), "hw.trezor.messages.ethereum.EthereumTxRequest") - proto.RegisterType((*EthereumTxAck)(nil), "hw.trezor.messages.ethereum.EthereumTxAck") - proto.RegisterType((*EthereumSignMessage)(nil), "hw.trezor.messages.ethereum.EthereumSignMessage") - proto.RegisterType((*EthereumMessageSignature)(nil), "hw.trezor.messages.ethereum.EthereumMessageSignature") - proto.RegisterType((*EthereumVerifyMessage)(nil), "hw.trezor.messages.ethereum.EthereumVerifyMessage") +var File_messages_ethereum_proto protoreflect.FileDescriptor + +var file_messages_ethereum_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x75, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x68, 0x77, 0x2e, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x65, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x1a, 0x15, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, + 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x56, 0x0a, + 0x14, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4e, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, + 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x22, 0x62, 0x0a, 0x11, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, + 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x04, 0x6e, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x48, 0x44, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x70, 0x75, 0x62, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x78, 0x70, 0x75, 0x62, 0x22, 0x54, 0x0a, 0x12, 0x45, 0x74, 0x68, + 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, + 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x4e, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0b, 0x73, 0x68, 0x6f, 0x77, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x22, + 0x51, 0x0a, 0x0f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, + 0x69, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, + 0x65, 0x78, 0x22, 0xc2, 0x02, 0x0a, 0x0e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x53, + 0x69, 0x67, 0x6e, 0x54, 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x4e, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, + 0x70, 0x72, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x61, 0x73, + 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x42, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x42, 0x69, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x48, 0x65, + 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x48, 0x65, 0x78, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x69, + 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x17, + 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x74, 0x78, 0x54, 0x79, 0x70, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x11, 0x45, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, + 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1f, + 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x76, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x56, 0x12, + 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x53, 0x22, 0x2e, 0x0a, 0x0d, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x41, + 0x63, 0x6b, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x22, 0x4c, 0x0a, 0x13, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x53, 0x69, 0x67, + 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x4e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x78, 0x0a, 0x18, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x22, 0x8f, 0x01, 0x0a, 0x15, 0x45, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x42, 0x69, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x42, 0x69, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x65, 0x78, 0x42, 0x77, 0x0a, 0x23, 0x63, + 0x6f, 0x6d, 0x2e, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x74, + 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x42, 0x15, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, + 0x6f, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, } -func init() { proto.RegisterFile("messages-ethereum.proto", fileDescriptor_cb33f46ba915f15c) } +var ( + file_messages_ethereum_proto_rawDescOnce sync.Once + file_messages_ethereum_proto_rawDescData = file_messages_ethereum_proto_rawDesc +) -var fileDescriptor_cb33f46ba915f15c = []byte{ - // 593 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0x95, 0x9b, 0xb4, 0x49, 0x26, 0x0d, 0x1f, 0xa6, 0x55, 0x17, 0x0a, 0x34, 0x18, 0x21, 0xe5, - 0x00, 0x3e, 0x70, 0x43, 0xe2, 0xd2, 0x52, 0x44, 0x2b, 0x4a, 0x55, 0xdc, 0xa8, 0x57, 0x6b, 0x63, - 0x6f, 0xe3, 0x55, 0x9d, 0xdd, 0xe0, 0x5d, 0xb7, 0x0e, 0x7f, 0x82, 0x23, 0xff, 0x87, 0x5f, 0x86, - 0xf6, 0x2b, 0x71, 0x52, 0x54, 0x0e, 0xbd, 0x65, 0xde, 0xbc, 0x7d, 0xf3, 0x66, 0xf4, 0x62, 0xd8, - 0x99, 0x10, 0x21, 0xf0, 0x98, 0x88, 0x77, 0x44, 0x66, 0xa4, 0x20, 0xe5, 0x24, 0x9c, 0x16, 0x5c, - 0x72, 0x7f, 0x37, 0xbb, 0x09, 0x65, 0x41, 0x7e, 0xf2, 0x22, 0x74, 0x94, 0xd0, 0x51, 0x9e, 0x6d, - 0xcf, 0x5f, 0x25, 0x7c, 0x32, 0xe1, 0xcc, 0xbc, 0x09, 0x2e, 0x60, 0xeb, 0xb3, 0xa5, 0x7c, 0x21, - 0xf2, 0xac, 0x1c, 0xe5, 0x34, 0xf9, 0x4a, 0x66, 0xfe, 0x2e, 0x74, 0x70, 0x9a, 0x16, 0x44, 0x88, - 0x98, 0x21, 0xaf, 0xdf, 0x18, 0xf4, 0xa2, 0xb6, 0x05, 0x4e, 0xfd, 0x57, 0xb0, 0x29, 0x32, 0x7e, - 0x13, 0xa7, 0x54, 0x4c, 0x73, 0x3c, 0x43, 0x6b, 0x7d, 0x6f, 0xd0, 0x8e, 0xba, 0x0a, 0x3b, 0x34, - 0x50, 0x30, 0x82, 0xc7, 0x4e, 0x77, 0x21, 0xfa, 0x01, 0x9a, 0x8c, 0xa7, 0x04, 0x79, 0x7d, 0x6f, - 0xd0, 0x7d, 0xff, 0x26, 0xfc, 0x87, 0x5f, 0x6b, 0xee, 0xe8, 0xf0, 0x94, 0xa7, 0x64, 0x38, 0x9b, - 0x92, 0x48, 0x3f, 0xf1, 0x7d, 0x68, 0x56, 0xd3, 0x72, 0xa4, 0x47, 0x75, 0x22, 0xfd, 0x3b, 0x18, - 0x82, 0x5f, 0xf3, 0xbe, 0x6f, 0xdc, 0xdd, 0xdb, 0xf9, 0x77, 0x78, 0xe8, 0x54, 0x9d, 0xe4, 0x4b, - 0x00, 0xab, 0x70, 0x40, 0x99, 0x76, 0xbf, 0x19, 0xd5, 0x90, 0x5a, 0xff, 0x88, 0x54, 0xd6, 0x62, - 0x0d, 0x09, 0xfe, 0xac, 0xc1, 0x03, 0xa7, 0x79, 0x4e, 0xc7, 0x6c, 0x58, 0xdd, 0xed, 0x72, 0x0b, - 0xd6, 0x19, 0x67, 0x09, 0xd1, 0x52, 0x9b, 0x91, 0x29, 0xd4, 0x93, 0x31, 0x16, 0xf1, 0xb4, 0xa0, - 0x09, 0x41, 0x0d, 0xdd, 0x69, 0x8f, 0xb1, 0x38, 0x53, 0xb5, 0x6b, 0xe6, 0x74, 0x42, 0x25, 0x6a, - 0xce, 0x9b, 0x27, 0xaa, 0x56, 0x7a, 0x92, 0x2b, 0xeb, 0xeb, 0x46, 0x4f, 0x17, 0x06, 0x55, 0x86, - 0xbb, 0xda, 0xb0, 0x29, 0x14, 0x7a, 0x8d, 0xf3, 0x92, 0xa0, 0x0d, 0xc3, 0xd5, 0x85, 0xff, 0x16, - 0xfc, 0x14, 0x4b, 0x1c, 0x53, 0x46, 0x25, 0xc5, 0x79, 0x9c, 0x64, 0x25, 0xbb, 0x42, 0x2d, 0x4d, - 0x79, 0xa4, 0x3a, 0xc7, 0xa6, 0xf1, 0x49, 0xe1, 0xfe, 0x1e, 0x74, 0x35, 0x3b, 0x27, 0x6c, 0x2c, - 0x33, 0xd4, 0xee, 0x7b, 0x83, 0x5e, 0x04, 0x0a, 0x3a, 0xd1, 0x88, 0xff, 0x14, 0xda, 0x49, 0x86, - 0x29, 0x8b, 0x69, 0x8a, 0x3a, 0xba, 0xdb, 0xd2, 0xf5, 0x71, 0xea, 0xef, 0x40, 0x4b, 0x56, 0xb1, - 0x9c, 0x4d, 0x09, 0x02, 0xdd, 0xd9, 0x90, 0x95, 0xca, 0x41, 0xf0, 0xdb, 0x5b, 0x44, 0x6a, 0x58, - 0x45, 0xe4, 0x47, 0x49, 0x84, 0x5c, 0x1d, 0xe5, 0xdd, 0x1a, 0xb5, 0x07, 0x5d, 0x41, 0xc7, 0x0c, - 0xcb, 0xb2, 0x20, 0xf1, 0xb5, 0xbe, 0x68, 0x2f, 0x82, 0x39, 0x74, 0xb1, 0x4c, 0x28, 0xec, 0x61, - 0x17, 0x84, 0x68, 0x99, 0x20, 0xec, 0x71, 0x17, 0x84, 0xf3, 0x20, 0x84, 0xde, 0xc2, 0xd8, 0x7e, - 0x72, 0xe5, 0xbf, 0x00, 0xed, 0xc0, 0x5e, 0xc9, 0xe4, 0xa5, 0xa3, 0x10, 0x7d, 0x9e, 0xe0, 0x04, - 0x9e, 0xd4, 0xd3, 0xf0, 0xcd, 0x64, 0xff, 0xee, 0x48, 0x20, 0x68, 0xd9, 0xff, 0x88, 0x0d, 0x85, - 0x2b, 0x83, 0x0a, 0x90, 0x53, 0xb3, 0x4a, 0xe7, 0xce, 0xda, 0x7f, 0x83, 0xfb, 0x1c, 0x3a, 0xf3, - 0x3d, 0xac, 0xee, 0x02, 0x58, 0x89, 0x75, 0xe3, 0x56, 0xac, 0x7f, 0x79, 0xb0, 0xed, 0x46, 0x5f, - 0x90, 0x82, 0x5e, 0xce, 0xdc, 0x2a, 0xf7, 0x9b, 0x5b, 0xdb, 0xb5, 0xb1, 0xb4, 0xeb, 0x8a, 0xa3, - 0xe6, 0xaa, 0xa3, 0x83, 0x8f, 0xf0, 0x3a, 0xe1, 0x93, 0x50, 0x60, 0xc9, 0x45, 0x46, 0x73, 0x3c, - 0x12, 0xee, 0x03, 0x93, 0xd3, 0x91, 0xf9, 0xe2, 0x8d, 0xca, 0xcb, 0x83, 0xed, 0xa1, 0x06, 0xad, - 0x5b, 0xb7, 0xc2, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8a, 0xce, 0x81, 0xc8, 0x59, 0x05, 0x00, - 0x00, +func file_messages_ethereum_proto_rawDescGZIP() []byte { + file_messages_ethereum_proto_rawDescOnce.Do(func() { + file_messages_ethereum_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_ethereum_proto_rawDescData) + }) + return file_messages_ethereum_proto_rawDescData +} + +var file_messages_ethereum_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_messages_ethereum_proto_goTypes = []interface{}{ + (*EthereumGetPublicKey)(nil), // 0: hw.trezor.messages.ethereum.EthereumGetPublicKey + (*EthereumPublicKey)(nil), // 1: hw.trezor.messages.ethereum.EthereumPublicKey + (*EthereumGetAddress)(nil), // 2: hw.trezor.messages.ethereum.EthereumGetAddress + (*EthereumAddress)(nil), // 3: hw.trezor.messages.ethereum.EthereumAddress + (*EthereumSignTx)(nil), // 4: hw.trezor.messages.ethereum.EthereumSignTx + (*EthereumTxRequest)(nil), // 5: hw.trezor.messages.ethereum.EthereumTxRequest + (*EthereumTxAck)(nil), // 6: hw.trezor.messages.ethereum.EthereumTxAck + (*EthereumSignMessage)(nil), // 7: hw.trezor.messages.ethereum.EthereumSignMessage + (*EthereumMessageSignature)(nil), // 8: hw.trezor.messages.ethereum.EthereumMessageSignature + (*EthereumVerifyMessage)(nil), // 9: hw.trezor.messages.ethereum.EthereumVerifyMessage + (*HDNodeType)(nil), // 10: hw.trezor.messages.common.HDNodeType +} +var file_messages_ethereum_proto_depIdxs = []int32{ + 10, // 0: hw.trezor.messages.ethereum.EthereumPublicKey.node:type_name -> hw.trezor.messages.common.HDNodeType + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_messages_ethereum_proto_init() } +func file_messages_ethereum_proto_init() { + if File_messages_ethereum_proto != nil { + return + } + file_messages_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_messages_ethereum_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumGetPublicKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumPublicKey); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumGetAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumSignTx); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumTxRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumTxAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumSignMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumMessageSignature); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_ethereum_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EthereumVerifyMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_ethereum_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_ethereum_proto_goTypes, + DependencyIndexes: file_messages_ethereum_proto_depIdxs, + MessageInfos: file_messages_ethereum_proto_msgTypes, + }.Build() + File_messages_ethereum_proto = out.File + file_messages_ethereum_proto_rawDesc = nil + file_messages_ethereum_proto_goTypes = nil + file_messages_ethereum_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages-ethereum.proto b/accounts/usbwallet/trezor/messages-ethereum.proto index 096bed2e4a..8e1150abb6 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.proto +++ b/accounts/usbwallet/trezor/messages-ethereum.proto @@ -5,6 +5,8 @@ syntax = "proto2"; package hw.trezor.messages.ethereum; +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + // Sugar for easier handling in Java option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessageEthereum"; diff --git a/accounts/usbwallet/trezor/messages-management.pb.go b/accounts/usbwallet/trezor/messages-management.pb.go index 91bfca1e3f..6df4cbdc29 100644 --- a/accounts/usbwallet/trezor/messages-management.pb.go +++ b/accounts/usbwallet/trezor/messages-management.pb.go @@ -1,25 +1,28 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages-management.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages-management.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) // * // Structure representing passphrase source @@ -31,17 +34,19 @@ const ( ApplySettings_HOST ApplySettings_PassphraseSourceType = 2 ) -var ApplySettings_PassphraseSourceType_name = map[int32]string{ - 0: "ASK", - 1: "DEVICE", - 2: "HOST", -} - -var ApplySettings_PassphraseSourceType_value = map[string]int32{ - "ASK": 0, - "DEVICE": 1, - "HOST": 2, -} +// Enum value maps for ApplySettings_PassphraseSourceType. +var ( + ApplySettings_PassphraseSourceType_name = map[int32]string{ + 0: "ASK", + 1: "DEVICE", + 2: "HOST", + } + ApplySettings_PassphraseSourceType_value = map[string]int32{ + "ASK": 0, + "DEVICE": 1, + "HOST": 2, + } +) func (x ApplySettings_PassphraseSourceType) Enum() *ApplySettings_PassphraseSourceType { p := new(ApplySettings_PassphraseSourceType) @@ -50,20 +55,34 @@ func (x ApplySettings_PassphraseSourceType) Enum() *ApplySettings_PassphraseSour } func (x ApplySettings_PassphraseSourceType) String() string { - return proto.EnumName(ApplySettings_PassphraseSourceType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *ApplySettings_PassphraseSourceType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(ApplySettings_PassphraseSourceType_value, data, "ApplySettings_PassphraseSourceType") +func (ApplySettings_PassphraseSourceType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_management_proto_enumTypes[0].Descriptor() +} + +func (ApplySettings_PassphraseSourceType) Type() protoreflect.EnumType { + return &file_messages_management_proto_enumTypes[0] +} + +func (x ApplySettings_PassphraseSourceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *ApplySettings_PassphraseSourceType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = ApplySettings_PassphraseSourceType(value) + *x = ApplySettings_PassphraseSourceType(num) return nil } +// Deprecated: Use ApplySettings_PassphraseSourceType.Descriptor instead. func (ApplySettings_PassphraseSourceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{4, 0} + return file_messages_management_proto_rawDescGZIP(), []int{4, 0} } // * @@ -77,19 +96,21 @@ type RecoveryDevice_RecoveryDeviceType int32 const ( // use powers of two when extending this field - RecoveryDevice_RecoveryDeviceType_ScrambledWords RecoveryDevice_RecoveryDeviceType = 0 - RecoveryDevice_RecoveryDeviceType_Matrix RecoveryDevice_RecoveryDeviceType = 1 + RecoveryDevice_RecoveryDeviceType_ScrambledWords RecoveryDevice_RecoveryDeviceType = 0 // words in scrambled order + RecoveryDevice_RecoveryDeviceType_Matrix RecoveryDevice_RecoveryDeviceType = 1 // matrix recovery type ) -var RecoveryDevice_RecoveryDeviceType_name = map[int32]string{ - 0: "RecoveryDeviceType_ScrambledWords", - 1: "RecoveryDeviceType_Matrix", -} - -var RecoveryDevice_RecoveryDeviceType_value = map[string]int32{ - "RecoveryDeviceType_ScrambledWords": 0, - "RecoveryDeviceType_Matrix": 1, -} +// Enum value maps for RecoveryDevice_RecoveryDeviceType. +var ( + RecoveryDevice_RecoveryDeviceType_name = map[int32]string{ + 0: "RecoveryDeviceType_ScrambledWords", + 1: "RecoveryDeviceType_Matrix", + } + RecoveryDevice_RecoveryDeviceType_value = map[string]int32{ + "RecoveryDeviceType_ScrambledWords": 0, + "RecoveryDeviceType_Matrix": 1, + } +) func (x RecoveryDevice_RecoveryDeviceType) Enum() *RecoveryDevice_RecoveryDeviceType { p := new(RecoveryDevice_RecoveryDeviceType) @@ -98,20 +119,34 @@ func (x RecoveryDevice_RecoveryDeviceType) Enum() *RecoveryDevice_RecoveryDevice } func (x RecoveryDevice_RecoveryDeviceType) String() string { - return proto.EnumName(RecoveryDevice_RecoveryDeviceType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *RecoveryDevice_RecoveryDeviceType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(RecoveryDevice_RecoveryDeviceType_value, data, "RecoveryDevice_RecoveryDeviceType") +func (RecoveryDevice_RecoveryDeviceType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_management_proto_enumTypes[1].Descriptor() +} + +func (RecoveryDevice_RecoveryDeviceType) Type() protoreflect.EnumType { + return &file_messages_management_proto_enumTypes[1] +} + +func (x RecoveryDevice_RecoveryDeviceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *RecoveryDevice_RecoveryDeviceType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = RecoveryDevice_RecoveryDeviceType(value) + *x = RecoveryDevice_RecoveryDeviceType(num) return nil } +// Deprecated: Use RecoveryDevice_RecoveryDeviceType.Descriptor instead. func (RecoveryDevice_RecoveryDeviceType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{17, 0} + return file_messages_management_proto_rawDescGZIP(), []int{17, 0} } // * @@ -124,17 +159,19 @@ const ( WordRequest_WordRequestType_Matrix6 WordRequest_WordRequestType = 2 ) -var WordRequest_WordRequestType_name = map[int32]string{ - 0: "WordRequestType_Plain", - 1: "WordRequestType_Matrix9", - 2: "WordRequestType_Matrix6", -} - -var WordRequest_WordRequestType_value = map[string]int32{ - "WordRequestType_Plain": 0, - "WordRequestType_Matrix9": 1, - "WordRequestType_Matrix6": 2, -} +// Enum value maps for WordRequest_WordRequestType. +var ( + WordRequest_WordRequestType_name = map[int32]string{ + 0: "WordRequestType_Plain", + 1: "WordRequestType_Matrix9", + 2: "WordRequestType_Matrix6", + } + WordRequest_WordRequestType_value = map[string]int32{ + "WordRequestType_Plain": 0, + "WordRequestType_Matrix9": 1, + "WordRequestType_Matrix6": 2, + } +) func (x WordRequest_WordRequestType) Enum() *WordRequest_WordRequestType { p := new(WordRequest_WordRequestType) @@ -143,20 +180,34 @@ func (x WordRequest_WordRequestType) Enum() *WordRequest_WordRequestType { } func (x WordRequest_WordRequestType) String() string { - return proto.EnumName(WordRequest_WordRequestType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *WordRequest_WordRequestType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(WordRequest_WordRequestType_value, data, "WordRequest_WordRequestType") +func (WordRequest_WordRequestType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_management_proto_enumTypes[2].Descriptor() +} + +func (WordRequest_WordRequestType) Type() protoreflect.EnumType { + return &file_messages_management_proto_enumTypes[2] +} + +func (x WordRequest_WordRequestType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *WordRequest_WordRequestType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = WordRequest_WordRequestType(value) + *x = WordRequest_WordRequestType(num) return nil } +// Deprecated: Use WordRequest_WordRequestType.Descriptor instead. func (WordRequest_WordRequestType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{18, 0} + return file_messages_management_proto_rawDescGZIP(), []int{18, 0} } // * @@ -164,48 +215,56 @@ func (WordRequest_WordRequestType) EnumDescriptor() ([]byte, []int) { // @start // @next Features type Initialize struct { - State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` - SkipPassphrase *bool `protobuf:"varint,2,opt,name=skip_passphrase,json=skipPassphrase" json:"skip_passphrase,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State []byte `protobuf:"bytes,1,opt,name=state" json:"state,omitempty"` // assumed device state, clear session if set and different + SkipPassphrase *bool `protobuf:"varint,2,opt,name=skip_passphrase,json=skipPassphrase" json:"skip_passphrase,omitempty"` // this session should always assume empty passphrase } -func (m *Initialize) Reset() { *m = Initialize{} } -func (m *Initialize) String() string { return proto.CompactTextString(m) } -func (*Initialize) ProtoMessage() {} +func (x *Initialize) Reset() { + *x = Initialize{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Initialize) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Initialize) ProtoMessage() {} + +func (x *Initialize) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Initialize.ProtoReflect.Descriptor instead. func (*Initialize) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{0} + return file_messages_management_proto_rawDescGZIP(), []int{0} } -func (m *Initialize) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Initialize.Unmarshal(m, b) -} -func (m *Initialize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Initialize.Marshal(b, m, deterministic) -} -func (m *Initialize) XXX_Merge(src proto.Message) { - xxx_messageInfo_Initialize.Merge(m, src) -} -func (m *Initialize) XXX_Size() int { - return xxx_messageInfo_Initialize.Size(m) -} -func (m *Initialize) XXX_DiscardUnknown() { - xxx_messageInfo_Initialize.DiscardUnknown(m) -} - -var xxx_messageInfo_Initialize proto.InternalMessageInfo - -func (m *Initialize) GetState() []byte { - if m != nil { - return m.State +func (x *Initialize) GetState() []byte { + if x != nil { + return x.State } return nil } -func (m *Initialize) GetSkipPassphrase() bool { - if m != nil && m.SkipPassphrase != nil { - return *m.SkipPassphrase +func (x *Initialize) GetSkipPassphrase() bool { + if x != nil && x.SkipPassphrase != nil { + return *x.SkipPassphrase } return false } @@ -215,282 +274,297 @@ func (m *Initialize) GetSkipPassphrase() bool { // @start // @next Features type GetFeatures struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *GetFeatures) Reset() { *m = GetFeatures{} } -func (m *GetFeatures) String() string { return proto.CompactTextString(m) } -func (*GetFeatures) ProtoMessage() {} +func (x *GetFeatures) Reset() { + *x = GetFeatures{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetFeatures) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetFeatures) ProtoMessage() {} + +func (x *GetFeatures) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetFeatures.ProtoReflect.Descriptor instead. func (*GetFeatures) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{1} + return file_messages_management_proto_rawDescGZIP(), []int{1} } -func (m *GetFeatures) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetFeatures.Unmarshal(m, b) -} -func (m *GetFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetFeatures.Marshal(b, m, deterministic) -} -func (m *GetFeatures) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetFeatures.Merge(m, src) -} -func (m *GetFeatures) XXX_Size() int { - return xxx_messageInfo_GetFeatures.Size(m) -} -func (m *GetFeatures) XXX_DiscardUnknown() { - xxx_messageInfo_GetFeatures.DiscardUnknown(m) -} - -var xxx_messageInfo_GetFeatures proto.InternalMessageInfo - // * // Response: Reports various information about the device // @end type Features struct { - Vendor *string `protobuf:"bytes,1,opt,name=vendor" json:"vendor,omitempty"` - MajorVersion *uint32 `protobuf:"varint,2,opt,name=major_version,json=majorVersion" json:"major_version,omitempty"` - MinorVersion *uint32 `protobuf:"varint,3,opt,name=minor_version,json=minorVersion" json:"minor_version,omitempty"` - PatchVersion *uint32 `protobuf:"varint,4,opt,name=patch_version,json=patchVersion" json:"patch_version,omitempty"` - BootloaderMode *bool `protobuf:"varint,5,opt,name=bootloader_mode,json=bootloaderMode" json:"bootloader_mode,omitempty"` - DeviceId *string `protobuf:"bytes,6,opt,name=device_id,json=deviceId" json:"device_id,omitempty"` - PinProtection *bool `protobuf:"varint,7,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - PassphraseProtection *bool `protobuf:"varint,8,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - Language *string `protobuf:"bytes,9,opt,name=language" json:"language,omitempty"` - Label *string `protobuf:"bytes,10,opt,name=label" json:"label,omitempty"` - Initialized *bool `protobuf:"varint,12,opt,name=initialized" json:"initialized,omitempty"` - Revision []byte `protobuf:"bytes,13,opt,name=revision" json:"revision,omitempty"` - BootloaderHash []byte `protobuf:"bytes,14,opt,name=bootloader_hash,json=bootloaderHash" json:"bootloader_hash,omitempty"` - Imported *bool `protobuf:"varint,15,opt,name=imported" json:"imported,omitempty"` - PinCached *bool `protobuf:"varint,16,opt,name=pin_cached,json=pinCached" json:"pin_cached,omitempty"` - PassphraseCached *bool `protobuf:"varint,17,opt,name=passphrase_cached,json=passphraseCached" json:"passphrase_cached,omitempty"` - FirmwarePresent *bool `protobuf:"varint,18,opt,name=firmware_present,json=firmwarePresent" json:"firmware_present,omitempty"` - NeedsBackup *bool `protobuf:"varint,19,opt,name=needs_backup,json=needsBackup" json:"needs_backup,omitempty"` - Flags *uint32 `protobuf:"varint,20,opt,name=flags" json:"flags,omitempty"` - Model *string `protobuf:"bytes,21,opt,name=model" json:"model,omitempty"` - FwMajor *uint32 `protobuf:"varint,22,opt,name=fw_major,json=fwMajor" json:"fw_major,omitempty"` - FwMinor *uint32 `protobuf:"varint,23,opt,name=fw_minor,json=fwMinor" json:"fw_minor,omitempty"` - FwPatch *uint32 `protobuf:"varint,24,opt,name=fw_patch,json=fwPatch" json:"fw_patch,omitempty"` - FwVendor *string `protobuf:"bytes,25,opt,name=fw_vendor,json=fwVendor" json:"fw_vendor,omitempty"` - FwVendorKeys []byte `protobuf:"bytes,26,opt,name=fw_vendor_keys,json=fwVendorKeys" json:"fw_vendor_keys,omitempty"` - UnfinishedBackup *bool `protobuf:"varint,27,opt,name=unfinished_backup,json=unfinishedBackup" json:"unfinished_backup,omitempty"` - NoBackup *bool `protobuf:"varint,28,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Vendor *string `protobuf:"bytes,1,opt,name=vendor" json:"vendor,omitempty"` // name of the manufacturer, e.g. "trezor.io" + MajorVersion *uint32 `protobuf:"varint,2,opt,name=major_version,json=majorVersion" json:"major_version,omitempty"` // major version of the firmware/bootloader, e.g. 1 + MinorVersion *uint32 `protobuf:"varint,3,opt,name=minor_version,json=minorVersion" json:"minor_version,omitempty"` // minor version of the firmware/bootloader, e.g. 0 + PatchVersion *uint32 `protobuf:"varint,4,opt,name=patch_version,json=patchVersion" json:"patch_version,omitempty"` // patch version of the firmware/bootloader, e.g. 0 + BootloaderMode *bool `protobuf:"varint,5,opt,name=bootloader_mode,json=bootloaderMode" json:"bootloader_mode,omitempty"` // is device in bootloader mode? + DeviceId *string `protobuf:"bytes,6,opt,name=device_id,json=deviceId" json:"device_id,omitempty"` // device's unique identifier + PinProtection *bool `protobuf:"varint,7,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // is device protected by PIN? + PassphraseProtection *bool `protobuf:"varint,8,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // is node/mnemonic encrypted using passphrase? + Language *string `protobuf:"bytes,9,opt,name=language" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,10,opt,name=label" json:"label,omitempty"` // device description label + Initialized *bool `protobuf:"varint,12,opt,name=initialized" json:"initialized,omitempty"` // does device contain seed? + Revision []byte `protobuf:"bytes,13,opt,name=revision" json:"revision,omitempty"` // SCM revision of firmware + BootloaderHash []byte `protobuf:"bytes,14,opt,name=bootloader_hash,json=bootloaderHash" json:"bootloader_hash,omitempty"` // hash of the bootloader + Imported *bool `protobuf:"varint,15,opt,name=imported" json:"imported,omitempty"` // was storage imported from an external source? + PinCached *bool `protobuf:"varint,16,opt,name=pin_cached,json=pinCached" json:"pin_cached,omitempty"` // is PIN already cached in session? + PassphraseCached *bool `protobuf:"varint,17,opt,name=passphrase_cached,json=passphraseCached" json:"passphrase_cached,omitempty"` // is passphrase already cached in session? + FirmwarePresent *bool `protobuf:"varint,18,opt,name=firmware_present,json=firmwarePresent" json:"firmware_present,omitempty"` // is valid firmware loaded? + NeedsBackup *bool `protobuf:"varint,19,opt,name=needs_backup,json=needsBackup" json:"needs_backup,omitempty"` // does storage need backup? (equals to Storage.needs_backup) + Flags *uint32 `protobuf:"varint,20,opt,name=flags" json:"flags,omitempty"` // device flags (equals to Storage.flags) + Model *string `protobuf:"bytes,21,opt,name=model" json:"model,omitempty"` // device hardware model + FwMajor *uint32 `protobuf:"varint,22,opt,name=fw_major,json=fwMajor" json:"fw_major,omitempty"` // reported firmware version if in bootloader mode + FwMinor *uint32 `protobuf:"varint,23,opt,name=fw_minor,json=fwMinor" json:"fw_minor,omitempty"` // reported firmware version if in bootloader mode + FwPatch *uint32 `protobuf:"varint,24,opt,name=fw_patch,json=fwPatch" json:"fw_patch,omitempty"` // reported firmware version if in bootloader mode + FwVendor *string `protobuf:"bytes,25,opt,name=fw_vendor,json=fwVendor" json:"fw_vendor,omitempty"` // reported firmware vendor if in bootloader mode + FwVendorKeys []byte `protobuf:"bytes,26,opt,name=fw_vendor_keys,json=fwVendorKeys" json:"fw_vendor_keys,omitempty"` // reported firmware vendor keys (their hash) + UnfinishedBackup *bool `protobuf:"varint,27,opt,name=unfinished_backup,json=unfinishedBackup" json:"unfinished_backup,omitempty"` // report unfinished backup (equals to Storage.unfinished_backup) + NoBackup *bool `protobuf:"varint,28,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` // report no backup (equals to Storage.no_backup) } -func (m *Features) Reset() { *m = Features{} } -func (m *Features) String() string { return proto.CompactTextString(m) } -func (*Features) ProtoMessage() {} +func (x *Features) Reset() { + *x = Features{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Features) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Features) ProtoMessage() {} + +func (x *Features) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Features.ProtoReflect.Descriptor instead. func (*Features) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{2} + return file_messages_management_proto_rawDescGZIP(), []int{2} } -func (m *Features) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Features.Unmarshal(m, b) -} -func (m *Features) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Features.Marshal(b, m, deterministic) -} -func (m *Features) XXX_Merge(src proto.Message) { - xxx_messageInfo_Features.Merge(m, src) -} -func (m *Features) XXX_Size() int { - return xxx_messageInfo_Features.Size(m) -} -func (m *Features) XXX_DiscardUnknown() { - xxx_messageInfo_Features.DiscardUnknown(m) -} - -var xxx_messageInfo_Features proto.InternalMessageInfo - -func (m *Features) GetVendor() string { - if m != nil && m.Vendor != nil { - return *m.Vendor +func (x *Features) GetVendor() string { + if x != nil && x.Vendor != nil { + return *x.Vendor } return "" } -func (m *Features) GetMajorVersion() uint32 { - if m != nil && m.MajorVersion != nil { - return *m.MajorVersion +func (x *Features) GetMajorVersion() uint32 { + if x != nil && x.MajorVersion != nil { + return *x.MajorVersion } return 0 } -func (m *Features) GetMinorVersion() uint32 { - if m != nil && m.MinorVersion != nil { - return *m.MinorVersion +func (x *Features) GetMinorVersion() uint32 { + if x != nil && x.MinorVersion != nil { + return *x.MinorVersion } return 0 } -func (m *Features) GetPatchVersion() uint32 { - if m != nil && m.PatchVersion != nil { - return *m.PatchVersion +func (x *Features) GetPatchVersion() uint32 { + if x != nil && x.PatchVersion != nil { + return *x.PatchVersion } return 0 } -func (m *Features) GetBootloaderMode() bool { - if m != nil && m.BootloaderMode != nil { - return *m.BootloaderMode +func (x *Features) GetBootloaderMode() bool { + if x != nil && x.BootloaderMode != nil { + return *x.BootloaderMode } return false } -func (m *Features) GetDeviceId() string { - if m != nil && m.DeviceId != nil { - return *m.DeviceId +func (x *Features) GetDeviceId() string { + if x != nil && x.DeviceId != nil { + return *x.DeviceId } return "" } -func (m *Features) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *Features) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *Features) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *Features) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *Features) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *Features) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return "" } -func (m *Features) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *Features) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *Features) GetInitialized() bool { - if m != nil && m.Initialized != nil { - return *m.Initialized +func (x *Features) GetInitialized() bool { + if x != nil && x.Initialized != nil { + return *x.Initialized } return false } -func (m *Features) GetRevision() []byte { - if m != nil { - return m.Revision +func (x *Features) GetRevision() []byte { + if x != nil { + return x.Revision } return nil } -func (m *Features) GetBootloaderHash() []byte { - if m != nil { - return m.BootloaderHash +func (x *Features) GetBootloaderHash() []byte { + if x != nil { + return x.BootloaderHash } return nil } -func (m *Features) GetImported() bool { - if m != nil && m.Imported != nil { - return *m.Imported +func (x *Features) GetImported() bool { + if x != nil && x.Imported != nil { + return *x.Imported } return false } -func (m *Features) GetPinCached() bool { - if m != nil && m.PinCached != nil { - return *m.PinCached +func (x *Features) GetPinCached() bool { + if x != nil && x.PinCached != nil { + return *x.PinCached } return false } -func (m *Features) GetPassphraseCached() bool { - if m != nil && m.PassphraseCached != nil { - return *m.PassphraseCached +func (x *Features) GetPassphraseCached() bool { + if x != nil && x.PassphraseCached != nil { + return *x.PassphraseCached } return false } -func (m *Features) GetFirmwarePresent() bool { - if m != nil && m.FirmwarePresent != nil { - return *m.FirmwarePresent +func (x *Features) GetFirmwarePresent() bool { + if x != nil && x.FirmwarePresent != nil { + return *x.FirmwarePresent } return false } -func (m *Features) GetNeedsBackup() bool { - if m != nil && m.NeedsBackup != nil { - return *m.NeedsBackup +func (x *Features) GetNeedsBackup() bool { + if x != nil && x.NeedsBackup != nil { + return *x.NeedsBackup } return false } -func (m *Features) GetFlags() uint32 { - if m != nil && m.Flags != nil { - return *m.Flags +func (x *Features) GetFlags() uint32 { + if x != nil && x.Flags != nil { + return *x.Flags } return 0 } -func (m *Features) GetModel() string { - if m != nil && m.Model != nil { - return *m.Model +func (x *Features) GetModel() string { + if x != nil && x.Model != nil { + return *x.Model } return "" } -func (m *Features) GetFwMajor() uint32 { - if m != nil && m.FwMajor != nil { - return *m.FwMajor +func (x *Features) GetFwMajor() uint32 { + if x != nil && x.FwMajor != nil { + return *x.FwMajor } return 0 } -func (m *Features) GetFwMinor() uint32 { - if m != nil && m.FwMinor != nil { - return *m.FwMinor +func (x *Features) GetFwMinor() uint32 { + if x != nil && x.FwMinor != nil { + return *x.FwMinor } return 0 } -func (m *Features) GetFwPatch() uint32 { - if m != nil && m.FwPatch != nil { - return *m.FwPatch +func (x *Features) GetFwPatch() uint32 { + if x != nil && x.FwPatch != nil { + return *x.FwPatch } return 0 } -func (m *Features) GetFwVendor() string { - if m != nil && m.FwVendor != nil { - return *m.FwVendor +func (x *Features) GetFwVendor() string { + if x != nil && x.FwVendor != nil { + return *x.FwVendor } return "" } -func (m *Features) GetFwVendorKeys() []byte { - if m != nil { - return m.FwVendorKeys +func (x *Features) GetFwVendorKeys() []byte { + if x != nil { + return x.FwVendorKeys } return nil } -func (m *Features) GetUnfinishedBackup() bool { - if m != nil && m.UnfinishedBackup != nil { - return *m.UnfinishedBackup +func (x *Features) GetUnfinishedBackup() bool { + if x != nil && x.UnfinishedBackup != nil { + return *x.UnfinishedBackup } return false } -func (m *Features) GetNoBackup() bool { - if m != nil && m.NoBackup != nil { - return *m.NoBackup +func (x *Features) GetNoBackup() bool { + if x != nil && x.NoBackup != nil { + return *x.NoBackup } return false } @@ -500,124 +574,139 @@ func (m *Features) GetNoBackup() bool { // @start // @next Success type ClearSession struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *ClearSession) Reset() { *m = ClearSession{} } -func (m *ClearSession) String() string { return proto.CompactTextString(m) } -func (*ClearSession) ProtoMessage() {} +func (x *ClearSession) Reset() { + *x = ClearSession{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ClearSession) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ClearSession) ProtoMessage() {} + +func (x *ClearSession) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ClearSession.ProtoReflect.Descriptor instead. func (*ClearSession) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{3} + return file_messages_management_proto_rawDescGZIP(), []int{3} } -func (m *ClearSession) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ClearSession.Unmarshal(m, b) -} -func (m *ClearSession) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ClearSession.Marshal(b, m, deterministic) -} -func (m *ClearSession) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClearSession.Merge(m, src) -} -func (m *ClearSession) XXX_Size() int { - return xxx_messageInfo_ClearSession.Size(m) -} -func (m *ClearSession) XXX_DiscardUnknown() { - xxx_messageInfo_ClearSession.DiscardUnknown(m) -} - -var xxx_messageInfo_ClearSession proto.InternalMessageInfo - // * // Request: change language and/or label of the device // @start // @next Success // @next Failure type ApplySettings struct { - Language *string `protobuf:"bytes,1,opt,name=language" json:"language,omitempty"` - Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` - UsePassphrase *bool `protobuf:"varint,3,opt,name=use_passphrase,json=usePassphrase" json:"use_passphrase,omitempty"` - Homescreen []byte `protobuf:"bytes,4,opt,name=homescreen" json:"homescreen,omitempty"` - PassphraseSource *ApplySettings_PassphraseSourceType `protobuf:"varint,5,opt,name=passphrase_source,json=passphraseSource,enum=hw.trezor.messages.management.ApplySettings_PassphraseSourceType" json:"passphrase_source,omitempty"` - AutoLockDelayMs *uint32 `protobuf:"varint,6,opt,name=auto_lock_delay_ms,json=autoLockDelayMs" json:"auto_lock_delay_ms,omitempty"` - DisplayRotation *uint32 `protobuf:"varint,7,opt,name=display_rotation,json=displayRotation" json:"display_rotation,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Language *string `protobuf:"bytes,1,opt,name=language" json:"language,omitempty"` + Label *string `protobuf:"bytes,2,opt,name=label" json:"label,omitempty"` + UsePassphrase *bool `protobuf:"varint,3,opt,name=use_passphrase,json=usePassphrase" json:"use_passphrase,omitempty"` + Homescreen []byte `protobuf:"bytes,4,opt,name=homescreen" json:"homescreen,omitempty"` + PassphraseSource *ApplySettings_PassphraseSourceType `protobuf:"varint,5,opt,name=passphrase_source,json=passphraseSource,enum=hw.trezor.messages.management.ApplySettings_PassphraseSourceType" json:"passphrase_source,omitempty"` + AutoLockDelayMs *uint32 `protobuf:"varint,6,opt,name=auto_lock_delay_ms,json=autoLockDelayMs" json:"auto_lock_delay_ms,omitempty"` + DisplayRotation *uint32 `protobuf:"varint,7,opt,name=display_rotation,json=displayRotation" json:"display_rotation,omitempty"` // in degrees from North } -func (m *ApplySettings) Reset() { *m = ApplySettings{} } -func (m *ApplySettings) String() string { return proto.CompactTextString(m) } -func (*ApplySettings) ProtoMessage() {} +func (x *ApplySettings) Reset() { + *x = ApplySettings{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplySettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplySettings) ProtoMessage() {} + +func (x *ApplySettings) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplySettings.ProtoReflect.Descriptor instead. func (*ApplySettings) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{4} + return file_messages_management_proto_rawDescGZIP(), []int{4} } -func (m *ApplySettings) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ApplySettings.Unmarshal(m, b) -} -func (m *ApplySettings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ApplySettings.Marshal(b, m, deterministic) -} -func (m *ApplySettings) XXX_Merge(src proto.Message) { - xxx_messageInfo_ApplySettings.Merge(m, src) -} -func (m *ApplySettings) XXX_Size() int { - return xxx_messageInfo_ApplySettings.Size(m) -} -func (m *ApplySettings) XXX_DiscardUnknown() { - xxx_messageInfo_ApplySettings.DiscardUnknown(m) -} - -var xxx_messageInfo_ApplySettings proto.InternalMessageInfo - -func (m *ApplySettings) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *ApplySettings) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return "" } -func (m *ApplySettings) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *ApplySettings) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *ApplySettings) GetUsePassphrase() bool { - if m != nil && m.UsePassphrase != nil { - return *m.UsePassphrase +func (x *ApplySettings) GetUsePassphrase() bool { + if x != nil && x.UsePassphrase != nil { + return *x.UsePassphrase } return false } -func (m *ApplySettings) GetHomescreen() []byte { - if m != nil { - return m.Homescreen +func (x *ApplySettings) GetHomescreen() []byte { + if x != nil { + return x.Homescreen } return nil } -func (m *ApplySettings) GetPassphraseSource() ApplySettings_PassphraseSourceType { - if m != nil && m.PassphraseSource != nil { - return *m.PassphraseSource +func (x *ApplySettings) GetPassphraseSource() ApplySettings_PassphraseSourceType { + if x != nil && x.PassphraseSource != nil { + return *x.PassphraseSource } return ApplySettings_ASK } -func (m *ApplySettings) GetAutoLockDelayMs() uint32 { - if m != nil && m.AutoLockDelayMs != nil { - return *m.AutoLockDelayMs +func (x *ApplySettings) GetAutoLockDelayMs() uint32 { + if x != nil && x.AutoLockDelayMs != nil { + return *x.AutoLockDelayMs } return 0 } -func (m *ApplySettings) GetDisplayRotation() uint32 { - if m != nil && m.DisplayRotation != nil { - return *m.DisplayRotation +func (x *ApplySettings) GetDisplayRotation() uint32 { + if x != nil && x.DisplayRotation != nil { + return *x.DisplayRotation } return 0 } @@ -628,40 +717,48 @@ func (m *ApplySettings) GetDisplayRotation() uint32 { // @next Success // @next Failure type ApplyFlags struct { - Flags *uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Flags *uint32 `protobuf:"varint,1,opt,name=flags" json:"flags,omitempty"` // bitmask, can only set bits, not unset } -func (m *ApplyFlags) Reset() { *m = ApplyFlags{} } -func (m *ApplyFlags) String() string { return proto.CompactTextString(m) } -func (*ApplyFlags) ProtoMessage() {} +func (x *ApplyFlags) Reset() { + *x = ApplyFlags{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyFlags) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyFlags) ProtoMessage() {} + +func (x *ApplyFlags) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ApplyFlags.ProtoReflect.Descriptor instead. func (*ApplyFlags) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{5} + return file_messages_management_proto_rawDescGZIP(), []int{5} } -func (m *ApplyFlags) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ApplyFlags.Unmarshal(m, b) -} -func (m *ApplyFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ApplyFlags.Marshal(b, m, deterministic) -} -func (m *ApplyFlags) XXX_Merge(src proto.Message) { - xxx_messageInfo_ApplyFlags.Merge(m, src) -} -func (m *ApplyFlags) XXX_Size() int { - return xxx_messageInfo_ApplyFlags.Size(m) -} -func (m *ApplyFlags) XXX_DiscardUnknown() { - xxx_messageInfo_ApplyFlags.DiscardUnknown(m) -} - -var xxx_messageInfo_ApplyFlags proto.InternalMessageInfo - -func (m *ApplyFlags) GetFlags() uint32 { - if m != nil && m.Flags != nil { - return *m.Flags +func (x *ApplyFlags) GetFlags() uint32 { + if x != nil && x.Flags != nil { + return *x.Flags } return 0 } @@ -672,40 +769,48 @@ func (m *ApplyFlags) GetFlags() uint32 { // @next Success // @next Failure type ChangePin struct { - Remove *bool `protobuf:"varint,1,opt,name=remove" json:"remove,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Remove *bool `protobuf:"varint,1,opt,name=remove" json:"remove,omitempty"` // is PIN removal requested? } -func (m *ChangePin) Reset() { *m = ChangePin{} } -func (m *ChangePin) String() string { return proto.CompactTextString(m) } -func (*ChangePin) ProtoMessage() {} +func (x *ChangePin) Reset() { + *x = ChangePin{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChangePin) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChangePin) ProtoMessage() {} + +func (x *ChangePin) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChangePin.ProtoReflect.Descriptor instead. func (*ChangePin) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{6} + return file_messages_management_proto_rawDescGZIP(), []int{6} } -func (m *ChangePin) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ChangePin.Unmarshal(m, b) -} -func (m *ChangePin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ChangePin.Marshal(b, m, deterministic) -} -func (m *ChangePin) XXX_Merge(src proto.Message) { - xxx_messageInfo_ChangePin.Merge(m, src) -} -func (m *ChangePin) XXX_Size() int { - return xxx_messageInfo_ChangePin.Size(m) -} -func (m *ChangePin) XXX_DiscardUnknown() { - xxx_messageInfo_ChangePin.DiscardUnknown(m) -} - -var xxx_messageInfo_ChangePin proto.InternalMessageInfo - -func (m *ChangePin) GetRemove() bool { - if m != nil && m.Remove != nil { - return *m.Remove +func (x *ChangePin) GetRemove() bool { + if x != nil && x.Remove != nil { + return *x.Remove } return false } @@ -715,64 +820,72 @@ func (m *ChangePin) GetRemove() bool { // @start // @next Success type Ping struct { - Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` - ButtonProtection *bool `protobuf:"varint,2,opt,name=button_protection,json=buttonProtection" json:"button_protection,omitempty"` - PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message *string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` // message to send back in Success message + ButtonProtection *bool `protobuf:"varint,2,opt,name=button_protection,json=buttonProtection" json:"button_protection,omitempty"` // ask for button press + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // ask for PIN if set in device + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // ask for passphrase if set in device } -func (m *Ping) Reset() { *m = Ping{} } -func (m *Ping) String() string { return proto.CompactTextString(m) } -func (*Ping) ProtoMessage() {} +func (x *Ping) Reset() { + *x = Ping{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Ping) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Ping) ProtoMessage() {} + +func (x *Ping) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Ping.ProtoReflect.Descriptor instead. func (*Ping) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{7} + return file_messages_management_proto_rawDescGZIP(), []int{7} } -func (m *Ping) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Ping.Unmarshal(m, b) -} -func (m *Ping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Ping.Marshal(b, m, deterministic) -} -func (m *Ping) XXX_Merge(src proto.Message) { - xxx_messageInfo_Ping.Merge(m, src) -} -func (m *Ping) XXX_Size() int { - return xxx_messageInfo_Ping.Size(m) -} -func (m *Ping) XXX_DiscardUnknown() { - xxx_messageInfo_Ping.DiscardUnknown(m) -} - -var xxx_messageInfo_Ping proto.InternalMessageInfo - -func (m *Ping) GetMessage() string { - if m != nil && m.Message != nil { - return *m.Message +func (x *Ping) GetMessage() string { + if x != nil && x.Message != nil { + return *x.Message } return "" } -func (m *Ping) GetButtonProtection() bool { - if m != nil && m.ButtonProtection != nil { - return *m.ButtonProtection +func (x *Ping) GetButtonProtection() bool { + if x != nil && x.ButtonProtection != nil { + return *x.ButtonProtection } return false } -func (m *Ping) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *Ping) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *Ping) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *Ping) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } @@ -782,76 +895,91 @@ func (m *Ping) GetPassphraseProtection() bool { // @start // @next Failure type Cancel struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *Cancel) Reset() { *m = Cancel{} } -func (m *Cancel) String() string { return proto.CompactTextString(m) } -func (*Cancel) ProtoMessage() {} +func (x *Cancel) Reset() { + *x = Cancel{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Cancel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cancel) ProtoMessage() {} + +func (x *Cancel) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cancel.ProtoReflect.Descriptor instead. func (*Cancel) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{8} + return file_messages_management_proto_rawDescGZIP(), []int{8} } -func (m *Cancel) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Cancel.Unmarshal(m, b) -} -func (m *Cancel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Cancel.Marshal(b, m, deterministic) -} -func (m *Cancel) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cancel.Merge(m, src) -} -func (m *Cancel) XXX_Size() int { - return xxx_messageInfo_Cancel.Size(m) -} -func (m *Cancel) XXX_DiscardUnknown() { - xxx_messageInfo_Cancel.DiscardUnknown(m) -} - -var xxx_messageInfo_Cancel proto.InternalMessageInfo - // * // Request: Request a sample of random data generated by hardware RNG. May be used for testing. // @start // @next Entropy // @next Failure type GetEntropy struct { - Size *uint32 `protobuf:"varint,1,req,name=size" json:"size,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Size *uint32 `protobuf:"varint,1,req,name=size" json:"size,omitempty"` // size of requested entropy } -func (m *GetEntropy) Reset() { *m = GetEntropy{} } -func (m *GetEntropy) String() string { return proto.CompactTextString(m) } -func (*GetEntropy) ProtoMessage() {} +func (x *GetEntropy) Reset() { + *x = GetEntropy{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetEntropy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetEntropy) ProtoMessage() {} + +func (x *GetEntropy) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetEntropy.ProtoReflect.Descriptor instead. func (*GetEntropy) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{9} + return file_messages_management_proto_rawDescGZIP(), []int{9} } -func (m *GetEntropy) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetEntropy.Unmarshal(m, b) -} -func (m *GetEntropy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetEntropy.Marshal(b, m, deterministic) -} -func (m *GetEntropy) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetEntropy.Merge(m, src) -} -func (m *GetEntropy) XXX_Size() int { - return xxx_messageInfo_GetEntropy.Size(m) -} -func (m *GetEntropy) XXX_DiscardUnknown() { - xxx_messageInfo_GetEntropy.DiscardUnknown(m) -} - -var xxx_messageInfo_GetEntropy proto.InternalMessageInfo - -func (m *GetEntropy) GetSize() uint32 { - if m != nil && m.Size != nil { - return *m.Size +func (x *GetEntropy) GetSize() uint32 { + if x != nil && x.Size != nil { + return *x.Size } return 0 } @@ -860,40 +988,48 @@ func (m *GetEntropy) GetSize() uint32 { // Response: Reply with random data generated by internal RNG // @end type Entropy struct { - Entropy []byte `protobuf:"bytes,1,req,name=entropy" json:"entropy,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entropy []byte `protobuf:"bytes,1,req,name=entropy" json:"entropy,omitempty"` // chunk of random generated bytes } -func (m *Entropy) Reset() { *m = Entropy{} } -func (m *Entropy) String() string { return proto.CompactTextString(m) } -func (*Entropy) ProtoMessage() {} +func (x *Entropy) Reset() { + *x = Entropy{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Entropy) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Entropy) ProtoMessage() {} + +func (x *Entropy) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Entropy.ProtoReflect.Descriptor instead. func (*Entropy) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{10} + return file_messages_management_proto_rawDescGZIP(), []int{10} } -func (m *Entropy) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Entropy.Unmarshal(m, b) -} -func (m *Entropy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Entropy.Marshal(b, m, deterministic) -} -func (m *Entropy) XXX_Merge(src proto.Message) { - xxx_messageInfo_Entropy.Merge(m, src) -} -func (m *Entropy) XXX_Size() int { - return xxx_messageInfo_Entropy.Size(m) -} -func (m *Entropy) XXX_DiscardUnknown() { - xxx_messageInfo_Entropy.DiscardUnknown(m) -} - -var xxx_messageInfo_Entropy proto.InternalMessageInfo - -func (m *Entropy) GetEntropy() []byte { - if m != nil { - return m.Entropy +func (x *Entropy) GetEntropy() []byte { + if x != nil { + return x.Entropy } return nil } @@ -904,134 +1040,152 @@ func (m *Entropy) GetEntropy() []byte { // @next Success // @next Failure type WipeDevice struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *WipeDevice) Reset() { *m = WipeDevice{} } -func (m *WipeDevice) String() string { return proto.CompactTextString(m) } -func (*WipeDevice) ProtoMessage() {} +func (x *WipeDevice) Reset() { + *x = WipeDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WipeDevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WipeDevice) ProtoMessage() {} + +func (x *WipeDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WipeDevice.ProtoReflect.Descriptor instead. func (*WipeDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{11} + return file_messages_management_proto_rawDescGZIP(), []int{11} } -func (m *WipeDevice) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WipeDevice.Unmarshal(m, b) -} -func (m *WipeDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WipeDevice.Marshal(b, m, deterministic) -} -func (m *WipeDevice) XXX_Merge(src proto.Message) { - xxx_messageInfo_WipeDevice.Merge(m, src) -} -func (m *WipeDevice) XXX_Size() int { - return xxx_messageInfo_WipeDevice.Size(m) -} -func (m *WipeDevice) XXX_DiscardUnknown() { - xxx_messageInfo_WipeDevice.DiscardUnknown(m) -} - -var xxx_messageInfo_WipeDevice proto.InternalMessageInfo - // * // Request: Load seed and related internal settings from the computer // @start // @next Success // @next Failure type LoadDevice struct { - Mnemonic *string `protobuf:"bytes,1,opt,name=mnemonic" json:"mnemonic,omitempty"` - Node *HDNodeType `protobuf:"bytes,2,opt,name=node" json:"node,omitempty"` - Pin *string `protobuf:"bytes,3,opt,name=pin" json:"pin,omitempty"` - PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` - Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` - SkipChecksum *bool `protobuf:"varint,7,opt,name=skip_checksum,json=skipChecksum" json:"skip_checksum,omitempty"` - U2FCounter *uint32 `protobuf:"varint,8,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mnemonic *string `protobuf:"bytes,1,opt,name=mnemonic" json:"mnemonic,omitempty"` // seed encoded as BIP-39 mnemonic (12, 18 or 24 words) + Node *HDNodeType `protobuf:"bytes,2,opt,name=node" json:"node,omitempty"` // BIP-32 node + Pin *string `protobuf:"bytes,3,opt,name=pin" json:"pin,omitempty"` // set PIN protection + PassphraseProtection *bool `protobuf:"varint,4,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // enable master node encryption using passphrase + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` // device label + SkipChecksum *bool `protobuf:"varint,7,opt,name=skip_checksum,json=skipChecksum" json:"skip_checksum,omitempty"` // do not test mnemonic for valid BIP-39 checksum + U2FCounter *uint32 `protobuf:"varint,8,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // U2F counter } -func (m *LoadDevice) Reset() { *m = LoadDevice{} } -func (m *LoadDevice) String() string { return proto.CompactTextString(m) } -func (*LoadDevice) ProtoMessage() {} +// Default values for LoadDevice fields. +const ( + Default_LoadDevice_Language = string("english") +) + +func (x *LoadDevice) Reset() { + *x = LoadDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoadDevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoadDevice) ProtoMessage() {} + +func (x *LoadDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoadDevice.ProtoReflect.Descriptor instead. func (*LoadDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{12} + return file_messages_management_proto_rawDescGZIP(), []int{12} } -func (m *LoadDevice) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LoadDevice.Unmarshal(m, b) -} -func (m *LoadDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LoadDevice.Marshal(b, m, deterministic) -} -func (m *LoadDevice) XXX_Merge(src proto.Message) { - xxx_messageInfo_LoadDevice.Merge(m, src) -} -func (m *LoadDevice) XXX_Size() int { - return xxx_messageInfo_LoadDevice.Size(m) -} -func (m *LoadDevice) XXX_DiscardUnknown() { - xxx_messageInfo_LoadDevice.DiscardUnknown(m) -} - -var xxx_messageInfo_LoadDevice proto.InternalMessageInfo - -const Default_LoadDevice_Language string = "english" - -func (m *LoadDevice) GetMnemonic() string { - if m != nil && m.Mnemonic != nil { - return *m.Mnemonic +func (x *LoadDevice) GetMnemonic() string { + if x != nil && x.Mnemonic != nil { + return *x.Mnemonic } return "" } -func (m *LoadDevice) GetNode() *HDNodeType { - if m != nil { - return m.Node +func (x *LoadDevice) GetNode() *HDNodeType { + if x != nil { + return x.Node } return nil } -func (m *LoadDevice) GetPin() string { - if m != nil && m.Pin != nil { - return *m.Pin +func (x *LoadDevice) GetPin() string { + if x != nil && x.Pin != nil { + return *x.Pin } return "" } -func (m *LoadDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *LoadDevice) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *LoadDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *LoadDevice) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return Default_LoadDevice_Language } -func (m *LoadDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *LoadDevice) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *LoadDevice) GetSkipChecksum() bool { - if m != nil && m.SkipChecksum != nil { - return *m.SkipChecksum +func (x *LoadDevice) GetSkipChecksum() bool { + if x != nil && x.SkipChecksum != nil { + return *x.SkipChecksum } return false } -func (m *LoadDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *LoadDevice) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } @@ -1042,107 +1196,118 @@ func (m *LoadDevice) GetU2FCounter() uint32 { // @next EntropyRequest // @next Failure type ResetDevice struct { - DisplayRandom *bool `protobuf:"varint,1,opt,name=display_random,json=displayRandom" json:"display_random,omitempty"` - Strength *uint32 `protobuf:"varint,2,opt,name=strength,def=256" json:"strength,omitempty"` - PassphraseProtection *bool `protobuf:"varint,3,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - PinProtection *bool `protobuf:"varint,4,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` - Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` - U2FCounter *uint32 `protobuf:"varint,7,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - SkipBackup *bool `protobuf:"varint,8,opt,name=skip_backup,json=skipBackup" json:"skip_backup,omitempty"` - NoBackup *bool `protobuf:"varint,9,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DisplayRandom *bool `protobuf:"varint,1,opt,name=display_random,json=displayRandom" json:"display_random,omitempty"` // display entropy generated by the device before asking for additional entropy + Strength *uint32 `protobuf:"varint,2,opt,name=strength,def=256" json:"strength,omitempty"` // strength of seed in bits + PassphraseProtection *bool `protobuf:"varint,3,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // enable master node encryption using passphrase + PinProtection *bool `protobuf:"varint,4,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // enable PIN protection + Language *string `protobuf:"bytes,5,opt,name=language,def=english" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,6,opt,name=label" json:"label,omitempty"` // device label + U2FCounter *uint32 `protobuf:"varint,7,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // U2F counter + SkipBackup *bool `protobuf:"varint,8,opt,name=skip_backup,json=skipBackup" json:"skip_backup,omitempty"` // postpone seed backup to BackupDevice workflow + NoBackup *bool `protobuf:"varint,9,opt,name=no_backup,json=noBackup" json:"no_backup,omitempty"` // indicate that no backup is going to be made } -func (m *ResetDevice) Reset() { *m = ResetDevice{} } -func (m *ResetDevice) String() string { return proto.CompactTextString(m) } -func (*ResetDevice) ProtoMessage() {} +// Default values for ResetDevice fields. +const ( + Default_ResetDevice_Strength = uint32(256) + Default_ResetDevice_Language = string("english") +) + +func (x *ResetDevice) Reset() { + *x = ResetDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ResetDevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResetDevice) ProtoMessage() {} + +func (x *ResetDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResetDevice.ProtoReflect.Descriptor instead. func (*ResetDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{13} + return file_messages_management_proto_rawDescGZIP(), []int{13} } -func (m *ResetDevice) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ResetDevice.Unmarshal(m, b) -} -func (m *ResetDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ResetDevice.Marshal(b, m, deterministic) -} -func (m *ResetDevice) XXX_Merge(src proto.Message) { - xxx_messageInfo_ResetDevice.Merge(m, src) -} -func (m *ResetDevice) XXX_Size() int { - return xxx_messageInfo_ResetDevice.Size(m) -} -func (m *ResetDevice) XXX_DiscardUnknown() { - xxx_messageInfo_ResetDevice.DiscardUnknown(m) -} - -var xxx_messageInfo_ResetDevice proto.InternalMessageInfo - -const Default_ResetDevice_Strength uint32 = 256 -const Default_ResetDevice_Language string = "english" - -func (m *ResetDevice) GetDisplayRandom() bool { - if m != nil && m.DisplayRandom != nil { - return *m.DisplayRandom +func (x *ResetDevice) GetDisplayRandom() bool { + if x != nil && x.DisplayRandom != nil { + return *x.DisplayRandom } return false } -func (m *ResetDevice) GetStrength() uint32 { - if m != nil && m.Strength != nil { - return *m.Strength +func (x *ResetDevice) GetStrength() uint32 { + if x != nil && x.Strength != nil { + return *x.Strength } return Default_ResetDevice_Strength } -func (m *ResetDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *ResetDevice) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *ResetDevice) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *ResetDevice) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *ResetDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *ResetDevice) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return Default_ResetDevice_Language } -func (m *ResetDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *ResetDevice) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *ResetDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *ResetDevice) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } -func (m *ResetDevice) GetSkipBackup() bool { - if m != nil && m.SkipBackup != nil { - return *m.SkipBackup +func (x *ResetDevice) GetSkipBackup() bool { + if x != nil && x.SkipBackup != nil { + return *x.SkipBackup } return false } -func (m *ResetDevice) GetNoBackup() bool { - if m != nil && m.NoBackup != nil { - return *m.NoBackup +func (x *ResetDevice) GetNoBackup() bool { + if x != nil && x.NoBackup != nil { + return *x.NoBackup } return false } @@ -1152,108 +1317,130 @@ func (m *ResetDevice) GetNoBackup() bool { // @start // @next Success type BackupDevice struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *BackupDevice) Reset() { *m = BackupDevice{} } -func (m *BackupDevice) String() string { return proto.CompactTextString(m) } -func (*BackupDevice) ProtoMessage() {} +func (x *BackupDevice) Reset() { + *x = BackupDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BackupDevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BackupDevice) ProtoMessage() {} + +func (x *BackupDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BackupDevice.ProtoReflect.Descriptor instead. func (*BackupDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{14} + return file_messages_management_proto_rawDescGZIP(), []int{14} } -func (m *BackupDevice) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_BackupDevice.Unmarshal(m, b) -} -func (m *BackupDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_BackupDevice.Marshal(b, m, deterministic) -} -func (m *BackupDevice) XXX_Merge(src proto.Message) { - xxx_messageInfo_BackupDevice.Merge(m, src) -} -func (m *BackupDevice) XXX_Size() int { - return xxx_messageInfo_BackupDevice.Size(m) -} -func (m *BackupDevice) XXX_DiscardUnknown() { - xxx_messageInfo_BackupDevice.DiscardUnknown(m) -} - -var xxx_messageInfo_BackupDevice proto.InternalMessageInfo - // * // Response: Ask for additional entropy from host computer // @next EntropyAck type EntropyRequest struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields } -func (m *EntropyRequest) Reset() { *m = EntropyRequest{} } -func (m *EntropyRequest) String() string { return proto.CompactTextString(m) } -func (*EntropyRequest) ProtoMessage() {} +func (x *EntropyRequest) Reset() { + *x = EntropyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EntropyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EntropyRequest) ProtoMessage() {} + +func (x *EntropyRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EntropyRequest.ProtoReflect.Descriptor instead. func (*EntropyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{15} + return file_messages_management_proto_rawDescGZIP(), []int{15} } -func (m *EntropyRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EntropyRequest.Unmarshal(m, b) -} -func (m *EntropyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EntropyRequest.Marshal(b, m, deterministic) -} -func (m *EntropyRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_EntropyRequest.Merge(m, src) -} -func (m *EntropyRequest) XXX_Size() int { - return xxx_messageInfo_EntropyRequest.Size(m) -} -func (m *EntropyRequest) XXX_DiscardUnknown() { - xxx_messageInfo_EntropyRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_EntropyRequest proto.InternalMessageInfo - // * // Request: Provide additional entropy for seed generation function // @next Success type EntropyAck struct { - Entropy []byte `protobuf:"bytes,1,opt,name=entropy" json:"entropy,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Entropy []byte `protobuf:"bytes,1,opt,name=entropy" json:"entropy,omitempty"` // 256 bits (32 bytes) of random data } -func (m *EntropyAck) Reset() { *m = EntropyAck{} } -func (m *EntropyAck) String() string { return proto.CompactTextString(m) } -func (*EntropyAck) ProtoMessage() {} +func (x *EntropyAck) Reset() { + *x = EntropyAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EntropyAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EntropyAck) ProtoMessage() {} + +func (x *EntropyAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EntropyAck.ProtoReflect.Descriptor instead. func (*EntropyAck) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{16} + return file_messages_management_proto_rawDescGZIP(), []int{16} } -func (m *EntropyAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EntropyAck.Unmarshal(m, b) -} -func (m *EntropyAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EntropyAck.Marshal(b, m, deterministic) -} -func (m *EntropyAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_EntropyAck.Merge(m, src) -} -func (m *EntropyAck) XXX_Size() int { - return xxx_messageInfo_EntropyAck.Size(m) -} -func (m *EntropyAck) XXX_DiscardUnknown() { - xxx_messageInfo_EntropyAck.DiscardUnknown(m) -} - -var xxx_messageInfo_EntropyAck proto.InternalMessageInfo - -func (m *EntropyAck) GetEntropy() []byte { - if m != nil { - return m.Entropy +func (x *EntropyAck) GetEntropy() []byte { + if x != nil { + return x.Entropy } return nil } @@ -1264,107 +1451,118 @@ func (m *EntropyAck) GetEntropy() []byte { // @start // @next WordRequest type RecoveryDevice struct { - WordCount *uint32 `protobuf:"varint,1,opt,name=word_count,json=wordCount" json:"word_count,omitempty"` - PassphraseProtection *bool `protobuf:"varint,2,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` - PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` - Language *string `protobuf:"bytes,4,opt,name=language,def=english" json:"language,omitempty"` - Label *string `protobuf:"bytes,5,opt,name=label" json:"label,omitempty"` - EnforceWordlist *bool `protobuf:"varint,6,opt,name=enforce_wordlist,json=enforceWordlist" json:"enforce_wordlist,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + WordCount *uint32 `protobuf:"varint,1,opt,name=word_count,json=wordCount" json:"word_count,omitempty"` // number of words in BIP-39 mnemonic + PassphraseProtection *bool `protobuf:"varint,2,opt,name=passphrase_protection,json=passphraseProtection" json:"passphrase_protection,omitempty"` // enable master node encryption using passphrase + PinProtection *bool `protobuf:"varint,3,opt,name=pin_protection,json=pinProtection" json:"pin_protection,omitempty"` // enable PIN protection + Language *string `protobuf:"bytes,4,opt,name=language,def=english" json:"language,omitempty"` // device language + Label *string `protobuf:"bytes,5,opt,name=label" json:"label,omitempty"` // device label + EnforceWordlist *bool `protobuf:"varint,6,opt,name=enforce_wordlist,json=enforceWordlist" json:"enforce_wordlist,omitempty"` // enforce BIP-39 wordlist during the process // 7 reserved for unused recovery method - Type *RecoveryDevice_RecoveryDeviceType `protobuf:"varint,8,opt,name=type,enum=hw.trezor.messages.management.RecoveryDevice_RecoveryDeviceType" json:"type,omitempty"` - U2FCounter *uint32 `protobuf:"varint,9,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - DryRun *bool `protobuf:"varint,10,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Type *RecoveryDevice_RecoveryDeviceType `protobuf:"varint,8,opt,name=type,enum=hw.trezor.messages.management.RecoveryDevice_RecoveryDeviceType" json:"type,omitempty"` // supported recovery type + U2FCounter *uint32 `protobuf:"varint,9,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // U2F counter + DryRun *bool `protobuf:"varint,10,opt,name=dry_run,json=dryRun" json:"dry_run,omitempty"` // perform dry-run recovery workflow (for safe mnemonic validation) } -func (m *RecoveryDevice) Reset() { *m = RecoveryDevice{} } -func (m *RecoveryDevice) String() string { return proto.CompactTextString(m) } -func (*RecoveryDevice) ProtoMessage() {} +// Default values for RecoveryDevice fields. +const ( + Default_RecoveryDevice_Language = string("english") +) + +func (x *RecoveryDevice) Reset() { + *x = RecoveryDevice{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RecoveryDevice) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecoveryDevice) ProtoMessage() {} + +func (x *RecoveryDevice) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RecoveryDevice.ProtoReflect.Descriptor instead. func (*RecoveryDevice) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{17} + return file_messages_management_proto_rawDescGZIP(), []int{17} } -func (m *RecoveryDevice) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_RecoveryDevice.Unmarshal(m, b) -} -func (m *RecoveryDevice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_RecoveryDevice.Marshal(b, m, deterministic) -} -func (m *RecoveryDevice) XXX_Merge(src proto.Message) { - xxx_messageInfo_RecoveryDevice.Merge(m, src) -} -func (m *RecoveryDevice) XXX_Size() int { - return xxx_messageInfo_RecoveryDevice.Size(m) -} -func (m *RecoveryDevice) XXX_DiscardUnknown() { - xxx_messageInfo_RecoveryDevice.DiscardUnknown(m) -} - -var xxx_messageInfo_RecoveryDevice proto.InternalMessageInfo - -const Default_RecoveryDevice_Language string = "english" - -func (m *RecoveryDevice) GetWordCount() uint32 { - if m != nil && m.WordCount != nil { - return *m.WordCount +func (x *RecoveryDevice) GetWordCount() uint32 { + if x != nil && x.WordCount != nil { + return *x.WordCount } return 0 } -func (m *RecoveryDevice) GetPassphraseProtection() bool { - if m != nil && m.PassphraseProtection != nil { - return *m.PassphraseProtection +func (x *RecoveryDevice) GetPassphraseProtection() bool { + if x != nil && x.PassphraseProtection != nil { + return *x.PassphraseProtection } return false } -func (m *RecoveryDevice) GetPinProtection() bool { - if m != nil && m.PinProtection != nil { - return *m.PinProtection +func (x *RecoveryDevice) GetPinProtection() bool { + if x != nil && x.PinProtection != nil { + return *x.PinProtection } return false } -func (m *RecoveryDevice) GetLanguage() string { - if m != nil && m.Language != nil { - return *m.Language +func (x *RecoveryDevice) GetLanguage() string { + if x != nil && x.Language != nil { + return *x.Language } return Default_RecoveryDevice_Language } -func (m *RecoveryDevice) GetLabel() string { - if m != nil && m.Label != nil { - return *m.Label +func (x *RecoveryDevice) GetLabel() string { + if x != nil && x.Label != nil { + return *x.Label } return "" } -func (m *RecoveryDevice) GetEnforceWordlist() bool { - if m != nil && m.EnforceWordlist != nil { - return *m.EnforceWordlist +func (x *RecoveryDevice) GetEnforceWordlist() bool { + if x != nil && x.EnforceWordlist != nil { + return *x.EnforceWordlist } return false } -func (m *RecoveryDevice) GetType() RecoveryDevice_RecoveryDeviceType { - if m != nil && m.Type != nil { - return *m.Type +func (x *RecoveryDevice) GetType() RecoveryDevice_RecoveryDeviceType { + if x != nil && x.Type != nil { + return *x.Type } return RecoveryDevice_RecoveryDeviceType_ScrambledWords } -func (m *RecoveryDevice) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *RecoveryDevice) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } -func (m *RecoveryDevice) GetDryRun() bool { - if m != nil && m.DryRun != nil { - return *m.DryRun +func (x *RecoveryDevice) GetDryRun() bool { + if x != nil && x.DryRun != nil { + return *x.DryRun } return false } @@ -1374,40 +1572,48 @@ func (m *RecoveryDevice) GetDryRun() bool { // Its position is shown only on device's internal display. // @next WordAck type WordRequest struct { - Type *WordRequest_WordRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.management.WordRequest_WordRequestType" json:"type,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type *WordRequest_WordRequestType `protobuf:"varint,1,opt,name=type,enum=hw.trezor.messages.management.WordRequest_WordRequestType" json:"type,omitempty"` } -func (m *WordRequest) Reset() { *m = WordRequest{} } -func (m *WordRequest) String() string { return proto.CompactTextString(m) } -func (*WordRequest) ProtoMessage() {} +func (x *WordRequest) Reset() { + *x = WordRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WordRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WordRequest) ProtoMessage() {} + +func (x *WordRequest) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WordRequest.ProtoReflect.Descriptor instead. func (*WordRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{18} + return file_messages_management_proto_rawDescGZIP(), []int{18} } -func (m *WordRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WordRequest.Unmarshal(m, b) -} -func (m *WordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WordRequest.Marshal(b, m, deterministic) -} -func (m *WordRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_WordRequest.Merge(m, src) -} -func (m *WordRequest) XXX_Size() int { - return xxx_messageInfo_WordRequest.Size(m) -} -func (m *WordRequest) XXX_DiscardUnknown() { - xxx_messageInfo_WordRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_WordRequest proto.InternalMessageInfo - -func (m *WordRequest) GetType() WordRequest_WordRequestType { - if m != nil && m.Type != nil { - return *m.Type +func (x *WordRequest) GetType() WordRequest_WordRequestType { + if x != nil && x.Type != nil { + return *x.Type } return WordRequest_WordRequestType_Plain } @@ -1418,40 +1624,48 @@ func (m *WordRequest) GetType() WordRequest_WordRequestType { // @next Success // @next Failure type WordAck struct { - Word *string `protobuf:"bytes,1,req,name=word" json:"word,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Word *string `protobuf:"bytes,1,req,name=word" json:"word,omitempty"` // one word of mnemonic on asked position } -func (m *WordAck) Reset() { *m = WordAck{} } -func (m *WordAck) String() string { return proto.CompactTextString(m) } -func (*WordAck) ProtoMessage() {} +func (x *WordAck) Reset() { + *x = WordAck{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *WordAck) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WordAck) ProtoMessage() {} + +func (x *WordAck) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WordAck.ProtoReflect.Descriptor instead. func (*WordAck) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{19} + return file_messages_management_proto_rawDescGZIP(), []int{19} } -func (m *WordAck) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WordAck.Unmarshal(m, b) -} -func (m *WordAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WordAck.Marshal(b, m, deterministic) -} -func (m *WordAck) XXX_Merge(src proto.Message) { - xxx_messageInfo_WordAck.Merge(m, src) -} -func (m *WordAck) XXX_Size() int { - return xxx_messageInfo_WordAck.Size(m) -} -func (m *WordAck) XXX_DiscardUnknown() { - xxx_messageInfo_WordAck.DiscardUnknown(m) -} - -var xxx_messageInfo_WordAck proto.InternalMessageInfo - -func (m *WordAck) GetWord() string { - if m != nil && m.Word != nil { - return *m.Word +func (x *WordAck) GetWord() string { + if x != nil && x.Word != nil { + return *x.Word } return "" } @@ -1461,161 +1675,602 @@ func (m *WordAck) GetWord() string { // @start // @next Success type SetU2FCounter struct { - U2FCounter *uint32 `protobuf:"varint,1,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + U2FCounter *uint32 `protobuf:"varint,1,opt,name=u2f_counter,json=u2fCounter" json:"u2f_counter,omitempty"` // counter } -func (m *SetU2FCounter) Reset() { *m = SetU2FCounter{} } -func (m *SetU2FCounter) String() string { return proto.CompactTextString(m) } -func (*SetU2FCounter) ProtoMessage() {} +func (x *SetU2FCounter) Reset() { + *x = SetU2FCounter{} + if protoimpl.UnsafeEnabled { + mi := &file_messages_management_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetU2FCounter) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetU2FCounter) ProtoMessage() {} + +func (x *SetU2FCounter) ProtoReflect() protoreflect.Message { + mi := &file_messages_management_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetU2FCounter.ProtoReflect.Descriptor instead. func (*SetU2FCounter) Descriptor() ([]byte, []int) { - return fileDescriptor_0c720c20d27aa029, []int{20} + return file_messages_management_proto_rawDescGZIP(), []int{20} } -func (m *SetU2FCounter) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SetU2FCounter.Unmarshal(m, b) -} -func (m *SetU2FCounter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SetU2FCounter.Marshal(b, m, deterministic) -} -func (m *SetU2FCounter) XXX_Merge(src proto.Message) { - xxx_messageInfo_SetU2FCounter.Merge(m, src) -} -func (m *SetU2FCounter) XXX_Size() int { - return xxx_messageInfo_SetU2FCounter.Size(m) -} -func (m *SetU2FCounter) XXX_DiscardUnknown() { - xxx_messageInfo_SetU2FCounter.DiscardUnknown(m) -} - -var xxx_messageInfo_SetU2FCounter proto.InternalMessageInfo - -func (m *SetU2FCounter) GetU2FCounter() uint32 { - if m != nil && m.U2FCounter != nil { - return *m.U2FCounter +func (x *SetU2FCounter) GetU2FCounter() uint32 { + if x != nil && x.U2FCounter != nil { + return *x.U2FCounter } return 0 } -func init() { - proto.RegisterEnum("hw.trezor.messages.management.ApplySettings_PassphraseSourceType", ApplySettings_PassphraseSourceType_name, ApplySettings_PassphraseSourceType_value) - proto.RegisterEnum("hw.trezor.messages.management.RecoveryDevice_RecoveryDeviceType", RecoveryDevice_RecoveryDeviceType_name, RecoveryDevice_RecoveryDeviceType_value) - proto.RegisterEnum("hw.trezor.messages.management.WordRequest_WordRequestType", WordRequest_WordRequestType_name, WordRequest_WordRequestType_value) - proto.RegisterType((*Initialize)(nil), "hw.trezor.messages.management.Initialize") - proto.RegisterType((*GetFeatures)(nil), "hw.trezor.messages.management.GetFeatures") - proto.RegisterType((*Features)(nil), "hw.trezor.messages.management.Features") - proto.RegisterType((*ClearSession)(nil), "hw.trezor.messages.management.ClearSession") - proto.RegisterType((*ApplySettings)(nil), "hw.trezor.messages.management.ApplySettings") - proto.RegisterType((*ApplyFlags)(nil), "hw.trezor.messages.management.ApplyFlags") - proto.RegisterType((*ChangePin)(nil), "hw.trezor.messages.management.ChangePin") - proto.RegisterType((*Ping)(nil), "hw.trezor.messages.management.Ping") - proto.RegisterType((*Cancel)(nil), "hw.trezor.messages.management.Cancel") - proto.RegisterType((*GetEntropy)(nil), "hw.trezor.messages.management.GetEntropy") - proto.RegisterType((*Entropy)(nil), "hw.trezor.messages.management.Entropy") - proto.RegisterType((*WipeDevice)(nil), "hw.trezor.messages.management.WipeDevice") - proto.RegisterType((*LoadDevice)(nil), "hw.trezor.messages.management.LoadDevice") - proto.RegisterType((*ResetDevice)(nil), "hw.trezor.messages.management.ResetDevice") - proto.RegisterType((*BackupDevice)(nil), "hw.trezor.messages.management.BackupDevice") - proto.RegisterType((*EntropyRequest)(nil), "hw.trezor.messages.management.EntropyRequest") - proto.RegisterType((*EntropyAck)(nil), "hw.trezor.messages.management.EntropyAck") - proto.RegisterType((*RecoveryDevice)(nil), "hw.trezor.messages.management.RecoveryDevice") - proto.RegisterType((*WordRequest)(nil), "hw.trezor.messages.management.WordRequest") - proto.RegisterType((*WordAck)(nil), "hw.trezor.messages.management.WordAck") - proto.RegisterType((*SetU2FCounter)(nil), "hw.trezor.messages.management.SetU2FCounter") +var File_messages_management_proto protoreflect.FileDescriptor + +var file_messages_management_proto_rawDesc = []byte{ + 0x0a, 0x19, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x68, 0x77, 0x2e, + 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x15, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x4b, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x70, 0x61, + 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, + 0x73, 0x6b, 0x69, 0x70, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x22, 0x0d, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x8c, 0x07, + 0x0a, 0x08, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x6a, 0x6f, 0x72, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, 0x72, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, + 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, + 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x70, 0x61, 0x74, 0x63, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x5f, + 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x62, 0x6f, 0x6f, 0x74, + 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x70, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, + 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, + 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, + 0x69, 0x7a, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, + 0x72, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x62, 0x6f, + 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x69, 0x6e, 0x5f, + 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x70, 0x69, + 0x6e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x61, 0x73, 0x73, 0x70, + 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x43, 0x61, + 0x63, 0x68, 0x65, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, + 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, + 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x65, 0x65, 0x64, 0x73, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x19, + 0x0a, 0x08, 0x66, 0x77, 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x07, 0x66, 0x77, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x77, 0x5f, + 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x77, 0x4d, + 0x69, 0x6e, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x66, 0x77, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x66, 0x77, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, + 0x1b, 0x0a, 0x09, 0x66, 0x77, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x66, 0x77, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x12, 0x24, 0x0a, 0x0e, + 0x66, 0x77, 0x5f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x1a, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x66, 0x77, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x4b, 0x65, + 0x79, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x75, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x75, + 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x1c, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x0e, 0x0a, 0x0c, + 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x87, 0x03, 0x0a, + 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, + 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x50, 0x61, 0x73, + 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x6f, 0x6d, 0x65, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x68, 0x6f, 0x6d, + 0x65, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x12, 0x6e, 0x0a, 0x11, 0x70, 0x61, 0x73, 0x73, 0x70, + 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x41, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x2e, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, + 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x12, 0x61, 0x75, 0x74, 0x6f, 0x5f, + 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x61, 0x75, 0x74, 0x6f, 0x4c, 0x6f, 0x63, 0x6b, 0x44, 0x65, 0x6c, + 0x61, 0x79, 0x4d, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x35, 0x0a, 0x14, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x53, 0x4b, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, + 0x48, 0x4f, 0x53, 0x54, 0x10, 0x02, 0x22, 0x22, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x46, + 0x6c, 0x61, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x23, 0x0a, 0x09, 0x43, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x50, 0x69, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, + 0xa9, 0x01, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x62, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x62, + 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x70, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, + 0x65, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x08, 0x0a, 0x06, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x22, 0x20, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x6f, 0x70, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x23, 0x0a, 0x07, 0x45, 0x6e, 0x74, 0x72, 0x6f, + 0x70, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, + 0x02, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x22, 0x0c, 0x0a, 0x0a, + 0x57, 0x69, 0x70, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0xab, 0x02, 0x0a, 0x0a, 0x4c, + 0x6f, 0x61, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6e, 0x65, + 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6e, 0x65, + 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x39, 0x0a, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x48, 0x44, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, + 0x69, 0x6e, 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x3a, 0x07, 0x65, 0x6e, 0x67, 0x6c, 0x69, + 0x73, 0x68, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, + 0x73, 0x75, 0x6d, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, 0x66, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x75, 0x32, + 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0xcb, 0x02, 0x0a, 0x0b, 0x52, 0x65, 0x73, + 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x69, 0x73, 0x70, + 0x6c, 0x61, 0x79, 0x5f, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x12, + 0x1f, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x3a, 0x03, 0x32, 0x35, 0x36, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x70, + 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x08, + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x3a, 0x07, + 0x65, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, 0x66, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x75, 0x32, + 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6b, 0x69, 0x70, + 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x73, + 0x6b, 0x69, 0x70, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x5f, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6e, 0x6f, + 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x22, 0x0e, 0x0a, 0x0c, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x10, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x26, 0x0a, 0x0a, 0x45, 0x6e, 0x74, 0x72, + 0x6f, 0x70, 0x79, 0x41, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, + 0x22, 0xdd, 0x03, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x33, 0x0a, 0x15, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x14, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x69, 0x6e, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x0d, 0x70, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x23, + 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x3a, 0x07, 0x65, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, + 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x6e, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x77, 0x6f, 0x72, 0x64, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x65, 0x6e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x57, 0x6f, 0x72, 0x64, + 0x6c, 0x69, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x40, 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, + 0x66, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0a, 0x75, 0x32, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x07, 0x64, + 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, + 0x79, 0x52, 0x75, 0x6e, 0x22, 0x5a, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x21, 0x52, 0x65, + 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x53, 0x63, 0x72, 0x61, 0x6d, 0x62, 0x6c, 0x65, 0x64, 0x57, 0x6f, 0x72, 0x64, 0x73, 0x10, + 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x10, 0x01, + 0x22, 0xc5, 0x01, 0x0a, 0x0b, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x4e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3a, + 0x2e, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x6f, 0x72, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x22, 0x66, 0x0a, 0x0f, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x1b, + 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x39, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x57, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, + 0x61, 0x74, 0x72, 0x69, 0x78, 0x36, 0x10, 0x02, 0x22, 0x1d, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x64, + 0x41, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x09, 0x52, 0x04, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x30, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x55, 0x32, + 0x46, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x32, 0x66, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x75, + 0x32, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x42, 0x79, 0x0a, 0x23, 0x63, 0x6f, 0x6d, + 0x2e, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x74, 0x72, 0x65, + 0x7a, 0x6f, 0x72, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x42, 0x17, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, + 0x6f, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, + 0x65, 0x7a, 0x6f, 0x72, } -func init() { proto.RegisterFile("messages-management.proto", fileDescriptor_0c720c20d27aa029) } +var ( + file_messages_management_proto_rawDescOnce sync.Once + file_messages_management_proto_rawDescData = file_messages_management_proto_rawDesc +) -var fileDescriptor_0c720c20d27aa029 = []byte{ - // 1393 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0xdd, 0x6e, 0xdb, 0xc8, - 0x15, 0x8e, 0x7e, 0x62, 0x49, 0xc7, 0xfa, 0xcb, 0xd4, 0x8e, 0xe9, 0xb8, 0x6e, 0x1c, 0xba, 0x6e, - 0x12, 0x04, 0x15, 0x0a, 0x17, 0x09, 0x90, 0x5c, 0x14, 0x75, 0xec, 0xfc, 0x21, 0x71, 0x6a, 0xd0, - 0x6e, 0x02, 0xf4, 0x86, 0x18, 0x91, 0x47, 0xd2, 0xd4, 0xe4, 0x0c, 0xcb, 0x19, 0xda, 0x55, 0x5e, - 0x60, 0x6f, 0xf6, 0x45, 0x16, 0xfb, 0x1c, 0x7b, 0xb5, 0xcf, 0xb0, 0xef, 0xb2, 0x98, 0x19, 0x52, - 0xa2, 0x65, 0x3b, 0x46, 0x76, 0xef, 0xe6, 0x7c, 0xe7, 0xe3, 0x68, 0xce, 0x77, 0xbe, 0x39, 0x63, - 0xc3, 0x7a, 0x8c, 0x52, 0xd2, 0x31, 0xca, 0xbf, 0xc6, 0x94, 0xd3, 0x31, 0xc6, 0xc8, 0xd5, 0x20, - 0x49, 0x85, 0x12, 0x64, 0x73, 0x72, 0x3e, 0x50, 0x29, 0x7e, 0x11, 0xe9, 0xa0, 0x20, 0x0d, 0xe6, - 0xa4, 0x7b, 0xab, 0xb3, 0x2f, 0x03, 0x11, 0xc7, 0x82, 0xdb, 0xaf, 0xdc, 0xf7, 0x00, 0xef, 0x38, - 0x53, 0x8c, 0x46, 0xec, 0x0b, 0x92, 0x15, 0xb8, 0x2d, 0x15, 0x55, 0xe8, 0x54, 0xb6, 0x2a, 0x8f, - 0xda, 0x9e, 0x0d, 0xc8, 0x43, 0xe8, 0xc9, 0x53, 0x96, 0xf8, 0x09, 0x95, 0x32, 0x99, 0xa4, 0x54, - 0xa2, 0x53, 0xdd, 0xaa, 0x3c, 0x6a, 0x7a, 0x5d, 0x0d, 0x1f, 0xcd, 0x50, 0xb7, 0x03, 0xcb, 0x6f, - 0x50, 0xbd, 0x46, 0xaa, 0xb2, 0x14, 0xa5, 0xfb, 0x7d, 0x03, 0x9a, 0x45, 0x40, 0xee, 0xc2, 0xd2, - 0x19, 0xf2, 0x50, 0xa4, 0x66, 0xef, 0x96, 0x97, 0x47, 0x64, 0x1b, 0x3a, 0x31, 0xfd, 0xaf, 0x48, - 0xfd, 0x33, 0x4c, 0x25, 0x13, 0xdc, 0x6c, 0xdd, 0xf1, 0xda, 0x06, 0xfc, 0x64, 0x31, 0x43, 0x62, - 0xbc, 0x44, 0xaa, 0xe5, 0x24, 0x0d, 0x96, 0x48, 0x09, 0x55, 0xc1, 0x64, 0x46, 0xaa, 0x5b, 0x92, - 0x01, 0x0b, 0xd2, 0x43, 0xe8, 0x0d, 0x85, 0x50, 0x91, 0xa0, 0x21, 0xa6, 0x7e, 0x2c, 0x42, 0x74, - 0x6e, 0xdb, 0x5a, 0xe6, 0xf0, 0xa1, 0x08, 0x91, 0x6c, 0x40, 0x2b, 0xc4, 0x33, 0x16, 0xa0, 0xcf, - 0x42, 0x67, 0xc9, 0x1c, 0xb9, 0x69, 0x81, 0x77, 0x21, 0xd9, 0x81, 0x6e, 0xc2, 0xb8, 0xaf, 0x25, - 0xc4, 0x40, 0xe9, 0xdf, 0x6a, 0x98, 0x4d, 0x3a, 0x09, 0xe3, 0x47, 0x33, 0x90, 0xfc, 0x1d, 0x56, - 0xe7, 0x9a, 0x95, 0xd9, 0x4d, 0xc3, 0x5e, 0x99, 0x27, 0x4b, 0x1f, 0xdd, 0x83, 0x66, 0x44, 0xf9, - 0x38, 0xa3, 0x63, 0x74, 0x5a, 0xf6, 0x77, 0x8b, 0x58, 0xf7, 0x27, 0xa2, 0x43, 0x8c, 0x1c, 0x30, - 0x09, 0x1b, 0x90, 0x2d, 0x58, 0x66, 0xb3, 0x1e, 0x86, 0x4e, 0xdb, 0x6c, 0x5e, 0x86, 0xf4, 0x9e, - 0x29, 0x9e, 0x31, 0xa3, 0x4a, 0xc7, 0xb4, 0x76, 0x16, 0x2f, 0x28, 0x32, 0xa1, 0x72, 0xe2, 0x74, - 0x0d, 0xa5, 0xa4, 0xc8, 0x5b, 0x2a, 0x27, 0x7a, 0x13, 0x16, 0x27, 0x22, 0x55, 0x18, 0x3a, 0x3d, - 0xf3, 0x1b, 0xb3, 0x98, 0x6c, 0x02, 0x68, 0x41, 0x02, 0x1a, 0x4c, 0x30, 0x74, 0xfa, 0x26, 0xdb, - 0x4a, 0x18, 0xdf, 0x37, 0x00, 0x79, 0x02, 0x77, 0x4a, 0x42, 0xe4, 0xac, 0x3b, 0x86, 0xd5, 0x9f, - 0x27, 0x72, 0xf2, 0x63, 0xe8, 0x8f, 0x58, 0x1a, 0x9f, 0xd3, 0x54, 0x6b, 0x86, 0x12, 0xb9, 0x72, - 0x88, 0xe1, 0xf6, 0x0a, 0xfc, 0xc8, 0xc2, 0xe4, 0x01, 0xb4, 0x39, 0x62, 0x28, 0xfd, 0x21, 0x0d, - 0x4e, 0xb3, 0xc4, 0xf9, 0x83, 0x2d, 0xdd, 0x60, 0x2f, 0x0d, 0xa4, 0x25, 0x1b, 0x45, 0x74, 0x2c, - 0x9d, 0x15, 0xe3, 0x06, 0x1b, 0x68, 0x54, 0xf7, 0x3e, 0x72, 0x56, 0xad, 0x90, 0x26, 0x20, 0xeb, - 0xd0, 0x1c, 0x9d, 0xfb, 0xc6, 0x79, 0xce, 0x5d, 0x43, 0x6f, 0x8c, 0xce, 0x0f, 0x75, 0x58, 0xa4, - 0xb4, 0xdf, 0x9c, 0xb5, 0x59, 0x4a, 0x87, 0x79, 0xca, 0xb8, 0xcc, 0x71, 0x8a, 0xd4, 0x91, 0x0e, - 0xb5, 0x89, 0x46, 0xe7, 0x7e, 0xee, 0xfb, 0x75, 0xdb, 0xcc, 0xd1, 0xf9, 0x27, 0xeb, 0xfc, 0x3f, - 0x43, 0x77, 0x96, 0xf4, 0x4f, 0x71, 0x2a, 0x9d, 0x7b, 0x46, 0xf7, 0x76, 0xc1, 0x78, 0x8f, 0x53, - 0xa9, 0xa5, 0xcb, 0xf8, 0x88, 0x71, 0x26, 0x27, 0x18, 0x16, 0x75, 0x6e, 0x58, 0xe9, 0xe6, 0x89, - 0xbc, 0xd8, 0x0d, 0x68, 0x71, 0x51, 0x90, 0xfe, 0x68, 0x7b, 0xc4, 0x85, 0x4d, 0xba, 0x5d, 0x68, - 0xef, 0x47, 0x48, 0xd3, 0x63, 0x94, 0xba, 0xf1, 0xee, 0x77, 0x35, 0xe8, 0xec, 0x25, 0x49, 0x34, - 0x3d, 0x46, 0xa5, 0x18, 0x1f, 0xcb, 0x0b, 0xd6, 0xab, 0x5c, 0x67, 0xbd, 0x6a, 0xd9, 0x7a, 0x3b, - 0xd0, 0xcd, 0xb4, 0xb5, 0xe7, 0x93, 0xa1, 0x66, 0x2f, 0x42, 0x26, 0x71, 0x3e, 0x18, 0xc8, 0x9f, - 0x00, 0x26, 0x22, 0x46, 0x19, 0xa4, 0x88, 0xf6, 0x5e, 0xb6, 0xbd, 0x12, 0x42, 0xf8, 0x05, 0x7f, - 0x48, 0x91, 0xa5, 0x81, 0xbd, 0x97, 0xdd, 0xdd, 0xbd, 0xc1, 0x57, 0xe7, 0xda, 0xe0, 0x42, 0x05, - 0x83, 0xf9, 0x6f, 0x1e, 0x9b, 0x4d, 0x4e, 0xa6, 0x09, 0x96, 0x2d, 0x66, 0x51, 0xf2, 0x04, 0x08, - 0xcd, 0x94, 0xf0, 0x23, 0x11, 0x9c, 0xfa, 0x21, 0x46, 0x74, 0xea, 0xc7, 0xd2, 0xdc, 0xf2, 0x8e, - 0xd7, 0xd3, 0x99, 0x0f, 0x22, 0x38, 0x3d, 0xd0, 0xf8, 0xa1, 0xd4, 0x7e, 0x0c, 0x99, 0x4c, 0x34, - 0x29, 0x15, 0x8a, 0xce, 0xae, 0x7b, 0xc7, 0xeb, 0xe5, 0xb8, 0x97, 0xc3, 0xee, 0x53, 0x58, 0xb9, - 0xea, 0x04, 0xa4, 0x01, 0xb5, 0xbd, 0xe3, 0xf7, 0xfd, 0x5b, 0x04, 0x60, 0xe9, 0xe0, 0xd5, 0xa7, - 0x77, 0xfb, 0xaf, 0xfa, 0x15, 0xd2, 0x84, 0xfa, 0xdb, 0x7f, 0x1d, 0x9f, 0xf4, 0xab, 0xae, 0x0b, - 0x60, 0xca, 0x78, 0x5d, 0x78, 0xd3, 0x3a, 0xb6, 0x52, 0x72, 0xac, 0xbb, 0x0d, 0xad, 0xfd, 0x09, - 0xe5, 0x63, 0x3c, 0x62, 0x5c, 0x0f, 0xd3, 0x14, 0x63, 0x71, 0x66, 0xdb, 0xd4, 0xf4, 0xf2, 0xc8, - 0xfd, 0xa1, 0x02, 0xf5, 0x23, 0xc6, 0xc7, 0xc4, 0x81, 0x46, 0x2e, 0x56, 0xde, 0xc8, 0x22, 0xd4, - 0x7e, 0x1a, 0x66, 0x4a, 0x89, 0x0b, 0xd3, 0xcb, 0x8e, 0xf3, 0xbe, 0x4d, 0x94, 0x66, 0xd1, 0xe5, - 0x39, 0x57, 0xfb, 0xa6, 0x39, 0x57, 0xbf, 0x7e, 0xce, 0xb9, 0x4d, 0x58, 0xda, 0xa7, 0x3c, 0xc0, - 0xc8, 0xdd, 0x02, 0x78, 0x83, 0xea, 0x15, 0x57, 0xa9, 0x48, 0xa6, 0x84, 0x40, 0x5d, 0xb2, 0x2f, - 0xfa, 0xdc, 0xd5, 0x47, 0x1d, 0xcf, 0xac, 0xdd, 0x6d, 0x68, 0x14, 0x69, 0x07, 0x1a, 0x68, 0x97, - 0x86, 0xd1, 0xf6, 0x8a, 0xd0, 0x6d, 0x03, 0x7c, 0x66, 0x09, 0x1e, 0x98, 0x21, 0xed, 0xfe, 0x58, - 0x05, 0xf8, 0x20, 0x68, 0x68, 0x43, 0x6d, 0xed, 0x98, 0x63, 0x2c, 0x38, 0x0b, 0x0a, 0x6b, 0x17, - 0x31, 0x79, 0x0e, 0x75, 0xae, 0x1f, 0x02, 0xad, 0xc2, 0xf2, 0xee, 0xce, 0x55, 0x86, 0xcb, 0xdf, - 0xcc, 0xb7, 0x07, 0x1f, 0x45, 0x68, 0x4d, 0x65, 0x3e, 0x21, 0x7d, 0xa8, 0x25, 0xcc, 0xaa, 0xd2, - 0xf2, 0xf4, 0xf2, 0x37, 0x69, 0x41, 0xb6, 0x4b, 0x17, 0x4f, 0xdb, 0xbe, 0xf5, 0xa2, 0x81, 0x7c, - 0x1c, 0x31, 0x39, 0xb9, 0xea, 0x06, 0x2e, 0x95, 0x6f, 0xe0, 0x36, 0x74, 0xcc, 0xe3, 0x1c, 0x4c, - 0x30, 0x38, 0x95, 0x59, 0x9c, 0xbf, 0x44, 0x6d, 0x0d, 0xee, 0xe7, 0x18, 0xb9, 0x0f, 0xcb, 0xd9, - 0xee, 0xc8, 0x0f, 0x44, 0xc6, 0x15, 0xa6, 0xe6, 0xf9, 0xe9, 0x78, 0x90, 0xed, 0x8e, 0xf6, 0x2d, - 0xe2, 0xfe, 0x5c, 0x85, 0x65, 0x0f, 0x25, 0xaa, 0x5c, 0xae, 0x1d, 0xe8, 0xce, 0x3c, 0x4f, 0x79, - 0x28, 0xe2, 0xdc, 0x68, 0x9d, 0xc2, 0xf1, 0x06, 0x24, 0xf7, 0xa1, 0x29, 0x55, 0x8a, 0x7c, 0xac, - 0x26, 0xf6, 0xdd, 0x7e, 0x51, 0xdb, 0x7d, 0xfa, 0xcc, 0x9b, 0x81, 0xd7, 0xab, 0x51, 0xfb, 0x8a, - 0x1a, 0x97, 0x5d, 0x57, 0xbf, 0xca, 0x75, 0xbf, 0x43, 0xb4, 0x05, 0x3d, 0x1a, 0x8b, 0x7a, 0x68, - 0x82, 0x51, 0x35, 0x1f, 0xa5, 0xf6, 0xbd, 0x06, 0x0d, 0x5d, 0x35, 0x69, 0x5b, 0x97, 0x27, 0xad, - 0x5d, 0xe5, 0x5e, 0xec, 0x43, 0x37, 0xb7, 0xaf, 0x87, 0xff, 0xcb, 0x50, 0x2a, 0xf7, 0x2f, 0x00, - 0x39, 0xb2, 0x17, 0x9c, 0x5e, 0xf4, 0x74, 0xa5, 0xec, 0xe9, 0x5f, 0x6a, 0xd0, 0xf5, 0x30, 0x10, - 0x67, 0x98, 0x4e, 0xf3, 0xd6, 0x6c, 0x02, 0x9c, 0x8b, 0x34, 0xb4, 0x87, 0xcf, 0x67, 0x44, 0x4b, - 0x23, 0xe6, 0xec, 0xd7, 0x2b, 0x5e, 0xfd, 0x26, 0xc5, 0x6b, 0x37, 0x29, 0x5e, 0xbf, 0x51, 0xf1, - 0xdb, 0x65, 0xc5, 0x1f, 0x43, 0x1f, 0xf9, 0x48, 0xa4, 0x01, 0xfa, 0xfa, 0xac, 0x11, 0x93, 0xca, - 0xb4, 0xa4, 0xe9, 0xf5, 0x72, 0xfc, 0x73, 0x0e, 0x93, 0x13, 0xa8, 0xab, 0x69, 0x82, 0x46, 0xf4, - 0xee, 0xee, 0x3f, 0x6f, 0x98, 0xff, 0x17, 0xd5, 0x59, 0x08, 0xed, 0x4d, 0xd5, 0xbb, 0x2d, 0xb6, - 0xbc, 0x75, 0xa9, 0xe5, 0x6b, 0xd0, 0x08, 0xd3, 0xa9, 0x9f, 0x66, 0xdc, 0xfc, 0x75, 0xd5, 0xf4, - 0x96, 0xc2, 0x74, 0xea, 0x65, 0xdc, 0xfd, 0x0f, 0x90, 0xcb, 0xbb, 0x92, 0x1d, 0x78, 0x70, 0x19, - 0xf5, 0x8f, 0x83, 0x94, 0xc6, 0xc3, 0x08, 0x43, 0x5d, 0x8d, 0xec, 0xdf, 0x22, 0x9b, 0xb0, 0x7e, - 0x05, 0xed, 0x90, 0xaa, 0x94, 0xfd, 0xbf, 0x5f, 0x71, 0x7f, 0xaa, 0xc0, 0xb2, 0xa6, 0xe6, 0xbe, - 0x20, 0x1f, 0xf3, 0xda, 0x2b, 0xa6, 0xf6, 0x17, 0x37, 0xd4, 0x5e, 0xfa, 0xb2, 0xbc, 0x9e, 0x57, - 0xed, 0x8e, 0xa0, 0xb7, 0x90, 0x20, 0xeb, 0xb0, 0xba, 0x00, 0xf9, 0x47, 0x11, 0x65, 0xbc, 0x7f, - 0x8b, 0x6c, 0xc0, 0xda, 0x62, 0xca, 0x9e, 0xf4, 0x79, 0xbf, 0x72, 0x7d, 0xf2, 0x59, 0xbf, 0xea, - 0x6e, 0x42, 0x43, 0x27, 0xb5, 0x99, 0x09, 0xd4, 0x75, 0x87, 0xcd, 0x74, 0x6e, 0x79, 0x66, 0xed, - 0xfe, 0x0d, 0x3a, 0xc7, 0xa8, 0xfe, 0xbd, 0xfb, 0xba, 0x74, 0xbf, 0xca, 0xdd, 0xa8, 0x2c, 0x76, - 0xe3, 0xe5, 0x3f, 0x60, 0x3b, 0x10, 0xf1, 0x40, 0x52, 0x25, 0xe4, 0x84, 0x45, 0x74, 0x28, 0x0b, - 0x21, 0x22, 0x36, 0xb4, 0xff, 0xbb, 0x0c, 0xb3, 0xd1, 0xcb, 0xb5, 0x13, 0x03, 0x1e, 0x5a, 0x71, - 0x0e, 0x67, 0xd2, 0xfc, 0x1a, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x6e, 0xfc, 0x59, 0x29, 0x0d, 0x00, - 0x00, +func file_messages_management_proto_rawDescGZIP() []byte { + file_messages_management_proto_rawDescOnce.Do(func() { + file_messages_management_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_management_proto_rawDescData) + }) + return file_messages_management_proto_rawDescData +} + +var file_messages_management_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_messages_management_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_messages_management_proto_goTypes = []interface{}{ + (ApplySettings_PassphraseSourceType)(0), // 0: hw.trezor.messages.management.ApplySettings.PassphraseSourceType + (RecoveryDevice_RecoveryDeviceType)(0), // 1: hw.trezor.messages.management.RecoveryDevice.RecoveryDeviceType + (WordRequest_WordRequestType)(0), // 2: hw.trezor.messages.management.WordRequest.WordRequestType + (*Initialize)(nil), // 3: hw.trezor.messages.management.Initialize + (*GetFeatures)(nil), // 4: hw.trezor.messages.management.GetFeatures + (*Features)(nil), // 5: hw.trezor.messages.management.Features + (*ClearSession)(nil), // 6: hw.trezor.messages.management.ClearSession + (*ApplySettings)(nil), // 7: hw.trezor.messages.management.ApplySettings + (*ApplyFlags)(nil), // 8: hw.trezor.messages.management.ApplyFlags + (*ChangePin)(nil), // 9: hw.trezor.messages.management.ChangePin + (*Ping)(nil), // 10: hw.trezor.messages.management.Ping + (*Cancel)(nil), // 11: hw.trezor.messages.management.Cancel + (*GetEntropy)(nil), // 12: hw.trezor.messages.management.GetEntropy + (*Entropy)(nil), // 13: hw.trezor.messages.management.Entropy + (*WipeDevice)(nil), // 14: hw.trezor.messages.management.WipeDevice + (*LoadDevice)(nil), // 15: hw.trezor.messages.management.LoadDevice + (*ResetDevice)(nil), // 16: hw.trezor.messages.management.ResetDevice + (*BackupDevice)(nil), // 17: hw.trezor.messages.management.BackupDevice + (*EntropyRequest)(nil), // 18: hw.trezor.messages.management.EntropyRequest + (*EntropyAck)(nil), // 19: hw.trezor.messages.management.EntropyAck + (*RecoveryDevice)(nil), // 20: hw.trezor.messages.management.RecoveryDevice + (*WordRequest)(nil), // 21: hw.trezor.messages.management.WordRequest + (*WordAck)(nil), // 22: hw.trezor.messages.management.WordAck + (*SetU2FCounter)(nil), // 23: hw.trezor.messages.management.SetU2FCounter + (*HDNodeType)(nil), // 24: hw.trezor.messages.common.HDNodeType +} +var file_messages_management_proto_depIdxs = []int32{ + 0, // 0: hw.trezor.messages.management.ApplySettings.passphrase_source:type_name -> hw.trezor.messages.management.ApplySettings.PassphraseSourceType + 24, // 1: hw.trezor.messages.management.LoadDevice.node:type_name -> hw.trezor.messages.common.HDNodeType + 1, // 2: hw.trezor.messages.management.RecoveryDevice.type:type_name -> hw.trezor.messages.management.RecoveryDevice.RecoveryDeviceType + 2, // 3: hw.trezor.messages.management.WordRequest.type:type_name -> hw.trezor.messages.management.WordRequest.WordRequestType + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_messages_management_proto_init() } +func file_messages_management_proto_init() { + if File_messages_management_proto != nil { + return + } + file_messages_common_proto_init() + if !protoimpl.UnsafeEnabled { + file_messages_management_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Initialize); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetFeatures); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Features); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClearSession); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplySettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ApplyFlags); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChangePin); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Ping); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cancel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetEntropy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Entropy); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WipeDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoadDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ResetDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BackupDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EntropyRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EntropyAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RecoveryDevice); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WordRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*WordAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_messages_management_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetU2FCounter); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_management_proto_rawDesc, + NumEnums: 3, + NumMessages: 21, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_messages_management_proto_goTypes, + DependencyIndexes: file_messages_management_proto_depIdxs, + EnumInfos: file_messages_management_proto_enumTypes, + MessageInfos: file_messages_management_proto_msgTypes, + }.Build() + File_messages_management_proto = out.File + file_messages_management_proto_rawDesc = nil + file_messages_management_proto_goTypes = nil + file_messages_management_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages-management.proto b/accounts/usbwallet/trezor/messages-management.proto index 0ab825a1bc..55eb58983e 100644 --- a/accounts/usbwallet/trezor/messages-management.proto +++ b/accounts/usbwallet/trezor/messages-management.proto @@ -5,6 +5,8 @@ syntax = "proto2"; package hw.trezor.messages.management; +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + // Sugar for easier handling in Java option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessageManagement"; diff --git a/accounts/usbwallet/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go index af0c957144..3e80d7c9c3 100644 --- a/accounts/usbwallet/trezor/messages.pb.go +++ b/accounts/usbwallet/trezor/messages.pb.go @@ -1,26 +1,29 @@ +// This file originates from the SatoshiLabs Trezor `common` repository at: +// https://github.com/trezor/trezor-common/blob/master/protob/messages.proto +// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v5.27.1 // source: messages.proto package trezor import ( - fmt "fmt" - math "math" - - proto "github.com/golang/protobuf/proto" - descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) // * // Mapping between TREZOR wire identifier (uint) and a protobuf message @@ -241,397 +244,399 @@ const ( MessageType_MessageType_BinanceSignedTx MessageType = 709 ) -var MessageType_name = map[int32]string{ - 0: "MessageType_Initialize", - 1: "MessageType_Ping", - 2: "MessageType_Success", - 3: "MessageType_Failure", - 4: "MessageType_ChangePin", - 5: "MessageType_WipeDevice", - 9: "MessageType_GetEntropy", - 10: "MessageType_Entropy", - 13: "MessageType_LoadDevice", - 14: "MessageType_ResetDevice", - 17: "MessageType_Features", - 18: "MessageType_PinMatrixRequest", - 19: "MessageType_PinMatrixAck", - 20: "MessageType_Cancel", - 24: "MessageType_ClearSession", - 25: "MessageType_ApplySettings", - 26: "MessageType_ButtonRequest", - 27: "MessageType_ButtonAck", - 28: "MessageType_ApplyFlags", - 34: "MessageType_BackupDevice", - 35: "MessageType_EntropyRequest", - 36: "MessageType_EntropyAck", - 41: "MessageType_PassphraseRequest", - 42: "MessageType_PassphraseAck", - 77: "MessageType_PassphraseStateRequest", - 78: "MessageType_PassphraseStateAck", - 45: "MessageType_RecoveryDevice", - 46: "MessageType_WordRequest", - 47: "MessageType_WordAck", - 55: "MessageType_GetFeatures", - 63: "MessageType_SetU2FCounter", - 6: "MessageType_FirmwareErase", - 7: "MessageType_FirmwareUpload", - 8: "MessageType_FirmwareRequest", - 32: "MessageType_SelfTest", - 11: "MessageType_GetPublicKey", - 12: "MessageType_PublicKey", - 15: "MessageType_SignTx", - 21: "MessageType_TxRequest", - 22: "MessageType_TxAck", - 29: "MessageType_GetAddress", - 30: "MessageType_Address", - 38: "MessageType_SignMessage", - 39: "MessageType_VerifyMessage", - 40: "MessageType_MessageSignature", - 23: "MessageType_CipherKeyValue", - 48: "MessageType_CipheredKeyValue", - 53: "MessageType_SignIdentity", - 54: "MessageType_SignedIdentity", - 61: "MessageType_GetECDHSessionKey", - 62: "MessageType_ECDHSessionKey", - 71: "MessageType_CosiCommit", - 72: "MessageType_CosiCommitment", - 73: "MessageType_CosiSign", - 74: "MessageType_CosiSignature", - 100: "MessageType_DebugLinkDecision", - 101: "MessageType_DebugLinkGetState", - 102: "MessageType_DebugLinkState", - 103: "MessageType_DebugLinkStop", - 104: "MessageType_DebugLinkLog", - 110: "MessageType_DebugLinkMemoryRead", - 111: "MessageType_DebugLinkMemory", - 112: "MessageType_DebugLinkMemoryWrite", - 113: "MessageType_DebugLinkFlashErase", - 450: "MessageType_EthereumGetPublicKey", - 451: "MessageType_EthereumPublicKey", - 56: "MessageType_EthereumGetAddress", - 57: "MessageType_EthereumAddress", - 58: "MessageType_EthereumSignTx", - 59: "MessageType_EthereumTxRequest", - 60: "MessageType_EthereumTxAck", - 64: "MessageType_EthereumSignMessage", - 65: "MessageType_EthereumVerifyMessage", - 66: "MessageType_EthereumMessageSignature", - 67: "MessageType_NEMGetAddress", - 68: "MessageType_NEMAddress", - 69: "MessageType_NEMSignTx", - 70: "MessageType_NEMSignedTx", - 75: "MessageType_NEMDecryptMessage", - 76: "MessageType_NEMDecryptedMessage", - 114: "MessageType_LiskGetAddress", - 115: "MessageType_LiskAddress", - 116: "MessageType_LiskSignTx", - 117: "MessageType_LiskSignedTx", - 118: "MessageType_LiskSignMessage", - 119: "MessageType_LiskMessageSignature", - 120: "MessageType_LiskVerifyMessage", - 121: "MessageType_LiskGetPublicKey", - 122: "MessageType_LiskPublicKey", - 150: "MessageType_TezosGetAddress", - 151: "MessageType_TezosAddress", - 152: "MessageType_TezosSignTx", - 153: "MessageType_TezosSignedTx", - 154: "MessageType_TezosGetPublicKey", - 155: "MessageType_TezosPublicKey", - 202: "MessageType_StellarSignTx", - 203: "MessageType_StellarTxOpRequest", - 207: "MessageType_StellarGetAddress", - 208: "MessageType_StellarAddress", - 210: "MessageType_StellarCreateAccountOp", - 211: "MessageType_StellarPaymentOp", - 212: "MessageType_StellarPathPaymentOp", - 213: "MessageType_StellarManageOfferOp", - 214: "MessageType_StellarCreatePassiveOfferOp", - 215: "MessageType_StellarSetOptionsOp", - 216: "MessageType_StellarChangeTrustOp", - 217: "MessageType_StellarAllowTrustOp", - 218: "MessageType_StellarAccountMergeOp", - 220: "MessageType_StellarManageDataOp", - 221: "MessageType_StellarBumpSequenceOp", - 230: "MessageType_StellarSignedTx", - 250: "MessageType_TronGetAddress", - 251: "MessageType_TronAddress", - 252: "MessageType_TronSignTx", - 253: "MessageType_TronSignedTx", - 303: "MessageType_CardanoSignTx", - 304: "MessageType_CardanoTxRequest", - 305: "MessageType_CardanoGetPublicKey", - 306: "MessageType_CardanoPublicKey", - 307: "MessageType_CardanoGetAddress", - 308: "MessageType_CardanoAddress", - 309: "MessageType_CardanoTxAck", - 310: "MessageType_CardanoSignedTx", - 350: "MessageType_OntologyGetAddress", - 351: "MessageType_OntologyAddress", - 352: "MessageType_OntologyGetPublicKey", - 353: "MessageType_OntologyPublicKey", - 354: "MessageType_OntologySignTransfer", - 355: "MessageType_OntologySignedTransfer", - 356: "MessageType_OntologySignWithdrawOng", - 357: "MessageType_OntologySignedWithdrawOng", - 358: "MessageType_OntologySignOntIdRegister", - 359: "MessageType_OntologySignedOntIdRegister", - 360: "MessageType_OntologySignOntIdAddAttributes", - 361: "MessageType_OntologySignedOntIdAddAttributes", - 400: "MessageType_RippleGetAddress", - 401: "MessageType_RippleAddress", - 402: "MessageType_RippleSignTx", - 403: "MessageType_RippleSignedTx", - 501: "MessageType_MoneroTransactionInitRequest", - 502: "MessageType_MoneroTransactionInitAck", - 503: "MessageType_MoneroTransactionSetInputRequest", - 504: "MessageType_MoneroTransactionSetInputAck", - 505: "MessageType_MoneroTransactionInputsPermutationRequest", - 506: "MessageType_MoneroTransactionInputsPermutationAck", - 507: "MessageType_MoneroTransactionInputViniRequest", - 508: "MessageType_MoneroTransactionInputViniAck", - 509: "MessageType_MoneroTransactionAllInputsSetRequest", - 510: "MessageType_MoneroTransactionAllInputsSetAck", - 511: "MessageType_MoneroTransactionSetOutputRequest", - 512: "MessageType_MoneroTransactionSetOutputAck", - 513: "MessageType_MoneroTransactionAllOutSetRequest", - 514: "MessageType_MoneroTransactionAllOutSetAck", - 515: "MessageType_MoneroTransactionSignInputRequest", - 516: "MessageType_MoneroTransactionSignInputAck", - 517: "MessageType_MoneroTransactionFinalRequest", - 518: "MessageType_MoneroTransactionFinalAck", - 530: "MessageType_MoneroKeyImageExportInitRequest", - 531: "MessageType_MoneroKeyImageExportInitAck", - 532: "MessageType_MoneroKeyImageSyncStepRequest", - 533: "MessageType_MoneroKeyImageSyncStepAck", - 534: "MessageType_MoneroKeyImageSyncFinalRequest", - 535: "MessageType_MoneroKeyImageSyncFinalAck", - 540: "MessageType_MoneroGetAddress", - 541: "MessageType_MoneroAddress", - 542: "MessageType_MoneroGetWatchKey", - 543: "MessageType_MoneroWatchKey", - 546: "MessageType_DebugMoneroDiagRequest", - 547: "MessageType_DebugMoneroDiagAck", - 550: "MessageType_MoneroGetTxKeyRequest", - 551: "MessageType_MoneroGetTxKeyAck", - 552: "MessageType_MoneroLiveRefreshStartRequest", - 553: "MessageType_MoneroLiveRefreshStartAck", - 554: "MessageType_MoneroLiveRefreshStepRequest", - 555: "MessageType_MoneroLiveRefreshStepAck", - 556: "MessageType_MoneroLiveRefreshFinalRequest", - 557: "MessageType_MoneroLiveRefreshFinalAck", - 600: "MessageType_EosGetPublicKey", - 601: "MessageType_EosPublicKey", - 602: "MessageType_EosSignTx", - 603: "MessageType_EosTxActionRequest", - 604: "MessageType_EosTxActionAck", - 605: "MessageType_EosSignedTx", - 700: "MessageType_BinanceGetAddress", - 701: "MessageType_BinanceAddress", - 702: "MessageType_BinanceGetPublicKey", - 703: "MessageType_BinancePublicKey", - 704: "MessageType_BinanceSignTx", - 705: "MessageType_BinanceTxRequest", - 706: "MessageType_BinanceTransferMsg", - 707: "MessageType_BinanceOrderMsg", - 708: "MessageType_BinanceCancelMsg", - 709: "MessageType_BinanceSignedTx", -} - -var MessageType_value = map[string]int32{ - "MessageType_Initialize": 0, - "MessageType_Ping": 1, - "MessageType_Success": 2, - "MessageType_Failure": 3, - "MessageType_ChangePin": 4, - "MessageType_WipeDevice": 5, - "MessageType_GetEntropy": 9, - "MessageType_Entropy": 10, - "MessageType_LoadDevice": 13, - "MessageType_ResetDevice": 14, - "MessageType_Features": 17, - "MessageType_PinMatrixRequest": 18, - "MessageType_PinMatrixAck": 19, - "MessageType_Cancel": 20, - "MessageType_ClearSession": 24, - "MessageType_ApplySettings": 25, - "MessageType_ButtonRequest": 26, - "MessageType_ButtonAck": 27, - "MessageType_ApplyFlags": 28, - "MessageType_BackupDevice": 34, - "MessageType_EntropyRequest": 35, - "MessageType_EntropyAck": 36, - "MessageType_PassphraseRequest": 41, - "MessageType_PassphraseAck": 42, - "MessageType_PassphraseStateRequest": 77, - "MessageType_PassphraseStateAck": 78, - "MessageType_RecoveryDevice": 45, - "MessageType_WordRequest": 46, - "MessageType_WordAck": 47, - "MessageType_GetFeatures": 55, - "MessageType_SetU2FCounter": 63, - "MessageType_FirmwareErase": 6, - "MessageType_FirmwareUpload": 7, - "MessageType_FirmwareRequest": 8, - "MessageType_SelfTest": 32, - "MessageType_GetPublicKey": 11, - "MessageType_PublicKey": 12, - "MessageType_SignTx": 15, - "MessageType_TxRequest": 21, - "MessageType_TxAck": 22, - "MessageType_GetAddress": 29, - "MessageType_Address": 30, - "MessageType_SignMessage": 38, - "MessageType_VerifyMessage": 39, - "MessageType_MessageSignature": 40, - "MessageType_CipherKeyValue": 23, - "MessageType_CipheredKeyValue": 48, - "MessageType_SignIdentity": 53, - "MessageType_SignedIdentity": 54, - "MessageType_GetECDHSessionKey": 61, - "MessageType_ECDHSessionKey": 62, - "MessageType_CosiCommit": 71, - "MessageType_CosiCommitment": 72, - "MessageType_CosiSign": 73, - "MessageType_CosiSignature": 74, - "MessageType_DebugLinkDecision": 100, - "MessageType_DebugLinkGetState": 101, - "MessageType_DebugLinkState": 102, - "MessageType_DebugLinkStop": 103, - "MessageType_DebugLinkLog": 104, - "MessageType_DebugLinkMemoryRead": 110, - "MessageType_DebugLinkMemory": 111, - "MessageType_DebugLinkMemoryWrite": 112, - "MessageType_DebugLinkFlashErase": 113, - "MessageType_EthereumGetPublicKey": 450, - "MessageType_EthereumPublicKey": 451, - "MessageType_EthereumGetAddress": 56, - "MessageType_EthereumAddress": 57, - "MessageType_EthereumSignTx": 58, - "MessageType_EthereumTxRequest": 59, - "MessageType_EthereumTxAck": 60, - "MessageType_EthereumSignMessage": 64, - "MessageType_EthereumVerifyMessage": 65, - "MessageType_EthereumMessageSignature": 66, - "MessageType_NEMGetAddress": 67, - "MessageType_NEMAddress": 68, - "MessageType_NEMSignTx": 69, - "MessageType_NEMSignedTx": 70, - "MessageType_NEMDecryptMessage": 75, - "MessageType_NEMDecryptedMessage": 76, - "MessageType_LiskGetAddress": 114, - "MessageType_LiskAddress": 115, - "MessageType_LiskSignTx": 116, - "MessageType_LiskSignedTx": 117, - "MessageType_LiskSignMessage": 118, - "MessageType_LiskMessageSignature": 119, - "MessageType_LiskVerifyMessage": 120, - "MessageType_LiskGetPublicKey": 121, - "MessageType_LiskPublicKey": 122, - "MessageType_TezosGetAddress": 150, - "MessageType_TezosAddress": 151, - "MessageType_TezosSignTx": 152, - "MessageType_TezosSignedTx": 153, - "MessageType_TezosGetPublicKey": 154, - "MessageType_TezosPublicKey": 155, - "MessageType_StellarSignTx": 202, - "MessageType_StellarTxOpRequest": 203, - "MessageType_StellarGetAddress": 207, - "MessageType_StellarAddress": 208, - "MessageType_StellarCreateAccountOp": 210, - "MessageType_StellarPaymentOp": 211, - "MessageType_StellarPathPaymentOp": 212, - "MessageType_StellarManageOfferOp": 213, - "MessageType_StellarCreatePassiveOfferOp": 214, - "MessageType_StellarSetOptionsOp": 215, - "MessageType_StellarChangeTrustOp": 216, - "MessageType_StellarAllowTrustOp": 217, - "MessageType_StellarAccountMergeOp": 218, - "MessageType_StellarManageDataOp": 220, - "MessageType_StellarBumpSequenceOp": 221, - "MessageType_StellarSignedTx": 230, - "MessageType_TronGetAddress": 250, - "MessageType_TronAddress": 251, - "MessageType_TronSignTx": 252, - "MessageType_TronSignedTx": 253, - "MessageType_CardanoSignTx": 303, - "MessageType_CardanoTxRequest": 304, - "MessageType_CardanoGetPublicKey": 305, - "MessageType_CardanoPublicKey": 306, - "MessageType_CardanoGetAddress": 307, - "MessageType_CardanoAddress": 308, - "MessageType_CardanoTxAck": 309, - "MessageType_CardanoSignedTx": 310, - "MessageType_OntologyGetAddress": 350, - "MessageType_OntologyAddress": 351, - "MessageType_OntologyGetPublicKey": 352, - "MessageType_OntologyPublicKey": 353, - "MessageType_OntologySignTransfer": 354, - "MessageType_OntologySignedTransfer": 355, - "MessageType_OntologySignWithdrawOng": 356, - "MessageType_OntologySignedWithdrawOng": 357, - "MessageType_OntologySignOntIdRegister": 358, - "MessageType_OntologySignedOntIdRegister": 359, - "MessageType_OntologySignOntIdAddAttributes": 360, - "MessageType_OntologySignedOntIdAddAttributes": 361, - "MessageType_RippleGetAddress": 400, - "MessageType_RippleAddress": 401, - "MessageType_RippleSignTx": 402, - "MessageType_RippleSignedTx": 403, - "MessageType_MoneroTransactionInitRequest": 501, - "MessageType_MoneroTransactionInitAck": 502, - "MessageType_MoneroTransactionSetInputRequest": 503, - "MessageType_MoneroTransactionSetInputAck": 504, - "MessageType_MoneroTransactionInputsPermutationRequest": 505, - "MessageType_MoneroTransactionInputsPermutationAck": 506, - "MessageType_MoneroTransactionInputViniRequest": 507, - "MessageType_MoneroTransactionInputViniAck": 508, - "MessageType_MoneroTransactionAllInputsSetRequest": 509, - "MessageType_MoneroTransactionAllInputsSetAck": 510, - "MessageType_MoneroTransactionSetOutputRequest": 511, - "MessageType_MoneroTransactionSetOutputAck": 512, - "MessageType_MoneroTransactionAllOutSetRequest": 513, - "MessageType_MoneroTransactionAllOutSetAck": 514, - "MessageType_MoneroTransactionSignInputRequest": 515, - "MessageType_MoneroTransactionSignInputAck": 516, - "MessageType_MoneroTransactionFinalRequest": 517, - "MessageType_MoneroTransactionFinalAck": 518, - "MessageType_MoneroKeyImageExportInitRequest": 530, - "MessageType_MoneroKeyImageExportInitAck": 531, - "MessageType_MoneroKeyImageSyncStepRequest": 532, - "MessageType_MoneroKeyImageSyncStepAck": 533, - "MessageType_MoneroKeyImageSyncFinalRequest": 534, - "MessageType_MoneroKeyImageSyncFinalAck": 535, - "MessageType_MoneroGetAddress": 540, - "MessageType_MoneroAddress": 541, - "MessageType_MoneroGetWatchKey": 542, - "MessageType_MoneroWatchKey": 543, - "MessageType_DebugMoneroDiagRequest": 546, - "MessageType_DebugMoneroDiagAck": 547, - "MessageType_MoneroGetTxKeyRequest": 550, - "MessageType_MoneroGetTxKeyAck": 551, - "MessageType_MoneroLiveRefreshStartRequest": 552, - "MessageType_MoneroLiveRefreshStartAck": 553, - "MessageType_MoneroLiveRefreshStepRequest": 554, - "MessageType_MoneroLiveRefreshStepAck": 555, - "MessageType_MoneroLiveRefreshFinalRequest": 556, - "MessageType_MoneroLiveRefreshFinalAck": 557, - "MessageType_EosGetPublicKey": 600, - "MessageType_EosPublicKey": 601, - "MessageType_EosSignTx": 602, - "MessageType_EosTxActionRequest": 603, - "MessageType_EosTxActionAck": 604, - "MessageType_EosSignedTx": 605, - "MessageType_BinanceGetAddress": 700, - "MessageType_BinanceAddress": 701, - "MessageType_BinanceGetPublicKey": 702, - "MessageType_BinancePublicKey": 703, - "MessageType_BinanceSignTx": 704, - "MessageType_BinanceTxRequest": 705, - "MessageType_BinanceTransferMsg": 706, - "MessageType_BinanceOrderMsg": 707, - "MessageType_BinanceCancelMsg": 708, - "MessageType_BinanceSignedTx": 709, -} +// Enum value maps for MessageType. +var ( + MessageType_name = map[int32]string{ + 0: "MessageType_Initialize", + 1: "MessageType_Ping", + 2: "MessageType_Success", + 3: "MessageType_Failure", + 4: "MessageType_ChangePin", + 5: "MessageType_WipeDevice", + 9: "MessageType_GetEntropy", + 10: "MessageType_Entropy", + 13: "MessageType_LoadDevice", + 14: "MessageType_ResetDevice", + 17: "MessageType_Features", + 18: "MessageType_PinMatrixRequest", + 19: "MessageType_PinMatrixAck", + 20: "MessageType_Cancel", + 24: "MessageType_ClearSession", + 25: "MessageType_ApplySettings", + 26: "MessageType_ButtonRequest", + 27: "MessageType_ButtonAck", + 28: "MessageType_ApplyFlags", + 34: "MessageType_BackupDevice", + 35: "MessageType_EntropyRequest", + 36: "MessageType_EntropyAck", + 41: "MessageType_PassphraseRequest", + 42: "MessageType_PassphraseAck", + 77: "MessageType_PassphraseStateRequest", + 78: "MessageType_PassphraseStateAck", + 45: "MessageType_RecoveryDevice", + 46: "MessageType_WordRequest", + 47: "MessageType_WordAck", + 55: "MessageType_GetFeatures", + 63: "MessageType_SetU2FCounter", + 6: "MessageType_FirmwareErase", + 7: "MessageType_FirmwareUpload", + 8: "MessageType_FirmwareRequest", + 32: "MessageType_SelfTest", + 11: "MessageType_GetPublicKey", + 12: "MessageType_PublicKey", + 15: "MessageType_SignTx", + 21: "MessageType_TxRequest", + 22: "MessageType_TxAck", + 29: "MessageType_GetAddress", + 30: "MessageType_Address", + 38: "MessageType_SignMessage", + 39: "MessageType_VerifyMessage", + 40: "MessageType_MessageSignature", + 23: "MessageType_CipherKeyValue", + 48: "MessageType_CipheredKeyValue", + 53: "MessageType_SignIdentity", + 54: "MessageType_SignedIdentity", + 61: "MessageType_GetECDHSessionKey", + 62: "MessageType_ECDHSessionKey", + 71: "MessageType_CosiCommit", + 72: "MessageType_CosiCommitment", + 73: "MessageType_CosiSign", + 74: "MessageType_CosiSignature", + 100: "MessageType_DebugLinkDecision", + 101: "MessageType_DebugLinkGetState", + 102: "MessageType_DebugLinkState", + 103: "MessageType_DebugLinkStop", + 104: "MessageType_DebugLinkLog", + 110: "MessageType_DebugLinkMemoryRead", + 111: "MessageType_DebugLinkMemory", + 112: "MessageType_DebugLinkMemoryWrite", + 113: "MessageType_DebugLinkFlashErase", + 450: "MessageType_EthereumGetPublicKey", + 451: "MessageType_EthereumPublicKey", + 56: "MessageType_EthereumGetAddress", + 57: "MessageType_EthereumAddress", + 58: "MessageType_EthereumSignTx", + 59: "MessageType_EthereumTxRequest", + 60: "MessageType_EthereumTxAck", + 64: "MessageType_EthereumSignMessage", + 65: "MessageType_EthereumVerifyMessage", + 66: "MessageType_EthereumMessageSignature", + 67: "MessageType_NEMGetAddress", + 68: "MessageType_NEMAddress", + 69: "MessageType_NEMSignTx", + 70: "MessageType_NEMSignedTx", + 75: "MessageType_NEMDecryptMessage", + 76: "MessageType_NEMDecryptedMessage", + 114: "MessageType_LiskGetAddress", + 115: "MessageType_LiskAddress", + 116: "MessageType_LiskSignTx", + 117: "MessageType_LiskSignedTx", + 118: "MessageType_LiskSignMessage", + 119: "MessageType_LiskMessageSignature", + 120: "MessageType_LiskVerifyMessage", + 121: "MessageType_LiskGetPublicKey", + 122: "MessageType_LiskPublicKey", + 150: "MessageType_TezosGetAddress", + 151: "MessageType_TezosAddress", + 152: "MessageType_TezosSignTx", + 153: "MessageType_TezosSignedTx", + 154: "MessageType_TezosGetPublicKey", + 155: "MessageType_TezosPublicKey", + 202: "MessageType_StellarSignTx", + 203: "MessageType_StellarTxOpRequest", + 207: "MessageType_StellarGetAddress", + 208: "MessageType_StellarAddress", + 210: "MessageType_StellarCreateAccountOp", + 211: "MessageType_StellarPaymentOp", + 212: "MessageType_StellarPathPaymentOp", + 213: "MessageType_StellarManageOfferOp", + 214: "MessageType_StellarCreatePassiveOfferOp", + 215: "MessageType_StellarSetOptionsOp", + 216: "MessageType_StellarChangeTrustOp", + 217: "MessageType_StellarAllowTrustOp", + 218: "MessageType_StellarAccountMergeOp", + 220: "MessageType_StellarManageDataOp", + 221: "MessageType_StellarBumpSequenceOp", + 230: "MessageType_StellarSignedTx", + 250: "MessageType_TronGetAddress", + 251: "MessageType_TronAddress", + 252: "MessageType_TronSignTx", + 253: "MessageType_TronSignedTx", + 303: "MessageType_CardanoSignTx", + 304: "MessageType_CardanoTxRequest", + 305: "MessageType_CardanoGetPublicKey", + 306: "MessageType_CardanoPublicKey", + 307: "MessageType_CardanoGetAddress", + 308: "MessageType_CardanoAddress", + 309: "MessageType_CardanoTxAck", + 310: "MessageType_CardanoSignedTx", + 350: "MessageType_OntologyGetAddress", + 351: "MessageType_OntologyAddress", + 352: "MessageType_OntologyGetPublicKey", + 353: "MessageType_OntologyPublicKey", + 354: "MessageType_OntologySignTransfer", + 355: "MessageType_OntologySignedTransfer", + 356: "MessageType_OntologySignWithdrawOng", + 357: "MessageType_OntologySignedWithdrawOng", + 358: "MessageType_OntologySignOntIdRegister", + 359: "MessageType_OntologySignedOntIdRegister", + 360: "MessageType_OntologySignOntIdAddAttributes", + 361: "MessageType_OntologySignedOntIdAddAttributes", + 400: "MessageType_RippleGetAddress", + 401: "MessageType_RippleAddress", + 402: "MessageType_RippleSignTx", + 403: "MessageType_RippleSignedTx", + 501: "MessageType_MoneroTransactionInitRequest", + 502: "MessageType_MoneroTransactionInitAck", + 503: "MessageType_MoneroTransactionSetInputRequest", + 504: "MessageType_MoneroTransactionSetInputAck", + 505: "MessageType_MoneroTransactionInputsPermutationRequest", + 506: "MessageType_MoneroTransactionInputsPermutationAck", + 507: "MessageType_MoneroTransactionInputViniRequest", + 508: "MessageType_MoneroTransactionInputViniAck", + 509: "MessageType_MoneroTransactionAllInputsSetRequest", + 510: "MessageType_MoneroTransactionAllInputsSetAck", + 511: "MessageType_MoneroTransactionSetOutputRequest", + 512: "MessageType_MoneroTransactionSetOutputAck", + 513: "MessageType_MoneroTransactionAllOutSetRequest", + 514: "MessageType_MoneroTransactionAllOutSetAck", + 515: "MessageType_MoneroTransactionSignInputRequest", + 516: "MessageType_MoneroTransactionSignInputAck", + 517: "MessageType_MoneroTransactionFinalRequest", + 518: "MessageType_MoneroTransactionFinalAck", + 530: "MessageType_MoneroKeyImageExportInitRequest", + 531: "MessageType_MoneroKeyImageExportInitAck", + 532: "MessageType_MoneroKeyImageSyncStepRequest", + 533: "MessageType_MoneroKeyImageSyncStepAck", + 534: "MessageType_MoneroKeyImageSyncFinalRequest", + 535: "MessageType_MoneroKeyImageSyncFinalAck", + 540: "MessageType_MoneroGetAddress", + 541: "MessageType_MoneroAddress", + 542: "MessageType_MoneroGetWatchKey", + 543: "MessageType_MoneroWatchKey", + 546: "MessageType_DebugMoneroDiagRequest", + 547: "MessageType_DebugMoneroDiagAck", + 550: "MessageType_MoneroGetTxKeyRequest", + 551: "MessageType_MoneroGetTxKeyAck", + 552: "MessageType_MoneroLiveRefreshStartRequest", + 553: "MessageType_MoneroLiveRefreshStartAck", + 554: "MessageType_MoneroLiveRefreshStepRequest", + 555: "MessageType_MoneroLiveRefreshStepAck", + 556: "MessageType_MoneroLiveRefreshFinalRequest", + 557: "MessageType_MoneroLiveRefreshFinalAck", + 600: "MessageType_EosGetPublicKey", + 601: "MessageType_EosPublicKey", + 602: "MessageType_EosSignTx", + 603: "MessageType_EosTxActionRequest", + 604: "MessageType_EosTxActionAck", + 605: "MessageType_EosSignedTx", + 700: "MessageType_BinanceGetAddress", + 701: "MessageType_BinanceAddress", + 702: "MessageType_BinanceGetPublicKey", + 703: "MessageType_BinancePublicKey", + 704: "MessageType_BinanceSignTx", + 705: "MessageType_BinanceTxRequest", + 706: "MessageType_BinanceTransferMsg", + 707: "MessageType_BinanceOrderMsg", + 708: "MessageType_BinanceCancelMsg", + 709: "MessageType_BinanceSignedTx", + } + MessageType_value = map[string]int32{ + "MessageType_Initialize": 0, + "MessageType_Ping": 1, + "MessageType_Success": 2, + "MessageType_Failure": 3, + "MessageType_ChangePin": 4, + "MessageType_WipeDevice": 5, + "MessageType_GetEntropy": 9, + "MessageType_Entropy": 10, + "MessageType_LoadDevice": 13, + "MessageType_ResetDevice": 14, + "MessageType_Features": 17, + "MessageType_PinMatrixRequest": 18, + "MessageType_PinMatrixAck": 19, + "MessageType_Cancel": 20, + "MessageType_ClearSession": 24, + "MessageType_ApplySettings": 25, + "MessageType_ButtonRequest": 26, + "MessageType_ButtonAck": 27, + "MessageType_ApplyFlags": 28, + "MessageType_BackupDevice": 34, + "MessageType_EntropyRequest": 35, + "MessageType_EntropyAck": 36, + "MessageType_PassphraseRequest": 41, + "MessageType_PassphraseAck": 42, + "MessageType_PassphraseStateRequest": 77, + "MessageType_PassphraseStateAck": 78, + "MessageType_RecoveryDevice": 45, + "MessageType_WordRequest": 46, + "MessageType_WordAck": 47, + "MessageType_GetFeatures": 55, + "MessageType_SetU2FCounter": 63, + "MessageType_FirmwareErase": 6, + "MessageType_FirmwareUpload": 7, + "MessageType_FirmwareRequest": 8, + "MessageType_SelfTest": 32, + "MessageType_GetPublicKey": 11, + "MessageType_PublicKey": 12, + "MessageType_SignTx": 15, + "MessageType_TxRequest": 21, + "MessageType_TxAck": 22, + "MessageType_GetAddress": 29, + "MessageType_Address": 30, + "MessageType_SignMessage": 38, + "MessageType_VerifyMessage": 39, + "MessageType_MessageSignature": 40, + "MessageType_CipherKeyValue": 23, + "MessageType_CipheredKeyValue": 48, + "MessageType_SignIdentity": 53, + "MessageType_SignedIdentity": 54, + "MessageType_GetECDHSessionKey": 61, + "MessageType_ECDHSessionKey": 62, + "MessageType_CosiCommit": 71, + "MessageType_CosiCommitment": 72, + "MessageType_CosiSign": 73, + "MessageType_CosiSignature": 74, + "MessageType_DebugLinkDecision": 100, + "MessageType_DebugLinkGetState": 101, + "MessageType_DebugLinkState": 102, + "MessageType_DebugLinkStop": 103, + "MessageType_DebugLinkLog": 104, + "MessageType_DebugLinkMemoryRead": 110, + "MessageType_DebugLinkMemory": 111, + "MessageType_DebugLinkMemoryWrite": 112, + "MessageType_DebugLinkFlashErase": 113, + "MessageType_EthereumGetPublicKey": 450, + "MessageType_EthereumPublicKey": 451, + "MessageType_EthereumGetAddress": 56, + "MessageType_EthereumAddress": 57, + "MessageType_EthereumSignTx": 58, + "MessageType_EthereumTxRequest": 59, + "MessageType_EthereumTxAck": 60, + "MessageType_EthereumSignMessage": 64, + "MessageType_EthereumVerifyMessage": 65, + "MessageType_EthereumMessageSignature": 66, + "MessageType_NEMGetAddress": 67, + "MessageType_NEMAddress": 68, + "MessageType_NEMSignTx": 69, + "MessageType_NEMSignedTx": 70, + "MessageType_NEMDecryptMessage": 75, + "MessageType_NEMDecryptedMessage": 76, + "MessageType_LiskGetAddress": 114, + "MessageType_LiskAddress": 115, + "MessageType_LiskSignTx": 116, + "MessageType_LiskSignedTx": 117, + "MessageType_LiskSignMessage": 118, + "MessageType_LiskMessageSignature": 119, + "MessageType_LiskVerifyMessage": 120, + "MessageType_LiskGetPublicKey": 121, + "MessageType_LiskPublicKey": 122, + "MessageType_TezosGetAddress": 150, + "MessageType_TezosAddress": 151, + "MessageType_TezosSignTx": 152, + "MessageType_TezosSignedTx": 153, + "MessageType_TezosGetPublicKey": 154, + "MessageType_TezosPublicKey": 155, + "MessageType_StellarSignTx": 202, + "MessageType_StellarTxOpRequest": 203, + "MessageType_StellarGetAddress": 207, + "MessageType_StellarAddress": 208, + "MessageType_StellarCreateAccountOp": 210, + "MessageType_StellarPaymentOp": 211, + "MessageType_StellarPathPaymentOp": 212, + "MessageType_StellarManageOfferOp": 213, + "MessageType_StellarCreatePassiveOfferOp": 214, + "MessageType_StellarSetOptionsOp": 215, + "MessageType_StellarChangeTrustOp": 216, + "MessageType_StellarAllowTrustOp": 217, + "MessageType_StellarAccountMergeOp": 218, + "MessageType_StellarManageDataOp": 220, + "MessageType_StellarBumpSequenceOp": 221, + "MessageType_StellarSignedTx": 230, + "MessageType_TronGetAddress": 250, + "MessageType_TronAddress": 251, + "MessageType_TronSignTx": 252, + "MessageType_TronSignedTx": 253, + "MessageType_CardanoSignTx": 303, + "MessageType_CardanoTxRequest": 304, + "MessageType_CardanoGetPublicKey": 305, + "MessageType_CardanoPublicKey": 306, + "MessageType_CardanoGetAddress": 307, + "MessageType_CardanoAddress": 308, + "MessageType_CardanoTxAck": 309, + "MessageType_CardanoSignedTx": 310, + "MessageType_OntologyGetAddress": 350, + "MessageType_OntologyAddress": 351, + "MessageType_OntologyGetPublicKey": 352, + "MessageType_OntologyPublicKey": 353, + "MessageType_OntologySignTransfer": 354, + "MessageType_OntologySignedTransfer": 355, + "MessageType_OntologySignWithdrawOng": 356, + "MessageType_OntologySignedWithdrawOng": 357, + "MessageType_OntologySignOntIdRegister": 358, + "MessageType_OntologySignedOntIdRegister": 359, + "MessageType_OntologySignOntIdAddAttributes": 360, + "MessageType_OntologySignedOntIdAddAttributes": 361, + "MessageType_RippleGetAddress": 400, + "MessageType_RippleAddress": 401, + "MessageType_RippleSignTx": 402, + "MessageType_RippleSignedTx": 403, + "MessageType_MoneroTransactionInitRequest": 501, + "MessageType_MoneroTransactionInitAck": 502, + "MessageType_MoneroTransactionSetInputRequest": 503, + "MessageType_MoneroTransactionSetInputAck": 504, + "MessageType_MoneroTransactionInputsPermutationRequest": 505, + "MessageType_MoneroTransactionInputsPermutationAck": 506, + "MessageType_MoneroTransactionInputViniRequest": 507, + "MessageType_MoneroTransactionInputViniAck": 508, + "MessageType_MoneroTransactionAllInputsSetRequest": 509, + "MessageType_MoneroTransactionAllInputsSetAck": 510, + "MessageType_MoneroTransactionSetOutputRequest": 511, + "MessageType_MoneroTransactionSetOutputAck": 512, + "MessageType_MoneroTransactionAllOutSetRequest": 513, + "MessageType_MoneroTransactionAllOutSetAck": 514, + "MessageType_MoneroTransactionSignInputRequest": 515, + "MessageType_MoneroTransactionSignInputAck": 516, + "MessageType_MoneroTransactionFinalRequest": 517, + "MessageType_MoneroTransactionFinalAck": 518, + "MessageType_MoneroKeyImageExportInitRequest": 530, + "MessageType_MoneroKeyImageExportInitAck": 531, + "MessageType_MoneroKeyImageSyncStepRequest": 532, + "MessageType_MoneroKeyImageSyncStepAck": 533, + "MessageType_MoneroKeyImageSyncFinalRequest": 534, + "MessageType_MoneroKeyImageSyncFinalAck": 535, + "MessageType_MoneroGetAddress": 540, + "MessageType_MoneroAddress": 541, + "MessageType_MoneroGetWatchKey": 542, + "MessageType_MoneroWatchKey": 543, + "MessageType_DebugMoneroDiagRequest": 546, + "MessageType_DebugMoneroDiagAck": 547, + "MessageType_MoneroGetTxKeyRequest": 550, + "MessageType_MoneroGetTxKeyAck": 551, + "MessageType_MoneroLiveRefreshStartRequest": 552, + "MessageType_MoneroLiveRefreshStartAck": 553, + "MessageType_MoneroLiveRefreshStepRequest": 554, + "MessageType_MoneroLiveRefreshStepAck": 555, + "MessageType_MoneroLiveRefreshFinalRequest": 556, + "MessageType_MoneroLiveRefreshFinalAck": 557, + "MessageType_EosGetPublicKey": 600, + "MessageType_EosPublicKey": 601, + "MessageType_EosSignTx": 602, + "MessageType_EosTxActionRequest": 603, + "MessageType_EosTxActionAck": 604, + "MessageType_EosSignedTx": 605, + "MessageType_BinanceGetAddress": 700, + "MessageType_BinanceAddress": 701, + "MessageType_BinanceGetPublicKey": 702, + "MessageType_BinancePublicKey": 703, + "MessageType_BinanceSignTx": 704, + "MessageType_BinanceTxRequest": 705, + "MessageType_BinanceTransferMsg": 706, + "MessageType_BinanceOrderMsg": 707, + "MessageType_BinanceCancelMsg": 708, + "MessageType_BinanceSignedTx": 709, + } +) func (x MessageType) Enum() *MessageType { p := new(MessageType) @@ -640,250 +645,722 @@ func (x MessageType) Enum() *MessageType { } func (x MessageType) String() string { - return proto.EnumName(MessageType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (x *MessageType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(MessageType_value, data, "MessageType") +func (MessageType) Descriptor() protoreflect.EnumDescriptor { + return file_messages_proto_enumTypes[0].Descriptor() +} + +func (MessageType) Type() protoreflect.EnumType { + return &file_messages_proto_enumTypes[0] +} + +func (x MessageType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *MessageType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) if err != nil { return err } - *x = MessageType(value) + *x = MessageType(num) return nil } +// Deprecated: Use MessageType.Descriptor instead. func (MessageType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_4dc296cbfe5ffcd5, []int{0} + return file_messages_proto_rawDescGZIP(), []int{0} } -var E_WireIn = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50002, - Name: "hw.trezor.messages.wire_in", - Tag: "varint,50002,opt,name=wire_in", - Filename: "messages.proto", +var file_messages_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50002, + Name: "hw.trezor.messages.wire_in", + Tag: "varint,50002,opt,name=wire_in", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50003, + Name: "hw.trezor.messages.wire_out", + Tag: "varint,50003,opt,name=wire_out", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50004, + Name: "hw.trezor.messages.wire_debug_in", + Tag: "varint,50004,opt,name=wire_debug_in", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50005, + Name: "hw.trezor.messages.wire_debug_out", + Tag: "varint,50005,opt,name=wire_debug_out", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50006, + Name: "hw.trezor.messages.wire_tiny", + Tag: "varint,50006,opt,name=wire_tiny", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50007, + Name: "hw.trezor.messages.wire_bootloader", + Tag: "varint,50007,opt,name=wire_bootloader", + Filename: "messages.proto", + }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50008, + Name: "hw.trezor.messages.wire_no_fsm", + Tag: "varint,50008,opt,name=wire_no_fsm", + Filename: "messages.proto", + }, } -var E_WireOut = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50003, - Name: "hw.trezor.messages.wire_out", - Tag: "varint,50003,opt,name=wire_out", - Filename: "messages.proto", +// Extension fields to descriptorpb.EnumValueOptions. +var ( + // optional bool wire_in = 50002; + E_WireIn = &file_messages_proto_extTypes[0] // message can be transmitted via wire from PC to TREZOR + // optional bool wire_out = 50003; + E_WireOut = &file_messages_proto_extTypes[1] // message can be transmitted via wire from TREZOR to PC + // optional bool wire_debug_in = 50004; + E_WireDebugIn = &file_messages_proto_extTypes[2] // message can be transmitted via debug wire from PC to TREZOR + // optional bool wire_debug_out = 50005; + E_WireDebugOut = &file_messages_proto_extTypes[3] // message can be transmitted via debug wire from TREZOR to PC + // optional bool wire_tiny = 50006; + E_WireTiny = &file_messages_proto_extTypes[4] // message is handled by TREZOR when the USB stack is in tiny mode + // optional bool wire_bootloader = 50007; + E_WireBootloader = &file_messages_proto_extTypes[5] // message is only handled by TREZOR Bootloader + // optional bool wire_no_fsm = 50008; + E_WireNoFsm = &file_messages_proto_extTypes[6] // message is not handled by TREZOR unless the USB stack is in tiny mode +) + +var File_messages_proto protoreflect.FileDescriptor + +var file_messages_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x12, 0x68, 0x77, 0x2e, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0xb9, 0x3f, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, + 0x10, 0x00, 0x1a, 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0x12, 0x1a, 0x0a, 0x10, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x67, + 0x10, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x10, + 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x10, 0x03, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x69, 0x6e, 0x10, + 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x57, 0x69, 0x70, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x10, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74, 0x72, + 0x6f, 0x70, 0x79, 0x10, 0x09, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6e, 0x74, 0x72, 0x6f, + 0x70, 0x79, 0x10, 0x0a, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x6f, 0x61, 0x64, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x10, 0x0d, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x52, 0x65, 0x73, 0x65, + 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x0e, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, + 0x1e, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x46, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x10, 0x11, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, + 0x26, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, + 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, + 0x12, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, + 0x41, 0x63, 0x6b, 0x10, 0x13, 0x1a, 0x0c, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, + 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x10, 0x14, 0x1a, 0x08, 0x90, 0xb5, 0x18, + 0x01, 0xb0, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x10, 0x18, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x10, 0x19, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, + 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x75, + 0x74, 0x74, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x1a, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x42, 0x75, 0x74, 0x74, 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x10, 0x1b, 0x1a, 0x0c, + 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x10, 0x1c, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, + 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x22, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x10, 0x23, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x41, + 0x63, 0x6b, 0x10, 0x24, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, + 0x72, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x29, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x41, 0x63, 0x6b, + 0x10, 0x2a, 0x1a, 0x0c, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, + 0x12, 0x2c, 0x0a, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x4d, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x30, + 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x61, + 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x63, 0x6b, + 0x10, 0x4e, 0x1a, 0x0c, 0x90, 0xb5, 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, + 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x10, 0x2d, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x57, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x10, 0x2e, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x57, 0x6f, 0x72, 0x64, 0x41, 0x63, 0x6b, + 0x10, 0x2f, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x10, 0x37, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x65, 0x74, 0x55, 0x32, + 0x46, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x10, 0x3f, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, + 0x12, 0x27, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x45, 0x72, 0x61, 0x73, 0x65, 0x10, 0x06, 0x1a, + 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb8, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1a, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, + 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x10, 0x07, 0x1a, 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb8, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x46, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0x08, 0x1a, 0x08, 0x98, 0xb5, 0x18, 0x01, 0xb8, 0xb5, 0x18, 0x01, 0x12, 0x22, + 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x65, + 0x6c, 0x66, 0x54, 0x65, 0x73, 0x74, 0x10, 0x20, 0x1a, 0x08, 0x90, 0xb5, 0x18, 0x01, 0xb8, 0xb5, + 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x0b, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, + 0x0c, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1c, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0x0f, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x15, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1b, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x78, 0x41, 0x63, 0x6b, 0x10, 0x16, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x1d, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x1d, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x1e, 0x1a, 0x04, + 0x98, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, + 0x26, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x10, 0x27, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x28, 0x1a, 0x04, + 0x98, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x10, 0x17, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1c, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x69, 0x70, 0x68, 0x65, 0x72, + 0x65, 0x64, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x10, 0x30, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x10, 0x35, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x10, 0x36, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x47, 0x65, 0x74, 0x45, + 0x43, 0x44, 0x48, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x3d, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x43, 0x44, 0x48, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x4b, 0x65, 0x79, 0x10, 0x3e, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, 0x69, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x10, 0x47, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, + 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, + 0x69, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0x48, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x1e, 0x0a, 0x14, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x10, 0x49, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x43, 0x6f, 0x73, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x10, 0x4a, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2f, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, + 0x6b, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x10, 0x64, 0x1a, 0x0c, 0xa0, 0xb5, 0x18, + 0x01, 0xb0, 0xb5, 0x18, 0x01, 0xc0, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x1d, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, + 0x6e, 0x6b, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x10, 0x65, 0x1a, 0x08, 0xa0, 0xb5, + 0x18, 0x01, 0xb0, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x10, 0x66, 0x1a, 0x04, 0xa8, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x74, 0x6f, 0x70, 0x10, 0x67, 0x1a, 0x04, 0xa0, 0xb5, 0x18, + 0x01, 0x12, 0x22, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x4c, 0x6f, 0x67, 0x10, 0x68, 0x1a, + 0x04, 0xa8, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x61, 0x64, 0x10, 0x6e, 0x1a, 0x04, 0xa0, 0xb5, 0x18, 0x01, + 0x12, 0x25, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x10, + 0x6f, 0x1a, 0x04, 0xa8, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, + 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x10, 0x70, 0x1a, 0x04, 0xa0, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x4c, 0x69, 0x6e, 0x6b, 0x46, 0x6c, 0x61, 0x73, + 0x68, 0x45, 0x72, 0x61, 0x73, 0x65, 0x10, 0x71, 0x1a, 0x04, 0xa0, 0xb5, 0x18, 0x01, 0x12, 0x2b, + 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, + 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x10, 0xc2, 0x03, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, + 0x65, 0x75, 0x6d, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xc3, 0x03, 0x1a, + 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x47, 0x65, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x38, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, + 0x25, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, + 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x39, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x53, 0x69, + 0x67, 0x6e, 0x54, 0x78, 0x10, 0x3a, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x3b, 0x1a, + 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x54, 0x78, 0x41, + 0x63, 0x6b, 0x10, 0x3c, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, + 0x75, 0x6d, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x40, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x41, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x2e, 0x0a, 0x24, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x45, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x42, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, + 0x43, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x10, 0x44, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x1f, 0x0a, 0x15, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x53, 0x69, 0x67, 0x6e, + 0x54, 0x78, 0x10, 0x45, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0x46, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, + 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, + 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x4b, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4e, 0x45, 0x4d, 0x44, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0x4c, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x24, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, + 0x72, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x10, 0x73, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x20, 0x0a, 0x16, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x53, 0x69, + 0x67, 0x6e, 0x54, 0x78, 0x10, 0x74, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x18, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0x75, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x25, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4c, 0x69, 0x73, 0x6b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, + 0x76, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x10, 0x77, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x10, 0x78, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, + 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x79, 0x1a, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x4c, 0x69, 0x73, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x10, 0x7a, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x47, 0x65, + 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x96, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x12, 0x23, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x97, 0x01, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x54, + 0x78, 0x10, 0x98, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0x99, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x10, 0x9a, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x65, 0x7a, 0x6f, 0x73, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0x9b, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xca, + 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x54, 0x78, + 0x4f, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xcb, 0x01, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x10, 0xcf, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, + 0x6c, 0x61, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xd0, 0x01, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x2d, 0x0a, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4f, 0x70, 0x10, 0xd2, 0x01, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, + 0x4f, 0x70, 0x10, 0xd3, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, + 0x61, 0x72, 0x50, 0x61, 0x74, 0x68, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x10, + 0xd4, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x4d, + 0x61, 0x6e, 0x61, 0x67, 0x65, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x4f, 0x70, 0x10, 0xd5, 0x01, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x32, 0x0a, 0x27, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x4f, 0x70, + 0x10, 0xd6, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, + 0x53, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x4f, 0x70, 0x10, 0xd7, 0x01, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x4f, 0x70, 0x10, 0xd8, 0x01, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x54, 0x72, + 0x75, 0x73, 0x74, 0x4f, 0x70, 0x10, 0xd9, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2c, + 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, + 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4d, 0x65, 0x72, 0x67, + 0x65, 0x4f, 0x70, 0x10, 0xda, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, + 0x6c, 0x61, 0x72, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4f, 0x70, 0x10, + 0xdc, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2c, 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x42, + 0x75, 0x6d, 0x70, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x4f, 0x70, 0x10, 0xdd, 0x01, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x53, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x72, 0x53, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xe6, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x25, + 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, + 0x6f, 0x6e, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xfa, 0x01, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, 0x6f, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x10, 0xfb, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x21, 0x0a, 0x16, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, 0x6f, 0x6e, 0x53, 0x69, 0x67, + 0x6e, 0x54, 0x78, 0x10, 0xfc, 0x01, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x18, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x54, 0x72, 0x6f, 0x6e, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xfd, 0x01, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xaf, + 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x54, 0x78, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xb0, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x10, 0xb1, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, + 0x61, 0x6e, 0x6f, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xb2, 0x02, 0x1a, + 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x47, 0x65, 0x74, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xb3, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, + 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, + 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xb4, 0x02, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x54, 0x78, 0x41, + 0x63, 0x6b, 0x10, 0xb5, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x61, + 0x6e, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xb6, 0x02, 0x1a, 0x04, 0x98, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x47, 0x65, 0x74, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xde, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, + 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, + 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xdf, 0x02, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x47, 0x65, + 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xe0, 0x02, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x10, 0xe1, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2b, 0x0a, + 0x20, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, + 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x10, 0xe2, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2d, 0x0a, 0x22, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, + 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x10, 0xe3, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2e, 0x0a, 0x23, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, + 0x79, 0x53, 0x69, 0x67, 0x6e, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x4f, 0x6e, 0x67, + 0x10, 0xe4, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, + 0x79, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x4f, + 0x6e, 0x67, 0x10, 0xe5, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, + 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x6e, 0x74, 0x49, 0x64, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x10, 0xe6, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x32, 0x0a, + 0x27, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, + 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x6e, 0x74, 0x49, 0x64, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0xe7, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x35, 0x0a, 0x2a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x6e, 0x74, + 0x49, 0x64, 0x41, 0x64, 0x64, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x10, + 0xe8, 0x02, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x37, 0x0a, 0x2c, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4f, 0x6e, 0x74, 0x6f, 0x6c, 0x6f, 0x67, 0x79, + 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x6e, 0x74, 0x49, 0x64, 0x41, 0x64, 0x64, 0x41, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x10, 0xe9, 0x02, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x10, 0x90, 0x03, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x91, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x23, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0x92, 0x03, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x52, 0x69, 0x70, 0x70, 0x6c, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x54, 0x78, 0x10, 0x93, 0x03, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x33, 0x0a, 0x28, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x69, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xf5, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x2f, 0x0a, 0x24, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xf6, 0x03, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x37, 0x0a, 0x2c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0xf7, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x33, 0x0a, 0x28, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, + 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xf8, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x40, 0x0a, 0x35, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x75, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xf9, 0x03, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x3c, 0x0a, 0x31, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x50, 0x65, 0x72, 0x6d, 0x75, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x10, 0xfa, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x56, 0x69, 0x6e, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x10, 0xfb, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x56, 0x69, 0x6e, 0x69, 0x41, 0x63, 0x6b, 0x10, 0xfc, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x3b, 0x0a, 0x30, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x41, 0x6c, 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x10, 0xfd, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x37, 0x0a, + 0x2c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, + 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, + 0x6c, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x53, 0x65, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xfe, 0x03, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xff, 0x03, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x63, 0x6b, 0x10, 0x80, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x6c, 0x6c, 0x4f, 0x75, 0x74, 0x53, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x81, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x41, 0x6c, 0x6c, 0x4f, 0x75, 0x74, 0x53, 0x65, 0x74, 0x41, 0x63, 0x6b, 0x10, 0x82, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x38, 0x0a, 0x2d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x83, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x41, 0x63, 0x6b, 0x10, 0x84, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x10, 0x85, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x69, 0x6e, + 0x61, 0x6c, 0x41, 0x63, 0x6b, 0x10, 0x86, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x36, + 0x0a, 0x2b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, + 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x92, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x32, 0x0a, 0x27, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x41, 0x63, + 0x6b, 0x10, 0x93, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, + 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x74, 0x65, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x94, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, + 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x79, + 0x6e, 0x63, 0x53, 0x74, 0x65, 0x70, 0x41, 0x63, 0x6b, 0x10, 0x95, 0x04, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x12, 0x35, 0x0a, 0x2a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x10, 0x96, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x31, 0x0a, 0x26, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4b, + 0x65, 0x79, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x46, 0x69, 0x6e, 0x61, 0x6c, + 0x41, 0x63, 0x6b, 0x10, 0x97, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x9c, 0x04, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x10, 0x9d, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, + 0x6f, 0x47, 0x65, 0x74, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x10, 0x9e, 0x04, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x4b, 0x65, 0x79, 0x10, 0x9f, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2d, 0x0a, 0x22, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x44, 0x69, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0xa2, 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x44, 0x65, 0x62, 0x75, 0x67, + 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x44, 0x69, 0x61, 0x67, 0x41, 0x63, 0x6b, 0x10, 0xa3, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2c, 0x0a, 0x21, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x47, 0x65, 0x74, 0x54, + 0x78, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xa6, 0x04, 0x1a, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x47, 0x65, 0x74, 0x54, 0x78, 0x4b, + 0x65, 0x79, 0x41, 0x63, 0x6b, 0x10, 0xa7, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, + 0x0a, 0x29, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, + 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xa8, 0x04, 0x1a, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, + 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x63, 0x6b, 0x10, 0xa9, 0x04, + 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x33, 0x0a, 0x28, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x65, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x10, 0xaa, 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x2f, 0x0a, 0x24, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, + 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x65, 0x70, + 0x41, 0x63, 0x6b, 0x10, 0xab, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x34, 0x0a, 0x29, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, + 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x46, 0x69, 0x6e, + 0x61, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xac, 0x04, 0x1a, 0x04, 0x90, 0xb5, + 0x18, 0x01, 0x12, 0x30, 0x0a, 0x25, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x5f, 0x4d, 0x6f, 0x6e, 0x65, 0x72, 0x6f, 0x4c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x6b, 0x10, 0xad, 0x04, 0x1a, 0x04, + 0x98, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x10, 0xd8, 0x04, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x23, 0x0a, 0x18, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x50, + 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xd9, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, + 0x01, 0x12, 0x20, 0x0a, 0x15, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x45, 0x6f, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xda, 0x04, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x29, 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x54, 0x78, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xdb, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x25, + 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, + 0x73, 0x54, 0x78, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x63, 0x6b, 0x10, 0xdc, 0x04, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x22, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x45, 0x6f, 0x73, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, + 0x10, 0xdd, 0x04, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x28, 0x0a, 0x1d, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x47, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0xbc, 0x05, 0x1a, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x12, 0x25, 0x0a, 0x1a, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x10, 0xbd, 0x05, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x2a, 0x0a, 0x1f, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x47, 0x65, 0x74, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xbe, 0x05, + 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x10, 0xbf, 0x05, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, + 0x24, 0x0a, 0x19, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, + 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x54, 0x78, 0x10, 0xc0, 0x05, 0x1a, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x78, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xc1, 0x05, 0x1a, 0x04, 0x98, 0xb5, 0x18, 0x01, 0x12, 0x29, + 0x0a, 0x1e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, + 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4d, 0x73, 0x67, + 0x10, 0xc2, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, + 0x4f, 0x72, 0x64, 0x65, 0x72, 0x4d, 0x73, 0x67, 0x10, 0xc3, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x12, 0x27, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4d, 0x73, + 0x67, 0x10, 0xc4, 0x05, 0x1a, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x12, 0x26, 0x0a, 0x1b, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x5f, 0x42, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x65, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x78, 0x10, 0xc5, 0x05, 0x1a, 0x04, 0x98, 0xb5, + 0x18, 0x01, 0x3a, 0x3c, 0x0a, 0x07, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x69, 0x6e, 0x12, 0x21, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0xd2, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x77, 0x69, 0x72, 0x65, 0x49, 0x6e, + 0x3a, 0x3e, 0x0a, 0x08, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x6f, 0x75, 0x74, 0x12, 0x21, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0xd3, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x77, 0x69, 0x72, 0x65, 0x4f, 0x75, 0x74, + 0x3a, 0x47, 0x0a, 0x0d, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, + 0x6e, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd4, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x69, + 0x72, 0x65, 0x44, 0x65, 0x62, 0x75, 0x67, 0x49, 0x6e, 0x3a, 0x49, 0x0a, 0x0e, 0x77, 0x69, 0x72, + 0x65, 0x5f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6f, 0x75, 0x74, 0x12, 0x21, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, + 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd5, + 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x77, 0x69, 0x72, 0x65, 0x44, 0x65, 0x62, 0x75, + 0x67, 0x4f, 0x75, 0x74, 0x3a, 0x40, 0x0a, 0x09, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x74, 0x69, 0x6e, + 0x79, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd6, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, + 0x72, 0x65, 0x54, 0x69, 0x6e, 0x79, 0x3a, 0x4c, 0x0a, 0x0f, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x62, + 0x6f, 0x6f, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd7, 0x86, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x77, 0x69, 0x72, 0x65, 0x42, 0x6f, 0x6f, 0x74, 0x6c, 0x6f, + 0x61, 0x64, 0x65, 0x72, 0x3a, 0x43, 0x0a, 0x0b, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x6e, 0x6f, 0x5f, + 0x66, 0x73, 0x6d, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd8, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x77, 0x69, 0x72, 0x65, 0x4e, 0x6f, 0x46, 0x73, 0x6d, 0x42, 0x6f, 0x0a, 0x23, 0x63, 0x6f, 0x6d, + 0x2e, 0x73, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x61, 0x62, 0x73, 0x2e, 0x74, 0x72, 0x65, + 0x7a, 0x6f, 0x72, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x42, 0x0d, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5a, + 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x65, 0x75, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, 0x75, 0x6d, + 0x2f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2f, 0x75, 0x73, 0x62, 0x77, 0x61, 0x6c, + 0x6c, 0x65, 0x74, 0x2f, 0x74, 0x72, 0x65, 0x7a, 0x6f, 0x72, } -var E_WireDebugIn = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50004, - Name: "hw.trezor.messages.wire_debug_in", - Tag: "varint,50004,opt,name=wire_debug_in", - Filename: "messages.proto", +var ( + file_messages_proto_rawDescOnce sync.Once + file_messages_proto_rawDescData = file_messages_proto_rawDesc +) + +func file_messages_proto_rawDescGZIP() []byte { + file_messages_proto_rawDescOnce.Do(func() { + file_messages_proto_rawDescData = protoimpl.X.CompressGZIP(file_messages_proto_rawDescData) + }) + return file_messages_proto_rawDescData } -var E_WireDebugOut = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50005, - Name: "hw.trezor.messages.wire_debug_out", - Tag: "varint,50005,opt,name=wire_debug_out", - Filename: "messages.proto", +var file_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_messages_proto_goTypes = []interface{}{ + (MessageType)(0), // 0: hw.trezor.messages.MessageType + (*descriptorpb.EnumValueOptions)(nil), // 1: google.protobuf.EnumValueOptions +} +var file_messages_proto_depIdxs = []int32{ + 1, // 0: hw.trezor.messages.wire_in:extendee -> google.protobuf.EnumValueOptions + 1, // 1: hw.trezor.messages.wire_out:extendee -> google.protobuf.EnumValueOptions + 1, // 2: hw.trezor.messages.wire_debug_in:extendee -> google.protobuf.EnumValueOptions + 1, // 3: hw.trezor.messages.wire_debug_out:extendee -> google.protobuf.EnumValueOptions + 1, // 4: hw.trezor.messages.wire_tiny:extendee -> google.protobuf.EnumValueOptions + 1, // 5: hw.trezor.messages.wire_bootloader:extendee -> google.protobuf.EnumValueOptions + 1, // 6: hw.trezor.messages.wire_no_fsm:extendee -> google.protobuf.EnumValueOptions + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 0, // [0:7] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } -var E_WireTiny = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50006, - Name: "hw.trezor.messages.wire_tiny", - Tag: "varint,50006,opt,name=wire_tiny", - Filename: "messages.proto", -} - -var E_WireBootloader = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50007, - Name: "hw.trezor.messages.wire_bootloader", - Tag: "varint,50007,opt,name=wire_bootloader", - Filename: "messages.proto", -} - -var E_WireNoFsm = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.EnumValueOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50008, - Name: "hw.trezor.messages.wire_no_fsm", - Tag: "varint,50008,opt,name=wire_no_fsm", - Filename: "messages.proto", -} - -func init() { - proto.RegisterEnum("hw.trezor.messages.MessageType", MessageType_name, MessageType_value) - proto.RegisterExtension(E_WireIn) - proto.RegisterExtension(E_WireOut) - proto.RegisterExtension(E_WireDebugIn) - proto.RegisterExtension(E_WireDebugOut) - proto.RegisterExtension(E_WireTiny) - proto.RegisterExtension(E_WireBootloader) - proto.RegisterExtension(E_WireNoFsm) -} - -func init() { proto.RegisterFile("messages.proto", fileDescriptor_4dc296cbfe5ffcd5) } - -var fileDescriptor_4dc296cbfe5ffcd5 = []byte{ - // 2430 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x9a, 0xd9, 0x73, 0x1c, 0xc5, - 0x1d, 0xc7, 0xb3, 0xab, 0x11, 0x88, 0xf6, 0x41, 0x23, 0xb0, 0x2d, 0xaf, 0x2f, 0xf9, 0xc0, 0x96, - 0x2f, 0xd9, 0x10, 0x0c, 0x44, 0x38, 0x60, 0x69, 0xb5, 0x12, 0x8a, 0xb5, 0x5a, 0x97, 0x76, 0xb1, - 0x1f, 0x5d, 0xa3, 0x9d, 0xd6, 0x6e, 0x97, 0x67, 0x67, 0x86, 0x9e, 0x1e, 0x49, 0xeb, 0xa7, 0x9c, - 0x3c, 0x13, 0x48, 0xc0, 0xb9, 0xa9, 0xa4, 0x2a, 0x21, 0x57, 0x85, 0x1c, 0x4e, 0x25, 0x55, 0x39, - 0x08, 0x24, 0x2f, 0xc9, 0x43, 0x52, 0x9c, 0x86, 0x40, 0xee, 0x90, 0xe4, 0x0f, 0xc8, 0xc5, 0x91, - 0xa4, 0x7a, 0xa6, 0xbb, 0xe7, 0xd8, 0xdf, 0xae, 0x36, 0x6f, 0x58, 0xf3, 0xf9, 0x7d, 0x7f, 0x47, - 0xff, 0xfa, 0x37, 0xdd, 0xb3, 0xa0, 0xcd, 0x2d, 0xe2, 0xfb, 0x66, 0x83, 0xf8, 0xe3, 0x1e, 0x73, - 0xb9, 0x3b, 0x3c, 0xdc, 0x5c, 0x1d, 0xe7, 0x8c, 0x5c, 0x76, 0xd9, 0xb8, 0x7a, 0x52, 0x18, 0x6d, - 0xb8, 0x6e, 0xc3, 0x26, 0x27, 0x42, 0x62, 0x29, 0x58, 0x3e, 0x61, 0x11, 0xbf, 0xce, 0xa8, 0xc7, - 0x5d, 0x16, 0x59, 0x1d, 0xf9, 0xfe, 0x7d, 0x68, 0x43, 0x39, 0xc2, 0x6b, 0x6d, 0x8f, 0x0c, 0x1f, - 0x40, 0x5b, 0x13, 0xff, 0xbc, 0x38, 0xe7, 0x50, 0x4e, 0x4d, 0x9b, 0x5e, 0x26, 0xf8, 0x5d, 0x85, - 0xa1, 0x87, 0xaf, 0x8e, 0xe4, 0x9e, 0xba, 0x3a, 0x92, 0x1b, 0x2e, 0x20, 0x9c, 0xa4, 0xce, 0x51, - 0xa7, 0x81, 0x73, 0x05, 0x43, 0x3c, 0x1f, 0xde, 0x85, 0x6e, 0x4e, 0x3e, 0xab, 0x06, 0xf5, 0x3a, - 0xf1, 0x7d, 0x9c, 0x2f, 0x18, 0x57, 0x80, 0xc7, 0x33, 0x26, 0xb5, 0x03, 0x46, 0xf0, 0x80, 0x7c, - 0xbc, 0x07, 0x6d, 0x49, 0x3e, 0x2e, 0x36, 0x4d, 0xa7, 0x41, 0xce, 0x51, 0x07, 0x1b, 0x52, 0x7e, - 0x34, 0x1d, 0xe0, 0x05, 0xea, 0x91, 0x69, 0xb2, 0x42, 0xeb, 0x04, 0x0f, 0xc2, 0xc4, 0x2c, 0xe1, - 0x25, 0x87, 0x33, 0xd7, 0x6b, 0xe3, 0x1b, 0xe0, 0x10, 0xd5, 0x63, 0x24, 0x63, 0xc8, 0x08, 0xcc, - 0xbb, 0xa6, 0x25, 0x5d, 0x6c, 0x92, 0x02, 0x7b, 0xd1, 0xb6, 0x24, 0xb1, 0x48, 0x7c, 0xc2, 0x25, - 0xb2, 0x59, 0x22, 0xbb, 0xd1, 0x2d, 0xa9, 0x3c, 0x89, 0xc9, 0x03, 0x46, 0x7c, 0x7c, 0x93, 0x74, - 0x72, 0x10, 0xed, 0xcc, 0x94, 0xb0, 0x6c, 0x72, 0x46, 0xd7, 0x16, 0xc9, 0x83, 0x01, 0xf1, 0x39, - 0x1e, 0x96, 0xdc, 0x11, 0x34, 0x02, 0x72, 0x93, 0xf5, 0x4b, 0xf8, 0xe6, 0xc2, 0x46, 0xb5, 0x24, - 0x4f, 0x47, 0x81, 0x0f, 0xa7, 0x8a, 0x67, 0x3a, 0x75, 0x62, 0xe3, 0x5b, 0x12, 0x0b, 0xb7, 0x2f, - 0xad, 0x56, 0xb4, 0x89, 0xc9, 0xaa, 0xc4, 0xf7, 0xa9, 0xeb, 0xe0, 0x11, 0x19, 0xf9, 0x7e, 0xb4, - 0x3d, 0xc9, 0x4c, 0x7a, 0x9e, 0xdd, 0xae, 0x12, 0xce, 0xa9, 0xd3, 0xf0, 0xf1, 0x76, 0x18, 0x9a, - 0x0a, 0x38, 0x77, 0x1d, 0x15, 0x7b, 0x41, 0xc6, 0x7e, 0x28, 0xbd, 0x98, 0x11, 0x24, 0x02, 0xdf, - 0xd1, 0x11, 0xf8, 0xd6, 0x0e, 0x97, 0x33, 0xb6, 0xd9, 0xf0, 0xf1, 0x4e, 0xe9, 0x2f, 0x13, 0xf8, - 0x94, 0x59, 0xbf, 0x14, 0x78, 0xb2, 0xe4, 0xfb, 0x24, 0x73, 0x00, 0x15, 0x80, 0x65, 0x55, 0x41, - 0xed, 0x87, 0x57, 0x57, 0x52, 0x22, 0xaa, 0x03, 0x52, 0xe7, 0x10, 0xda, 0x95, 0x2a, 0xb9, 0xe9, - 0xfb, 0x5e, 0x93, 0x99, 0x3e, 0x51, 0x52, 0x87, 0xa5, 0xd4, 0xd1, 0x74, 0x11, 0x62, 0x50, 0xa8, - 0x1d, 0xc9, 0xe4, 0x78, 0x0c, 0xed, 0x83, 0xe1, 0x2a, 0x37, 0xb9, 0x96, 0x2e, 0x4b, 0xe9, 0x93, - 0x68, 0x77, 0x0f, 0x5a, 0xe8, 0x2f, 0x64, 0xf4, 0x33, 0xd9, 0x2f, 0x92, 0xba, 0xbb, 0x42, 0x58, - 0x5b, 0xd6, 0xe8, 0x38, 0xdc, 0xb9, 0x17, 0x5c, 0x66, 0x29, 0xd7, 0xe3, 0xf0, 0x0e, 0x15, 0x88, - 0xf0, 0x77, 0x02, 0x56, 0x98, 0x25, 0x5c, 0xf7, 0xf6, 0x5d, 0x70, 0x73, 0x54, 0x09, 0x7f, 0xe0, - 0xf6, 0x99, 0xa2, 0x1b, 0x38, 0x9c, 0x30, 0x7c, 0x9f, 0xae, 0x72, 0x0a, 0x9a, 0xa1, 0xac, 0xb5, - 0x6a, 0x32, 0x52, 0x12, 0x49, 0xe2, 0xeb, 0xa2, 0x9e, 0xfd, 0x9e, 0x00, 0xc7, 0xd2, 0x89, 0x29, - 0xf0, 0x01, 0xcf, 0x76, 0x4d, 0x0b, 0x5f, 0x9f, 0x20, 0x0f, 0xa3, 0x1d, 0x10, 0xa9, 0x12, 0x1c, - 0x2a, 0x0c, 0x5d, 0x51, 0xe8, 0xbe, 0xf4, 0xf6, 0xac, 0x12, 0x7b, 0xb9, 0x26, 0x98, 0xd1, 0x84, - 0x5c, 0xa6, 0xe7, 0x66, 0x09, 0x3f, 0x17, 0x2c, 0xd9, 0xb4, 0x7e, 0x96, 0xb4, 0xf1, 0x06, 0x99, - 0x45, 0x66, 0x5e, 0xc5, 0xc0, 0x46, 0x59, 0xcd, 0x9d, 0xe9, 0x3d, 0x59, 0xa5, 0x0d, 0xa7, 0xb6, - 0x86, 0x6f, 0x84, 0xcd, 0x6b, 0x7a, 0xfb, 0x6f, 0x91, 0xe6, 0x3b, 0xd0, 0x4d, 0x69, 0x40, 0x2c, - 0xc5, 0xd6, 0xae, 0x93, 0x6e, 0xd2, 0xb2, 0x98, 0x98, 0xb6, 0xbb, 0xe0, 0x49, 0xa7, 0x1e, 0xef, - 0x96, 0xea, 0x99, 0xb5, 0x14, 0xc1, 0xc9, 0x7f, 0xe3, 0x83, 0xf0, 0x5a, 0x9e, 0x27, 0x8c, 0x2e, - 0xb7, 0x15, 0x74, 0x48, 0x42, 0x99, 0x61, 0x26, 0xff, 0x5b, 0xc8, 0x85, 0x9d, 0x81, 0xc7, 0xa4, - 0xbf, 0x4c, 0x8f, 0x16, 0xa9, 0xd7, 0x24, 0xec, 0x2c, 0x69, 0x9f, 0x37, 0xed, 0x80, 0xe0, 0x6d, - 0xb0, 0x5a, 0x44, 0x11, 0x4b, 0x73, 0x27, 0xa5, 0x5a, 0x66, 0x7d, 0x84, 0xbb, 0x39, 0x8b, 0x38, - 0x9c, 0xf2, 0x36, 0x3e, 0x05, 0xcf, 0x04, 0xc1, 0x10, 0x4b, 0x53, 0x77, 0xea, 0x41, 0xb5, 0x2b, - 0xfb, 0xca, 0x28, 0x4e, 0xdf, 0x2f, 0x07, 0xa3, 0x58, 0xcd, 0xf7, 0x76, 0x19, 0x31, 0x69, 0xea, - 0x5e, 0x78, 0xc4, 0x14, 0x5d, 0x9f, 0x16, 0xdd, 0x56, 0x8b, 0x72, 0x3c, 0x0b, 0xeb, 0xc4, 0x44, - 0x8b, 0x38, 0x1c, 0xdf, 0x2f, 0x75, 0x32, 0xef, 0x10, 0x41, 0x89, 0x04, 0xf0, 0x1c, 0xbc, 0x36, - 0xea, 0x79, 0x54, 0xf3, 0xf7, 0x49, 0x91, 0x13, 0xe9, 0xdc, 0xa6, 0xc9, 0x52, 0xd0, 0x98, 0xa7, - 0xce, 0xa5, 0x69, 0x52, 0xa7, 0xe1, 0xdc, 0xb7, 0x0a, 0x1b, 0x9f, 0x48, 0x0e, 0x92, 0xa3, 0x5d, - 0x0c, 0x66, 0x09, 0x0f, 0x87, 0x0f, 0x26, 0x85, 0x21, 0x65, 0x90, 0x4d, 0x44, 0xc3, 0x11, 0xb9, - 0x5c, 0x30, 0x9e, 0x04, 0x02, 0x4d, 0x50, 0xae, 0x87, 0x1b, 0x05, 0xe3, 0x09, 0x60, 0x39, 0x35, - 0x34, 0xef, 0x36, 0x70, 0x53, 0x0a, 0x1d, 0x46, 0x7b, 0x40, 0xa6, 0x4c, 0x5a, 0x2e, 0x6b, 0x2f, - 0x12, 0xd3, 0xc2, 0x8e, 0x94, 0xbb, 0x35, 0x3d, 0x0c, 0x32, 0x28, 0x76, 0xa5, 0xe2, 0x11, 0x34, - 0xda, 0x03, 0xbb, 0xc0, 0x28, 0x27, 0xd8, 0x93, 0x92, 0xdd, 0xbc, 0xcf, 0xd8, 0xa6, 0xdf, 0x8c, - 0x06, 0xd7, 0x83, 0x12, 0x3d, 0x9a, 0x96, 0x2d, 0x71, 0xd1, 0xc2, 0x41, 0x2b, 0x35, 0x43, 0x9e, - 0x19, 0x90, 0xeb, 0x38, 0x96, 0xae, 0xb8, 0x82, 0x63, 0xf2, 0x59, 0x75, 0x3c, 0x1a, 0x4b, 0xbf, - 0x16, 0x12, 0xb2, 0x6a, 0x6b, 0xdf, 0x2d, 0x35, 0x33, 0xe9, 0x2b, 0x52, 0x61, 0xef, 0x81, 0x77, - 0xa4, 0xc2, 0xe4, 0x98, 0x9a, 0x80, 0xdf, 0x88, 0x8a, 0x8a, 0xc7, 0xd5, 0x3d, 0x52, 0x2e, 0xb3, - 0xd0, 0x31, 0x28, 0xc6, 0xd6, 0x69, 0xa9, 0x96, 0x29, 0x63, 0xd2, 0xa7, 0x1a, 0x2c, 0x67, 0x24, - 0x7a, 0x14, 0xed, 0x85, 0xd0, 0xf4, 0x14, 0x9a, 0x94, 0xf0, 0x38, 0x3a, 0x00, 0xc1, 0x1d, 0xd3, - 0x68, 0x0a, 0x0e, 0x76, 0xa1, 0x54, 0x4e, 0xd4, 0xb1, 0x08, 0xcf, 0xd8, 0x85, 0x52, 0x59, 0x11, - 0xd3, 0xf0, 0x91, 0x75, 0xa1, 0x54, 0x96, 0xd5, 0x2b, 0xc1, 0x6f, 0x4c, 0x09, 0x10, 0xab, 0xb6, - 0x86, 0x67, 0xe0, 0x01, 0xb4, 0x50, 0x2a, 0x4f, 0x93, 0x3a, 0x6b, 0x7b, 0x5c, 0xe5, 0x78, 0x16, - 0xae, 0x5d, 0x0c, 0x12, 0x4b, 0xa1, 0xf3, 0xf0, 0xd2, 0xce, 0x53, 0xff, 0x52, 0x22, 0x3f, 0x06, - 0x07, 0x27, 0x28, 0x85, 0xf8, 0x5d, 0xce, 0xc3, 0xd4, 0xbf, 0x24, 0x33, 0xe4, 0xf0, 0xe9, 0x4c, - 0x11, 0x61, 0x8a, 0x81, 0x54, 0xc9, 0x34, 0xa4, 0x62, 0x54, 0xd4, 0x2b, 0x52, 0x2a, 0xb3, 0x1f, - 0x05, 0xd6, 0xb1, 0x80, 0xab, 0x70, 0xd5, 0x04, 0x9b, 0xee, 0x8c, 0x35, 0xf8, 0x8d, 0x22, 0x4b, - 0x11, 0xef, 0xaf, 0x36, 0x3c, 0x50, 0x05, 0x17, 0x43, 0x97, 0xf5, 0xc9, 0x3d, 0x95, 0x48, 0x8d, - 0x5c, 0x76, 0xfd, 0x44, 0x61, 0x1f, 0xcb, 0x69, 0xb1, 0x91, 0x0e, 0x4e, 0x41, 0x8f, 0xe7, 0xf4, - 0x3b, 0x6c, 0x5b, 0x07, 0x24, 0x8b, 0x7b, 0x25, 0xa7, 0x5f, 0x16, 0xdb, 0x41, 0x26, 0x2c, 0xef, - 0x27, 0x72, 0x7a, 0x34, 0xec, 0x82, 0xc2, 0x8a, 0xe3, 0xff, 0x64, 0x4e, 0x8f, 0x86, 0x42, 0x07, - 0x19, 0x63, 0x9f, 0xca, 0xe9, 0xfe, 0x49, 0x9f, 0xe2, 0x38, 0xb1, 0x6d, 0x93, 0xc9, 0xe0, 0x7e, - 0x9e, 0xd3, 0x0d, 0xb9, 0x1b, 0xa0, 0x6a, 0x6b, 0x15, 0x4f, 0xcd, 0x86, 0x5f, 0x74, 0x89, 0x50, - 0xa2, 0x89, 0xd2, 0xfd, 0xb2, 0x4b, 0x84, 0x92, 0x54, 0xd8, 0xaf, 0x94, 0xe0, 0xf1, 0xf4, 0x91, - 0x5a, 0x62, 0x45, 0x46, 0xc2, 0x23, 0x72, 0x5d, 0x1c, 0x38, 0x2b, 0x1e, 0x7e, 0x2e, 0xa7, 0xa7, - 0xd8, 0x4e, 0x00, 0x3f, 0x67, 0xb6, 0xc5, 0x4b, 0xb7, 0xe2, 0xe1, 0xe7, 0x73, 0x7a, 0xea, 0x8c, - 0x82, 0x20, 0x6f, 0xc6, 0xf0, 0x0b, 0xbd, 0xe1, 0xb2, 0xe9, 0x98, 0x0d, 0x52, 0x59, 0x5e, 0x26, - 0xac, 0xe2, 0xe1, 0x17, 0x15, 0x7c, 0x3b, 0x3a, 0xd4, 0x35, 0x62, 0x71, 0xc6, 0xa7, 0x2b, 0xda, - 0xe6, 0xa5, 0x9c, 0xde, 0x11, 0x7b, 0xa0, 0x75, 0x20, 0xbc, 0xe2, 0x71, 0xea, 0x3a, 0x7e, 0xc5, - 0xc3, 0x2f, 0xf7, 0x0e, 0x26, 0xba, 0x45, 0xd7, 0x58, 0xe0, 0x8b, 0xc8, 0xaf, 0xf5, 0x16, 0x9e, - 0xb4, 0x6d, 0x77, 0x55, 0xb1, 0xaf, 0x28, 0xf6, 0x58, 0x7a, 0x10, 0x2b, 0x36, 0x2a, 0x72, 0x99, - 0xb0, 0x06, 0xa9, 0x78, 0xf8, 0xd5, 0xde, 0xca, 0x51, 0x4d, 0xa6, 0x4d, 0x6e, 0x56, 0x3c, 0xfc, - 0x5a, 0x6f, 0xe5, 0xa9, 0xa0, 0xe5, 0x55, 0x45, 0x03, 0x39, 0x75, 0xa1, 0xfc, 0x7a, 0x4e, 0xef, - 0xe4, 0x1d, 0x5d, 0x9a, 0x32, 0xdc, 0x0d, 0x6f, 0xe4, 0xf4, 0xb4, 0x49, 0xf7, 0x38, 0x73, 0x9d, - 0x44, 0xa3, 0xbd, 0x99, 0xd3, 0x83, 0x6b, 0x5b, 0x16, 0x53, 0xcc, 0x5b, 0x39, 0x7d, 0x48, 0xde, - 0x9a, 0x65, 0xe4, 0x26, 0x78, 0xbb, 0xdb, 0x56, 0x97, 0x48, 0x18, 0xd2, 0x3b, 0x5d, 0xf6, 0x53, - 0xd1, 0x64, 0x96, 0xe9, 0xb8, 0x52, 0xea, 0x1b, 0x79, 0xb8, 0x49, 0x25, 0x15, 0xbf, 0x69, 0x9f, - 0xca, 0xeb, 0x0f, 0x03, 0x7b, 0x00, 0x30, 0xb5, 0xe3, 0xbf, 0xd9, 0x5b, 0x34, 0x06, 0xbf, 0x95, - 0x87, 0xb7, 0x68, 0x2c, 0xaa, 0xaa, 0xf2, 0xed, 0x3c, 0xbc, 0x45, 0x25, 0xa9, 0xb0, 0xef, 0xe4, - 0xf5, 0x3b, 0x76, 0x04, 0x4c, 0x47, 0x9c, 0x07, 0xae, 0xe6, 0xe1, 0x45, 0x4d, 0x54, 0x26, 0xac, - 0xe0, 0x77, 0x95, 0x58, 0x66, 0xd6, 0x54, 0x1c, 0xee, 0xda, 0x6e, 0xa3, 0x9d, 0x08, 0xef, 0x37, - 0x5d, 0x24, 0x15, 0xaa, 0xb8, 0xdf, 0xe6, 0xf5, 0x15, 0x7e, 0xb4, 0x8b, 0x64, 0x5c, 0x9d, 0xdf, - 0xe5, 0xe1, 0x73, 0x9a, 0x82, 0x63, 0xf2, 0xf7, 0xeb, 0xc8, 0x86, 0x8b, 0xcd, 0x4c, 0xc7, 0x5f, - 0x26, 0x0c, 0xff, 0x41, 0xc9, 0x66, 0xc6, 0x58, 0x12, 0x26, 0x96, 0xc6, 0xff, 0xa8, 0xb4, 0xc7, - 0xd1, 0xfe, 0x6e, 0xf8, 0x05, 0xca, 0x9b, 0x16, 0x33, 0x57, 0x2b, 0x4e, 0x03, 0xff, 0x49, 0xc9, - 0x9f, 0x44, 0xb7, 0x76, 0x97, 0x4f, 0x5a, 0xfc, 0x39, 0xaf, 0x3f, 0x3e, 0x74, 0xb5, 0xa8, 0x38, - 0x7c, 0xce, 0x5a, 0x24, 0x0d, 0xea, 0x8b, 0xbb, 0xfc, 0x1b, 0x79, 0x78, 0xae, 0xa5, 0x7d, 0xa4, - 0x6d, 0xfe, 0xa2, 0xbc, 0x9c, 0x42, 0x47, 0x7a, 0x7a, 0x99, 0xb4, 0xac, 0x49, 0xce, 0x19, 0x5d, - 0x0a, 0x38, 0xf1, 0xf1, 0x5f, 0x95, 0xab, 0xbb, 0xd0, 0xb1, 0x75, 0x5c, 0xa5, 0x0d, 0xff, 0x96, - 0xd7, 0xa7, 0x85, 0xd4, 0x26, 0x58, 0xa4, 0x9e, 0x67, 0x93, 0x44, 0xef, 0x3c, 0x3c, 0x00, 0xbf, - 0x6f, 0x23, 0x50, 0x51, 0x1f, 0x1d, 0x80, 0x3b, 0x3b, 0xa2, 0xe4, 0x6e, 0x7e, 0x64, 0x00, 0xde, - 0x25, 0x31, 0x14, 0x36, 0xf6, 0xa3, 0x0a, 0x7b, 0x37, 0x1a, 0x4b, 0xdd, 0x9f, 0x5d, 0x87, 0x30, - 0x37, 0x5c, 0x79, 0xb3, 0x2e, 0x66, 0xfc, 0x9c, 0x43, 0xb9, 0x1a, 0x00, 0x7f, 0x1f, 0xd0, 0x17, - 0xbb, 0x03, 0xeb, 0x1a, 0x89, 0x6d, 0xf6, 0x0f, 0x65, 0x90, 0xa9, 0x5c, 0x87, 0x41, 0x95, 0xf0, - 0x39, 0xc7, 0x0b, 0xb4, 0xa7, 0x7f, 0x2a, 0xc3, 0xf5, 0xc2, 0x53, 0x86, 0xc2, 0xdb, 0xbf, 0x94, - 0xd1, 0x19, 0x74, 0x6a, 0x9d, 0xf0, 0xbc, 0x80, 0xfb, 0xe7, 0x08, 0x6b, 0x05, 0xdc, 0x14, 0x7f, - 0x50, 0x6e, 0xff, 0xad, 0x14, 0x4e, 0xa3, 0xdb, 0xfe, 0x3f, 0x05, 0xe1, 0xff, 0x4d, 0x65, 0x7d, - 0x37, 0x3a, 0xbe, 0xbe, 0xf5, 0x79, 0xea, 0x50, 0xe5, 0xf7, 0x2d, 0x65, 0x79, 0x07, 0x3a, 0xdc, - 0x9f, 0xa5, 0xf0, 0xf7, 0xb6, 0xb2, 0xba, 0x07, 0x9d, 0xec, 0x69, 0x35, 0x69, 0xdb, 0x51, 0xc0, - 0x55, 0xa2, 0x2b, 0xfc, 0x4e, 0xbf, 0x4b, 0x93, 0x34, 0x16, 0x5e, 0xff, 0xd3, 0x6f, 0x96, 0xe2, - 0x98, 0x10, 0xf0, 0xc4, 0xa2, 0xfe, 0xb7, 0xdf, 0x2c, 0xb5, 0xa5, 0xf0, 0xf7, 0x7e, 0xa3, 0x4f, - 0x7f, 0x93, 0xb6, 0x5d, 0x09, 0x78, 0x22, 0xc5, 0x0f, 0x18, 0x7d, 0xfa, 0xd3, 0x96, 0xc2, 0xdf, - 0x07, 0xfb, 0xf5, 0x17, 0x7e, 0xf4, 0x49, 0x36, 0xed, 0x87, 0xfa, 0xf5, 0xa7, 0x2d, 0x85, 0xbf, - 0x0f, 0xf7, 0x6b, 0x35, 0x43, 0x1d, 0xd3, 0x56, 0xbe, 0x3e, 0x62, 0xc0, 0x03, 0x13, 0xb6, 0x12, - 0x7e, 0x1e, 0x52, 0x16, 0x77, 0xa2, 0xa3, 0x9d, 0x16, 0x67, 0x49, 0x7b, 0xae, 0x65, 0x36, 0x48, - 0x69, 0xcd, 0x73, 0x19, 0x4f, 0x6e, 0xfa, 0x47, 0x94, 0x5d, 0x66, 0xd0, 0x76, 0xb3, 0x13, 0xbe, - 0x1e, 0xed, 0x99, 0x93, 0xb2, 0xa9, 0xb6, 0x9d, 0x7a, 0x95, 0x13, 0x7d, 0x5a, 0xff, 0x58, 0xcf, - 0x9c, 0xb2, 0x56, 0xc2, 0xcf, 0xc7, 0x0d, 0x78, 0xa0, 0x77, 0x5a, 0xa4, 0x8a, 0xf7, 0x98, 0x32, - 0xbb, 0x0d, 0x1d, 0xec, 0xc3, 0x4c, 0x78, 0x7a, 0xdc, 0x80, 0x47, 0x79, 0x64, 0x92, 0x18, 0xe5, - 0x9f, 0x36, 0xe0, 0x51, 0x1e, 0x81, 0x8a, 0xfa, 0x8c, 0x01, 0x9f, 0x7a, 0xb4, 0xdc, 0x05, 0x93, - 0xd7, 0x9b, 0xe2, 0xbd, 0xfe, 0x59, 0x03, 0x9e, 0xe7, 0x11, 0xa9, 0xb1, 0xcf, 0x19, 0xf0, 0xc5, - 0x24, 0xfc, 0x50, 0x14, 0xb1, 0xd3, 0xd4, 0x6c, 0xa8, 0x0a, 0x7c, 0xde, 0x80, 0xef, 0x50, 0x19, - 0x5c, 0x64, 0xfe, 0x05, 0xa5, 0x9c, 0x39, 0x2d, 0xeb, 0x50, 0x6b, 0x6b, 0x67, 0x89, 0xfe, 0xa9, - 0xe3, 0x8b, 0x06, 0x7c, 0x60, 0x49, 0xd3, 0x42, 0xf7, 0x4b, 0x3d, 0x7b, 0x64, 0x9e, 0xae, 0x90, - 0x45, 0xb2, 0xcc, 0x88, 0xdf, 0xac, 0x72, 0x93, 0xe9, 0x6e, 0x7c, 0xd2, 0x80, 0x8f, 0x16, 0xb0, - 0x95, 0xf0, 0xf3, 0x65, 0xa3, 0xd7, 0xab, 0x24, 0x65, 0x11, 0xb7, 0xe2, 0x57, 0x94, 0x1b, 0xf0, - 0x4d, 0x97, 0x31, 0x12, 0x5e, 0xbe, 0xda, 0x6f, 0x36, 0xa9, 0x46, 0xfc, 0x5a, 0xbf, 0xd9, 0xe8, - 0x3e, 0xfc, 0xba, 0x01, 0x7f, 0x0a, 0x28, 0x65, 0x6e, 0xdc, 0xd7, 0x0c, 0xf8, 0x7e, 0x50, 0x4a, - 0xde, 0xb7, 0x5f, 0x31, 0xf4, 0x67, 0x96, 0x2d, 0x19, 0x48, 0x9e, 0x26, 0x5e, 0xed, 0xd2, 0x27, - 0x25, 0xd7, 0x17, 0x07, 0xe9, 0xe4, 0xbb, 0xf3, 0xd7, 0x06, 0x7c, 0xff, 0x49, 0xa0, 0x22, 0x81, - 0xd7, 0x0c, 0xf8, 0xfe, 0x53, 0x4a, 0x7c, 0x58, 0x78, 0xbd, 0xcb, 0xee, 0x98, 0xa2, 0x8e, 0xe9, - 0xd4, 0x93, 0x07, 0xa7, 0x1f, 0x0c, 0xc2, 0xbb, 0x43, 0x92, 0x0a, 0xfb, 0xe1, 0x20, 0x7c, 0x73, - 0x89, 0x05, 0xe3, 0xa2, 0xfc, 0x68, 0x10, 0xbe, 0xb9, 0x48, 0x36, 0x06, 0x7f, 0x3c, 0x08, 0xdf, - 0xae, 0x24, 0x28, 0x2b, 0xf8, 0x74, 0x6f, 0xb9, 0xf8, 0x76, 0xf5, 0x93, 0x41, 0xf8, 0xaa, 0xa1, - 0x40, 0x79, 0x18, 0x2f, 0xfb, 0x0d, 0xfc, 0xcc, 0x20, 0x7c, 0xd5, 0x90, 0x68, 0x85, 0x59, 0x11, - 0xf7, 0x6c, 0x6f, 0xdf, 0xd1, 0x8f, 0xb4, 0x02, 0xfc, 0x69, 0x6f, 0x41, 0xbd, 0x30, 0x3f, 0x93, - 0x31, 0x4e, 0x9c, 0x46, 0xd7, 0xaf, 0x52, 0x46, 0x2e, 0x52, 0x67, 0x78, 0xef, 0x78, 0xf4, 0x4b, - 0xff, 0xb8, 0xfa, 0xa5, 0x7f, 0xbc, 0xe4, 0x04, 0xad, 0xf0, 0xe7, 0x12, 0xf9, 0x95, 0x60, 0xe4, - 0xb9, 0x87, 0x06, 0x46, 0x73, 0x63, 0x43, 0x8b, 0xd7, 0x09, 0x9b, 0x39, 0x67, 0xe2, 0x5e, 0x34, - 0x14, 0x5a, 0xbb, 0x01, 0xef, 0xc7, 0xfc, 0x79, 0x69, 0x1e, 0xba, 0xac, 0x04, 0x7c, 0x62, 0x16, - 0x6d, 0x0a, 0xed, 0x2d, 0x31, 0xad, 0xfa, 0x8c, 0xe1, 0x05, 0x29, 0xb2, 0x41, 0x58, 0x86, 0x63, - 0x6e, 0xce, 0x99, 0x98, 0x43, 0x9b, 0x13, 0x42, 0x7d, 0x86, 0xf3, 0xa2, 0x54, 0xda, 0xa8, 0x95, - 0x44, 0x4c, 0x67, 0xd0, 0x0d, 0xa1, 0x14, 0xa7, 0x4e, 0xbb, 0x1f, 0x95, 0x97, 0xa4, 0x4a, 0x58, - 0x89, 0x1a, 0x75, 0xda, 0x13, 0xf3, 0xe8, 0xc6, 0x50, 0x61, 0xc9, 0x75, 0xb9, 0xed, 0x9a, 0x16, - 0x61, 0xfd, 0xe8, 0xbc, 0x2c, 0x75, 0xc2, 0x44, 0xa6, 0xb4, 0xe9, 0x44, 0x11, 0x85, 0x99, 0x5e, - 0x74, 0xdc, 0x8b, 0xcb, 0x7e, 0xab, 0x1f, 0xa5, 0x6b, 0x52, 0x29, 0xcc, 0x63, 0xc1, 0x9d, 0xf1, - 0x5b, 0x53, 0x77, 0xa0, 0xfd, 0x75, 0xb7, 0x35, 0xee, 0x9b, 0xdc, 0xf5, 0x9b, 0xd4, 0x36, 0x97, - 0x7c, 0xf5, 0xff, 0x79, 0xd8, 0x74, 0x49, 0x4b, 0x4d, 0x6d, 0xaa, 0x85, 0x7f, 0x94, 0x9d, 0xf3, - 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa3, 0x69, 0x67, 0x5d, 0x1f, 0x22, 0x00, 0x00, +func init() { file_messages_proto_init() } +func file_messages_proto_init() { + if File_messages_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_messages_proto_rawDesc, + NumEnums: 1, + NumMessages: 0, + NumExtensions: 7, + NumServices: 0, + }, + GoTypes: file_messages_proto_goTypes, + DependencyIndexes: file_messages_proto_depIdxs, + EnumInfos: file_messages_proto_enumTypes, + ExtensionInfos: file_messages_proto_extTypes, + }.Build() + File_messages_proto = out.File + file_messages_proto_rawDesc = nil + file_messages_proto_goTypes = nil + file_messages_proto_depIdxs = nil } diff --git a/accounts/usbwallet/trezor/messages.proto b/accounts/usbwallet/trezor/messages.proto index 3e0482e344..c232bef60d 100644 --- a/accounts/usbwallet/trezor/messages.proto +++ b/accounts/usbwallet/trezor/messages.proto @@ -9,10 +9,13 @@ package hw.trezor.messages; * Messages for TREZOR communication */ +option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"; + // Sugar for easier handling in Java option java_package = "com.satoshilabs.trezor.lib.protobuf"; option java_outer_classname = "TrezorMessage"; + import "google/protobuf/descriptor.proto"; /** diff --git a/accounts/usbwallet/trezor/trezor.go b/accounts/usbwallet/trezor/trezor.go index cdca6b4e0b..4324258314 100644 --- a/accounts/usbwallet/trezor/trezor.go +++ b/accounts/usbwallet/trezor/trezor.go @@ -42,7 +42,7 @@ // - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go` // - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...` -//go:generate protoc -I/usr/local/include:. --go_out=import_path=trezor:. 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 // Package trezor contains the wire protocol. package trezor From 41abab9e39323823ddc4549e1930c8932ffd4c00 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 1 Jul 2024 08:16:15 -0700 Subject: [PATCH 116/196] build: add check for stale generated files (#30037) Co-authored-by: Felix Lange --- .../usbwallet/trezor/messages-common.pb.go | 26 +-- .../usbwallet/trezor/messages-ethereum.pb.go | 24 +-- .../trezor/messages-management.pb.go | 46 ++--- accounts/usbwallet/trezor/messages.pb.go | 4 +- appveyor.yml | 1 + build/checksums.txt | 25 +++ build/ci.go | 174 ++++++++++++++++++ core/tracing/hooks.go | 2 +- internal/build/archive.go | 11 +- 9 files changed, 259 insertions(+), 54 deletions(-) diff --git a/accounts/usbwallet/trezor/messages-common.pb.go b/accounts/usbwallet/trezor/messages-common.pb.go index c5e305960b..73800802bb 100644 --- a/accounts/usbwallet/trezor/messages-common.pb.go +++ b/accounts/usbwallet/trezor/messages-common.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages-common.proto @@ -1010,7 +1010,7 @@ func file_messages_common_proto_rawDescGZIP() []byte { var file_messages_common_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_messages_common_proto_msgTypes = make([]protoimpl.MessageInfo, 11) -var file_messages_common_proto_goTypes = []interface{}{ +var file_messages_common_proto_goTypes = []any{ (Failure_FailureType)(0), // 0: hw.trezor.messages.common.Failure.FailureType (ButtonRequest_ButtonRequestType)(0), // 1: hw.trezor.messages.common.ButtonRequest.ButtonRequestType (PinMatrixRequest_PinMatrixRequestType)(0), // 2: hw.trezor.messages.common.PinMatrixRequest.PinMatrixRequestType @@ -1043,7 +1043,7 @@ func file_messages_common_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_messages_common_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Success); i { case 0: return &v.state @@ -1055,7 +1055,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Failure); i { case 0: return &v.state @@ -1067,7 +1067,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*ButtonRequest); i { case 0: return &v.state @@ -1079,7 +1079,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ButtonAck); i { case 0: return &v.state @@ -1091,7 +1091,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*PinMatrixRequest); i { case 0: return &v.state @@ -1103,7 +1103,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*PinMatrixAck); i { case 0: return &v.state @@ -1115,7 +1115,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*PassphraseRequest); i { case 0: return &v.state @@ -1127,7 +1127,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*PassphraseAck); i { case 0: return &v.state @@ -1139,7 +1139,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*PassphraseStateRequest); i { case 0: return &v.state @@ -1151,7 +1151,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*PassphraseStateAck); i { case 0: return &v.state @@ -1163,7 +1163,7 @@ func file_messages_common_proto_init() { return nil } } - file_messages_common_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_messages_common_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*HDNodeType); i { case 0: return &v.state diff --git a/accounts/usbwallet/trezor/messages-ethereum.pb.go b/accounts/usbwallet/trezor/messages-ethereum.pb.go index a080a1c3fe..a92123efcd 100644 --- a/accounts/usbwallet/trezor/messages-ethereum.pb.go +++ b/accounts/usbwallet/trezor/messages-ethereum.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages-ethereum.proto @@ -831,7 +831,7 @@ func file_messages_ethereum_proto_rawDescGZIP() []byte { } var file_messages_ethereum_proto_msgTypes = make([]protoimpl.MessageInfo, 10) -var file_messages_ethereum_proto_goTypes = []interface{}{ +var file_messages_ethereum_proto_goTypes = []any{ (*EthereumGetPublicKey)(nil), // 0: hw.trezor.messages.ethereum.EthereumGetPublicKey (*EthereumPublicKey)(nil), // 1: hw.trezor.messages.ethereum.EthereumPublicKey (*EthereumGetAddress)(nil), // 2: hw.trezor.messages.ethereum.EthereumGetAddress @@ -860,7 +860,7 @@ func file_messages_ethereum_proto_init() { } file_messages_common_proto_init() if !protoimpl.UnsafeEnabled { - file_messages_ethereum_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*EthereumGetPublicKey); i { case 0: return &v.state @@ -872,7 +872,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*EthereumPublicKey); i { case 0: return &v.state @@ -884,7 +884,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*EthereumGetAddress); i { case 0: return &v.state @@ -896,7 +896,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*EthereumAddress); i { case 0: return &v.state @@ -908,7 +908,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*EthereumSignTx); i { case 0: return &v.state @@ -920,7 +920,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*EthereumTxRequest); i { case 0: return &v.state @@ -932,7 +932,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*EthereumTxAck); i { case 0: return &v.state @@ -944,7 +944,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*EthereumSignMessage); i { case 0: return &v.state @@ -956,7 +956,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*EthereumMessageSignature); i { case 0: return &v.state @@ -968,7 +968,7 @@ func file_messages_ethereum_proto_init() { return nil } } - file_messages_ethereum_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_ethereum_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*EthereumVerifyMessage); i { case 0: return &v.state diff --git a/accounts/usbwallet/trezor/messages-management.pb.go b/accounts/usbwallet/trezor/messages-management.pb.go index 6df4cbdc29..983e2d281d 100644 --- a/accounts/usbwallet/trezor/messages-management.pb.go +++ b/accounts/usbwallet/trezor/messages-management.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages-management.proto @@ -1955,7 +1955,7 @@ func file_messages_management_proto_rawDescGZIP() []byte { var file_messages_management_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_messages_management_proto_msgTypes = make([]protoimpl.MessageInfo, 21) -var file_messages_management_proto_goTypes = []interface{}{ +var file_messages_management_proto_goTypes = []any{ (ApplySettings_PassphraseSourceType)(0), // 0: hw.trezor.messages.management.ApplySettings.PassphraseSourceType (RecoveryDevice_RecoveryDeviceType)(0), // 1: hw.trezor.messages.management.RecoveryDevice.RecoveryDeviceType (WordRequest_WordRequestType)(0), // 2: hw.trezor.messages.management.WordRequest.WordRequestType @@ -2001,7 +2001,7 @@ func file_messages_management_proto_init() { } file_messages_common_proto_init() if !protoimpl.UnsafeEnabled { - file_messages_management_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Initialize); i { case 0: return &v.state @@ -2013,7 +2013,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*GetFeatures); i { case 0: return &v.state @@ -2025,7 +2025,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*Features); i { case 0: return &v.state @@ -2037,7 +2037,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*ClearSession); i { case 0: return &v.state @@ -2049,7 +2049,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*ApplySettings); i { case 0: return &v.state @@ -2061,7 +2061,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*ApplyFlags); i { case 0: return &v.state @@ -2073,7 +2073,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*ChangePin); i { case 0: return &v.state @@ -2085,7 +2085,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*Ping); i { case 0: return &v.state @@ -2097,7 +2097,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*Cancel); i { case 0: return &v.state @@ -2109,7 +2109,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*GetEntropy); i { case 0: return &v.state @@ -2121,7 +2121,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*Entropy); i { case 0: return &v.state @@ -2133,7 +2133,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*WipeDevice); i { case 0: return &v.state @@ -2145,7 +2145,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*LoadDevice); i { case 0: return &v.state @@ -2157,7 +2157,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[13].Exporter = func(v any, i int) any { switch v := v.(*ResetDevice); i { case 0: return &v.state @@ -2169,7 +2169,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[14].Exporter = func(v any, i int) any { switch v := v.(*BackupDevice); i { case 0: return &v.state @@ -2181,7 +2181,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[15].Exporter = func(v any, i int) any { switch v := v.(*EntropyRequest); i { case 0: return &v.state @@ -2193,7 +2193,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[16].Exporter = func(v any, i int) any { switch v := v.(*EntropyAck); i { case 0: return &v.state @@ -2205,7 +2205,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[17].Exporter = func(v any, i int) any { switch v := v.(*RecoveryDevice); i { case 0: return &v.state @@ -2217,7 +2217,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[18].Exporter = func(v any, i int) any { switch v := v.(*WordRequest); i { case 0: return &v.state @@ -2229,7 +2229,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[19].Exporter = func(v any, i int) any { switch v := v.(*WordAck); i { case 0: return &v.state @@ -2241,7 +2241,7 @@ func file_messages_management_proto_init() { return nil } } - file_messages_management_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_messages_management_proto_msgTypes[20].Exporter = func(v any, i int) any { switch v := v.(*SetU2FCounter); i { case 0: return &v.state diff --git a/accounts/usbwallet/trezor/messages.pb.go b/accounts/usbwallet/trezor/messages.pb.go index 3e80d7c9c3..4518db679e 100644 --- a/accounts/usbwallet/trezor/messages.pb.go +++ b/accounts/usbwallet/trezor/messages.pb.go @@ -4,7 +4,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.34.2 // protoc v5.27.1 // source: messages.proto @@ -1320,7 +1320,7 @@ func file_messages_proto_rawDescGZIP() []byte { } var file_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_messages_proto_goTypes = []interface{}{ +var file_messages_proto_goTypes = []any{ (MessageType)(0), // 0: hw.trezor.messages.MessageType (*descriptorpb.EnumValueOptions)(nil), // 1: google.protobuf.EnumValueOptions } diff --git a/appveyor.yml b/appveyor.yml index 41c70491b4..92369537cd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,6 +24,7 @@ for: - image: Ubuntu build_script: - go run build/ci.go lint + - go run build/ci.go generate -verify - go run build/ci.go install -dlgo test_script: - go run build/ci.go test -dlgo -short diff --git a/build/checksums.txt b/build/checksums.txt index d099e53156..c6c9606865 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -99,3 +99,28 @@ d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.t # version:ppa-builder-2 1.21.9 # https://go.dev/dl/ 58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz + +# version:protoc 27.1 +# https://github.com/protocolbuffers/protobuf/releases/ +# https://github.com/protocolbuffers/protobuf/releases/download/v27.1/ +8809c2ec85368c6b6e9af161b6771a153aa92670a24adbe46dd34fa02a04df2f protoc-27.1-linux-aarch_64.zip +5d21979a6d27475e810b76b88863d1e784fa01ffb15e511a3ec5bd1924d89426 protoc-27.1-linux-ppcle_64.zip +84d8852750ed186dc4a057a1a86bcac409be5362d6af04770f42367fee6b7bc1 protoc-27.1-linux-s390_64.zip +2f028796ff5741691650e0eea290e61ff2f1c0d87f8d31fe45ef47fd967cef0c protoc-27.1-linux-x86_32.zip +8970e3d8bbd67d53768fe8c2e3971bdd71e51cfe2001ca06dacad17258a7dae3 protoc-27.1-linux-x86_64.zip +03b7af1bf469e7285dc51976ee5fa99412704dbd1c017105114852a37b165c12 protoc-27.1-osx-aarch_64.zip +f14d3973cf13283d07c520ed6f4c12405ad41b9efd18089a1c74897037d742b5 protoc-27.1-osx-universal_binary.zip +8520d944f3a3890fa296a3b3b0d4bb18337337e2526bbbf1b507eeea3c2a1ec4 protoc-27.1-osx-x86_64.zip +6263718ff96547b8392a079f6fdf02a4156f2e8d13cd51649a0d03fb7afa2de8 protoc-27.1-win32.zip +da531c51ccd1290d8d34821f0ce4e219c7fbaa6f9825f5a3fb092a9d03fe6206 protoc-27.1-win64.zip + +# version:protoc-gen-go 1.34.2 +# https://github.com/protocolbuffers/protobuf-go/releases/ +# https://github.com/protocolbuffers/protobuf-go/releases/download/v1.34.2/ +9b48d8f90add02e8e94e14962fed74e7ce2b2d6bda4dd42f1f4fbccf0f766f1a protoc-gen-go.v1.34.2.darwin.amd64.tar.gz +17aca7f948dbb624049030cf841e35895cf34183ba006e721247fdeb95ff2780 protoc-gen-go.v1.34.2.darwin.arm64.tar.gz +a191849433fd489f1d44f37788d762658f3f5fb225f3a85d4ce6ba32666703ed protoc-gen-go.v1.34.2.linux.386.tar.gz +b87bc134dee55576a842141bf0ed27761c635d746780fce5dee038c6dd16554f protoc-gen-go.v1.34.2.linux.amd64.tar.gz +63d400167e75ab9f6690688f6fdc6a9455aa20bc1faa71e32149dbd322f7f198 protoc-gen-go.v1.34.2.linux.arm64.tar.gz +56e7675816db6e62be4f833a51544d5716b8420c462515579e05ca8444ab06ed protoc-gen-go.v1.34.2.windows.386.zip +abafd39612177dd4e9a65207cadd5374a9352d8611e8e040f8462fcfa3010daf protoc-gen-go.v1.34.2.windows.amd64.zip diff --git a/build/ci.go b/build/ci.go index 9a2532f51f..db57633704 100644 --- a/build/ci.go +++ b/build/ci.go @@ -39,9 +39,11 @@ package main import ( "bytes" + "crypto/sha256" "encoding/base64" "flag" "fmt" + "io" "log" "os" "os/exec" @@ -169,6 +171,8 @@ func main() { doPurge(os.Args[2:]) case "sanitycheck": doSanityCheck() + case "generate": + doGenerate() default: log.Fatal("unknown command ", os.Args[1]) } @@ -345,6 +349,86 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { return filepath.Join(cachedir, base) } +// hashSourceFiles iterates all files under the top-level project directory +// computing the hash of each file (excluding files within the tests +// subrepo) +func hashSourceFiles() (map[string]common.Hash, error) { + res := make(map[string]common.Hash) + err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error { + if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) { + return filepath.SkipDir + } + if !d.Type().IsRegular() { + return nil + } + // open the file and hash it + f, err := os.OpenFile(path, os.O_RDONLY, 0666) + if err != nil { + return err + } + hasher := sha256.New() + if _, err := io.Copy(hasher, f); err != nil { + return err + } + res[path] = common.Hash(hasher.Sum(nil)) + return nil + }) + if err != nil { + return nil, err + } + return res, nil +} + +// doGenerate ensures that re-generating generated files does not cause +// any mutations in the source file tree: i.e. all generated files were +// updated and committed. Any stale generated files are updated. +func doGenerate() { + var ( + tc = new(build.GoToolchain) + cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.") + verify = flag.Bool("verify", false, "check whether any files are changed by go generate") + ) + + protocPath := downloadProtoc(*cachedir) + protocGenGoPath := downloadProtocGenGo(*cachedir) + + var preHashes map[string]common.Hash + if *verify { + var err error + preHashes, err = hashSourceFiles() + if err != nil { + log.Fatal("failed to compute map of source hashes", "err", err) + } + } + + c := tc.Go("generate", "./...") + pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")} + c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator))) + build.MustRun(c) + + if !*verify { + return + } + // Check if files were changed. + postHashes, err := hashSourceFiles() + if err != nil { + log.Fatal("error computing source tree file hashes", "err", err) + } + updates := []string{} + for path, postHash := range postHashes { + preHash, ok := preHashes[path] + if !ok || preHash != postHash { + updates = append(updates, path) + } + } + for _, updatedFile := range updates { + fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) + } + if len(updates) != 0 { + log.Fatal("One or more generated files were updated by running 'go generate ./...'") + } +} + // doLint runs golangci-lint on requested packages. func doLint(cmdline []string) { var ( @@ -390,6 +474,96 @@ func downloadLinter(cachedir string) string { return filepath.Join(cachedir, base, "golangci-lint") } +// protocArchiveBaseName returns the name of the protoc archive file for +// the current system, stripped of version and file suffix. +func protocArchiveBaseName() (string, error) { + switch runtime.GOOS + "-" + runtime.GOARCH { + case "windows-amd64": + return "win64", nil + case "windows-386": + return "win32", nil + case "linux-arm64": + return "linux-aarch_64", nil + case "linux-386": + return "linux-x86_32", nil + case "linux-amd64": + return "linux-x86_64", nil + case "darwin-arm64": + return "osx-aarch_64", nil + case "darwin-amd64": + return "osx-x86_64", nil + default: + return "", fmt.Errorf("no prebuilt release of protoc available for this system (os: %s, arch: %s)", runtime.GOOS, runtime.GOARCH) + } +} + +// downloadProtocGenGo downloads protoc-gen-go, which is used by protoc +// in the generate command. It returns the full path of the directory +// containing the 'protoc-gen-go' executable. +func downloadProtocGenGo(cachedir string) string { + csdb := build.MustLoadChecksums("build/checksums.txt") + version, err := build.Version(csdb, "protoc-gen-go") + if err != nil { + log.Fatal(err) + } + baseName := fmt.Sprintf("protoc-gen-go.v%s.%s.%s", version, runtime.GOOS, runtime.GOARCH) + archiveName := baseName + if runtime.GOOS == "windows" { + archiveName += ".zip" + } else { + archiveName += ".tar.gz" + } + + url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf-go/releases/download/v%s/%s", version, archiveName) + + archivePath := path.Join(cachedir, archiveName) + if err := csdb.DownloadFile(url, archivePath); err != nil { + log.Fatal(err) + } + extractDest := filepath.Join(cachedir, baseName) + if err := build.ExtractArchive(archivePath, extractDest); err != nil { + log.Fatal(err) + } + extractDest, err = filepath.Abs(extractDest) + if err != nil { + log.Fatal("error resolving absolute path for protoc", "err", err) + } + return extractDest +} + +// downloadProtoc downloads the prebuilt protoc binary used to lint generated +// files as a CI step. It returns the full path to the directory containing +// the protoc executable. +func downloadProtoc(cachedir string) string { + csdb := build.MustLoadChecksums("build/checksums.txt") + version, err := build.Version(csdb, "protoc") + if err != nil { + log.Fatal(err) + } + baseName, err := protocArchiveBaseName() + if err != nil { + log.Fatal(err) + } + + fileName := fmt.Sprintf("protoc-%s-%s", version, baseName) + archiveFileName := fileName + ".zip" + url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf/releases/download/v%s/%s", version, archiveFileName) + archivePath := filepath.Join(cachedir, archiveFileName) + + if err := csdb.DownloadFile(url, archivePath); err != nil { + log.Fatal(err) + } + extractDest := filepath.Join(cachedir, fileName) + if err := build.ExtractArchive(archivePath, extractDest); err != nil { + log.Fatal(err) + } + extractDest, err = filepath.Abs(extractDest) + if err != nil { + log.Fatal("error resolving absolute path for protoc", "err", err) + } + return extractDest +} + // Release Packaging func doArchive(cmdline []string) { var ( diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index db058e847c..aa66dc49ff 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -199,7 +199,7 @@ type Hooks struct { // for tracing and reporting. type BalanceChangeReason byte -//go:generate stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go +//go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go const ( BalanceChangeUnspecified BalanceChangeReason = 0 diff --git a/internal/build/archive.go b/internal/build/archive.go index 5b37c0edfa..645921c690 100644 --- a/internal/build/archive.go +++ b/internal/build/archive.go @@ -272,17 +272,22 @@ func extractFile(arpath string, armode os.FileMode, data io.Reader, dest string) return fmt.Errorf("path %q escapes archive destination", target) } - // Ensure the destination directory exists. + // Remove the preivously-extracted file if it exists + if err := os.RemoveAll(target); err != nil { + return err + } + + // Recreate the destination directory if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { return err } // Copy file data. - file, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, armode) + file, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY, armode) if err != nil { return err } - if _, err := io.Copy(file, data); err != nil { + if _, err = io.Copy(file, data); err != nil { file.Close() os.Remove(target) return err From 09056601d864d83a46e1020d5d919eaaa626df08 Mon Sep 17 00:00:00 2001 From: Hteev Oli Date: Tue, 2 Jul 2024 03:57:04 +0800 Subject: [PATCH 117/196] core/state: fix inconsistent verkle test error messages (#29753) --- core/state/access_events_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/state/access_events_test.go b/core/state/access_events_test.go index 705033fe0b..c8c93accfd 100644 --- a/core/state/access_events_test.go +++ b/core/state/access_events_test.go @@ -41,8 +41,8 @@ func TestAccountHeaderGas(t *testing.T) { // Check cold read cost gas := ae.VersionGas(testAddr, false) - if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost) + if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm read cost @@ -71,8 +71,8 @@ func TestAccountHeaderGas(t *testing.T) { // Check cold write cost gas = ae.VersionGas(testAddr, true) - if gas != params.WitnessBranchWriteCost+params.WitnessChunkWriteCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost) + if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm write cost @@ -83,8 +83,8 @@ func TestAccountHeaderGas(t *testing.T) { // Check a write without a read charges both read and write costs gas = ae.BalanceGas(testAddr2, true) - if gas != params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessBranchWriteCost+params.WitnessChunkWriteCost+params.WitnessChunkReadCost) + if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check that a write followed by a read charges nothing @@ -113,8 +113,8 @@ func TestContractCreateInitGas(t *testing.T) { // Check cold read cost, without a value gas := ae.ContractCreateInitGas(testAddr, false) - if gas != params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*2+params.WitnessChunkReadCost*2 { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchWriteCost+params.WitnessBranchReadCost+params.WitnessChunkWriteCost*3) + if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check warm read cost @@ -131,8 +131,8 @@ func TestMessageCallGas(t *testing.T) { // Check cold read cost, without a value gas := ae.MessageCallGas(testAddr) - if gas != params.WitnessBranchReadCost+params.WitnessChunkReadCost*2 { - t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessBranchReadCost+params.WitnessChunkReadCost*2) + if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want { + t.Fatalf("incorrect gas computed, got %d, want %d", gas, want) } // Check that reading the version and code size of the same account does not incur the branch read cost From de366fd2e2e2ee6b93161a245a91e93fc1b1862f Mon Sep 17 00:00:00 2001 From: winniehere Date: Tue, 2 Jul 2024 20:58:15 +0800 Subject: [PATCH 118/196] accounts/abi: embed Go template instead of string literal (#30098) refactor(accounts/abi): use embed pkg to split default template to file --- accounts/abi/bind/source.go.tpl | 487 +++++++++++++++++++++++++++++++ accounts/abi/bind/template.go | 498 +------------------------------- 2 files changed, 495 insertions(+), 490 deletions(-) create mode 100644 accounts/abi/bind/source.go.tpl diff --git a/accounts/abi/bind/source.go.tpl b/accounts/abi/bind/source.go.tpl new file mode 100644 index 0000000000..c84862d03b --- /dev/null +++ b/accounts/abi/bind/source.go.tpl @@ -0,0 +1,487 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package {{.Package}} + +import ( + "math/big" + "strings" + "errors" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +{{$structs := .Structs}} +{{range $structs}} + // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. + type {{.Name}} struct { + {{range $field := .Fields}} + {{$field.Name}} {{$field.Type}}{{end}} + } +{{end}} + +{{range $contract := .Contracts}} + // {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract. + var {{.Type}}MetaData = &bind.MetaData{ + ABI: "{{.InputABI}}", + {{if $contract.FuncSigs -}} + Sigs: map[string]string{ + {{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}", + {{end}} + }, + {{end -}} + {{if .InputBin -}} + Bin: "0x{{.InputBin}}", + {{end}} + } + // {{.Type}}ABI is the input ABI used to generate the binding from. + // Deprecated: Use {{.Type}}MetaData.ABI instead. + var {{.Type}}ABI = {{.Type}}MetaData.ABI + + {{if $contract.FuncSigs}} + // Deprecated: Use {{.Type}}MetaData.Sigs instead. + // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. + var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs + {{end}} + + {{if .InputBin}} + // {{.Type}}Bin is the compiled bytecode used for deploying new contracts. + // Deprecated: Use {{.Type}}MetaData.Bin instead. + var {{.Type}}Bin = {{.Type}}MetaData.Bin + + // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. + func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { + parsed, err := {{.Type}}MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + {{range $pattern, $name := .Libraries}} + {{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend) + {{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:]) + {{end}} + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}}) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil + } + {{end}} + + // {{.Type}} is an auto generated Go binding around an Ethereum contract. + type {{.Type}} struct { + {{.Type}}Caller // Read-only binding to the contract + {{.Type}}Transactor // Write-only binding to the contract + {{.Type}}Filterer // Log filterer for contract events + } + + // {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract. + type {{.Type}}Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls + } + + // {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract. + type {{.Type}}Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls + } + + // {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events. + type {{.Type}}Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls + } + + // {{.Type}}Session is an auto generated Go binding around an Ethereum contract, + // with pre-set call and transact options. + type {{.Type}}Session struct { + Contract *{{.Type}} // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session + } + + // {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract, + // with pre-set call options. + type {{.Type}}CallerSession struct { + Contract *{{.Type}}Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + } + + // {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract, + // with pre-set transact options. + type {{.Type}}TransactorSession struct { + Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session + } + + // {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract. + type {{.Type}}Raw struct { + Contract *{{.Type}} // Generic contract binding to access the raw methods on + } + + // {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. + type {{.Type}}CallerRaw struct { + Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on + } + + // {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. + type {{.Type}}TransactorRaw struct { + Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on + } + + // New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) { + contract, err := bind{{.Type}}(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil + } + + // New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) { + contract, err := bind{{.Type}}(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &{{.Type}}Caller{contract: contract}, nil + } + + // New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) { + contract, err := bind{{.Type}}(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &{{.Type}}Transactor{contract: contract}, nil + } + + // New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract. + func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) { + contract, err := bind{{.Type}}(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &{{.Type}}Filterer{contract: contract}, nil + } + + // bind{{.Type}} binds a generic wrapper to an already deployed contract. + func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := {{.Type}}MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil + } + + // Call invokes the (constant) contract method with params as input values and + // sets the output to result. The result type might be a single field for simple + // returns, a slice of interfaces for anonymous returns and a struct for named + // returns. + func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...) + } + + // Transfer initiates a plain transaction to move funds to the contract, calling + // its default method if one is available. + func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts) + } + + // Transact invokes the (paid) contract method with params as input values. + func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...) + } + + // Call invokes the (constant) contract method with params as input values and + // sets the output to result. The result type might be a single field for simple + // returns, a slice of interfaces for anonymous returns and a struct for named + // returns. + func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...) + } + + // Transfer initiates a plain transaction to move funds to the contract, calling + // its default method if one is available. + func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.contract.Transfer(opts) + } + + // Transact invokes the (paid) contract method with params as input values. + func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...) + } + + {{range .Calls}} + // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) { + var out []interface{} + err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + {{if .Structured}} + outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} }) + if err != nil { + return *outstruct, err + } + {{range $i, $t := .Normalized.Outputs}} + outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} + + return *outstruct, err + {{else}} + if err != nil { + return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err + } + {{range $i, $t := .Normalized.Outputs}} + out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} + + return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err + {{end}} + } + + // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + } + + // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + } + {{end}} + + {{range .Transacts}} + // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { + return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) + } + + // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) + } + + // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) + } + {{end}} + + {{if .Fallback}} + // Fallback is a paid mutator transaction binding the contract fallback function. + // + // Solidity: {{.Fallback.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _{{$contract.Type}}.contract.RawTransact(opts, calldata) + } + + // Fallback is a paid mutator transaction binding the contract fallback function. + // + // Solidity: {{.Fallback.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) + } + + // Fallback is a paid mutator transaction binding the contract fallback function. + // + // Solidity: {{.Fallback.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) + } + {{end}} + + {{if .Receive}} + // Receive is a paid mutator transaction binding the contract receive function. + // + // Solidity: {{.Receive.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function + } + + // Receive is a paid mutator transaction binding the contract receive function. + // + // Solidity: {{.Receive.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) + } + + // Receive is a paid mutator transaction binding the contract receive function. + // + // Solidity: {{.Receive.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) { + return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) + } + {{end}} + + {{range .Events}} + // {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract. + type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { + Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration + } + // Next advances the iterator to the subsequent event, returning whether there + // are any more events found. In case of a retrieval or parsing error, false is + // returned and Error() can be queried for the exact failure. + func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool { + // If the iterator failed, stop iterating + if (it.fail != nil) { + return false + } + // If the iterator completed, deliver directly whatever's available + if (it.done) { + select { + case log := <-it.logs: + it.Event = new({{$contract.Type}}{{.Normalized.Name}}) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new({{$contract.Type}}{{.Normalized.Name}}) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } + } + // Error returns any retrieval or parsing error occurred during filtering. + func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error { + return it.fail + } + // Close terminates the iteration process, releasing any pending underlying + // resources. + func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error { + it.sub.Unsubscribe() + return nil + } + + // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract. + type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}} + {{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}} + Raw types.Log // Blockchain specific contextual infos + } + + // Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) { + {{range .Normalized.Inputs}} + {{if .Indexed}}var {{.Name}}Rule []interface{} + for _, {{.Name}}Item := range {{.Name}} { + {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) + }{{end}}{{end}} + + logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) + if err != nil { + return nil, err + } + return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil + } + + // Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) { + {{range .Normalized.Inputs}} + {{if .Indexed}}var {{.Name}}Rule []interface{} + for _, {{.Name}}Item := range {{.Name}} { + {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) + }{{end}}{{end}} + + logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new({{$contract.Type}}{{.Normalized.Name}}) + if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil + } + + // Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}. + // + // Solidity: {{.Original.String}} + func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) { + event := new({{$contract.Type}}{{.Normalized.Name}}) + if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil + } + + {{end}} +{{end}} \ No newline at end of file diff --git a/accounts/abi/bind/template.go b/accounts/abi/bind/template.go index 95dc13cc18..4a0062af0a 100644 --- a/accounts/abi/bind/template.go +++ b/accounts/abi/bind/template.go @@ -16,7 +16,11 @@ package bind -import "github.com/ethereum/go-ethereum/accounts/abi" +import ( + _ "embed" + + "github.com/ethereum/go-ethereum/accounts/abi" +) // tmplData is the data structure required to fill the binding template. type tmplData struct { @@ -80,492 +84,6 @@ var tmplSource = map[Lang]string{ // tmplSourceGo is the Go source template that the generated Go contract binding // is based on. -const tmplSourceGo = ` -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package {{.Package}} - -import ( - "math/big" - "strings" - "errors" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -{{$structs := .Structs}} -{{range $structs}} - // {{.Name}} is an auto generated low-level Go binding around an user-defined struct. - type {{.Name}} struct { - {{range $field := .Fields}} - {{$field.Name}} {{$field.Type}}{{end}} - } -{{end}} - -{{range $contract := .Contracts}} - // {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract. - var {{.Type}}MetaData = &bind.MetaData{ - ABI: "{{.InputABI}}", - {{if $contract.FuncSigs -}} - Sigs: map[string]string{ - {{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}", - {{end}} - }, - {{end -}} - {{if .InputBin -}} - Bin: "0x{{.InputBin}}", - {{end}} - } - // {{.Type}}ABI is the input ABI used to generate the binding from. - // Deprecated: Use {{.Type}}MetaData.ABI instead. - var {{.Type}}ABI = {{.Type}}MetaData.ABI - - {{if $contract.FuncSigs}} - // Deprecated: Use {{.Type}}MetaData.Sigs instead. - // {{.Type}}FuncSigs maps the 4-byte function signature to its string representation. - var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs - {{end}} - - {{if .InputBin}} - // {{.Type}}Bin is the compiled bytecode used for deploying new contracts. - // Deprecated: Use {{.Type}}MetaData.Bin instead. - var {{.Type}}Bin = {{.Type}}MetaData.Bin - - // Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it. - func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) { - parsed, err := {{.Type}}MetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - {{range $pattern, $name := .Libraries}} - {{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend) - {{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:]) - {{end}} - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}}) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil - } - {{end}} - - // {{.Type}} is an auto generated Go binding around an Ethereum contract. - type {{.Type}} struct { - {{.Type}}Caller // Read-only binding to the contract - {{.Type}}Transactor // Write-only binding to the contract - {{.Type}}Filterer // Log filterer for contract events - } - - // {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract. - type {{.Type}}Caller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract. - type {{.Type}}Transactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events. - type {{.Type}}Filterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls - } - - // {{.Type}}Session is an auto generated Go binding around an Ethereum contract, - // with pre-set call and transact options. - type {{.Type}}Session struct { - Contract *{{.Type}} // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session - } - - // {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract, - // with pre-set call options. - type {{.Type}}CallerSession struct { - Contract *{{.Type}}Caller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - } - - // {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract, - // with pre-set transact options. - type {{.Type}}TransactorSession struct { - Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session - } - - // {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract. - type {{.Type}}Raw struct { - Contract *{{.Type}} // Generic contract binding to access the raw methods on - } - - // {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. - type {{.Type}}CallerRaw struct { - Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on - } - - // {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. - type {{.Type}}TransactorRaw struct { - Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on - } - - // New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) { - contract, err := bind{{.Type}}(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil - } - - // New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) { - contract, err := bind{{.Type}}(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &{{.Type}}Caller{contract: contract}, nil - } - - // New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) { - contract, err := bind{{.Type}}(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &{{.Type}}Transactor{contract: contract}, nil - } - - // New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract. - func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) { - contract, err := bind{{.Type}}(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &{{.Type}}Filterer{contract: contract}, nil - } - - // bind{{.Type}} binds a generic wrapper to an already deployed contract. - func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := {{.Type}}MetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil - } - - // Call invokes the (constant) contract method with params as input values and - // sets the output to result. The result type might be a single field for simple - // returns, a slice of interfaces for anonymous returns and a struct for named - // returns. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...) - } - - // Transfer initiates a plain transaction to move funds to the contract, calling - // its default method if one is available. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts) - } - - // Transact invokes the (paid) contract method with params as input values. - func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...) - } - - // Call invokes the (constant) contract method with params as input values and - // sets the output to result. The result type might be a single field for simple - // returns, a slice of interfaces for anonymous returns and a struct for named - // returns. - func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...) - } - - // Transfer initiates a plain transaction to move funds to the contract, calling - // its default method if one is available. - func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.contract.Transfer(opts) - } - - // Transact invokes the (paid) contract method with params as input values. - func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...) - } - - {{range .Calls}} - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) { - var out []interface{} - err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - {{if .Structured}} - outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} }) - if err != nil { - return *outstruct, err - } - {{range $i, $t := .Normalized.Outputs}} - outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} - - return *outstruct, err - {{else}} - if err != nil { - return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err - } - {{range $i, $t := .Normalized.Outputs}} - out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}} - - return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err - {{end}} - } - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - {{end}} - - {{range .Transacts}} - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) - } - - // {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}}) - } - {{end}} - - {{if .Fallback}} - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.RawTransact(opts, calldata) - } - - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) - } - - // Fallback is a paid mutator transaction binding the contract fallback function. - // - // Solidity: {{.Fallback.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata) - } - {{end}} - - {{if .Receive}} - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { - return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function - } - - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) - } - - // Receive is a paid mutator transaction binding the contract receive function. - // - // Solidity: {{.Receive.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) { - return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts) - } - {{end}} - - {{range .Events}} - // {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract. - type {{$contract.Type}}{{.Normalized.Name}}Iterator struct { - Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration - } - // Next advances the iterator to the subsequent event, returning whether there - // are any more events found. In case of a retrieval or parsing error, false is - // returned and Error() can be queried for the exact failure. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool { - // If the iterator failed, stop iterating - if (it.fail != nil) { - return false - } - // If the iterator completed, deliver directly whatever's available - if (it.done) { - select { - case log := <-it.logs: - it.Event = new({{$contract.Type}}{{.Normalized.Name}}) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new({{$contract.Type}}{{.Normalized.Name}}) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } - } - // Error returns any retrieval or parsing error occurred during filtering. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error { - return it.fail - } - // Close terminates the iteration process, releasing any pending underlying - // resources. - func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error { - it.sub.Unsubscribe() - return nil - } - - // {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract. - type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}} - {{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}} - Raw types.Log // Blockchain specific contextual infos - } - - // Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) { - {{range .Normalized.Inputs}} - {{if .Indexed}}var {{.Name}}Rule []interface{} - for _, {{.Name}}Item := range {{.Name}} { - {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) - }{{end}}{{end}} - - logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) - if err != nil { - return nil, err - } - return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil - } - - // Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) { - {{range .Normalized.Inputs}} - {{if .Indexed}}var {{.Name}}Rule []interface{} - for _, {{.Name}}Item := range {{.Name}} { - {{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item) - }{{end}}{{end}} - - logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}}) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new({{$contract.Type}}{{.Normalized.Name}}) - if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil - } - - // Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}. - // - // Solidity: {{.Original.String}} - func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) { - event := new({{$contract.Type}}{{.Normalized.Name}}) - if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil - } - - {{end}} -{{end}} -` +// +//go:embed source.go.tpl +var tmplSourceGo string From 6f2e1cff47cb24897983b1a2a3fffc1186b58d4a Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:58:42 +0200 Subject: [PATCH 119/196] params: release Geth v1.14.6 --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 48bca3c5b2..cc607ea29c 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 6 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 640e0f15fd881e44f58e303fa768e10490541764 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:59:41 +0200 Subject: [PATCH 120/196] params: begin v1.14.7 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index cc607ea29c..a3e841750e 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 7 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From 2d9d42376436cd275c28056cffd0eb97cb8daed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Wed, 3 Jul 2024 12:11:43 +0200 Subject: [PATCH 121/196] build: upgrade -dlgo version to Go 1.22.5 (#30112) --- build/checksums.txt | 96 ++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index c6c9606865..15c74559e6 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,55 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.4 +# version:golang 1.22.5 # https://go.dev/dl/ -fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz -b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz -7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg -c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz -4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg -242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz -f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz -7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz -88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz -3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz -726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz -5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz -d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz -47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz -ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz -a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz -e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz -e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz -73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz -417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz -7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz -69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz -dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz -a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz -56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz -7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz -ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz -33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz -fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz -c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz -d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz -72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz -1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz -a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz -9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz -a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz -5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz -6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz -e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz -5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi -aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip -3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi -26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip -c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi -5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip -553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi -8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip +ac9c723f224969aee624bc34fd34c9e13f2a212d75c71c807de644bb46e112f6 go1.22.5.src.tar.gz +c82ba3403c45a4aa4b84b08244656a51e55b86fb130dcc500f5291d0f3b12222 go1.22.5.aix-ppc64.tar.gz +8a8872b1bac959b3b76f2e3978c46406d22a54a99c83ca55840ca08b4f2960bc go1.22.5.darwin-amd64.pkg +95d9933cdcf45f211243c42c7705c37353cccd99f27eb4d8e2d1bf2f4165cb50 go1.22.5.darwin-amd64.tar.gz +8c943512d1fa4e849f0078b03721df02aac19d8bb872dd17ab3ee7127ae6b732 go1.22.5.darwin-arm64.pkg +4cd1bcb05be03cecb77bccd765785d5ff69d79adf4dd49790471d00c06b41133 go1.22.5.darwin-arm64.tar.gz +1f1f035e968a877cd8ed62adae6edb2feeee62470660b7587ddcb904a3877a21 go1.22.5.dragonfly-amd64.tar.gz +d660698411465531d475ec1c617fdb415df68740f3511138a8d15506665a06f9 go1.22.5.freebsd-386.tar.gz +75f43ef46c2ad46c534ded25d26fba9bef036fc07074dfa45c0b3b90856a8151 go1.22.5.freebsd-amd64.tar.gz +75614714e7e4a4dd721f0eddd6555b3f6afc4c07e59c1b9b769cf663996165f9 go1.22.5.freebsd-arm.tar.gz +1377d0d7233f1b8f4cb8e3456f2e7ed44aca4a95daab79ae09605d34aa967c6b go1.22.5.freebsd-arm64.tar.gz +07baf198587abc05ea789dbe5810a2d6612ad56a51718bbf74de2c93bdbe676a go1.22.5.freebsd-riscv64.tar.gz +c0bd4f0d44252f3ec93ca850a41b167bb868179c7c283f8af9439e73b2654b17 go1.22.5.illumos-amd64.tar.gz +3ea4c78e6fa52978ae1ed2e5927ad17495da440c9fae7787b1ebc1d0572f7f43 go1.22.5.linux-386.tar.gz +904b924d435eaea086515bc63235b192ea441bd8c9b198c507e85009e6e4c7f0 go1.22.5.linux-amd64.tar.gz +8d21325bfcf431be3660527c1a39d3d9ad71535fabdf5041c826e44e31642b5a go1.22.5.linux-arm64.tar.gz +8c4587cf3e63c9aefbcafa92818c4d9d51683af93ea687bf6c7508d6fa36f85e go1.22.5.linux-armv6l.tar.gz +780e2eeb6376a763c564f776eaac6700f33f95e29302faa54b040b19cb1f6fd2 go1.22.5.linux-loong64.tar.gz +f784aa1adfb605da3bfe8cd534b545bddae3eb893e9302f7c2f5d44656b1cae2 go1.22.5.linux-mips.tar.gz +aaa3756571467768388f2ab641a02ff54f98f1684808cda047a7be3026e4b438 go1.22.5.linux-mips64.tar.gz +b7956d925c9ef5a4dc53017feaed2d78dba5d0a1036bad5ea513f1f15ba08fbc go1.22.5.linux-mips64le.tar.gz +7baf605be9b787acd750b6b48a91818a5590ec9289b14aea5696a46b41853888 go1.22.5.linux-mipsle.tar.gz +f09b2a6c1a409662e8e8fe267e1eabeba0a1fd00eb1422fd88297b013803952e go1.22.5.linux-ppc64.tar.gz +5312bb420ac0b59175a58927e70b4660b14ab7319aab54398b6071fabcbfbb09 go1.22.5.linux-ppc64le.tar.gz +f8d0c7d96b336f4133409ff9da7241cfe91e65723c2e8e7c7f9b58a9f9603476 go1.22.5.linux-riscv64.tar.gz +24c6c5c9d515adea5d58ae78388348c97614a0c21ac4d4f4c0dab75e893b0b5d go1.22.5.linux-s390x.tar.gz +39144c62acbaa85e4f1ab57bad8f5b3dc67d6fa24b711ec1fa593f4a0ea1fe91 go1.22.5.netbsd-386.tar.gz +118f79640588eb878529b46cdf56599012da6575f0ac07069ec1e9a8e78ddd0b go1.22.5.netbsd-amd64.tar.gz +d39c2b94ae3fd0a6399e545cbecb673496293075291bd98ef15f24d21625a490 go1.22.5.netbsd-arm.tar.gz +f7fb617d10c39248996521d72370db82d50724fa894089c76ae4298fbbe1fb0b go1.22.5.netbsd-arm64.tar.gz +e0f778a34746587ae7c18e8a24cfaba1b2eaabce75d0ceb470adf576ad1cd90f go1.22.5.openbsd-386.tar.gz +b417311df26ef7ae8b34fcb991519a5c496010561c12386d9469aea03c1bdf0b go1.22.5.openbsd-amd64.tar.gz +e78e8ad05605d530a4f79e55031c7c65f2020a9d442e05d490bd08f0d947a34f go1.22.5.openbsd-arm.tar.gz +8027898948f17742717786ead2ff2e960ee1fc82995d6edbad0050d551710f59 go1.22.5.openbsd-arm64.tar.gz +99c5b81d75bcc0d83d25dedc9535682c42c0e761276c88bcc4db6340344644fd go1.22.5.openbsd-ppc64.tar.gz +30d5dacdee0481f0b8cabb75b706465e2177c3a4a1d1c46293332f4b90a3d199 go1.22.5.plan9-386.tar.gz +65628650cd7665387cfe6fa386c381f4de1ef7b03a12067ae9ccf06d2feaea2c go1.22.5.plan9-amd64.tar.gz +322541cbfc9ae95b48b9eec4eb45df48299784592e23121084f790cf1082787e go1.22.5.plan9-arm.tar.gz +87c590e3eb81fcffa3dc1524c03c2847f0890e95c2a43586e82b56c262eb03d8 go1.22.5.solaris-amd64.tar.gz +3ec89ed822b38f4483977a90913fbe39d0857f0ed16c4642dec1950ddbe8c943 go1.22.5.windows-386.msi +c44fc421075022add78fbf8db38519dd5520a11832749be2189e64b3cf4f02f9 go1.22.5.windows-386.zip +86b0299ab8cb9c44882a9080dac03f7f4d9546f51ed1ba1015599114bcbc66d0 go1.22.5.windows-amd64.msi +59968438b8d90f108fd240d4d2f95b037e59716995f7409e0a322dcb996e9f42 go1.22.5.windows-amd64.zip +013d3b300e6b8f26482d6dd17b02830b83ee63795498bd8c0c9d80bb2c4d6cf7 go1.22.5.windows-arm.msi +8cc860630a84e2dbff3e84280f46a571741f26f8a1819aa4fbcb3164fdd51312 go1.22.5.windows-arm.zip +8f90519d9f305f2caa05d1d4fb0656b50f1bf89d76e194279f480e5a484c891f go1.22.5.windows-arm64.msi +6717d5841162aa8c05f932eb74a643f1310b8a88f80f0830e86d194289734bbf go1.22.5.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From c4b4d05e695c7926baa8f3776f91349d0ef76daf Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 9 Jul 2024 19:19:25 +0800 Subject: [PATCH 122/196] crypto: remove hardcoded value for secp256k1.N (#30126) --- crypto/crypto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/crypto.go b/crypto/crypto.go index 7f7171f730..aaa5cc43a2 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -45,7 +45,7 @@ const RecoveryIDOffset = 64 const DigestLength = 32 var ( - secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) + secp256k1N = S256().Params().N secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) ) From 10467acc713d6f110a56ade5ceaddf4b4cef7044 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Tue, 9 Jul 2024 14:17:43 +0200 Subject: [PATCH 123/196] go.mod: update uint256 to 1.3.0 (#30134) --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index b578ec07b5..a757b6705d 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/hashicorp/go-bexpr v0.1.10 github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.2.4 + github.com/holiman/uint256 v1.3.0 github.com/huin/goupnp v1.3.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c @@ -74,6 +74,7 @@ require ( golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 golang.org/x/tools v0.20.0 + google.golang.org/protobuf v1.33.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -143,7 +144,6 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.24.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index 168637b0ad..826f0f674f 100644 --- a/go.sum +++ b/go.sum @@ -312,8 +312,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8 github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= -github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= +github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= From 37590b2c5579c36d846c788c70861685b0ea240e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 9 Jul 2024 08:19:55 -0400 Subject: [PATCH 124/196] eth/catalyst: fix params in failure log (#30131) --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 0efa61587d..00cce259c8 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -335,7 +335,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl log.Warn("Final block not available in database", "hash", update.FinalizedBlockHash) return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not available in database")) } else if rawdb.ReadCanonicalHash(api.eth.ChainDb(), finalBlock.NumberU64()) != update.FinalizedBlockHash { - log.Warn("Final block not in canonical chain", "number", block.NumberU64(), "hash", update.HeadBlockHash) + log.Warn("Final block not in canonical chain", "number", finalBlock.NumberU64(), "hash", update.FinalizedBlockHash) return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("final block not in canonical chain")) } // Set the finalized block From 803dc6b664376df8a69aed113b986b08b2c41784 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 11 Jul 2024 09:28:27 +0200 Subject: [PATCH 125/196] core/txpool/blobpool: revert #29989, WLock on Nonce (#30142) --- core/txpool/blobpool/blobpool.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 2fca5c7b3e..6ff8847a76 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -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 // by the pool already applied on top. func (p *BlobPool) Nonce(addr common.Address) uint64 { - p.lock.RLock() - defer p.lock.RUnlock() + // We need a write lock here, since state.GetNonce might write the cache. + p.lock.Lock() + defer p.lock.Unlock() if txs, ok := p.index[addr]; ok { return txs[len(txs)-1].nonce + 1 From 0aafbb31ab6836c1a3ab3b2c16f31bd833407ff5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 11 Jul 2024 14:23:27 +0200 Subject: [PATCH 126/196] params: go-ethereum v1.14.7 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index a3e841750e..c4e1274ad2 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release - VersionMeta = "unstable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 7 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From bcaf3747f8443c6f8042f4f058f74404bb8c0a22 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 11 Jul 2024 14:24:09 +0200 Subject: [PATCH 127/196] params: begin v1.14.8 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index c4e1274ad2..852f9fd1e1 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor 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 ) // Version holds the textual version string. From cf0378499f1bcae65c093c58cd6ca8225e91b125 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 11 Jul 2024 22:09:24 +0800 Subject: [PATCH 128/196] core/state: fix prefetcher for verkle (#29760) --- core/state/statedb.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index ac82a8e3e3..1664a446f4 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -907,9 +907,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 // _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. + // + // 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() - - if s.prefetcher != nil { + if s.prefetcher != nil && (s.trie == nil || !s.trie.IsVerkle()) { if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil { log.Error("Failed to retrieve account pre-fetcher trie") } else { From a0631f3ebd228eebd8ef809a09cee89bf630e0df Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:28:06 +0700 Subject: [PATCH 129/196] core/txpool/blobpool: use nonce from argument instead of tx.Nonce() (#30148) This does not change the behavior here as the nonce in the argument is tx.Nonce(). This commit helps to make the function easier to read and avoid capturing the tx in the function. --- core/txpool/blobpool/blobpool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index 6ff8847a76..cb266fd10a 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1116,7 +1116,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { ExistingCost: func(addr common.Address, nonce uint64) *big.Int { next := p.state.GetNonce(addr) 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 }, From 79d2327771e5a10e363bdd6542c624b8060bac7b Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:05:59 +0200 Subject: [PATCH 130/196] trie: add RollBackAccount function to verkle trees (#30135) --- trie/verkle.go | 51 ++++++++++++++++++++++++++++ trie/verkle_test.go | 82 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/trie/verkle.go b/trie/verkle.go index a457097e95..fb4d81281c 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -199,6 +199,57 @@ func (t *VerkleTrie) DeleteAccount(addr common.Address) error { 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 // 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. diff --git a/trie/verkle_test.go b/trie/verkle_test.go index 0cbe28bf01..55438d45e1 100644 --- a/trie/verkle_test.go +++ b/trie/verkle_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie/utils" "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") + } +} From 4bbe993252f0f54f58a09ab32822e09281c25e79 Mon Sep 17 00:00:00 2001 From: Nathan Jo <162083209+qqqeck@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:15:35 +0900 Subject: [PATCH 131/196] p2p: fix ip change log parameter (#30158) --- p2p/server_nat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/server_nat.go b/p2p/server_nat.go index 299d275490..933993bc1f 100644 --- a/p2p/server_nat.go +++ b/p2p/server_nat.go @@ -125,7 +125,7 @@ func (srv *Server) portMappingLoop() { if err != nil { log.Debug("Couldn't get external IP", "err", err, "interface", srv.NAT) } 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 { continue } From 169aa914497f3dff4dec2fdd68a29e185a4091a6 Mon Sep 17 00:00:00 2001 From: Jeremy Schlatter Date: Mon, 15 Jul 2024 02:36:21 -0700 Subject: [PATCH 132/196] cmd/utils: fix typo in flag description (#30127) --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 46d380b984..96a3cf55bb 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -291,7 +291,7 @@ var ( } BeaconApiHeaderFlag = &cli.StringSliceFlag{ 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, } BeaconThresholdFlag = &cli.IntFlag{ From a0d2613ef0814c5cde83909cf48b2c3eea274faf Mon Sep 17 00:00:00 2001 From: Danyal Prout Date: Mon, 15 Jul 2024 05:09:32 -0500 Subject: [PATCH 133/196] core/types: don't modify signature V when reading large chainID (#30157) --- core/types/transaction_signing.go | 4 ++-- core/types/transaction_test.go | 35 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 339fee6f97..dd25f081f7 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -572,6 +572,6 @@ func deriveChainId(v *big.Int) *big.Int { } return new(big.Int).SetUint64((v - 35) / 2) } - v.Sub(v, big.NewInt(35)) - return v.Rsh(v, 1) + vCopy := new(big.Int).Sub(v, big.NewInt(35)) + return vCopy.Rsh(vCopy, 1) } diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 5dbf367073..eed13ee205 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -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) { data, err := json.Marshal(tx) if err != nil { From 8adce57b411267faac6cf744aee84f5c51445bb9 Mon Sep 17 00:00:00 2001 From: JeukHwang <92910273+JeukHwang@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:29:13 +0900 Subject: [PATCH 134/196] SECURITY.md: correct PGP key block formatting (#30123) --- SECURITY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 41b900d5e9..1c99ab5950 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -171,5 +171,5 @@ i4O1UeWKs9owWttan9+PI47ozBSKOTxmMqLSQ0f56Np9FJsV0ilGxRKfjhzJ4KniOMUBA7mP epy6lH7HmxjjOR7eo0DaSxQGQpThAtFGwkWkFh8yki8j3E42kkrxvEyyYZDXn2YcI3bpqhJx PtwCMZUJ3kc/skOrs6bOI19iBNaEoNX5Dllm7UHjOgWNDQkcCuOCxucKano= =arte ------END PGP PUBLIC KEY BLOCK------ +-----END PGP PUBLIC KEY BLOCK----- ``` From 71210b0630e4f8dd2e7bcc7c39424fb2382e4f00 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Mon, 15 Jul 2024 21:26:58 +0800 Subject: [PATCH 135/196] all: simplify tests using t.TempDir() (#30150) --- accounts/keystore/account_cache_test.go | 3 +-- cmd/clef/consolecmd_test.go | 9 +++----- cmd/devp2p/internal/ethtest/suite_test.go | 8 ++++---- cmd/geth/exportcmd_test.go | 3 +-- cmd/geth/logging_test.go | 6 ++---- cmd/utils/export_test.go | 25 +++++------------------ core/rawdb/freezer_meta_test.go | 6 ++++-- 7 files changed, 20 insertions(+), 40 deletions(-) diff --git a/accounts/keystore/account_cache_test.go b/accounts/keystore/account_cache_test.go index 41a3002248..c9a8cdfcef 100644 --- a/accounts/keystore/account_cache_test.go +++ b/accounts/keystore/account_cache_test.go @@ -114,7 +114,7 @@ func TestWatchNewFile(t *testing.T) { func TestWatchNoDir(t *testing.T) { t.Parallel() // 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) list := ks.Accounts() if len(list) > 0 { @@ -126,7 +126,6 @@ func TestWatchNoDir(t *testing.T) { } // Create the directory and copy a key file into it. os.MkdirAll(dir, 0700) - defer os.RemoveAll(dir) file := filepath.Join(dir, "aaa") if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil { t.Fatal(err) diff --git a/cmd/clef/consolecmd_test.go b/cmd/clef/consolecmd_test.go index c8b37f5b92..a5b324c53f 100644 --- a/cmd/clef/consolecmd_test.go +++ b/cmd/clef/consolecmd_test.go @@ -27,9 +27,8 @@ import ( // TestImportRaw tests clef --importraw func TestImportRaw(t *testing.T) { 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) - t.Cleanup(func() { os.Remove(keyPath) }) t.Run("happy-path", func(t *testing.T) { t.Parallel() @@ -68,9 +67,8 @@ func TestImportRaw(t *testing.T) { // TestListAccounts tests clef --list-accounts func TestListAccounts(t *testing.T) { 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) - t.Cleanup(func() { os.Remove(keyPath) }) t.Run("no-accounts", func(t *testing.T) { t.Parallel() @@ -97,9 +95,8 @@ func TestListAccounts(t *testing.T) { // TestListWallets tests clef --list-wallets func TestListWallets(t *testing.T) { 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) - t.Cleanup(func() { os.Remove(keyPath) }) t.Run("no-accounts", func(t *testing.T) { t.Parallel() diff --git a/cmd/devp2p/internal/ethtest/suite_test.go b/cmd/devp2p/internal/ethtest/suite_test.go index d70adda51f..a6fca0e524 100644 --- a/cmd/devp2p/internal/ethtest/suite_test.go +++ b/cmd/devp2p/internal/ethtest/suite_test.go @@ -34,12 +34,12 @@ import ( "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 if _, err := crand.Read(secret[:]); err != nil { 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 { 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) { - jwtPath, secret, err := makeJWTSecret() + jwtPath, secret, err := makeJWTSecret(t) if err != nil { t.Fatalf("could not make jwt secret: %v", err) } @@ -75,7 +75,7 @@ func TestEthSuite(t *testing.T) { } func TestSnapSuite(t *testing.T) { - jwtPath, secret, err := makeJWTSecret() + jwtPath, secret, err := makeJWTSecret(t) if err != nil { t.Fatalf("could not make jwt secret: %v", err) } diff --git a/cmd/geth/exportcmd_test.go b/cmd/geth/exportcmd_test.go index 9570b1ffd2..d08c890734 100644 --- a/cmd/geth/exportcmd_test.go +++ b/cmd/geth/exportcmd_test.go @@ -28,8 +28,7 @@ import ( // TestExport does a basic test of "geth export", exporting the test-genesis. func TestExport(t *testing.T) { t.Parallel() - outfile := fmt.Sprintf("%v/testExport.out", os.TempDir()) - defer os.Remove(outfile) + outfile := fmt.Sprintf("%v/testExport.out", t.TempDir()) geth := runGeth(t, "--datadir", initGeth(t), "export", outfile) geth.WaitExit() if have, want := geth.ExitStatus(), 0; have != want { diff --git a/cmd/geth/logging_test.go b/cmd/geth/logging_test.go index f426b138bb..4293a860ec 100644 --- a/cmd/geth/logging_test.go +++ b/cmd/geth/logging_test.go @@ -201,9 +201,8 @@ func TestFileOut(t *testing.T) { var ( have, want []byte 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 { t.Fatal(err) } @@ -222,9 +221,8 @@ func TestRotatingFileOut(t *testing.T) { var ( have, want []byte 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 { t.Fatal(err) } diff --git a/cmd/utils/export_test.go b/cmd/utils/export_test.go index c22aad64b8..b70d2451c6 100644 --- a/cmd/utils/export_test.go +++ b/cmd/utils/export_test.go @@ -29,18 +29,12 @@ import ( // TestExport does basic sanity checks on the export/import functionality func TestExport(t *testing.T) { - f := fmt.Sprintf("%v/tempdump", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump", t.TempDir()) testExport(t, f) } func TestExportGzip(t *testing.T) { - f := fmt.Sprintf("%v/tempdump.gz", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump.gz", t.TempDir()) 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 func TestDeletionExport(t *testing.T) { - f := fmt.Sprintf("%v/tempdump", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump", t.TempDir()) testDeletion(t, f) } // TestDeletionExportGzip tests if the deletion markers can be exported/imported // correctly with gz compression. func TestDeletionExportGzip(t *testing.T) { - f := fmt.Sprintf("%v/tempdump.gz", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump.gz", t.TempDir()) testDeletion(t, f) } @@ -171,10 +159,7 @@ func testDeletion(t *testing.T, f string) { // TestImportFutureFormat tests that we reject unsupported future versions. func TestImportFutureFormat(t *testing.T) { t.Parallel() - f := fmt.Sprintf("%v/tempdump-future", os.TempDir()) - defer func() { - os.Remove(f) - }() + f := fmt.Sprintf("%v/tempdump-future", t.TempDir()) fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) if err != nil { t.Fatal(err) diff --git a/core/rawdb/freezer_meta_test.go b/core/rawdb/freezer_meta_test.go index ba1a95e453..409e811026 100644 --- a/core/rawdb/freezer_meta_test.go +++ b/core/rawdb/freezer_meta_test.go @@ -22,10 +22,11 @@ import ( ) func TestReadWriteFreezerTableMeta(t *testing.T) { - f, err := os.CreateTemp(os.TempDir(), "*") + f, err := os.CreateTemp(t.TempDir(), "*") if err != nil { t.Fatalf("Failed to create file %v", err) } + defer f.Close() err = writeMetadata(f, newMetadata(100)) if err != nil { t.Fatalf("Failed to write metadata %v", err) @@ -43,10 +44,11 @@ func TestReadWriteFreezerTableMeta(t *testing.T) { } func TestInitializeFreezerTableMeta(t *testing.T) { - f, err := os.CreateTemp(os.TempDir(), "*") + f, err := os.CreateTemp(t.TempDir(), "*") if err != nil { t.Fatalf("Failed to create file %v", err) } + defer f.Close() meta, err := loadMetadata(f, uint64(100)) if err != nil { t.Fatalf("Failed to read metadata %v", err) From 0d38b0cd34fd8fef3388feb529bb241b725b7364 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 16 Jul 2024 04:47:11 -0500 Subject: [PATCH 136/196] eth/catalyst: fix (*SimulatedBeacon).AdjustTime() conversion (#30138) --- eth/catalyst/simulated_beacon.go | 2 +- ethclient/simulated/backend_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/catalyst/simulated_beacon.go b/eth/catalyst/simulated_beacon.go index 2d6569e422..8bdf94b80e 100644 --- a/eth/catalyst/simulated_beacon.go +++ b/eth/catalyst/simulated_beacon.go @@ -302,7 +302,7 @@ func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error { return errors.New("parent not found") } 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) { diff --git a/ethclient/simulated/backend_test.go b/ethclient/simulated/backend_test.go index a8fd7913c3..b70086b385 100644 --- a/ethclient/simulated/backend_test.go +++ b/ethclient/simulated/backend_test.go @@ -106,7 +106,7 @@ func TestAdjustTime(t *testing.T) { block2, _ := client.BlockByNumber(context.Background(), nil) prevTime := block1.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) } } From b530d8e4552a583eb89538799b31aa92e281b4ed Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 16 Jul 2024 18:52:19 +0800 Subject: [PATCH 137/196] trie, triedb: remove unnecessary child resolver interface (#30167) --- trie/committer.go | 8 ++------ triedb/database.go | 10 +--------- triedb/hashdb/database.go | 30 +++++++++++------------------- 3 files changed, 14 insertions(+), 34 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 4e2f7b8bd6..863e7bafdc 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -154,12 +154,8 @@ func (c *committer) store(path []byte, n node) node { return hash } -// MerkleResolver the children resolver in merkle-patricia-tree. -type MerkleResolver struct{} - -// ForEach implements childResolver, decodes the provided node and -// traverses the children inside. -func (resolver MerkleResolver) ForEach(node []byte, onChild func(common.Hash)) { +// ForGatherChildren decodes the provided node and traverses the children inside. +func ForGatherChildren(node []byte, onChild func(common.Hash)) { forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild) } diff --git a/triedb/database.go b/triedb/database.go index 91386a9dbc..1f9f38388b 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" "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/triestate" "github.com/ethereum/go-ethereum/triedb/database" @@ -112,14 +111,7 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { if config.PathDB != nil { db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle) } else { - var resolver hashdb.ChildResolver - 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) + db.backend = hashdb.New(diskdb, config.HashDB) } return db } diff --git a/triedb/hashdb/database.go b/triedb/hashdb/database.go index bb0deca9a7..4def10e338 100644 --- a/triedb/hashdb/database.go +++ b/triedb/hashdb/database.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "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/triestate" "github.com/ethereum/go-ethereum/triedb/database" @@ -60,12 +61,6 @@ var ( 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. type Config struct { 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 // periodically flush a couple tries to disk, garbage collecting the remainder. type Database struct { - diskdb ethdb.Database // Persistent storage for matured trie nodes - resolver ChildResolver // The handler to resolve children of nodes - + diskdb ethdb.Database // Persistent storage for matured trie nodes cleans *fastcache.Cache // GC friendly memory cache of clean node RLPs dirties map[common.Hash]*cachedNode // Data and references relationships of dirty trie nodes 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, // both the implicit ones from inside the node as well as the explicit ones // 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 { onChild(child) } - resolver.ForEach(n.node, onChild) + trie.ForGatherChildren(n.node, onChild) } // 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 { config = Defaults } @@ -141,10 +134,9 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas cleans = fastcache.New(config.CleanCacheSize) } return &Database{ - diskdb: diskdb, - resolver: resolver, - cleans: cleans, - dirties: make(map[common.Hash]*cachedNode), + diskdb: diskdb, + cleans: cleans, + dirties: make(map[common.Hash]*cachedNode), } } @@ -163,7 +155,7 @@ func (db *Database) insert(hash common.Hash, node []byte) { node: node, flushPrev: db.newest, } - entry.forChildren(db.resolver, func(child common.Hash) { + entry.forChildren(func(child common.Hash) { if c := db.dirties[child]; c != nil { c.parents++ } @@ -316,7 +308,7 @@ func (db *Database) dereference(hash common.Hash) { db.dirties[node.flushNext].flushPrev = node.flushPrev } // Dereference all children and delete the node - node.forChildren(db.resolver, func(child common.Hash) { + node.forChildren(func(child common.Hash) { db.dereference(child) }) delete(db.dirties, hash) @@ -465,7 +457,7 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane var err error // Dereference all children and delete the node - node.forChildren(db.resolver, func(child common.Hash) { + node.forChildren(func(child common.Hash) { if err == nil { err = db.commit(child, batch, uncacher) } From 15936c64a26d624026ae2df953cc3d5369a8131f Mon Sep 17 00:00:00 2001 From: maskpp Date: Tue, 16 Jul 2024 19:42:30 +0800 Subject: [PATCH 138/196] core/txpool/legacypool: use maps.Keys and maps.Copy (#30091) --- core/txpool/legacypool/legacypool.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index 4e1d26acf4..5506ecc31f 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" + "golang.org/x/exp/maps" ) const ( @@ -1717,7 +1718,7 @@ func (a addressesByHeartbeat) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type accountSet struct { accounts map[common.Address]struct{} signer types.Signer - cache *[]common.Address + cache []common.Address } // 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! func (as *accountSet) flatten() []common.Address { if as.cache == nil { - accounts := make([]common.Address, 0, len(as.accounts)) - for account := range as.accounts { - accounts = append(accounts, account) - } - as.cache = &accounts + as.cache = maps.Keys(as.accounts) } - return *as.cache + return as.cache } // merge adds all addresses from the 'other' set into 'as'. func (as *accountSet) merge(other *accountSet) { - for addr := range other.accounts { - as.accounts[addr] = struct{}{} - } + maps.Copy(as.accounts, other.accounts) as.cache = nil } From c54294bd41fdea30f715d9f0a4f3f9e44dcc9101 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:06:22 +0200 Subject: [PATCH 139/196] core/state: don't compute verkle storage tree roots (#30130) --- core/state/statedb.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 1664a446f4..641775b0bd 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -860,12 +860,16 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { } obj := s.stateObjects[addr] // closure for the task runner below 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, - // gather the witnesses for its specific storage trie - if s.witness != nil && obj.trie != nil { - s.witness.AddState(obj.trie.Witness()) + // If witness building is enabled and the state object has a trie, + // gather the witnesses for its specific storage trie + if s.witness != nil && obj.trie != nil { + s.witness.AddState(obj.trie.Witness()) + } } return nil }) From f59d013e4064adbb092b323781104c07550a8bff Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 16 Jul 2024 21:17:58 +0800 Subject: [PATCH 140/196] core/rawdb, triedb, cmd: create an isolated disk namespace for verkle (#30105) * core, triedb/pathdb, cmd: define verkle state ancient store * core/rawdb, triedb: add verkle namespace in pathdb --- cmd/geth/dbcmd.go | 3 ++- core/genesis_test.go | 6 +++--- core/rawdb/accessors_trie.go | 12 +++++++++++- core/rawdb/ancient_scheme.go | 17 ++++++++++++----- core/rawdb/ancient_utils.go | 6 +++--- core/rawdb/database.go | 24 ++++++++++++++++++++++++ core/rawdb/schema.go | 7 +++++++ triedb/database.go | 11 +++++++++-- triedb/pathdb/database.go | 10 +++++++++- triedb/pathdb/history_test.go | 8 ++++---- 10 files changed, 84 insertions(+), 20 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index 4b683569a4..052ae0eab2 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -248,7 +248,8 @@ func removeDB(ctx *cli.Context) error { // Delete state data statePaths := []string{ rootDir, - filepath.Join(ancientDir, rawdb.StateFreezerName), + filepath.Join(ancientDir, rawdb.MerkleStateFreezerName), + filepath.Join(ancientDir, rawdb.VerkleStateFreezerName), } confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name) diff --git a/core/genesis_test.go b/core/genesis_test.go index ab408327d4..002e58a961 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -311,7 +311,7 @@ func TestVerkleGenesisCommit(t *testing.T) { } 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) if !bytes.Equal(block.Root().Bytes(), expected) { 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() { t.Fatalf("expected trie to be verkle") } - - if !rawdb.HasAccountTrieNode(db, nil) { + vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix)) + if !rawdb.HasAccountTrieNode(vdb, nil) { t.Fatal("could not find node") } } diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index 44eb715d04..0f856d1804 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -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 // 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. if HasAccountTrieNode(db, nil) { return PathScheme @@ -255,6 +255,16 @@ func ReadStateScheme(db ethdb.Reader) string { if id := ReadPersistentStateID(db); id != 0 { 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 // on the disk. To assess the scheme of the persistent state, it // suffices to inspect the scheme of the genesis state. diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index 44867ded04..371fd384ad 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -72,12 +72,13 @@ var stateFreezerNoSnappy = map[string]bool{ // The list of identifiers of ancient stores. var ( - ChainFreezerName = "chain" // the folder name of chain segment ancient store. - StateFreezerName = "state" // the folder name of reverse diff ancient store. + ChainFreezerName = "chain" // the folder name of chain segment 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. -var freezers = []string{ChainFreezerName, StateFreezerName} +var freezers = []string{ChainFreezerName, MerkleStateFreezerName, VerkleStateFreezerName} // NewStateFreezer initializes the ancient store for state history. // @@ -85,9 +86,15 @@ var freezers = []string{ChainFreezerName, StateFreezerName} // state freezer (e.g. dev mode). // - if non-empty directory is given, initializes the regular file-based // state freezer. -func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) { +func NewStateFreezer(ancientDir string, verkle bool, readOnly bool) (ethdb.ResettableAncientStore, error) { if ancientDir == "" { 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) } diff --git a/core/rawdb/ancient_utils.go b/core/rawdb/ancient_utils.go index 1c69639c9d..6804d7a91a 100644 --- a/core/rawdb/ancient_utils.go +++ b/core/rawdb/ancient_utils.go @@ -88,12 +88,12 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) { } infos = append(infos, info) - case StateFreezerName: + case MerkleStateFreezerName, VerkleStateFreezerName: datadir, err := db.AncientDatadir() if err != nil { return nil, err } - f, err := NewStateFreezer(datadir, true) + f, err := NewStateFreezer(datadir, freezer == VerkleStateFreezerName, true) if err != nil { 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 { case ChainFreezerName: path, tables = resolveChainFreezerDir(ancient), chainFreezerNoSnappy - case StateFreezerName: + case MerkleStateFreezerName, VerkleStateFreezerName: path, tables = filepath.Join(ancient, freezerName), stateFreezerNoSnappy default: return fmt.Errorf("unknown freezer, supported ones: %v", freezers) diff --git a/core/rawdb/database.go b/core/rawdb/database.go index 3436958de7..831016da15 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -481,6 +481,10 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { beaconHeaders stat cliqueSnaps stat + // Verkle statistics + verkleTries stat + verkleStateLookups stat + // Les statistic chtTrieNodes stat bloomTrieNodes stat @@ -550,6 +554,24 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error { bytes.HasPrefix(key, BloomTrieIndexPrefix) || bytes.HasPrefix(key, BloomTriePrefix): // Bloomtrie sub 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: var accounted bool 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 account nodes", accountTries.Size(), accountTries.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", "Account snapshot", accountSnaps.Size(), accountSnaps.Count()}, {"Key-Value store", "Storage snapshot", storageSnaps.Size(), storageSnaps.Count()}, diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index dbf010be0c..04b5d0d6d2 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -117,6 +117,13 @@ var ( TrieNodeStoragePrefix = []byte("O") // TrieNodeStoragePrefix + accountHash + hexPath -> trie node 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 configPrefix = []byte("ethereum-config-") // config prefix for the db genesisPrefix = []byte("ethereum-genesis-") // genesis state prefix for the db diff --git a/triedb/database.go b/triedb/database.go index 1f9f38388b..aecb900f31 100644 --- a/triedb/database.go +++ b/triedb/database.go @@ -42,9 +42,18 @@ type Config struct { // default settings. var HashDefaults = &Config{ Preimages: false, + IsVerkle: false, 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 // state scheme. type backend interface { @@ -84,7 +93,6 @@ type backend interface { // relevant with trie nodes and node preimages. type Database struct { config *Config // Configuration for trie database - diskdb ethdb.Database // Persistent database to store the snapshot preimages *preimageStore // The store for caching preimages backend backend // The backend for managing trie nodes } @@ -102,7 +110,6 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database { } db := &Database{ config: config, - diskdb: diskdb, preimages: preimages, } if config.HashDB != nil && config.PathDB != nil { diff --git a/triedb/pathdb/database.go b/triedb/pathdb/database.go index 450c3a8f4f..31e478117c 100644 --- a/triedb/pathdb/database.go +++ b/triedb/pathdb/database.go @@ -152,6 +152,14 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database { } 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{ readOnly: config.ReadOnly, isVerkle: isVerkle, @@ -190,7 +198,7 @@ func (db *Database) repairHistory() error { // all of them. Fix the tests first. return nil } - freezer, err := rawdb.NewStateFreezer(ancient, db.readOnly) + freezer, err := rawdb.NewStateFreezer(ancient, db.isVerkle, db.readOnly) if err != nil { log.Crit("Failed to open state history freezer", "err", err) } diff --git a/triedb/pathdb/history_test.go b/triedb/pathdb/history_test.go index 4114aa1185..586f907fe4 100644 --- a/triedb/pathdb/history_test.go +++ b/triedb/pathdb/history_test.go @@ -129,7 +129,7 @@ func TestTruncateHeadHistory(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false) ) defer freezer.Close() @@ -157,7 +157,7 @@ func TestTruncateTailHistory(t *testing.T) { roots []common.Hash hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false) ) defer freezer.Close() @@ -200,7 +200,7 @@ func TestTruncateTailHistories(t *testing.T) { roots []common.Hash hs = makeHistories(10) 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() @@ -228,7 +228,7 @@ func TestTruncateOutOfRange(t *testing.T) { var ( hs = makeHistories(10) db = rawdb.NewMemoryDatabase() - freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false) + freezer, _ = rawdb.NewStateFreezer(t.TempDir(), false, false) ) defer freezer.Close() From ad49c708f5769602e0d7a2d8889616ae13327d3a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 18 Jul 2024 11:09:02 +0200 Subject: [PATCH 141/196] p2p/discover: remove type encPubkey (#30172) The pubkey type was moved to package v4wire a long time ago. Remaining uses of encPubkey were probably left in due to laziness. --- p2p/discover/node.go | 33 --------------------------------- p2p/discover/table_util_test.go | 3 ++- p2p/discover/v4_lookup_test.go | 18 +++++++++--------- p2p/discover/v4_udp.go | 12 ++++++------ p2p/discover/v4_udp_test.go | 4 ++-- p2p/discover/v5_udp_test.go | 7 ++++--- 6 files changed, 23 insertions(+), 54 deletions(-) diff --git a/p2p/discover/node.go b/p2p/discover/node.go index 042619221b..ac34b7c5b2 100644 --- a/p2p/discover/node.go +++ b/p2p/discover/node.go @@ -17,16 +17,10 @@ package discover import ( - "crypto/ecdsa" - "crypto/elliptic" - "errors" - "math/big" "slices" "sort" "time" - "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/crypto" "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 } -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 { result := make([]*enode.Node, len(ns)) for i, n := range ns { diff --git a/p2p/discover/table_util_test.go b/p2p/discover/table_util_test.go index 5b2699d460..fe10883fe6 100644 --- a/p2p/discover/table_util_test.go +++ b/p2p/discover/table_util_test.go @@ -30,6 +30,7 @@ import ( "time" "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/enr" ) @@ -284,7 +285,7 @@ func hexEncPrivkey(h string) *ecdsa.PrivateKey { } // 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) if err != nil { panic(err) diff --git a/p2p/discover/v4_lookup_test.go b/p2p/discover/v4_lookup_test.go index bc9475a8b3..70bd7056fb 100644 --- a/p2p/discover/v4_lookup_test.go +++ b/p2p/discover/v4_lookup_test.go @@ -34,7 +34,7 @@ func TestUDPv4_Lookup(t *testing.T) { test := newUDPTest(t) // 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 { 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 t.Logf("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 { 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: test.packetInFrom(nil, key, to, &v4wire.Pong{Expiration: futureExp, ReplyTok: hash}) case *v4wire.Findnode: - dist := enode.LogDist(n.ID(), testnet.target.id()) + dist := enode.LogDist(n.ID(), testnet.target.ID()) nodes := testnet.nodesAtDistance(dist - 1) 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.Logf("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) { 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") } wantNodes := tn.closest(len(results)) @@ -231,7 +231,7 @@ var lookupTestnet = &preminedTestnet{ } type preminedTestnet struct { - target encPubkey + target v4wire.Pubkey 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 { - return enode.DistCmp(tn.target.id(), a.ID(), b.ID()) + return enode.DistCmp(tn.target.ID(), a.ID(), b.ID()) }) return nodes[:n] } @@ -319,11 +319,11 @@ func (tn *preminedTestnet) mine() { tn.dists[i] = nil } - targetSha := tn.target.id() + targetSha := tn.target.ID() found, need := 0, 40 for found < need { 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 { tn.dists[ld] = append(tn.dists[ld], k) found++ diff --git a/p2p/discover/v4_udp.go b/p2p/discover/v4_udp.go index cca01bd3ce..321552ddc3 100644 --- a/p2p/discover/v4_udp.go +++ b/p2p/discover/v4_udp.go @@ -271,7 +271,7 @@ func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node { // case and run the bootstrapping logic. <-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. @@ -286,24 +286,24 @@ func (t *UDPv4) lookupRandom() []*enode.Node { // lookupSelf implements transport. 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 { - var target encPubkey + var target v4wire.Pubkey crand.Read(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[:])) - ekey := v4wire.Pubkey(targetKey) it := newLookup(ctx, t.tab, target, func(n *enode.Node) ([]*enode.Node, error) { addr, ok := n.UDPEndpoint() if !ok { return nil, errNoUDPEndpoint } - return t.findnode(n.ID(), addr, ekey) + return t.findnode(n.ID(), addr, targetKey) }) return it } diff --git a/p2p/discover/v4_udp_test.go b/p2p/discover/v4_udp_test.go index 9d6df08ead..1af31f4f1b 100644 --- a/p2p/discover/v4_udp_test.go +++ b/p2p/discover/v4_udp_test.go @@ -314,7 +314,7 @@ func TestUDPv4_findnodeMultiReply(t *testing.T) { // queue a pending findnode request resultc, errc := make(chan []*enode.Node, 1), make(chan error, 1) go func() { - rid := encodePubkey(&test.remotekey.PublicKey).id() + rid := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() ns, err := test.udp.findnode(rid, test.remoteaddr, testTarget) if err != nil && len(ns) == 0 { errc <- err @@ -433,7 +433,7 @@ func TestUDPv4_successfulPing(t *testing.T) { // pong packet. select { case n := <-added: - rid := encodePubkey(&test.remotekey.PublicKey).id() + rid := v4wire.EncodePubkey(&test.remotekey.PublicKey).ID() if n.ID() != rid { t.Errorf("node has wrong ID: got %v, want %v", n.ID(), rid) } diff --git a/p2p/discover/v5_udp_test.go b/p2p/discover/v5_udp_test.go index 1f8e972200..8631b918ff 100644 --- a/p2p/discover/v5_udp_test.go +++ b/p2p/discover/v5_udp_test.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/internal/testlog" "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/enode" "github.com/ethereum/go-ethereum/p2p/enr" @@ -576,7 +577,7 @@ func TestUDPv5_lookup(t *testing.T) { test := newUDPV5Test(t) // 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) } @@ -596,7 +597,7 @@ func TestUDPv5_lookup(t *testing.T) { // Start the lookup. resultC := make(chan []*enode.Node, 1) go func() { - resultC <- test.udp.Lookup(lookupTestnet.target.id()) + resultC <- test.udp.Lookup(lookupTestnet.target.ID()) 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. 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] if ln == nil { db, _ := enode.OpenDB("") From df3f0a81a7ef6fd56c90675c32b6d732380a9fd2 Mon Sep 17 00:00:00 2001 From: Alexander Mint Date: Thu, 18 Jul 2024 13:38:42 +0300 Subject: [PATCH 142/196] go.mod: upgrade to btcsuite/btcd/btcec v2.3.4 (#30181) --- crypto/signature_nocgo.go | 5 +---- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index 989057442b..5ac3765c71 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -88,10 +88,7 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { return nil, errors.New("invalid private key") } defer priv.Zero() - sig, err := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey - if err != nil { - return nil, err - } + sig := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey // Convert to Ethereum signature format with 'recovery id' v at the end. v := sig[0] - 27 copy(sig, sig[1:]) diff --git a/go.mod b/go.mod index a757b6705d..db5c713498 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( 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/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/cloudflare/cloudflare-go v0.79.0 github.com/cockroachdb/pebble v1.1.1 diff --git a/go.sum b/go.sum index 826f0f674f..e3cf5f3d63 100644 --- a/go.sum +++ b/go.sum @@ -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/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/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= -github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +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/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= From 944718bf165ae8c56528fe5c6dd52831513518e1 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Mon, 22 Jul 2024 05:40:14 +0200 Subject: [PATCH 143/196] ethdb: remove snapshot (#30189) --- core/rawdb/table.go | 7 ---- ethdb/database.go | 2 -- ethdb/dbtest/testsuite.go | 63 ----------------------------------- ethdb/leveldb/leveldb.go | 36 -------------------- ethdb/memorydb/memorydb.go | 67 -------------------------------------- ethdb/pebble/pebble.go | 49 ---------------------------- ethdb/remotedb/remotedb.go | 4 --- ethdb/snapshot.go | 41 ----------------------- trie/trie_test.go | 1 - 9 files changed, 270 deletions(-) delete mode 100644 ethdb/snapshot.go diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 90849fe9d9..0a25c5bcdd 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -200,13 +200,6 @@ func (t *table) NewBatchWithSize(size int) ethdb.Batch { 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 // with a pre-configured string. type tableBatch struct { diff --git a/ethdb/database.go b/ethdb/database.go index 9ef5942a13..89c793d0be 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -64,7 +64,6 @@ type KeyValueStore interface { Batcher Iteratee Compacter - Snapshotter io.Closer } @@ -199,6 +198,5 @@ type Database interface { Iteratee Stater Compacter - Snapshotter io.Closer } diff --git a/ethdb/dbtest/testsuite.go b/ethdb/dbtest/testsuite.go index 29a773ced4..1af55a0e38 100644 --- a/ethdb/dbtest/testsuite.go +++ b/ethdb/dbtest/testsuite.go @@ -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) { db := New() db.Put([]byte("key"), []byte("value")) diff --git a/ethdb/leveldb/leveldb.go b/ethdb/leveldb/leveldb.go index 92838ad7ab..24925a4f04 100644 --- a/ethdb/leveldb/leveldb.go +++ b/ethdb/leveldb/leveldb.go @@ -230,19 +230,6 @@ func (db *Database) NewIterator(prefix []byte, start []byte) ethdb.Iterator { 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. func (db *Database) Stat() (string, error) { var stats leveldb.DBStats @@ -498,26 +485,3 @@ func bytesPrefixRange(prefix, start []byte) *util.Range { r.Start = append(r.Start, start...) 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() -} diff --git a/ethdb/memorydb/memorydb.go b/ethdb/memorydb/memorydb.go index 9b0872f89a..532e0dfe3f 100644 --- a/ethdb/memorydb/memorydb.go +++ b/ethdb/memorydb/memorydb.go @@ -35,10 +35,6 @@ var ( // errMemorydbNotFound is returned if a key is requested that is not found in // the provided memory database. 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 @@ -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. func (db *Database) Stat() (string, error) { return "", nil @@ -332,59 +321,3 @@ func (it *iterator) Value() []byte { func (it *iterator) Release() { 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 -} diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 130d6617b5..8203dd136d 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -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 func upperBound(prefix []byte) (limit []byte) { for i := len(prefix) - 1; i >= 0; i-- { diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index bfecde4a32..c8b76eab4a 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -138,10 +138,6 @@ func (db *Database) Compact(start []byte, limit []byte) error { return nil } -func (db *Database) NewSnapshot() (ethdb.Snapshot, error) { - panic("not supported") -} - func (db *Database) Close() error { db.remote.Close() return nil diff --git a/ethdb/snapshot.go b/ethdb/snapshot.go deleted file mode 100644 index 03b7794a77..0000000000 --- a/ethdb/snapshot.go +++ /dev/null @@ -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 . - -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) -} diff --git a/trie/trie_test.go b/trie/trie_test.go index 5f706a28be..505b517bc5 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -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) NewBatch() 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) Compact(start []byte, limit []byte) error { panic("implement me") } func (s *spongeDb) Close() error { return nil } From 380688c636a654becc8f114438c2a5d93d2db032 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Mon, 22 Jul 2024 09:58:53 +0200 Subject: [PATCH 144/196] eth/gasprice: remove default from config (#30080) * eth/gasprice: remove default from config * eth/gasprice: sanitize startPrice --- eth/backend.go | 6 +----- eth/gasprice/feehistory_test.go | 2 +- eth/gasprice/gasprice.go | 8 +++++--- eth/gasprice/gasprice_test.go | 3 +-- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 91a07811f0..8679018dab 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -264,11 +264,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { if eth.APIBackend.allowUnprotectedTxs { log.Info("Unprotected transactions allowed") } - gpoParams := config.GPO - if gpoParams.Default == nil { - gpoParams.Default = config.Miner.GasPrice - } - eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) + eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice) // Setup DNS discovery iterators. dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) diff --git a/eth/gasprice/feehistory_test.go b/eth/gasprice/feehistory_test.go index 3d426db46f..241b91b810 100644 --- a/eth/gasprice/feehistory_test.go +++ b/eth/gasprice/feehistory_test.go @@ -59,7 +59,7 @@ func TestFeeHistory(t *testing.T) { MaxBlockHistory: c.maxBlock, } 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) backend.teardown() diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index c90408e363..19a6c0010a 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -45,7 +45,6 @@ type Config struct { Percentile int MaxHeaderHistory uint64 MaxBlockHistory uint64 - Default *big.Int `toml:",omitempty"` MaxPrice *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 // 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 if blocks < 1 { blocks = 1 @@ -115,6 +114,9 @@ func NewOracle(backend OracleBackend, params Config) *Oracle { maxBlockHistory = 1 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) headEvent := make(chan core.ChainHeadEvent, 1) @@ -131,7 +133,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle { return &Oracle{ backend: backend, - lastPrice: params.Default, + lastPrice: startPrice, maxPrice: maxPrice, ignorePrice: ignorePrice, checkBlocks: blocks, diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index b22e75666f..39f3c79b98 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -235,7 +235,6 @@ func TestSuggestTipCap(t *testing.T) { config := Config{ Blocks: 3, Percentile: 60, - Default: big.NewInt(params.GWei), } var cases = []struct { fork *big.Int // London fork number @@ -249,7 +248,7 @@ func TestSuggestTipCap(t *testing.T) { } for _, c := range cases { 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 got, err := oracle.SuggestTipCap(context.Background()) From 7abe84c8d724c1f92ca6f41ac6da72870c886ba0 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:38:04 -0600 Subject: [PATCH 145/196] rpc: use stable object in notifier test (#30193) This makes the test resilient to changes of types.Header -- otherwise the test needs to be updated each time the header structure is modified. --- rpc/subscription_test.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/rpc/subscription_test.go b/rpc/subscription_test.go index a7dac705c9..ab40ab169f 100644 --- a/rpc/subscription_test.go +++ b/rpc/subscription_test.go @@ -267,13 +267,9 @@ func TestNotify(t *testing.T) { sub: &Subscription{ID: id}, activated: true, } - msg := &types.Header{ - ParentHash: common.HexToHash("0x01"), - Number: big.NewInt(100), - } - notifier.Notify(id, msg) + notifier.Notify(id, "hello") 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 { t.Errorf("have:\n%v\nwant:\n%v\n", have, want) } From ef583e9d18a98dfea8dad9f027c9d8a989591579 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Jul 2024 05:44:31 +0800 Subject: [PATCH 146/196] core/state: remove useless metrics (#30184) Originally, these metrics were added to track the largest storage wiping. Since account self-destruction was deprecated with the Cancun fork, these metrics have become meaningless. --- core/state/metrics.go | 6 ------ core/state/statedb.go | 46 +++++++++++++------------------------------ 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/core/state/metrics.go b/core/state/metrics.go index 7447e44dfd..e702ef3a81 100644 --- a/core/state/metrics.go +++ b/core/state/metrics.go @@ -27,10 +27,4 @@ var ( storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil) accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", 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) ) diff --git a/core/state/statedb.go b/core/state/statedb.go index 641775b0bd..0bd6b37d04 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -992,76 +992,70 @@ func (s *StateDB) clearJournalAndRefund() { // of a specific account. It leverages the associated state snapshot for fast // storage iteration and constructs trie node deletion markers by creating // 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{}) if err != nil { - return 0, nil, nil, err + return nil, nil, err } defer iter.Release() var ( - size common.StorageSize nodes = trienode.NewNodeSet(addrHash) slots = make(map[common.Hash][]byte) ) stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { nodes.AddNode(path, trienode.NewDeleted()) - size += common.StorageSize(len(path)) }) for iter.Next() { slot := common.CopyBytes(iter.Slot()) 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 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 - return 0, nil, nil, err + return nil, nil, err } 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," // employed when the associated state snapshot is not available. It iterates the // 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) 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) 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 ( - size common.StorageSize nodes = trienode.NewNodeSet(addrHash) slots = make(map[common.Hash][]byte) ) for it.Next(true) { if it.Leaf() { slots[common.BytesToHash(it.LeafKey())] = common.CopyBytes(it.LeafBlob()) - size += common.StorageSize(common.HashLength + len(it.LeafBlob())) continue } if it.Hash() == (common.Hash{}) { continue } - size += common.StorageSize(len(it.Path())) nodes.AddNode(it.Path(), trienode.NewDeleted()) } 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. @@ -1070,9 +1064,7 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r // efficient approach. func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) { var ( - start = time.Now() err error - size common.StorageSize slots map[common.Hash][]byte nodes *trienode.NodeSet ) @@ -1080,24 +1072,14 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root // generated, or it's internally corrupted. Fallback to the slow // one just in case. 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 { - size, slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) + slots, nodes, err = s.slowDeleteStorage(addr, addrHash, root) } if err != nil { 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 } From 57e662793287651dcfd36c52fb40a83c54682810 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 23 Jul 2024 17:55:56 +0800 Subject: [PATCH 147/196] rpc: show more error detail for `invalidMessageError` (#30191) Here we add distinct error messages for network timeouts and JSON parsing errors. Note this specifically applies to HTTP connections serving a single RPC request. Co-authored-by: Felix Lange --- rpc/server.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/rpc/server.go b/rpc/server.go index 52866004f8..42b59f8f6f 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -18,7 +18,9 @@ package rpc import ( "context" + "errors" "io" + "net" "sync" "sync/atomic" @@ -151,8 +153,8 @@ func (s *Server) serveSingleRequest(ctx context.Context, codec ServerCodec) { reqs, batch, err := codec.readBatch() if err != nil { - if err != io.EOF { - resp := errorMessage(&invalidMessageError{"parse error"}) + if msg := messageForReadError(err); msg != "" { + resp := errorMessage(&invalidMessageError{msg}) codec.writeJSON(ctx, resp, true) } 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 // requests to finish, then closes all codecs which will cancel pending requests and // subscriptions. From 7026bae17c8d2fcf0b6ee134528c1a6b6e00c60c Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:05:46 +0200 Subject: [PATCH 148/196] core/tracing: update latest release version (#30211) --- core/tracing/CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/tracing/CHANGELOG.md b/core/tracing/CHANGELOG.md index 93b91cf479..cddc728fc0 100644 --- a/core/tracing/CHANGELOG.md +++ b/core/tracing/CHANGELOG.md @@ -2,7 +2,7 @@ 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. @@ -76,4 +76,5 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale - `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above. [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 \ No newline at end of file +[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 From 6693fe1be277d5c20cc39d82085dad0d5bebaa16 Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:07:06 +0700 Subject: [PATCH 149/196] core/txpool: use the cached address in ValidateTransactionWithState (#30208) The address recover is executed and cached in ValidateTransaction already. It's expected that the cached one is returned in ValidateTransaction. However, currently, we use the wrong function signer.Sender instead of types.Sender which will do all the address recover again. --- core/txpool/validation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 555b777505..7fd5f8bc79 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -201,7 +201,7 @@ type ValidationOptionsWithState struct { // rules without duplicating code and running the risk of missed updates. func ValidateTransactionWithState(tx *types.Transaction, signer types.Signer, opts *ValidationOptionsWithState) error { // 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 { log.Error("Transaction sender recovery failed", "err", err) return err From 1939813ece995084e3b7c55b46324d98219494a8 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Jul 2024 20:40:12 +0800 Subject: [PATCH 150/196] core/state: check db error after intermediate call (#30171) This pull request adds an additional error check after statedb.IntermediateRoot, ensuring that no errors occur during this call. This step is essential, as the call might encounter database errors. --- core/state/statedb.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/state/statedb.go b/core/state/statedb.go index 0bd6b37d04..f0de73733a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -1158,6 +1158,10 @@ func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) { // Finalize any pending changes and merge everything into the tries 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 var ( accountTrieNodesUpdated int From 35b4183caa59ddd6973606900b100523a090b0c1 Mon Sep 17 00:00:00 2001 From: minh-bq <97180373+minh-bq@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:44:01 +0700 Subject: [PATCH 151/196] cmd/utils: allow configurating blob pool from flags (#30203) Currently, we have 3 flags to configure blob pool. However, we don't read these flags and set the blob pool configuration in eth config accordingly. This commit adds a function to check if these flags are provided and set blob pool configuration based on them. --- cmd/utils/flags.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 96a3cf55bb..b9fa3b8b4e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -42,6 +42,7 @@ import ( "github.com/ethereum/go-ethereum/common/fdlimit" "github.com/ethereum/go-ethereum/core" "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/vm" "github.com/ethereum/go-ethereum/crypto" @@ -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) { if ctx.Bool(MiningEnabledFlag.Name) { 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) setGPO(ctx, &cfg.GPO) setTxPool(ctx, &cfg.TxPool) + setBlobPool(ctx, &cfg.BlobPool) setMiner(ctx, &cfg.Miner) setRequiredBlocks(ctx, cfg) setLes(ctx, cfg) From 766ce23032deae2519322b705e87c7a2ea9f1317 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Tue, 23 Jul 2024 20:54:35 +0800 Subject: [PATCH 152/196] core/state: fix SetStorage override behavior (#30185) This pull request fixes the broken feature where the entire storage set is overridden. Originally, the storage set override was achieved by marking the associated account as deleted, preventing access to the storage slot on disk. However, since #29520, this flag is also checked when accessing the account, rendering the account unreachable. A fix has been applied in this pull request, which re-creates a new state object with all account metadata inherited. --- core/state/statedb.go | 28 ++++++++++++++++++---------- internal/ethapi/api_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index f0de73733a..80a53dbb17 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -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 // must be discarded afterwards. func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) { - // SetStorage needs to wipe existing storage. We achieve this by pretending - // that the account self-destructed earlier in this block, by flagging - // it in stateObjectsDestruct. The effect of doing so is that storage lookups - // will not hit disk, since it is assumed that the disk-data is belonging + // SetStorage needs to wipe the existing storage. We achieve this by marking + // the account as self-destructed in this block. The effect is that storage + // lookups will not hit the disk, as it is assumed that the disk data belongs // to a previous incarnation of the object. // - // TODO(rjl493456442) this function should only be supported by 'unwritable' - // state and all mutations made should all be discarded afterwards. - if _, ok := s.stateObjectsDestruct[addr]; !ok { - s.stateObjectsDestruct[addr] = nil + // TODO (rjl493456442): This function should only be supported by 'unwritable' + // state, and all mutations made should be discarded afterward. + obj := s.getStateObject(addr) + 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 { - 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) } } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index cf5160caf7..b4041fc84c 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -781,15 +781,24 @@ func TestEstimateGas(t *testing.T) { func TestCall(t *testing.T) { t.Parallel() + // Initialize test accounts var ( accounts = newAccounts(3) + dad = common.HexToAddress("0x0000000000000000000000000000000000000dad") genesis = &core.Genesis{ Config: params.MergedTestChainConfig, Alloc: types.GenesisAlloc{ accounts[0].addr: {Balance: big.NewInt(params.Ether)}, accounts[1].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 @@ -949,6 +958,32 @@ func TestCall(t *testing.T) { }, 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 { result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides) From 4ad88e9463090a6363be5ed8dca733c890e91b7b Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 24 Jul 2024 20:32:28 +0800 Subject: [PATCH 153/196] triedb/pathdb: print out all trie owner and hash information (#30200) This pull request explicitly prints out the full hash for debugging purpose. --- triedb/pathdb/reader.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triedb/pathdb/reader.go b/triedb/pathdb/reader.go index 54dc98a543..6a58493ba6 100644 --- a/triedb/pathdb/reader.go +++ b/triedb/pathdb/reader.go @@ -78,7 +78,7 @@ func (r *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, if len(blob) > 0 { 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 blob, nil From 4dfc75deefd2d68fba682d089d9ae61771c19d66 Mon Sep 17 00:00:00 2001 From: yukionfire Date: Thu, 25 Jul 2024 06:32:58 +0800 Subject: [PATCH 154/196] beacon/types, cmd/devp2p, p2p/enr: clean up uses of fmt.Errorf (#30182) --- beacon/types/beacon_block.go | 2 +- beacon/types/exec_header.go | 2 +- cmd/devp2p/rlpxcmd.go | 2 +- p2p/enr/entries.go | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/beacon/types/beacon_block.go b/beacon/types/beacon_block.go index 370152114a..e4cd1340e5 100644 --- a/beacon/types/beacon_block.go +++ b/beacon/types/beacon_block.go @@ -48,7 +48,7 @@ func BlockFromJSON(forkName string, data []byte) (*BeaconBlock, error) { case "capella": obj = new(capella.BeaconBlock) default: - return nil, fmt.Errorf("unsupported fork: " + forkName) + return nil, fmt.Errorf("unsupported fork: %s", forkName) } if err := json.Unmarshal(data, obj); err != nil { return nil, err diff --git a/beacon/types/exec_header.go b/beacon/types/exec_header.go index dce101ba20..b5f90bae25 100644 --- a/beacon/types/exec_header.go +++ b/beacon/types/exec_header.go @@ -46,7 +46,7 @@ func ExecutionHeaderFromJSON(forkName string, data []byte) (*ExecutionHeader, er case "deneb": obj = new(deneb.ExecutionPayloadHeader) default: - return nil, fmt.Errorf("unsupported fork: " + forkName) + return nil, fmt.Errorf("unsupported fork: %s", forkName) } if err := json.Unmarshal(data, obj); err != nil { return nil, err diff --git a/cmd/devp2p/rlpxcmd.go b/cmd/devp2p/rlpxcmd.go index 77f09e6b85..118731fd6c 100644 --- a/cmd/devp2p/rlpxcmd.go +++ b/cmd/devp2p/rlpxcmd.go @@ -79,7 +79,7 @@ func rlpxPing(ctx *cli.Context) error { n := getNodeArg(ctx) tcpEndpoint, ok := n.TCPEndpoint() 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()) if err != nil { diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go index 917e1becba..155ec4c023 100644 --- a/p2p/enr/entries.go +++ b/p2p/enr/entries.go @@ -177,7 +177,7 @@ func (v IPv4Addr) ENRKey() string { return "ip" } func (v IPv4Addr) EncodeRLP(w io.Writer) error { addr := netip.Addr(v) if !addr.Is4() { - return fmt.Errorf("address is not IPv4") + return errors.New("address is not IPv4") } enc := rlp.NewEncoderBuffer(w) bytes := addr.As4() @@ -204,7 +204,7 @@ func (v IPv6Addr) ENRKey() string { return "ip6" } func (v IPv6Addr) EncodeRLP(w io.Writer) error { addr := netip.Addr(v) if !addr.Is6() { - return fmt.Errorf("address is not IPv6") + return errors.New("address is not IPv6") } enc := rlp.NewEncoderBuffer(w) bytes := addr.As16() From ac0f220040bd4271a040170bc0b039eb88dee9bd Mon Sep 17 00:00:00 2001 From: caseylove Date: Thu, 25 Jul 2024 07:01:59 +0800 Subject: [PATCH 155/196] eth/tracers, internal/ethapi: remove unnecessary map pointer in state override (#30094) --- eth/tracers/api_test.go | 10 +++++----- internal/ethapi/api.go | 16 ++++++++-------- internal/ethapi/api_test.go | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 6fbb50848d..e717f5352d 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -843,7 +843,7 @@ func TestTracingWithOverrides(t *testing.T) { byte(vm.PUSH1), 00, byte(vm.RETURN), }), - StateDiff: &map[common.Hash]common.Hash{ + StateDiff: map[common.Hash]common.Hash{ common.HexToHash("0x03"): common.HexToHash("0x11"), }, }, @@ -898,9 +898,9 @@ func newAccounts(n int) (accounts []Account) { return accounts } -func newRPCBalance(balance *big.Int) **hexutil.Big { +func newRPCBalance(balance *big.Int) *hexutil.Big { rpcBalance := (*hexutil.Big)(balance) - return &rpcBalance + return rpcBalance } func newRPCBytes(bytes []byte) *hexutil.Bytes { @@ -908,7 +908,7 @@ func newRPCBytes(bytes []byte) *hexutil.Bytes { 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) { 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++ { m[keys[i]] = vals[i] } - return &m + return m } func TestTraceChain(t *testing.T) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 0ecedf1130..1c3cb4adf9 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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 // message. type OverrideAccount struct { - Nonce *hexutil.Uint64 `json:"nonce"` - Code *hexutil.Bytes `json:"code"` - Balance **hexutil.Big `json:"balance"` - State *map[common.Hash]common.Hash `json:"state"` - StateDiff *map[common.Hash]common.Hash `json:"stateDiff"` + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance *hexutil.Big `json:"balance"` + State map[common.Hash]common.Hash `json:"state"` + StateDiff map[common.Hash]common.Hash `json:"stateDiff"` } // StateOverride is the collection of overridden accounts. @@ -994,7 +994,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB) error { } // Override account balance. if account.Balance != nil { - u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance)) + u256Balance, _ := uint256.FromBig((*big.Int)(account.Balance)) statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) } 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. if account.State != nil { - statedb.SetStorage(addr, *account.State) + statedb.SetStorage(addr, account.State) } // Apply state diff into specified accounts. if account.StateDiff != nil { - for key, value := range *account.StateDiff { + for key, value := range account.StateDiff { statedb.SetState(addr, key, value) } } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index b4041fc84c..e867f57284 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -913,7 +913,7 @@ func TestCall(t *testing.T) { overrides: StateOverride{ randomAccounts[2].addr: OverrideAccount{ 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", @@ -1343,9 +1343,9 @@ func newAccounts(n int) (accounts []account) { return accounts } -func newRPCBalance(balance *big.Int) **hexutil.Big { +func newRPCBalance(balance *big.Int) *hexutil.Big { rpcBalance := (*hexutil.Big)(balance) - return &rpcBalance + return rpcBalance } func hex2Bytes(str string) *hexutil.Bytes { From f94baab238a64895e78034522092e935628c6c74 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 25 Jul 2024 21:02:37 -0600 Subject: [PATCH 156/196] internal/ethapi: fix state override test (#30228) Looks like #30094 became a bit stale after #30185 was merged and now we have a stale ref to a state override object causing CI to fail on master. --- internal/ethapi/api_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index e867f57284..7465fb5529 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -979,7 +979,7 @@ func TestCall(t *testing.T) { }, overrides: StateOverride{ dad: OverrideAccount{ - State: &map[common.Hash]common.Hash{}, + State: map[common.Hash]common.Hash{}, }, }, want: "0x0000000000000000000000000000000000000000000000000000000000000000", From b0f66e34ca2a4ea7ae23475224451c8c9a569826 Mon Sep 17 00:00:00 2001 From: dknopik <107140945+dknopik@users.noreply.github.com> Date: Sat, 27 Jul 2024 10:18:05 +0200 Subject: [PATCH 157/196] p2p/nat: return correct port for ExtIP NAT (#30234) Return the actually requested external port instead of 0 in the AddMapping implementation for `--nat extip:`. --- p2p/nat/nat.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go index 2aa1f85585..c656044268 100644 --- a/p2p/nat/nat.go +++ b/p2p/nat/nat.go @@ -138,8 +138,10 @@ func (n ExtIP) String() string { return fmt.Sprintf("ExtIP(%v)", ne // These do nothing. -func (ExtIP) AddMapping(string, int, int, string, time.Duration) (uint16, error) { return 0, nil } -func (ExtIP) DeleteMapping(string, int, int) error { return nil } +func (ExtIP) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) (uint16, error) { + return uint16(extport), nil +} +func (ExtIP) DeleteMapping(string, int, int) error { return nil } // Any returns a port mapper that tries to discover any supported // mechanism on the local network. From 6e33dbf96a06cb3ad3bdbd5d0539e54de254ce6b Mon Sep 17 00:00:00 2001 From: Marius G <90795310+bearpebble@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:31:27 +0200 Subject: [PATCH 158/196] p2p: fix flaky test TestServerPortMapping (#30241) The test specifies `ListenAddr: ":0"`, which means a random ephemeral port will be chosen for the TCP listener by the OS. Additionally, since no `DiscAddr` was specified, the same port that is chosen automatically by the OS will also be used for the UDP listener in the discovery UDP setup. This sometimes leads to test failures if the TCP listener picks a free TCP port that is already taken for UDP. By specifying `DiscAddr: ":0"`, the UDP port will be chosen independently from the TCP port, fixing the random failure. See issue #29830. Verified using ``` cd p2p go test -c -race stress ./p2p.test -test.run=TestServerPortMapping ... 5m0s: 4556 runs so far, 0 failures ``` The issue described above can technically lead to sporadic failures on systems that specify a listen address via the `--port` flag of 0 while not setting `--discovery.port`. Since the default is using port `30303` and using a random ephemeral port is likely not used much to begin with, not addressing the root cause might be acceptable. --- p2p/server_nat_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/p2p/server_nat_test.go b/p2p/server_nat_test.go index cbb1f37e0a..7e19387210 100644 --- a/p2p/server_nat_test.go +++ b/p2p/server_nat_test.go @@ -36,6 +36,7 @@ func TestServerPortMapping(t *testing.T) { PrivateKey: newkey(), NoDial: true, ListenAddr: ":0", + DiscAddr: ":0", NAT: mockNAT, Logger: testlog.Logger(t, log.LvlTrace), clock: clock, From de6d5976794a9ed3b626d4eba57bf7f0806fb970 Mon Sep 17 00:00:00 2001 From: Daniel Knopik <107140945+dknopik@users.noreply.github.com> Date: Wed, 31 Jul 2024 21:38:23 +0200 Subject: [PATCH 159/196] p2p/discover: schedule revalidation also when all nodes are excluded (#30239) ## Issue If `nextTime` has passed, but all nodes are excluded, `get` would return `nil` and `run` would therefore not invoke `schedule`. Then, we schedule a timer for the past, as neither `nextTime` value has been updated. This creates a busy loop, as the timer immediately returns. ## Fix With this PR, revalidation will be also rescheduled when all nodes are excluded. --------- Co-authored-by: lightclient --- p2p/discover/table_reval.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index f2ea8b34fa..2465fee906 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -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 // to schedule a timer. However, run can be called at any time. func (tr *tableRevalidation) run(tab *Table, now mclock.AbsTime) (nextTime mclock.AbsTime) { - if n := tr.fast.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, n) - tr.fast.schedule(now, &tab.rand) - } - if n := tr.slow.get(now, &tab.rand, tr.activeReq); n != nil { - tr.startRequest(tab, n) - tr.slow.schedule(now, &tab.rand) + reval := func(list *revalidationList) { + if list.nextTime <= now { + if n := list.get(now, &tab.rand, tr.activeReq); n != nil { + tr.startRequest(tab, n) + } + // Update nextTime regardless if any requests were started because + // current value has passed. + list.schedule(now, &tab.rand) + } } + reval(&tr.fast) + reval(&tr.slow) 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. 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 } for i := 0; i < len(list.nodes)*3; i++ { From ff6e43e8c4db9f6d8afa7887ae9d2081c2c890d0 Mon Sep 17 00:00:00 2001 From: Darioush Jalali Date: Thu, 1 Aug 2024 07:06:43 -0700 Subject: [PATCH 160/196] miner: remove outdated comment (#30248) --- miner/worker.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 5dc3e2056b..9aae6e1609 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -205,8 +205,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) // makeEnv creates a new environment for the sealing block. 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 - // the miner to speed block sealing up a bit. + // Retrieve the parent state to execute on top. state, err := miner.chain.StateAt(parent.Root) if err != nil { return nil, err From dad8f237ffa5da2c2471f2d9f32d2bc5b580f667 Mon Sep 17 00:00:00 2001 From: Seungmin Kim Date: Thu, 1 Aug 2024 23:10:43 +0900 Subject: [PATCH 161/196] eth/downloader: correct sync mode logging to show old mode (#30219) This PR fixes an issue in the setMode method of beaconBackfiller where the log message was not displaying the previous mode correctly. The log message now shows both the old and new sync modes. --- eth/downloader/beaconsync.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 57c6eee40a..5ef3f91dc7 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -123,7 +123,8 @@ func (b *beaconBackfiller) resume() { func (b *beaconBackfiller) setMode(mode SyncMode) { // Update the old sync mode and track if it was changed b.lock.Lock() - updated := b.syncMode != mode + oldMode := b.syncMode + updated := oldMode != mode filling := b.filling b.syncMode = mode b.lock.Unlock() @@ -133,8 +134,8 @@ func (b *beaconBackfiller) setMode(mode SyncMode) { if !updated || !filling { return } - log.Error("Downloader sync mode changed mid-run", "old", mode.String(), "new", mode.String()) - b.suspend() + log.Error("Downloader sync mode changed mid-run", "old", oldMode.String(), "new", mode.String()) + b.suspend() b.resume() } From b635089c7c7b4d9ae840e2052cf9f086109242ee Mon Sep 17 00:00:00 2001 From: Icarus Wu Date: Thu, 1 Aug 2024 22:25:55 +0800 Subject: [PATCH 162/196] all: remove deprecated protobuf dependencies (#30232) The package `github.com/golang/protobuf/proto` is deprecated in favor `google.golang.org/protobuf/proto`. We should update the codes to recommended package. Signed-off-by: Icarus Wu --- .golangci.yml | 4 ---- Makefile | 2 +- accounts/usbwallet/trezor.go | 2 +- accounts/usbwallet/trezor/trezor.go | 6 +++--- build/tools/tools.go | 2 +- go.mod | 4 ++-- go.sum | 2 ++ 7 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 2132f5403a..75452472d0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -64,10 +64,6 @@ issues: text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - 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.' - - 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: - 'SA1019: event.TypeMux is deprecated: use Feed' - 'SA1019: strings.Title is deprecated' diff --git a/Makefile b/Makefile index 857cb8c978..f4932165a4 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ clean: devtools: 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/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 @type "solc" 2> /dev/null || echo 'Please install solc' @type "protoc" 2> /dev/null || echo 'Please install protoc' diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 9644dc4e02..1c4270d255 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -33,7 +33,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "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 diff --git a/accounts/usbwallet/trezor/trezor.go b/accounts/usbwallet/trezor/trezor.go index 4324258314..93aee3c289 100644 --- a/accounts/usbwallet/trezor/trezor.go +++ b/accounts/usbwallet/trezor/trezor.go @@ -39,8 +39,8 @@ // - Download the latest protoc https://github.com/protocolbuffers/protobuf/releases // - 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 -// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go` -// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...` +// - Grab the latest Go plugin `go get -u google.golang.org/protobuf/cmd/protoc-gen-go` +// - 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 @@ -50,7 +50,7 @@ package trezor import ( "reflect" - "github.com/golang/protobuf/proto" + "google.golang.org/protobuf/proto" ) // Type returns the protocol buffer type number of a specific message. If the diff --git a/build/tools/tools.go b/build/tools/tools.go index 506e26eeff..e9e2241d2f 100644 --- a/build/tools/tools.go +++ b/build/tools/tools.go @@ -22,6 +22,6 @@ package tools import ( // Tool imports for go:generate. _ "github.com/fjl/gencodec" - _ "github.com/golang/protobuf/protoc-gen-go" _ "golang.org/x/tools/cmd/stringer" + _ "google.golang.org/protobuf/cmd/protoc-gen-go" ) diff --git a/go.mod b/go.mod index db5c713498..5a0314d635 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,6 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.8.1 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/google/gofuzz v1.2.0 github.com/google/uuid v1.3.0 @@ -74,7 +73,7 @@ require ( golang.org/x/text v0.14.0 golang.org/x/time v0.5.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/yaml.v3 v3.0.1 ) @@ -112,6 +111,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/goccy/go-json v0.10.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/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect diff --git a/go.sum b/go.sum index e3cf5f3d63..465e98f337 100644 --- a/go.sum +++ b/go.sum @@ -842,6 +842,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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 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/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= From 67b81371008d147aa2ccebd3fa9655fe042b0f14 Mon Sep 17 00:00:00 2001 From: ysh0566 Date: Fri, 2 Aug 2024 02:09:04 +0800 Subject: [PATCH 163/196] accounts/abi/bind: add accessList support to base bond contract (#30195) Adding the correct accessList parameter when calling a contract can reduce gas consumption. However, the current version only allows adding the accessList manually when constructing the transaction. This PR can provide convenience for saving gas. --- accounts/abi/bind/base.go | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index c8972a9dff..0504089c71 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -59,11 +59,12 @@ type TransactOpts struct { Nonce *big.Int // Nonce to use for the transaction execution (nil = use pending state) Signer SignerFn // Method to use for signing the transaction (mandatory) - 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) - 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) - GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) + 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) + 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) + 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) @@ -300,20 +301,21 @@ func (c *BoundContract) createDynamicTx(opts *TransactOpts, contract *common.Add return nil, err } baseTx := &types.DynamicFeeTx{ - To: contract, - Nonce: nonce, - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Gas: gasLimit, - Value: value, - Data: input, + To: contract, + Nonce: nonce, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Gas: gasLimit, + Value: value, + Data: input, + AccessList: opts.AccessList, } return types.NewTx(baseTx), nil } func (c *BoundContract) createLegacyTx(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { - if opts.GasFeeCap != nil || opts.GasTipCap != nil { - return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") + if opts.GasFeeCap != nil || opts.GasTipCap != nil || opts.AccessList != nil { + return nil, errors.New("maxFeePerGas or maxPriorityFeePerGas or accessList specified but london is not active yet") } // Normalize value value := opts.Value From e4675771eda550e7eeb63a8884816982c1980644 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 2 Aug 2024 06:44:03 +0200 Subject: [PATCH 164/196] internal/debug: remove memsize (#30253) Removing because memsize will very likely be broken by Go 1.23. See https://github.com/fjl/memsize/issues/4 --- cmd/geth/main.go | 2 -- go.mod | 1 - go.sum | 2 -- internal/debug/flags.go | 4 ---- 4 files changed, 9 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index f6bb09ee54..a37bb5f987 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -360,8 +360,6 @@ func geth(ctx *cli.Context) error { // it unlocks any requested accounts, and starts the RPC/IPC interfaces and the // miner. func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) { - debug.Memsize.Add("node", stack) - // Start up the node itself utils.StartNode(ctx, stack, isConsole) diff --git a/go.mod b/go.mod index 5a0314d635..3e9837186d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,6 @@ require ( github.com/fatih/color v1.16.0 github.com/ferranbt/fastssz v0.1.2 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/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff github.com/gofrs/flock v0.8.1 diff --git a/go.sum b/go.sum index 465e98f337..d8e7a540c7 100644 --- a/go.sum +++ b/go.sum @@ -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/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/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.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= diff --git a/internal/debug/flags.go b/internal/debug/flags.go index 19222c8325..0e05975c7e 100644 --- a/internal/debug/flags.go +++ b/internal/debug/flags.go @@ -31,15 +31,12 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics/exp" - "github.com/fjl/memsize/memsizeui" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/urfave/cli/v2" "gopkg.in/natefinch/lumberjack.v2" ) -var Memsize memsizeui.Handler - var ( verbosityFlag = &cli.IntFlag{ Name: "verbosity", @@ -313,7 +310,6 @@ func StartPProf(address string, withMetrics bool) { if withMetrics { exp.Exp(metrics.DefaultRegistry) } - http.Handle("/memsize/", http.StripPrefix("/memsize", &Memsize)) log.Info("Starting pprof server", "addr", fmt.Sprintf("http://%s/debug/pprof", address)) go func() { if err := http.ListenAndServe(address, nil); err != nil { From 16cf5c5fed9f8f22ef31fcdb0057aa4ad4ea3a12 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 2 Aug 2024 17:36:28 +0200 Subject: [PATCH 165/196] eth/downloader: gofmt (#30261) Fixes a regression introduced in https://github.com/ethereum/go-ethereum/pull/30219 --- eth/downloader/beaconsync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/downloader/beaconsync.go b/eth/downloader/beaconsync.go index 5ef3f91dc7..e682536e07 100644 --- a/eth/downloader/beaconsync.go +++ b/eth/downloader/beaconsync.go @@ -135,7 +135,7 @@ func (b *beaconBackfiller) setMode(mode SyncMode) { return } log.Error("Downloader sync mode changed mid-run", "old", oldMode.String(), "new", mode.String()) - b.suspend() + b.suspend() b.resume() } From 142c94d62842c7801e8f4d71f080ae156ecd1f2b Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:49:01 -0600 Subject: [PATCH 166/196] cmd/evm: don't overwrite sender account (#30259) Fixes #30254 It seems like the removed CreateAccount call is very old and not needed anymore. After removing it, setting a sender that does not exist in the state doesn't seem to cause an issue. --- cmd/evm/runner.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index f179e733e6..d06f85ed59 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -162,7 +162,6 @@ func runCmd(ctx *cli.Context) error { if ctx.String(SenderFlag.Name) != "" { sender = common.HexToAddress(ctx.String(SenderFlag.Name)) } - statedb.CreateAccount(sender) if ctx.String(ReceiverFlag.Name) != "" { receiver = common.HexToAddress(ctx.String(ReceiverFlag.Name)) From 10586952dfad6d57ed0b24500f572f7889c8fa97 Mon Sep 17 00:00:00 2001 From: Delweng Date: Tue, 6 Aug 2024 01:14:22 +0800 Subject: [PATCH 167/196] eth/catalyst: get params.ExcessBlobGas but check with params.BlobGasUsed (#30267) Seems it is checked with the wrong argument Signed-off-by: jsvisa --- eth/catalyst/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 00cce259c8..5a001e1ee8 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -546,7 +546,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe bgu = strconv.Itoa(int(*params.BlobGasUsed)) } ebg := "nil" - if params.BlobGasUsed != nil { + if params.ExcessBlobGas != nil { ebg = strconv.Itoa(int(*params.ExcessBlobGas)) } log.Warn("Invalid NewPayload params", From cf8aa31e3edc6fc652963c5d5dee869cd69f077b Mon Sep 17 00:00:00 2001 From: stevemilk Date: Tue, 6 Aug 2024 19:49:48 +0800 Subject: [PATCH 168/196] params: remove unused les parameters (#30268) --- params/network_params.go | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/params/network_params.go b/params/network_params.go index 9311b5e2d5..61bd6b2f42 100644 --- a/params/network_params.go +++ b/params/network_params.go @@ -24,44 +24,13 @@ const ( // contains on the server side. 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 // considered probably final and its rotated bits are calculated. 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 // 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 // the freezer as the cutoff threshold and by clique as the snapshot trust limit. 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 ) From dbc1d04f5e4a6e466e32db08ed03678624a93307 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Tue, 6 Aug 2024 05:51:48 -0600 Subject: [PATCH 169/196] core/vm/runtime: ensure tracer benchmark calls `OnTxStart` (#30257) The struct-based tracing added in #29189 seems to have caused an issue with the benchmark `BenchmarkTracerStepVsCallFrame`. On master we see the following panic: ```console BenchmarkTracerStepVsCallFrame panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x2 addr=0x40 pc=0x1019782f0] goroutine 37 [running]: github.com/ethereum/go-ethereum/eth/tracers/js.(*jsTracer).OnOpcode(0x140004c4000, 0x0, 0x10?, 0x989680, 0x1, {0x101ea2298, 0x1400000e258}, {0x1400000e258?, 0x14000155928?, 0x10173020c?}, ...) /Users/matt/dev/go-ethereum/eth/tracers/js/goja.go:328 +0x140 github.com/ethereum/go-ethereum/core/vm.(*EVMInterpreter).Run(0x14000307da0, 0x140003cc0d0, {0x0, 0x0, 0x0}, 0x0) ... FAIL github.com/ethereum/go-ethereum/core/vm/runtime 0.420s FAIL ``` The issue seems to be that `OnOpcode` expects that `OnTxStart` has already been called to initialize the `env` value in the tracer. The JS tracer uses it in `OnOpcode` for the `GetRefund()` method. This patch resolves the issue by reusing the `Call` method already defined in `runtime_test.go` which correctly calls `OnTxStart`. --- core/vm/runtime/runtime_test.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index 04abc5480e..a49eca25d3 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -38,7 +38,6 @@ import ( // force-load js tracers to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" - "github.com/holiman/uint256" ) func TestDefaults(t *testing.T) { @@ -339,11 +338,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode Tracer: tracer.Hooks, } } - var ( - destination = common.BytesToAddress([]byte("contract")) - vmenv = NewEnv(cfg) - sender = vm.AccountRef(cfg.Origin) - ) + destination := common.BytesToAddress([]byte("contract")) cfg.State.CreateAccount(destination) eoa := common.HexToAddress("E0") { @@ -363,12 +358,12 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode //cfg.State.CreateAccount(cfg.Origin) // set the receiver's (the executing contract) code for execution. 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.ReportAllocs() for i := 0; i < b.N; i++ { - vmenv.Call(sender, destination, nil, gas, uint256.MustFromBig(cfg.Value)) + Call(destination, nil, cfg) } }) } From e9981bc6f72229f2bcc87b6721d2c06a195332b9 Mon Sep 17 00:00:00 2001 From: Zhihao Lin <3955922+kkqy@users.noreply.github.com> Date: Tue, 6 Aug 2024 20:14:37 +0800 Subject: [PATCH 170/196] ethclient: support networkID in hex format (#30263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some chains’ network IDs use hexadecimal such as Optimism ("0xa" instead of "10"), so when converting the string to big.Int, we cannot specify base 10; otherwise, it will encounter errors with hexadecimal network IDs. --- ethclient/ethclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 390f085677..f769ee8475 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -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 { 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 version, nil From b37ac5c1027847de2eb65162a7251b37b9466793 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:38:47 +0200 Subject: [PATCH 171/196] core/vm: improved stack swap performance (#30249) This PR adds the methods `Stack.swap1..16()` that faster than `Stack.swap(1..16)`. Co-authored-by: lmittmann --- core/vm/instructions.go | 90 +++++++++++++++++++++++++++++---- core/vm/jump_table.go | 32 ++++++------ core/vm/runtime/runtime_test.go | 29 +++++++++++ core/vm/stack.go | 51 +++++++++++++++++-- 4 files changed, 173 insertions(+), 29 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9ec4544643..1e8be295d8 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -583,6 +583,86 @@ func opGas(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte 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) { if interpreter.readOnly { return nil, ErrWriteProtection @@ -923,13 +1003,3 @@ func makeDup(size int64) executionFunc { 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 - } -} diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 5624f47ba7..6b2950194d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -892,97 +892,97 @@ func newFrontierInstructionSet() JumpTable { maxStack: maxDupStack(16), }, SWAP1: { - execute: makeSwap(1), + execute: opSwap1, constantGas: GasFastestStep, minStack: minSwapStack(2), maxStack: maxSwapStack(2), }, SWAP2: { - execute: makeSwap(2), + execute: opSwap2, constantGas: GasFastestStep, minStack: minSwapStack(3), maxStack: maxSwapStack(3), }, SWAP3: { - execute: makeSwap(3), + execute: opSwap3, constantGas: GasFastestStep, minStack: minSwapStack(4), maxStack: maxSwapStack(4), }, SWAP4: { - execute: makeSwap(4), + execute: opSwap4, constantGas: GasFastestStep, minStack: minSwapStack(5), maxStack: maxSwapStack(5), }, SWAP5: { - execute: makeSwap(5), + execute: opSwap5, constantGas: GasFastestStep, minStack: minSwapStack(6), maxStack: maxSwapStack(6), }, SWAP6: { - execute: makeSwap(6), + execute: opSwap6, constantGas: GasFastestStep, minStack: minSwapStack(7), maxStack: maxSwapStack(7), }, SWAP7: { - execute: makeSwap(7), + execute: opSwap7, constantGas: GasFastestStep, minStack: minSwapStack(8), maxStack: maxSwapStack(8), }, SWAP8: { - execute: makeSwap(8), + execute: opSwap8, constantGas: GasFastestStep, minStack: minSwapStack(9), maxStack: maxSwapStack(9), }, SWAP9: { - execute: makeSwap(9), + execute: opSwap9, constantGas: GasFastestStep, minStack: minSwapStack(10), maxStack: maxSwapStack(10), }, SWAP10: { - execute: makeSwap(10), + execute: opSwap10, constantGas: GasFastestStep, minStack: minSwapStack(11), maxStack: maxSwapStack(11), }, SWAP11: { - execute: makeSwap(11), + execute: opSwap11, constantGas: GasFastestStep, minStack: minSwapStack(12), maxStack: maxSwapStack(12), }, SWAP12: { - execute: makeSwap(12), + execute: opSwap12, constantGas: GasFastestStep, minStack: minSwapStack(13), maxStack: maxSwapStack(13), }, SWAP13: { - execute: makeSwap(13), + execute: opSwap13, constantGas: GasFastestStep, minStack: minSwapStack(14), maxStack: maxSwapStack(14), }, SWAP14: { - execute: makeSwap(14), + execute: opSwap14, constantGas: GasFastestStep, minStack: minSwapStack(15), maxStack: maxSwapStack(15), }, SWAP15: { - execute: makeSwap(15), + execute: opSwap15, constantGas: GasFastestStep, minStack: minSwapStack(16), maxStack: maxSwapStack(16), }, SWAP16: { - execute: makeSwap(16), + execute: opSwap16, constantGas: GasFastestStep, minStack: minSwapStack(17), maxStack: maxSwapStack(17), diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index a49eca25d3..f52484606b 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -212,6 +212,35 @@ func BenchmarkEVM_CREATE2_1200(bench *testing.B) { 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 fakeHeader(n uint64, parentHash common.Hash) *types.Header { header := types.Header{ Coinbase: common.HexToAddress("0x00000000000000000000000000000000deadbeef"), diff --git a/core/vm/stack.go b/core/vm/stack.go index e1a957e244..879dc9aa6d 100644 --- a/core/vm/stack.go +++ b/core/vm/stack.go @@ -30,7 +30,7 @@ var stackPool = sync.Pool{ // 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 -// initialised objects. +// initialized objects. type Stack struct { data []uint256.Int } @@ -64,8 +64,53 @@ func (st *Stack) len() int { return len(st.data) } -func (st *Stack) swap(n int) { - st.data[st.len()-n], st.data[st.len()-1] = st.data[st.len()-1], st.data[st.len()-n] +func (st *Stack) swap1() { + 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) { From 978041feeaffc3f91afd98c8495a63bfff4b12f4 Mon Sep 17 00:00:00 2001 From: llkhacquan <3724362+llkhacquan@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:13:18 +0700 Subject: [PATCH 172/196] signer/core: improve performance of isPrimitiveTypeValid function (#30274) (#30277) Precomputes valid primitive types into a map to use for validation, thus removing sprintf. --- signer/core/apitypes/types.go | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/signer/core/apitypes/types.go b/signer/core/apitypes/types.go index 73243b16a1..e886d7fc44 100644 --- a/signer/core/apitypes/types.go +++ b/signer/core/apitypes/types.go @@ -843,39 +843,35 @@ func (t Types) validate() error { return nil } -// Checks if the primitive value is valid -func isPrimitiveTypeValid(primitiveType string) bool { - if primitiveType == "address" || - primitiveType == "address[]" || - primitiveType == "bool" || - primitiveType == "bool[]" || - primitiveType == "string" || - primitiveType == "string[]" || - primitiveType == "bytes" || - primitiveType == "bytes[]" || - primitiveType == "int" || - primitiveType == "int[]" || - primitiveType == "uint" || - primitiveType == "uint[]" { - return true +var validPrimitiveTypes = map[string]struct{}{} + +// build the set of valid primitive types +func init() { + // Types those are trivially valid + for _, t := range []string{ + "address", "address[]", "bool", "bool[]", "string", "string[]", + "bytes", "bytes[]", "int", "int[]", "uint", "uint[]", + } { + validPrimitiveTypes[t] = struct{}{} } // For 'bytesN', 'bytesN[]', we allow N from 1 to 32 for n := 1; n <= 32; n++ { - // e.g. 'bytes28' or 'bytes28[]' - if primitiveType == fmt.Sprintf("bytes%d", n) || primitiveType == fmt.Sprintf("bytes%d[]", n) { - return true - } + validPrimitiveTypes[fmt.Sprintf("bytes%d", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("bytes%d[]", n)] = struct{}{} } // For 'intN','intN[]' and 'uintN','uintN[]' we allow N in increments of 8, from 8 up to 256 for n := 8; n <= 256; n += 8 { - if primitiveType == fmt.Sprintf("int%d", n) || primitiveType == fmt.Sprintf("int%d[]", n) { - return true - } - if primitiveType == fmt.Sprintf("uint%d", n) || primitiveType == fmt.Sprintf("uint%d[]", n) { - return true - } + validPrimitiveTypes[fmt.Sprintf("int%d", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("int%d[]", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("uint%d", n)] = struct{}{} + validPrimitiveTypes[fmt.Sprintf("uint%d[]", n)] = struct{}{} } - return false +} + +// Checks if the primitive value is valid +func isPrimitiveTypeValid(primitiveType string) bool { + _, ok := validPrimitiveTypes[primitiveType] + return ok } // validate checks if the given domain is valid, i.e. contains at least From 4a3aed380e91fc3e01ccc35e367865de89adb508 Mon Sep 17 00:00:00 2001 From: lmittmann <3458786+lmittmann@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:27:38 +0200 Subject: [PATCH 173/196] core/vm: use uint64 in memory for indices everywhere (#30252) Consistently use `uint64` for indices in `Memory` and drop lots of type conversions from `uint64` to `int64`. --------- Co-authored-by: lmittmann --- core/vm/instructions.go | 22 +++++++++++----------- core/vm/memory.go | 21 +++++++-------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1e8be295d8..2e0f4c40ab 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -232,7 +232,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.peek() - data := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) + data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) if interpreter.hasher == nil { interpreter.hasher = crypto.NewKeccakState() @@ -502,7 +502,7 @@ func opPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte func opMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { v := scope.Stack.peek() - offset := int64(v.Uint64()) + offset := v.Uint64() v.SetBytes(scope.Memory.GetPtr(offset, 32)) return nil, nil } @@ -670,7 +670,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b var ( value = scope.Stack.pop() offset, size = scope.Stack.pop(), scope.Stack.pop() - input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) gas = scope.Contract.Gas ) if interpreter.evm.chainRules.IsEIP150 { @@ -714,7 +714,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] endowment = scope.Stack.pop() offset, size = scope.Stack.pop(), scope.Stack.pop() salt = scope.Stack.pop() - input = scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64())) + input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64()) gas = scope.Contract.Gas ) @@ -752,7 +752,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get the arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) if interpreter.readOnly && !value.IsZero() { return nil, ErrWriteProtection @@ -788,7 +788,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) if !value.IsZero() { gas += params.CallStipend @@ -821,7 +821,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) ret, returnGas, err := interpreter.evm.DelegateCall(scope.Contract, toAddr, args, gas) if err != nil { @@ -850,7 +850,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.Address(addr.Bytes20()) // Get arguments from the memory. - args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64())) + args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) ret, returnGas, err := interpreter.evm.StaticCall(scope.Contract, toAddr, args, gas) if err != nil { @@ -871,14 +871,14 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) func opReturn(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() - ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) + ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) return ret, errStopToken } func opRevert(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { offset, size := scope.Stack.pop(), scope.Stack.pop() - ret := scope.Memory.GetPtr(int64(offset.Uint64()), int64(size.Uint64())) + ret := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) interpreter.returnData = ret return ret, ErrExecutionReverted @@ -947,7 +947,7 @@ func makeLog(size int) executionFunc { topics[i] = addr.Bytes32() } - d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64())) + d := scope.Memory.GetCopy(mStart.Uint64(), mSize.Uint64()) interpreter.evm.StateDB.AddLog(&types.Log{ Address: scope.Contract.Address(), Topics: topics, diff --git a/core/vm/memory.go b/core/vm/memory.go index e0202fd7c0..33203879ae 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -66,32 +66,25 @@ func (m *Memory) Resize(size uint64) { } // GetCopy returns offset + size as a new slice -func (m *Memory) GetCopy(offset, size int64) (cpy []byte) { +func (m *Memory) GetCopy(offset, size uint64) (cpy []byte) { if size == 0 { return nil } - if len(m.store) > int(offset) { - cpy = make([]byte, size) - copy(cpy, m.store[offset:offset+size]) - - return - } - + // memory is always resized before being accessed, no need to check bounds + cpy = make([]byte, size) + copy(cpy, m.store[offset:offset+size]) return } // GetPtr returns the offset + size -func (m *Memory) GetPtr(offset, size int64) []byte { +func (m *Memory) GetPtr(offset, size uint64) []byte { if size == 0 { return nil } - if len(m.store) > int(offset) { - return m.store[offset : offset+size] - } - - return nil + // memory is always resized before being accessed, no need to check bounds + return m.store[offset : offset+size] } // Len returns the length of the backing slice From 9ea766d6e9189e8fbec7dbcacaf4c3f5083276ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marius=20Kj=C3=A6rstad?= Date: Thu, 8 Aug 2024 13:47:43 +0200 Subject: [PATCH 174/196] build: upgrade -dlgo version to Go 1.22.6 (#30273) --- build/checksums.txt | 96 ++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 15c74559e6..5a25229885 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,55 +5,55 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/ ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz -# version:golang 1.22.5 +# version:golang 1.22.6 # https://go.dev/dl/ -ac9c723f224969aee624bc34fd34c9e13f2a212d75c71c807de644bb46e112f6 go1.22.5.src.tar.gz -c82ba3403c45a4aa4b84b08244656a51e55b86fb130dcc500f5291d0f3b12222 go1.22.5.aix-ppc64.tar.gz -8a8872b1bac959b3b76f2e3978c46406d22a54a99c83ca55840ca08b4f2960bc go1.22.5.darwin-amd64.pkg -95d9933cdcf45f211243c42c7705c37353cccd99f27eb4d8e2d1bf2f4165cb50 go1.22.5.darwin-amd64.tar.gz -8c943512d1fa4e849f0078b03721df02aac19d8bb872dd17ab3ee7127ae6b732 go1.22.5.darwin-arm64.pkg -4cd1bcb05be03cecb77bccd765785d5ff69d79adf4dd49790471d00c06b41133 go1.22.5.darwin-arm64.tar.gz -1f1f035e968a877cd8ed62adae6edb2feeee62470660b7587ddcb904a3877a21 go1.22.5.dragonfly-amd64.tar.gz -d660698411465531d475ec1c617fdb415df68740f3511138a8d15506665a06f9 go1.22.5.freebsd-386.tar.gz -75f43ef46c2ad46c534ded25d26fba9bef036fc07074dfa45c0b3b90856a8151 go1.22.5.freebsd-amd64.tar.gz -75614714e7e4a4dd721f0eddd6555b3f6afc4c07e59c1b9b769cf663996165f9 go1.22.5.freebsd-arm.tar.gz -1377d0d7233f1b8f4cb8e3456f2e7ed44aca4a95daab79ae09605d34aa967c6b go1.22.5.freebsd-arm64.tar.gz -07baf198587abc05ea789dbe5810a2d6612ad56a51718bbf74de2c93bdbe676a go1.22.5.freebsd-riscv64.tar.gz -c0bd4f0d44252f3ec93ca850a41b167bb868179c7c283f8af9439e73b2654b17 go1.22.5.illumos-amd64.tar.gz -3ea4c78e6fa52978ae1ed2e5927ad17495da440c9fae7787b1ebc1d0572f7f43 go1.22.5.linux-386.tar.gz -904b924d435eaea086515bc63235b192ea441bd8c9b198c507e85009e6e4c7f0 go1.22.5.linux-amd64.tar.gz -8d21325bfcf431be3660527c1a39d3d9ad71535fabdf5041c826e44e31642b5a go1.22.5.linux-arm64.tar.gz -8c4587cf3e63c9aefbcafa92818c4d9d51683af93ea687bf6c7508d6fa36f85e go1.22.5.linux-armv6l.tar.gz -780e2eeb6376a763c564f776eaac6700f33f95e29302faa54b040b19cb1f6fd2 go1.22.5.linux-loong64.tar.gz -f784aa1adfb605da3bfe8cd534b545bddae3eb893e9302f7c2f5d44656b1cae2 go1.22.5.linux-mips.tar.gz -aaa3756571467768388f2ab641a02ff54f98f1684808cda047a7be3026e4b438 go1.22.5.linux-mips64.tar.gz -b7956d925c9ef5a4dc53017feaed2d78dba5d0a1036bad5ea513f1f15ba08fbc go1.22.5.linux-mips64le.tar.gz -7baf605be9b787acd750b6b48a91818a5590ec9289b14aea5696a46b41853888 go1.22.5.linux-mipsle.tar.gz -f09b2a6c1a409662e8e8fe267e1eabeba0a1fd00eb1422fd88297b013803952e go1.22.5.linux-ppc64.tar.gz -5312bb420ac0b59175a58927e70b4660b14ab7319aab54398b6071fabcbfbb09 go1.22.5.linux-ppc64le.tar.gz -f8d0c7d96b336f4133409ff9da7241cfe91e65723c2e8e7c7f9b58a9f9603476 go1.22.5.linux-riscv64.tar.gz -24c6c5c9d515adea5d58ae78388348c97614a0c21ac4d4f4c0dab75e893b0b5d go1.22.5.linux-s390x.tar.gz -39144c62acbaa85e4f1ab57bad8f5b3dc67d6fa24b711ec1fa593f4a0ea1fe91 go1.22.5.netbsd-386.tar.gz -118f79640588eb878529b46cdf56599012da6575f0ac07069ec1e9a8e78ddd0b go1.22.5.netbsd-amd64.tar.gz -d39c2b94ae3fd0a6399e545cbecb673496293075291bd98ef15f24d21625a490 go1.22.5.netbsd-arm.tar.gz -f7fb617d10c39248996521d72370db82d50724fa894089c76ae4298fbbe1fb0b go1.22.5.netbsd-arm64.tar.gz -e0f778a34746587ae7c18e8a24cfaba1b2eaabce75d0ceb470adf576ad1cd90f go1.22.5.openbsd-386.tar.gz -b417311df26ef7ae8b34fcb991519a5c496010561c12386d9469aea03c1bdf0b go1.22.5.openbsd-amd64.tar.gz -e78e8ad05605d530a4f79e55031c7c65f2020a9d442e05d490bd08f0d947a34f go1.22.5.openbsd-arm.tar.gz -8027898948f17742717786ead2ff2e960ee1fc82995d6edbad0050d551710f59 go1.22.5.openbsd-arm64.tar.gz -99c5b81d75bcc0d83d25dedc9535682c42c0e761276c88bcc4db6340344644fd go1.22.5.openbsd-ppc64.tar.gz -30d5dacdee0481f0b8cabb75b706465e2177c3a4a1d1c46293332f4b90a3d199 go1.22.5.plan9-386.tar.gz -65628650cd7665387cfe6fa386c381f4de1ef7b03a12067ae9ccf06d2feaea2c go1.22.5.plan9-amd64.tar.gz -322541cbfc9ae95b48b9eec4eb45df48299784592e23121084f790cf1082787e go1.22.5.plan9-arm.tar.gz -87c590e3eb81fcffa3dc1524c03c2847f0890e95c2a43586e82b56c262eb03d8 go1.22.5.solaris-amd64.tar.gz -3ec89ed822b38f4483977a90913fbe39d0857f0ed16c4642dec1950ddbe8c943 go1.22.5.windows-386.msi -c44fc421075022add78fbf8db38519dd5520a11832749be2189e64b3cf4f02f9 go1.22.5.windows-386.zip -86b0299ab8cb9c44882a9080dac03f7f4d9546f51ed1ba1015599114bcbc66d0 go1.22.5.windows-amd64.msi -59968438b8d90f108fd240d4d2f95b037e59716995f7409e0a322dcb996e9f42 go1.22.5.windows-amd64.zip -013d3b300e6b8f26482d6dd17b02830b83ee63795498bd8c0c9d80bb2c4d6cf7 go1.22.5.windows-arm.msi -8cc860630a84e2dbff3e84280f46a571741f26f8a1819aa4fbcb3164fdd51312 go1.22.5.windows-arm.zip -8f90519d9f305f2caa05d1d4fb0656b50f1bf89d76e194279f480e5a484c891f go1.22.5.windows-arm64.msi -6717d5841162aa8c05f932eb74a643f1310b8a88f80f0830e86d194289734bbf go1.22.5.windows-arm64.zip +9e48d99d519882579917d8189c17e98c373ce25abaebb98772e2927088992a51 go1.22.6.src.tar.gz +eeb0cc42120cbae6d3695dae2e5420fa0e93a5db957db139b55efdb879dd9856 go1.22.6.aix-ppc64.tar.gz +b47ac340f0b072943fed1f558a26eb260cc23bd21b8af175582e9103141d465b go1.22.6.darwin-amd64.pkg +9c3c0124b01b5365f73a1489649f78f971ecf84844ad9ca58fde133096ddb61b go1.22.6.darwin-amd64.tar.gz +14d0355ec1c0eeb213a16efa8635fac1f16067ef78a8173abf9a8c7b805e551e go1.22.6.darwin-arm64.pkg +ebac39fd44fc22feed1bb519af431c84c55776e39b30f4fd62930da9c0cfd1e3 go1.22.6.darwin-arm64.tar.gz +3695b10c722a4920c8a736284f8820c142e1e752f3a87f797a45c64366f7a173 go1.22.6.dragonfly-amd64.tar.gz +a9b9570c80294a664d50b566d6bd1aa42465997d2d76a57936b32f55f5c69c63 go1.22.6.freebsd-386.tar.gz +424a5618406800365fe3ad96a795fb55ce394bea3ff48eaf56d292bf7a916d1e go1.22.6.freebsd-amd64.tar.gz +e0dce3a6dbe8e7e054d329dd4cb403935c63c0f7e22e693077aa60e12018b883 go1.22.6.freebsd-arm.tar.gz +34930b01f58889c71f7a78c51c6c3bd2ce289ac7862c76dab691303cfa935fd1 go1.22.6.freebsd-arm64.tar.gz +4c9d630e55d4d600a5b4297e59620c3bdfe63a441981682b3638e2fdda228a44 go1.22.6.freebsd-riscv64.tar.gz +9ed63feaf2ef56c56f1cf0d9d3fab4006efd22a38e2f1f5252e95c6ac09332f3 go1.22.6.illumos-amd64.tar.gz +9e680027b058beab10ce5938607660964b6d2c564bf50bdb01aa090dc5beda98 go1.22.6.linux-386.tar.gz +999805bed7d9039ec3da1a53bfbcafc13e367da52aa823cb60b68ba22d44c616 go1.22.6.linux-amd64.tar.gz +c15fa895341b8eaf7f219fada25c36a610eb042985dc1a912410c1c90098eaf2 go1.22.6.linux-arm64.tar.gz +b566484fe89a54c525dd1a4cbfec903c1f6e8f0b7b3dbaf94c79bc9145391083 go1.22.6.linux-armv6l.tar.gz +1ee6e1896aea856142d2af7045cea118995b39404aa61afd12677d023d47ee69 go1.22.6.linux-loong64.tar.gz +fdd0e1a3e178f9bc79adf6ff1e3de4554ce581b4c468fd6e113c43fbbbe1eec6 go1.22.6.linux-mips.tar.gz +d3e5a621fc5a07759e503a971af0b28ded6a7d6f5604ab511f51f930a18dd3e4 go1.22.6.linux-mips64.tar.gz +01547606c5b5c1b0e5587b3afd65172860d2f4755e523785832905759ecce2d7 go1.22.6.linux-mips64le.tar.gz +2cd771416ae03c11240cfdb551d66ab9a941077664f3727b966f94386c23b0fa go1.22.6.linux-mipsle.tar.gz +6ef61d517777925e6bdb0321ea42d5f60acc20c1314dd902b9d0bfa3a5fd4fca go1.22.6.linux-ppc64.tar.gz +9d99fce3f6f72a76630fe91ec0884dfe3db828def4713368424900fa98bb2bd6 go1.22.6.linux-ppc64le.tar.gz +30be9c9b9cc4f044d4da9a33ee601ab7b3aff4246107d323a79e08888710754e go1.22.6.linux-riscv64.tar.gz +82f3bae3ddb4ede45b848db48c5486fadb58551e74507bda45484257e7194a95 go1.22.6.linux-s390x.tar.gz +85b2eb9d40a930bd3e75d0096a6eb5847aac86c5085e6d13a5845e9ef03f8d4b go1.22.6.netbsd-386.tar.gz +6e9acbdc34fb2a942d547c47c9c1989bb6e32b4a37d57fb312499e2bb33b46b7 go1.22.6.netbsd-amd64.tar.gz +e6eff3cf0038f2a9b0c9e01e228577a783bddcd8051222a3d949e24ee392e769 go1.22.6.netbsd-arm.tar.gz +43a7e2ba22da700b844f7561e3dd5434540ed6c9781be2e9c42e8a8cbf558f8e go1.22.6.netbsd-arm64.tar.gz +a90b758ccb45d8a17af8e140fafa1e97607de5a7ecd53a4c55f69258bfb043d0 go1.22.6.openbsd-386.tar.gz +cc13436c4a644e55bedcea65981eb80ca8317b39b129f5563ab3b6da1391bd47 go1.22.6.openbsd-amd64.tar.gz +aee34f61ba2b0a8f2618f5c7065e20da7714ce7651680509eda30728fe01ee88 go1.22.6.openbsd-arm.tar.gz +c67d57daf8baada93c69c8fb02401270cd33159730b1f2d70d9e724ba1a918cf go1.22.6.openbsd-arm64.tar.gz +03e1f96002e94a6b381bcf66a0a62b9d5f63148682a780d727840ad540185c7c go1.22.6.openbsd-ppc64.tar.gz +0ac2b5bbe2c8a293d284512630e629bf0578aaa7b7b1f39ac4ee182c7924aaad go1.22.6.plan9-386.tar.gz +f9afdab8a72a8d874f023f5605482cc94160843ac768dbd840e6f772d16578c7 go1.22.6.plan9-amd64.tar.gz +4b9f01a47e6a29d57cbb3097b6770583336cef9c8f0d51d3d1451e42a851002e go1.22.6.plan9-arm.tar.gz +46c2552ac7b8d6314a52e14e0a0761aaeebdd6aba5f531de386f4cf2b66ec723 go1.22.6.solaris-amd64.tar.gz +a57821dab76af1ef7a6b62db1628f0caa74343e0c7cb829df9ce8ea0713a3e8e go1.22.6.windows-386.msi +eb734bacc9aabca1273b61dd392bb84a9bb33783f5e2fff2cd6ab9885bbefbe6 go1.22.6.windows-386.zip +1238a3e6892eb8a0eb3fe0640e18ab82ca21cc1a933f16897b2ad081f057b5da go1.22.6.windows-amd64.msi +6023083a6e4d3199b44c37e9ba7b25d9674da20fd846a35ee5f9589d81c21a6a go1.22.6.windows-amd64.zip +6791218c568a3d000cb36317506541d7fd67e7cfe613baaf361ca36cad5e2cd5 go1.22.6.windows-arm.msi +ee41ca83bb07c4fd46a1d6b2d083519bb8ca156fcd9db37ee711234d43126e2f go1.22.6.windows-arm.zip +91c6b3376612095315a0aeae4b03e3da34fabe9dfd4532d023e2a70f913cf22a go1.22.6.windows-arm64.msi +7cf55f357ba8116cd3bff992980e20a704ba451b3dab341cf1787b133d900512 go1.22.6.windows-arm64.zip # version:golangci 1.59.0 # https://github.com/golangci/golangci-lint/releases/ From d3dae66e594748c2fb608177726bd46715b0a3a6 Mon Sep 17 00:00:00 2001 From: taiking Date: Thu, 8 Aug 2024 20:50:00 +0900 Subject: [PATCH 175/196] tests: fix TransactionTest to actually run (#30272) Due to https://github.com/ethereum/tests/releases/tag/v10.1, the format of the TransactionTest changed, but it was not properly addressed, causing the test to pass unexpectedly. --------- Co-authored-by: Martin Holst Swende --- tests/transaction_test.go | 11 ++++------- tests/transaction_test_util.go | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/transaction_test.go b/tests/transaction_test.go index cb0f262318..5179fc9afe 100644 --- a/tests/transaction_test.go +++ b/tests/transaction_test.go @@ -26,20 +26,17 @@ func TestTransaction(t *testing.T) { t.Parallel() txt := new(testMatcher) - // These can't be parsed, invalid hex in RLP - txt.skipLoad("^ttWrongRLP/.*") // We don't allow more than uint64 in gas amount // This is a pseudo-consensus vulnerability, but not in practice // because of the gas limit txt.skipLoad("^ttGasLimit/TransactionWithGasLimitxPriceOverflow.json") // We _do_ allow more than uint64 in gas price, as opposed to the tests // This is also not a concern, as long as tx.Cost() uses big.Int for - // calculating the final cozt - txt.skipLoad(".*TransactionWithGasPriceOverflow.*") + // calculating the final cost + txt.skipLoad("^ttGasPrice/TransactionWithGasPriceOverflow.json") - // The nonce is too large for uint64. Not a concern, it means geth won't - // accept transactions at a certain point in the distant future - txt.skipLoad("^ttNonce/TransactionWithHighNonce256.json") + // The maximum value of nonce is 2^64 - 1 + txt.skipLoad("^ttNonce/TransactionWithHighNonce64Minus1.json") // The value is larger than uint64, which according to the test is invalid. // Geth accepts it, which is not a consensus issue since we use big.Int's diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 391aa57584..d3dbbd5db2 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -29,7 +29,11 @@ import ( // TransactionTest checks RLP decoding and sender derivation of transactions. type TransactionTest struct { - RLP hexutil.Bytes `json:"rlp"` + Txbytes hexutil.Bytes `json:"txbytes"` + Result ttResult +} + +type ttResult struct { Byzantium ttFork Constantinople ttFork Istanbul ttFork @@ -73,15 +77,15 @@ func (tt *TransactionTest) Run(config *params.ChainConfig) error { isHomestead bool isIstanbul bool }{ - {"Frontier", types.FrontierSigner{}, tt.Frontier, false, false}, - {"Homestead", types.HomesteadSigner{}, tt.Homestead, true, false}, - {"EIP150", types.HomesteadSigner{}, tt.EIP150, true, false}, - {"EIP158", types.NewEIP155Signer(config.ChainID), tt.EIP158, true, false}, - {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Byzantium, true, false}, - {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Constantinople, true, false}, - {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Istanbul, true, true}, + {"Frontier", types.FrontierSigner{}, tt.Result.Frontier, false, false}, + {"Homestead", types.HomesteadSigner{}, tt.Result.Homestead, true, false}, + {"EIP150", types.HomesteadSigner{}, tt.Result.EIP150, true, false}, + {"EIP158", types.NewEIP155Signer(config.ChainID), tt.Result.EIP158, true, false}, + {"Byzantium", types.NewEIP155Signer(config.ChainID), tt.Result.Byzantium, true, false}, + {"Constantinople", types.NewEIP155Signer(config.ChainID), tt.Result.Constantinople, true, false}, + {"Istanbul", types.NewEIP155Signer(config.ChainID), tt.Result.Istanbul, true, true}, } { - sender, txhash, err := validateTx(tt.RLP, testcase.signer, testcase.isHomestead, testcase.isIstanbul) + sender, txhash, err := validateTx(tt.Txbytes, testcase.signer, testcase.isHomestead, testcase.isIstanbul) if testcase.fork.Sender == (common.UnprefixedAddress{}) { if err == nil { From ebe31dfd5c8c053c098b65eac2ec3070b7f8e9a8 Mon Sep 17 00:00:00 2001 From: psogv0308 Date: Thu, 8 Aug 2024 22:14:00 +0900 Subject: [PATCH 176/196] eth/downloader, core/types: take withdrawals-size into account in downloader queue (#30276) Fixes a slight miscalculation in the downloader queue, which was not accurately taking block withdrawals into account when calculating the size of the items in the queue --- core/types/withdrawal.go | 7 +++++++ eth/downloader/queue.go | 1 + 2 files changed, 8 insertions(+) diff --git a/core/types/withdrawal.go b/core/types/withdrawal.go index d1ad918f98..6f99e53b56 100644 --- a/core/types/withdrawal.go +++ b/core/types/withdrawal.go @@ -18,6 +18,7 @@ package types import ( "bytes" + "reflect" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -48,6 +49,12 @@ type Withdrawals []*Withdrawal // Len returns the length of s. func (s Withdrawals) Len() int { return len(s) } +var withdrawalSize = int(reflect.TypeOf(Withdrawal{}).Size()) + +func (s Withdrawals) Size() int { + return withdrawalSize * len(s) +} + // EncodeIndex encodes the i'th withdrawal to w. Note that this does not check for errors // because we assume that *Withdrawal will only ever contain valid withdrawals that were either // constructed by decoding or via public API in this package. diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 267c23407f..5441ad1187 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -385,6 +385,7 @@ func (q *queue) Results(block bool) []*fetchResult { for _, tx := range result.Transactions { size += common.StorageSize(tx.Size()) } + size += common.StorageSize(result.Withdrawals.Size()) q.resultSize = common.StorageSize(blockCacheSizeWeight)*size + (1-common.StorageSize(blockCacheSizeWeight))*q.resultSize } From 83e70aa3d00bbee9713b31768a30a7741eee8945 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Thu, 8 Aug 2024 18:58:08 +0200 Subject: [PATCH 177/196] cmd/evm: fix evm basefee (#30281) fixes #30279 -- previously we did not use the basefee from the genesis, and instead the defaults were used from `runtime.go/setDefaults`-function --- cmd/evm/runner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index d06f85ed59..c02f9f0590 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -221,6 +221,7 @@ func runCmd(ctx *cli.Context) error { Time: genesisConfig.Timestamp, Coinbase: genesisConfig.Coinbase, BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), + BaseFee: genesisConfig.BaseFee, BlobHashes: blobHashes, BlobBaseFee: blobBaseFee, EVMConfig: vm.Config{ From 811a69cd3cf77fe9b63c7dc260ff92a79c631846 Mon Sep 17 00:00:00 2001 From: Martin HS Date: Fri, 9 Aug 2024 22:11:22 +0200 Subject: [PATCH 178/196] go.mod: update uint256 to 1.3.1 (#30280) Release notes: https://github.com/holiman/uint256/releases/tag/v1.3.1 --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 3e9837186d..763210decd 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/hashicorp/go-bexpr v0.1.10 github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 github.com/holiman/bloomfilter/v2 v2.0.3 - github.com/holiman/uint256 v1.3.0 + github.com/holiman/uint256 v1.3.1 github.com/huin/goupnp v1.3.0 github.com/influxdata/influxdb-client-go/v2 v2.4.0 github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c diff --git a/go.sum b/go.sum index d8e7a540c7..562362dee6 100644 --- a/go.sum +++ b/go.sum @@ -310,8 +310,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8 github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= -github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= @@ -838,8 +838,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 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/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= From 32a1e0643ca5012bda851d65194fb5eb3d83591b Mon Sep 17 00:00:00 2001 From: Artyom Aminov Date: Sat, 10 Aug 2024 13:44:31 +0300 Subject: [PATCH 179/196] beacon/engine, consensus/beacon: use params.MaximumExtraDataSize instead of hard-coded value (#29721) Co-authored-by: Felix Lange Co-authored-by: Marius van der Wijden Co-authored-by: lightclient --- beacon/engine/types.go | 57 ++++++++++++++++++----------------- consensus/beacon/consensus.go | 2 +- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 1dfcf5b71a..d1b3aa22ab 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" ) @@ -193,21 +194,21 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) { // // and that the blockhash of the constructed block matches the parameters. Nil // Withdrawals value will propagate through the returned block. Empty -// Withdrawals value must be passed via non-nil, length 0 value in params. -func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { - txs, err := decodeTransactions(params.Transactions) +// Withdrawals value must be passed via non-nil, length 0 value in data. +func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) { + txs, err := decodeTransactions(data.Transactions) if err != nil { return nil, err } - if len(params.ExtraData) > 32 { - return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData)) + if len(data.ExtraData) > int(params.MaximumExtraDataSize) { + return nil, fmt.Errorf("invalid extradata length: %v", len(data.ExtraData)) } - if len(params.LogsBloom) != 256 { - return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom)) + if len(data.LogsBloom) != 256 { + return nil, fmt.Errorf("invalid logsBloom length: %v", len(data.LogsBloom)) } // Check that baseFeePerGas is not negative or too big - if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) { - return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas) + if data.BaseFeePerGas != nil && (data.BaseFeePerGas.Sign() == -1 || data.BaseFeePerGas.BitLen() > 256) { + return nil, fmt.Errorf("invalid baseFeePerGas: %v", data.BaseFeePerGas) } var blobHashes = make([]common.Hash, 0, len(txs)) for _, tx := range txs { @@ -225,34 +226,34 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, // ExecutableData before withdrawals are enabled by marshaling // Withdrawals as the json null value. var withdrawalsRoot *common.Hash - if params.Withdrawals != nil { - h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil)) + if data.Withdrawals != nil { + h := types.DeriveSha(types.Withdrawals(data.Withdrawals), trie.NewStackTrie(nil)) withdrawalsRoot = &h } header := &types.Header{ - ParentHash: params.ParentHash, + ParentHash: data.ParentHash, UncleHash: types.EmptyUncleHash, - Coinbase: params.FeeRecipient, - Root: params.StateRoot, + Coinbase: data.FeeRecipient, + Root: data.StateRoot, TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: params.ReceiptsRoot, - Bloom: types.BytesToBloom(params.LogsBloom), + ReceiptHash: data.ReceiptsRoot, + Bloom: types.BytesToBloom(data.LogsBloom), Difficulty: common.Big0, - Number: new(big.Int).SetUint64(params.Number), - GasLimit: params.GasLimit, - GasUsed: params.GasUsed, - Time: params.Timestamp, - BaseFee: params.BaseFeePerGas, - Extra: params.ExtraData, - MixDigest: params.Random, + Number: new(big.Int).SetUint64(data.Number), + GasLimit: data.GasLimit, + GasUsed: data.GasUsed, + Time: data.Timestamp, + BaseFee: data.BaseFeePerGas, + Extra: data.ExtraData, + MixDigest: data.Random, WithdrawalsHash: withdrawalsRoot, - ExcessBlobGas: params.ExcessBlobGas, - BlobGasUsed: params.BlobGasUsed, + ExcessBlobGas: data.ExcessBlobGas, + BlobGasUsed: data.BlobGasUsed, ParentBeaconRoot: beaconRoot, } - block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: params.Withdrawals}) - if block.Hash() != params.BlockHash { - return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash()) + block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: data.Withdrawals}) + if block.Hash() != data.BlockHash { + return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", data.BlockHash, block.Hash()) } return block, nil } diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index b8946e0c71..19763ed303 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -229,7 +229,7 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo // (c) the extradata is limited to 32 bytes func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, parent *types.Header) error { // Ensure that the header's extra-data section is of a reasonable size - if len(header.Extra) > 32 { + if len(header.Extra) > int(params.MaximumExtraDataSize) { return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra)) } // Verify the seal parts. Ensure the nonce and uncle hash are the expected value. From 33a13b6f2110807a15c443ec234580cfce94a194 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Mon, 12 Aug 2024 02:36:48 -0600 Subject: [PATCH 180/196] p2p/simulations: remove packages (#30250) Looking at the history of these packages over the past several years, there haven't been any meaningful contributions or usages: https://github.com/ethereum/go-ethereum/commits/master/p2p/simulations?before=de6d5976794a9ed3b626d4eba57bf7f0806fb970+35 Almost all of the commits are part of larger refactors or low-hanging-fruit contributions. Seems like it's not providing much value and taking up team + contributor time. --- .github/CODEOWNERS | 3 - cmd/p2psim/main.go | 443 ------- .../pipes/pipes.go => pipes/pipe.go} | 14 +- p2p/rlpx/rlpx_test.go | 2 +- p2p/simulations/README.md | 174 --- p2p/simulations/adapters/exec.go | 567 --------- p2p/simulations/adapters/inproc.go | 344 ------ p2p/simulations/adapters/inproc_test.go | 202 --- p2p/simulations/adapters/types.go | 325 ----- p2p/simulations/connect.go | 153 --- p2p/simulations/connect_test.go | 172 --- p2p/simulations/events.go | 110 -- p2p/simulations/examples/README.md | 39 - p2p/simulations/examples/ping-pong.go | 173 --- p2p/simulations/examples/ping-pong.sh | 40 - p2p/simulations/http.go | 743 ----------- p2p/simulations/http_test.go | 869 ------------- p2p/simulations/mocker.go | 197 --- p2p/simulations/mocker_test.go | 174 --- p2p/simulations/network.go | 1093 ----------------- p2p/simulations/network_test.go | 872 ------------- p2p/simulations/simulation.go | 157 --- p2p/simulations/test.go | 150 --- p2p/transport_test.go | 2 +- 24 files changed, 5 insertions(+), 7013 deletions(-) delete mode 100644 cmd/p2psim/main.go rename p2p/{simulations/pipes/pipes.go => pipes/pipe.go} (85%) delete mode 100644 p2p/simulations/README.md delete mode 100644 p2p/simulations/adapters/exec.go delete mode 100644 p2p/simulations/adapters/inproc.go delete mode 100644 p2p/simulations/adapters/inproc_test.go delete mode 100644 p2p/simulations/adapters/types.go delete mode 100644 p2p/simulations/connect.go delete mode 100644 p2p/simulations/connect_test.go delete mode 100644 p2p/simulations/events.go delete mode 100644 p2p/simulations/examples/README.md delete mode 100644 p2p/simulations/examples/ping-pong.go delete mode 100755 p2p/simulations/examples/ping-pong.sh delete mode 100644 p2p/simulations/http.go delete mode 100644 p2p/simulations/http_test.go delete mode 100644 p2p/simulations/mocker.go delete mode 100644 p2p/simulations/mocker_test.go delete mode 100644 p2p/simulations/network.go delete mode 100644 p2p/simulations/network_test.go delete mode 100644 p2p/simulations/simulation.go delete mode 100644 p2p/simulations/test.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ec2efb10e3..b50561172f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -21,7 +21,4 @@ light/ @zsfelfoldi @rjl493456442 node/ @fjl p2p/ @fjl @zsfelfoldi rpc/ @fjl @holiman -p2p/simulations @fjl -p2p/protocols @fjl -p2p/testing @fjl signer/ @holiman diff --git a/cmd/p2psim/main.go b/cmd/p2psim/main.go deleted file mode 100644 index a0f5f0d288..0000000000 --- a/cmd/p2psim/main.go +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright 2017 The go-ethereum Authors -// This file is part of go-ethereum. -// -// go-ethereum is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// go-ethereum 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with go-ethereum. If not, see . - -// p2psim provides a command-line client for a simulation HTTP API. -// -// Here is an example of creating a 2 node network with the first node -// connected to the second: -// -// $ p2psim node create -// Created node01 -// -// $ p2psim node start node01 -// Started node01 -// -// $ p2psim node create -// Created node02 -// -// $ p2psim node start node02 -// Started node02 -// -// $ p2psim node connect node01 node02 -// Connected node01 to node02 -package main - -import ( - "context" - "encoding/json" - "fmt" - "io" - "os" - "strings" - "text/tabwriter" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/flags" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - "github.com/urfave/cli/v2" -) - -var client *simulations.Client - -var ( - // global command flags - apiFlag = &cli.StringFlag{ - Name: "api", - Value: "http://localhost:8888", - Usage: "simulation API URL", - EnvVars: []string{"P2PSIM_API_URL"}, - } - - // events subcommand flags - currentFlag = &cli.BoolFlag{ - Name: "current", - Usage: "get existing nodes and conns first", - } - filterFlag = &cli.StringFlag{ - Name: "filter", - Value: "", - Usage: "message filter", - } - - // node create subcommand flags - nameFlag = &cli.StringFlag{ - Name: "name", - Value: "", - Usage: "node name", - } - servicesFlag = &cli.StringFlag{ - Name: "services", - Value: "", - Usage: "node services (comma separated)", - } - keyFlag = &cli.StringFlag{ - Name: "key", - Value: "", - Usage: "node private key (hex encoded)", - } - - // node rpc subcommand flags - subscribeFlag = &cli.BoolFlag{ - Name: "subscribe", - Usage: "method is a subscription", - } -) - -func main() { - app := flags.NewApp("devp2p simulation command-line client") - app.Flags = []cli.Flag{ - apiFlag, - } - app.Before = func(ctx *cli.Context) error { - client = simulations.NewClient(ctx.String(apiFlag.Name)) - return nil - } - app.Commands = []*cli.Command{ - { - Name: "show", - Usage: "show network information", - Action: showNetwork, - }, - { - Name: "events", - Usage: "stream network events", - Action: streamNetwork, - Flags: []cli.Flag{ - currentFlag, - filterFlag, - }, - }, - { - Name: "snapshot", - Usage: "create a network snapshot to stdout", - Action: createSnapshot, - }, - { - Name: "load", - Usage: "load a network snapshot from stdin", - Action: loadSnapshot, - }, - { - Name: "node", - Usage: "manage simulation nodes", - Action: listNodes, - Subcommands: []*cli.Command{ - { - Name: "list", - Usage: "list nodes", - Action: listNodes, - }, - { - Name: "create", - Usage: "create a node", - Action: createNode, - Flags: []cli.Flag{ - nameFlag, - servicesFlag, - keyFlag, - }, - }, - { - Name: "show", - ArgsUsage: "", - Usage: "show node information", - Action: showNode, - }, - { - Name: "start", - ArgsUsage: "", - Usage: "start a node", - Action: startNode, - }, - { - Name: "stop", - ArgsUsage: "", - Usage: "stop a node", - Action: stopNode, - }, - { - Name: "connect", - ArgsUsage: " ", - Usage: "connect a node to a peer node", - Action: connectNode, - }, - { - Name: "disconnect", - ArgsUsage: " ", - Usage: "disconnect a node from a peer node", - Action: disconnectNode, - }, - { - Name: "rpc", - ArgsUsage: " []", - Usage: "call a node RPC method", - Action: rpcNode, - Flags: []cli.Flag{ - subscribeFlag, - }, - }, - }, - }, - } - if err := app.Run(os.Args); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func showNetwork(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - network, err := client.GetNetwork() - if err != nil { - return err - } - w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NODES\t%d\n", len(network.Nodes)) - fmt.Fprintf(w, "CONNS\t%d\n", len(network.Conns)) - return nil -} - -func streamNetwork(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - events := make(chan *simulations.Event) - sub, err := client.SubscribeNetwork(events, simulations.SubscribeOpts{ - Current: ctx.Bool(currentFlag.Name), - Filter: ctx.String(filterFlag.Name), - }) - if err != nil { - return err - } - defer sub.Unsubscribe() - enc := json.NewEncoder(ctx.App.Writer) - for { - select { - case event := <-events: - if err := enc.Encode(event); err != nil { - return err - } - case err := <-sub.Err(): - return err - } - } -} - -func createSnapshot(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - snap, err := client.CreateSnapshot() - if err != nil { - return err - } - return json.NewEncoder(os.Stdout).Encode(snap) -} - -func loadSnapshot(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - snap := &simulations.Snapshot{} - if err := json.NewDecoder(os.Stdin).Decode(snap); err != nil { - return err - } - return client.LoadSnapshot(snap) -} - -func listNodes(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodes, err := client.GetNodes() - if err != nil { - return err - } - w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NAME\tPROTOCOLS\tID\n") - for _, node := range nodes { - fmt.Fprintf(w, "%s\t%s\t%s\n", node.Name, strings.Join(protocolList(node), ","), node.ID) - } - return nil -} - -func protocolList(node *p2p.NodeInfo) []string { - protos := make([]string, 0, len(node.Protocols)) - for name := range node.Protocols { - protos = append(protos, name) - } - return protos -} - -func createNode(ctx *cli.Context) error { - if ctx.NArg() != 0 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - config := adapters.RandomNodeConfig() - config.Name = ctx.String(nameFlag.Name) - if key := ctx.String(keyFlag.Name); key != "" { - privKey, err := crypto.HexToECDSA(key) - if err != nil { - return err - } - config.ID = enode.PubkeyToIDV4(&privKey.PublicKey) - config.PrivateKey = privKey - } - if services := ctx.String(servicesFlag.Name); services != "" { - config.Lifecycles = strings.Split(services, ",") - } - node, err := client.CreateNode(config) - if err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Created", node.Name) - return nil -} - -func showNode(ctx *cli.Context) error { - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := ctx.Args().First() - node, err := client.GetNode(nodeName) - if err != nil { - return err - } - w := tabwriter.NewWriter(ctx.App.Writer, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintf(w, "NAME\t%s\n", node.Name) - fmt.Fprintf(w, "PROTOCOLS\t%s\n", strings.Join(protocolList(node), ",")) - fmt.Fprintf(w, "ID\t%s\n", node.ID) - fmt.Fprintf(w, "ENODE\t%s\n", node.Enode) - for name, proto := range node.Protocols { - fmt.Fprintln(w) - fmt.Fprintf(w, "--- PROTOCOL INFO: %s\n", name) - fmt.Fprintf(w, "%v\n", proto) - fmt.Fprintf(w, "---\n") - } - return nil -} - -func startNode(ctx *cli.Context) error { - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := ctx.Args().First() - if err := client.StartNode(nodeName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Started", nodeName) - return nil -} - -func stopNode(ctx *cli.Context) error { - if ctx.NArg() != 1 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := ctx.Args().First() - if err := client.StopNode(nodeName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Stopped", nodeName) - return nil -} - -func connectNode(ctx *cli.Context) error { - if ctx.NArg() != 2 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - args := ctx.Args() - nodeName := args.Get(0) - peerName := args.Get(1) - if err := client.ConnectNode(nodeName, peerName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Connected", nodeName, "to", peerName) - return nil -} - -func disconnectNode(ctx *cli.Context) error { - args := ctx.Args() - if args.Len() != 2 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := args.Get(0) - peerName := args.Get(1) - if err := client.DisconnectNode(nodeName, peerName); err != nil { - return err - } - fmt.Fprintln(ctx.App.Writer, "Disconnected", nodeName, "from", peerName) - return nil -} - -func rpcNode(ctx *cli.Context) error { - args := ctx.Args() - if args.Len() < 2 { - return cli.ShowCommandHelp(ctx, ctx.Command.Name) - } - nodeName := args.Get(0) - method := args.Get(1) - rpcClient, err := client.RPCClient(context.Background(), nodeName) - if err != nil { - return err - } - if ctx.Bool(subscribeFlag.Name) { - return rpcSubscribe(rpcClient, ctx.App.Writer, method, args.Slice()[3:]...) - } - var result interface{} - params := make([]interface{}, len(args.Slice()[3:])) - for i, v := range args.Slice()[3:] { - params[i] = v - } - if err := rpcClient.Call(&result, method, params...); err != nil { - return err - } - return json.NewEncoder(ctx.App.Writer).Encode(result) -} - -func rpcSubscribe(client *rpc.Client, out io.Writer, method string, args ...string) error { - namespace, method, _ := strings.Cut(method, "_") - ch := make(chan interface{}) - subArgs := make([]interface{}, len(args)+1) - subArgs[0] = method - for i, v := range args { - subArgs[i+1] = v - } - sub, err := client.Subscribe(context.Background(), namespace, ch, subArgs...) - if err != nil { - return err - } - defer sub.Unsubscribe() - enc := json.NewEncoder(out) - for { - select { - case v := <-ch: - if err := enc.Encode(v); err != nil { - return err - } - case err := <-sub.Err(): - return err - } - } -} diff --git a/p2p/simulations/pipes/pipes.go b/p2p/pipes/pipe.go similarity index 85% rename from p2p/simulations/pipes/pipes.go rename to p2p/pipes/pipe.go index ec277c0d14..cf1f3e2a80 100644 --- a/p2p/simulations/pipes/pipes.go +++ b/p2p/pipes/pipe.go @@ -1,4 +1,4 @@ -// Copyright 2018 The go-ethereum Authors +// Copyright 2024 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify @@ -16,17 +16,9 @@ package pipes -import ( - "net" -) +import "net" -// NetPipe wraps net.Pipe in a signature returning an error -func NetPipe() (net.Conn, net.Conn, error) { - p1, p2 := net.Pipe() - return p1, p2, nil -} - -// TCPPipe creates an in process full duplex pipe based on a localhost TCP socket +// TCPPipe creates an in process full duplex pipe based on a localhost TCP socket. func TCPPipe() (net.Conn, net.Conn, error) { l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { diff --git a/p2p/rlpx/rlpx_test.go b/p2p/rlpx/rlpx_test.go index 136cb1b5bf..27d51546e7 100644 --- a/p2p/rlpx/rlpx_test.go +++ b/p2p/rlpx/rlpx_test.go @@ -31,7 +31,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/ecies" - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" + "github.com/ethereum/go-ethereum/p2p/pipes" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/assert" ) diff --git a/p2p/simulations/README.md b/p2p/simulations/README.md deleted file mode 100644 index 1f9f72dcda..0000000000 --- a/p2p/simulations/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# devp2p Simulations - -The `p2p/simulations` package implements a simulation framework that supports -creating a collection of devp2p nodes, connecting them to form a -simulation network, performing simulation actions in that network and then -extracting useful information. - -## Nodes - -Each node in a simulation network runs multiple services by wrapping a collection -of objects which implement the `node.Service` interface meaning they: - -* can be started and stopped -* run p2p protocols -* expose RPC APIs - -This means that any object which implements the `node.Service` interface can be -used to run a node in the simulation. - -## Services - -Before running a simulation, a set of service initializers must be registered -which can then be used to run nodes in the network. - -A service initializer is a function with the following signature: - -```go -func(ctx *adapters.ServiceContext) (node.Service, error) -``` - -These initializers should be registered by calling the `adapters.RegisterServices` -function in an `init()` hook: - -```go -func init() { - adapters.RegisterServices(adapters.Services{ - "service1": initService1, - "service2": initService2, - }) -} -``` - -## Node Adapters - -The simulation framework includes multiple "node adapters" which are -responsible for creating an environment in which a node runs. - -### SimAdapter - -The `SimAdapter` runs nodes in-memory, connecting them using an in-memory, -synchronous `net.Pipe` and connecting to their RPC server using an in-memory -`rpc.Client`. - -### ExecAdapter - -The `ExecAdapter` runs nodes as child processes of the running simulation. - -It does this by executing the binary which is running the simulation but -setting `argv[0]` (i.e. the program name) to `p2p-node` which is then -detected by an init hook in the child process which runs the `node.Service` -using the devp2p node stack rather than executing `main()`. - -The nodes listen for devp2p connections and WebSocket RPC clients on random -localhost ports. - -## Network - -A simulation network is created with an ID and default service. The default -service is used if a node is created without an explicit service. The -network has exposed methods for creating, starting, stopping, connecting -and disconnecting nodes. It also emits events when certain actions occur. - -### Events - -A simulation network emits the following events: - -* node event - when nodes are created / started / stopped -* connection event - when nodes are connected / disconnected -* message event - when a protocol message is sent between two nodes - -The events have a "control" flag which when set indicates that the event is the -outcome of a controlled simulation action (e.g. creating a node or explicitly -connecting two nodes). - -This is in contrast to a non-control event, otherwise called a "live" event, -which is the outcome of something happening in the network as a result of a -control event (e.g. a node actually started up or a connection was actually -established between two nodes). - -Live events are detected by the simulation network by subscribing to node peer -events via RPC when the nodes start up. - -## Testing Framework - -The `Simulation` type can be used in tests to perform actions in a simulation -network and then wait for expectations to be met. - -With a running simulation network, the `Simulation.Run` method can be called -with a `Step` which has the following fields: - -* `Action` - a function that performs some action in the network - -* `Expect` - an expectation function which returns whether or not a - given node meets the expectation - -* `Trigger` - a channel that receives node IDs which then trigger a check - of the expectation function to be performed against that node - -As a concrete example, consider a simulated network of Ethereum nodes. An -`Action` could be the sending of a transaction, `Expect` it being included in -a block, and `Trigger` a check for every block that is mined. - -On return, the `Simulation.Run` method returns a `StepResult` which can be used -to determine if all nodes met the expectation, how long it took them to meet -the expectation and what network events were emitted during the step run. - -## HTTP API - -The simulation framework includes a HTTP API that can be used to control the -simulation. - -The API is initialised with a particular node adapter and has the following -endpoints: - -``` -OPTIONS / Response 200 with "Access-Control-Allow-Headers"" header set to "Content-Type"" -GET / Get network information -POST /start Start all nodes in the network -POST /stop Stop all nodes in the network -POST /mocker/start Start the mocker node simulation -POST /mocker/stop Stop the mocker node simulation -GET /mocker Get a list of available mockers -POST /reset Reset all properties of a network to initial (empty) state -GET /events Stream network events -GET /snapshot Take a network snapshot -POST /snapshot Load a network snapshot -POST /nodes Create a node -GET /nodes Get all nodes in the network -GET /nodes/:nodeid Get node information -POST /nodes/:nodeid/start Start a node -POST /nodes/:nodeid/stop Stop a node -POST /nodes/:nodeid/conn/:peerid Connect two nodes -DELETE /nodes/:nodeid/conn/:peerid Disconnect two nodes -GET /nodes/:nodeid/rpc Make RPC requests to a node via WebSocket -``` - -For convenience, `nodeid` in the URL can be the name of a node rather than its -ID. - -## Command line client - -`p2psim` is a command line client for the HTTP API, located in -`cmd/p2psim`. - -It provides the following commands: - -``` -p2psim show -p2psim events [--current] [--filter=FILTER] -p2psim snapshot -p2psim load -p2psim node create [--name=NAME] [--services=SERVICES] [--key=KEY] -p2psim node list -p2psim node show -p2psim node start -p2psim node stop -p2psim node connect -p2psim node disconnect -p2psim node rpc [] [--subscribe] -``` - -## Example - -See [p2p/simulations/examples/README.md](examples/README.md). diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go deleted file mode 100644 index 6307b90bf8..0000000000 --- a/p2p/simulations/adapters/exec.go +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright 2017 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 . - -package adapters - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "log/slog" - "net" - "net/http" - "os" - "os/exec" - "os/signal" - "path/filepath" - "strings" - "sync" - "syscall" - "time" - - "github.com/ethereum/go-ethereum/internal/reexec" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/rpc" - "github.com/gorilla/websocket" -) - -func init() { - // Register a reexec function to start a simulation node when the current binary is - // executed as "p2p-node" (rather than whatever the main() function would normally do). - reexec.Register("p2p-node", execP2PNode) -} - -// ExecAdapter is a NodeAdapter which runs simulation nodes by executing the current binary -// as a child process. -type ExecAdapter struct { - // BaseDir is the directory under which the data directories for each - // simulation node are created. - BaseDir string - - nodes map[enode.ID]*ExecNode -} - -// NewExecAdapter returns an ExecAdapter which stores node data in -// subdirectories of the given base directory -func NewExecAdapter(baseDir string) *ExecAdapter { - return &ExecAdapter{ - BaseDir: baseDir, - nodes: make(map[enode.ID]*ExecNode), - } -} - -// Name returns the name of the adapter for logging purposes -func (e *ExecAdapter) Name() string { - return "exec-adapter" -} - -// NewNode returns a new ExecNode using the given config -func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) { - if len(config.Lifecycles) == 0 { - return nil, errors.New("node must have at least one service lifecycle") - } - for _, service := range config.Lifecycles { - if _, exists := lifecycleConstructorFuncs[service]; !exists { - return nil, fmt.Errorf("unknown node service %q", service) - } - } - - // create the node directory using the first 12 characters of the ID - // as Unix socket paths cannot be longer than 256 characters - dir := filepath.Join(e.BaseDir, config.ID.String()[:12]) - if err := os.Mkdir(dir, 0755); err != nil { - return nil, fmt.Errorf("error creating node directory: %s", err) - } - - err := config.initDummyEnode() - if err != nil { - return nil, err - } - - // generate the config - conf := &execNodeConfig{ - Stack: node.DefaultConfig, - Node: config, - } - if config.DataDir != "" { - conf.Stack.DataDir = config.DataDir - } else { - conf.Stack.DataDir = filepath.Join(dir, "data") - } - - // these parameters are crucial for execadapter node to run correctly - conf.Stack.WSHost = "127.0.0.1" - conf.Stack.WSPort = 0 - conf.Stack.WSOrigins = []string{"*"} - conf.Stack.WSExposeAll = true - conf.Stack.P2P.EnableMsgEvents = config.EnableMsgEvents - conf.Stack.P2P.NoDiscovery = true - conf.Stack.P2P.NAT = nil - - // Listen on a localhost port, which we set when we - // initialise NodeConfig (usually a random port) - conf.Stack.P2P.ListenAddr = fmt.Sprintf(":%d", config.Port) - - node := &ExecNode{ - ID: config.ID, - Dir: dir, - Config: conf, - adapter: e, - } - node.newCmd = node.execCommand - e.nodes[node.ID] = node - return node, nil -} - -// ExecNode starts a simulation node by exec'ing the current binary and -// running the configured services -type ExecNode struct { - ID enode.ID - Dir string - Config *execNodeConfig - Cmd *exec.Cmd - Info *p2p.NodeInfo - - adapter *ExecAdapter - client *rpc.Client - wsAddr string - newCmd func() *exec.Cmd -} - -// Addr returns the node's enode URL -func (n *ExecNode) Addr() []byte { - if n.Info == nil { - return nil - } - return []byte(n.Info.Enode) -} - -// Client returns an rpc.Client which can be used to communicate with the -// underlying services (it is set once the node has started) -func (n *ExecNode) Client() (*rpc.Client, error) { - return n.client, nil -} - -// Start exec's the node passing the ID and service as command line arguments -// and the node config encoded as JSON in an environment variable. -func (n *ExecNode) Start(snapshots map[string][]byte) (err error) { - if n.Cmd != nil { - return errors.New("already started") - } - defer func() { - if err != nil { - n.Stop() - } - }() - - // encode a copy of the config containing the snapshot - confCopy := *n.Config - confCopy.Snapshots = snapshots - confCopy.PeerAddrs = make(map[string]string) - for id, node := range n.adapter.nodes { - confCopy.PeerAddrs[id.String()] = node.wsAddr - } - confData, err := json.Marshal(confCopy) - if err != nil { - return fmt.Errorf("error generating node config: %s", err) - } - // expose the admin namespace via websocket if it's not enabled - exposed := confCopy.Stack.WSExposeAll - if !exposed { - for _, api := range confCopy.Stack.WSModules { - if api == "admin" { - exposed = true - break - } - } - } - if !exposed { - confCopy.Stack.WSModules = append(confCopy.Stack.WSModules, "admin") - } - // start the one-shot server that waits for startup information - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - statusURL, statusC := n.waitForStartupJSON(ctx) - - // start the node - cmd := n.newCmd() - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Env = append(os.Environ(), - envStatusURL+"="+statusURL, - envNodeConfig+"="+string(confData), - ) - if err := cmd.Start(); err != nil { - return fmt.Errorf("error starting node: %s", err) - } - n.Cmd = cmd - - // Wait for the node to start. - status := <-statusC - if status.Err != "" { - return errors.New(status.Err) - } - client, err := rpc.DialWebsocket(ctx, status.WSEndpoint, "") - if err != nil { - return fmt.Errorf("can't connect to RPC server: %v", err) - } - - // Node ready :) - n.client = client - n.wsAddr = status.WSEndpoint - n.Info = status.NodeInfo - return nil -} - -// waitForStartupJSON runs a one-shot HTTP server to receive a startup report. -func (n *ExecNode) waitForStartupJSON(ctx context.Context) (string, chan nodeStartupJSON) { - var ( - ch = make(chan nodeStartupJSON, 1) - quitOnce sync.Once - srv http.Server - ) - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - ch <- nodeStartupJSON{Err: err.Error()} - return "", ch - } - quit := func(status nodeStartupJSON) { - quitOnce.Do(func() { - l.Close() - ch <- status - }) - } - srv.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var status nodeStartupJSON - if err := json.NewDecoder(r.Body).Decode(&status); err != nil { - status.Err = fmt.Sprintf("can't decode startup report: %v", err) - } - quit(status) - }) - // Run the HTTP server, but don't wait forever and shut it down - // if the context is canceled. - go srv.Serve(l) - go func() { - <-ctx.Done() - quit(nodeStartupJSON{Err: "didn't get startup report"}) - }() - - url := "http://" + l.Addr().String() - return url, ch -} - -// execCommand returns a command which runs the node locally by exec'ing -// the current binary but setting argv[0] to "p2p-node" so that the child -// runs execP2PNode -func (n *ExecNode) execCommand() *exec.Cmd { - return &exec.Cmd{ - Path: reexec.Self(), - Args: []string{"p2p-node", strings.Join(n.Config.Node.Lifecycles, ","), n.ID.String()}, - } -} - -// Stop stops the node by first sending SIGTERM and then SIGKILL if the node -// doesn't stop within 5s -func (n *ExecNode) Stop() error { - if n.Cmd == nil { - return nil - } - defer func() { - n.Cmd = nil - }() - - if n.client != nil { - n.client.Close() - n.client = nil - n.wsAddr = "" - n.Info = nil - } - - if err := n.Cmd.Process.Signal(syscall.SIGTERM); err != nil { - return n.Cmd.Process.Kill() - } - waitErr := make(chan error, 1) - go func() { - waitErr <- n.Cmd.Wait() - }() - timer := time.NewTimer(5 * time.Second) - defer timer.Stop() - - select { - case err := <-waitErr: - return err - case <-timer.C: - return n.Cmd.Process.Kill() - } -} - -// NodeInfo returns information about the node -func (n *ExecNode) NodeInfo() *p2p.NodeInfo { - info := &p2p.NodeInfo{ - ID: n.ID.String(), - } - if n.client != nil { - n.client.Call(&info, "admin_nodeInfo") - } - return info -} - -// ServeRPC serves RPC requests over the given connection by dialling the -// node's WebSocket address and joining the two connections -func (n *ExecNode) ServeRPC(clientConn *websocket.Conn) error { - conn, _, err := websocket.DefaultDialer.Dial(n.wsAddr, nil) - if err != nil { - return err - } - var wg sync.WaitGroup - wg.Add(2) - go wsCopy(&wg, conn, clientConn) - go wsCopy(&wg, clientConn, conn) - wg.Wait() - conn.Close() - return nil -} - -func wsCopy(wg *sync.WaitGroup, src, dst *websocket.Conn) { - defer wg.Done() - for { - msgType, r, err := src.NextReader() - if err != nil { - return - } - w, err := dst.NextWriter(msgType) - if err != nil { - return - } - if _, err = io.Copy(w, r); err != nil { - return - } - } -} - -// Snapshots creates snapshots of the services by calling the -// simulation_snapshot RPC method -func (n *ExecNode) Snapshots() (map[string][]byte, error) { - if n.client == nil { - return nil, errors.New("RPC not started") - } - var snapshots map[string][]byte - return snapshots, n.client.Call(&snapshots, "simulation_snapshot") -} - -// execNodeConfig is used to serialize the node configuration so it can be -// passed to the child process as a JSON encoded environment variable -type execNodeConfig struct { - Stack node.Config `json:"stack"` - Node *NodeConfig `json:"node"` - Snapshots map[string][]byte `json:"snapshots,omitempty"` - PeerAddrs map[string]string `json:"peer_addrs,omitempty"` -} - -func initLogging() { - // Initialize the logging by default first. - var innerHandler slog.Handler - innerHandler = slog.NewTextHandler(os.Stderr, nil) - glogger := log.NewGlogHandler(innerHandler) - glogger.Verbosity(log.LevelInfo) - log.SetDefault(log.NewLogger(glogger)) - - confEnv := os.Getenv(envNodeConfig) - if confEnv == "" { - return - } - var conf execNodeConfig - if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { - return - } - var writer = os.Stderr - if conf.Node.LogFile != "" { - logWriter, err := os.Create(conf.Node.LogFile) - if err != nil { - return - } - writer = logWriter - } - var verbosity = log.LevelInfo - if conf.Node.LogVerbosity <= log.LevelTrace && conf.Node.LogVerbosity >= log.LevelCrit { - verbosity = log.FromLegacyLevel(int(conf.Node.LogVerbosity)) - } - // Reinitialize the logger - innerHandler = log.NewTerminalHandler(writer, true) - glogger = log.NewGlogHandler(innerHandler) - glogger.Verbosity(verbosity) - log.SetDefault(log.NewLogger(glogger)) -} - -// execP2PNode starts a simulation node when the current binary is executed with -// argv[0] being "p2p-node", reading the service / ID from argv[1] / argv[2] -// and the node config from an environment variable. -func execP2PNode() { - initLogging() - - statusURL := os.Getenv(envStatusURL) - if statusURL == "" { - log.Crit("missing " + envStatusURL) - } - - // Start the node and gather startup report. - var status nodeStartupJSON - stack, stackErr := startExecNodeStack() - if stackErr != nil { - status.Err = stackErr.Error() - } else { - status.WSEndpoint = stack.WSEndpoint() - status.NodeInfo = stack.Server().NodeInfo() - } - - // Send status to the host. - statusJSON, _ := json.Marshal(status) - resp, err := http.Post(statusURL, "application/json", bytes.NewReader(statusJSON)) - if err != nil { - log.Crit("Can't post startup info", "url", statusURL, "err", err) - } - resp.Body.Close() - if stackErr != nil { - os.Exit(1) - } - - // Stop the stack if we get a SIGTERM signal. - go func() { - sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGTERM) - defer signal.Stop(sigc) - <-sigc - log.Info("Received SIGTERM, shutting down...") - stack.Close() - }() - stack.Wait() // Wait for the stack to exit. -} - -func startExecNodeStack() (*node.Node, error) { - // read the services from argv - serviceNames := strings.Split(os.Args[1], ",") - - // decode the config - confEnv := os.Getenv(envNodeConfig) - if confEnv == "" { - return nil, errors.New("missing " + envNodeConfig) - } - var conf execNodeConfig - if err := json.Unmarshal([]byte(confEnv), &conf); err != nil { - return nil, fmt.Errorf("error decoding %s: %v", envNodeConfig, err) - } - - // create enode record - nodeTcpConn, _ := net.ResolveTCPAddr("tcp", conf.Stack.P2P.ListenAddr) - if nodeTcpConn.IP == nil { - nodeTcpConn.IP = net.IPv4(127, 0, 0, 1) - } - conf.Node.initEnode(nodeTcpConn.IP, nodeTcpConn.Port, nodeTcpConn.Port) - conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey - conf.Stack.Logger = log.New("node.id", conf.Node.ID.String()) - - // initialize the devp2p stack - stack, err := node.New(&conf.Stack) - if err != nil { - return nil, fmt.Errorf("error creating node stack: %v", err) - } - - // Register the services, collecting them into a map so they can - // be accessed by the snapshot API. - services := make(map[string]node.Lifecycle, len(serviceNames)) - for _, name := range serviceNames { - lifecycleFunc, exists := lifecycleConstructorFuncs[name] - if !exists { - return nil, fmt.Errorf("unknown node service %q", err) - } - ctx := &ServiceContext{ - RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs}, - Config: conf.Node, - } - if conf.Snapshots != nil { - ctx.Snapshot = conf.Snapshots[name] - } - service, err := lifecycleFunc(ctx, stack) - if err != nil { - return nil, err - } - services[name] = service - } - - // Add the snapshot API. - stack.RegisterAPIs([]rpc.API{{ - Namespace: "simulation", - Service: SnapshotAPI{services}, - }}) - - if err = stack.Start(); err != nil { - err = fmt.Errorf("error starting stack: %v", err) - } - return stack, err -} - -const ( - envStatusURL = "_P2P_STATUS_URL" - envNodeConfig = "_P2P_NODE_CONFIG" -) - -// nodeStartupJSON is sent to the simulation host after startup. -type nodeStartupJSON struct { - Err string - WSEndpoint string - NodeInfo *p2p.NodeInfo -} - -// SnapshotAPI provides an RPC method to create snapshots of services -type SnapshotAPI struct { - services map[string]node.Lifecycle -} - -func (api SnapshotAPI) Snapshot() (map[string][]byte, error) { - snapshots := make(map[string][]byte) - for name, service := range api.services { - if s, ok := service.(interface { - Snapshot() ([]byte, error) - }); ok { - snap, err := s.Snapshot() - if err != nil { - return nil, err - } - snapshots[name] = snap - } - } - return snapshots, nil -} - -type wsRPCDialer struct { - addrs map[string]string -} - -// DialRPC implements the RPCDialer interface by creating a WebSocket RPC -// client of the given node -func (w *wsRPCDialer) DialRPC(id enode.ID) (*rpc.Client, error) { - addr, ok := w.addrs[id.String()] - if !ok { - return nil, fmt.Errorf("unknown node: %s", id) - } - return rpc.DialWebsocket(context.Background(), addr, "http://localhost") -} diff --git a/p2p/simulations/adapters/inproc.go b/p2p/simulations/adapters/inproc.go deleted file mode 100644 index 0efe9744a5..0000000000 --- a/p2p/simulations/adapters/inproc.go +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2017 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 . - -package adapters - -import ( - "context" - "errors" - "fmt" - "maps" - "math" - "net" - "sync" - - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" - "github.com/ethereum/go-ethereum/rpc" - "github.com/gorilla/websocket" -) - -// SimAdapter is a NodeAdapter which creates in-memory simulation nodes and -// connects them using net.Pipe -type SimAdapter struct { - pipe func() (net.Conn, net.Conn, error) - mtx sync.RWMutex - nodes map[enode.ID]*SimNode - lifecycles LifecycleConstructors -} - -// NewSimAdapter creates a SimAdapter which is capable of running in-memory -// simulation nodes running any of the given services (the services to run on a -// particular node are passed to the NewNode function in the NodeConfig) -// the adapter uses a net.Pipe for in-memory simulated network connections -func NewSimAdapter(services LifecycleConstructors) *SimAdapter { - return &SimAdapter{ - pipe: pipes.NetPipe, - nodes: make(map[enode.ID]*SimNode), - lifecycles: services, - } -} - -// Name returns the name of the adapter for logging purposes -func (s *SimAdapter) Name() string { - return "sim-adapter" -} - -// NewNode returns a new SimNode using the given config -func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) { - s.mtx.Lock() - defer s.mtx.Unlock() - - id := config.ID - // verify that the node has a private key in the config - if config.PrivateKey == nil { - return nil, fmt.Errorf("node is missing private key: %s", id) - } - - // check a node with the ID doesn't already exist - if _, exists := s.nodes[id]; exists { - return nil, fmt.Errorf("node already exists: %s", id) - } - - // check the services are valid - if len(config.Lifecycles) == 0 { - return nil, errors.New("node must have at least one service") - } - for _, service := range config.Lifecycles { - if _, exists := s.lifecycles[service]; !exists { - return nil, fmt.Errorf("unknown node service %q", service) - } - } - - err := config.initDummyEnode() - if err != nil { - return nil, err - } - - n, err := node.New(&node.Config{ - P2P: p2p.Config{ - PrivateKey: config.PrivateKey, - MaxPeers: math.MaxInt32, - NoDiscovery: true, - Dialer: s, - EnableMsgEvents: config.EnableMsgEvents, - }, - ExternalSigner: config.ExternalSigner, - Logger: log.New("node.id", id.String()), - }) - if err != nil { - return nil, err - } - - simNode := &SimNode{ - ID: id, - config: config, - node: n, - adapter: s, - running: make(map[string]node.Lifecycle), - } - s.nodes[id] = simNode - return simNode, nil -} - -// Dial implements the p2p.NodeDialer interface by connecting to the node using -// an in-memory net.Pipe -func (s *SimAdapter) Dial(ctx context.Context, dest *enode.Node) (conn net.Conn, err error) { - node, ok := s.GetNode(dest.ID()) - if !ok { - return nil, fmt.Errorf("unknown node: %s", dest.ID()) - } - srv := node.Server() - if srv == nil { - return nil, fmt.Errorf("node not running: %s", dest.ID()) - } - // SimAdapter.pipe is net.Pipe (NewSimAdapter) - pipe1, pipe2, err := s.pipe() - if err != nil { - return nil, err - } - // this is simulated 'listening' - // asynchronously call the dialed destination node's p2p server - // to set up connection on the 'listening' side - go srv.SetupConn(pipe1, 0, nil) - return pipe2, nil -} - -// DialRPC implements the RPCDialer interface by creating an in-memory RPC -// client of the given node -func (s *SimAdapter) DialRPC(id enode.ID) (*rpc.Client, error) { - node, ok := s.GetNode(id) - if !ok { - return nil, fmt.Errorf("unknown node: %s", id) - } - return node.node.Attach(), nil -} - -// GetNode returns the node with the given ID if it exists -func (s *SimAdapter) GetNode(id enode.ID) (*SimNode, bool) { - s.mtx.RLock() - defer s.mtx.RUnlock() - node, ok := s.nodes[id] - return node, ok -} - -// SimNode is an in-memory simulation node which connects to other nodes using -// net.Pipe (see SimAdapter.Dial), running devp2p protocols directly over that -// pipe -type SimNode struct { - lock sync.RWMutex - ID enode.ID - config *NodeConfig - adapter *SimAdapter - node *node.Node - running map[string]node.Lifecycle - client *rpc.Client - registerOnce sync.Once -} - -// Close closes the underlying node.Node to release -// acquired resources. -func (sn *SimNode) Close() error { - return sn.node.Close() -} - -// Addr returns the node's discovery address -func (sn *SimNode) Addr() []byte { - return []byte(sn.Node().String()) -} - -// Node returns a node descriptor representing the SimNode -func (sn *SimNode) Node() *enode.Node { - return sn.config.Node() -} - -// Client returns an rpc.Client which can be used to communicate with the -// underlying services (it is set once the node has started) -func (sn *SimNode) Client() (*rpc.Client, error) { - sn.lock.RLock() - defer sn.lock.RUnlock() - if sn.client == nil { - return nil, errors.New("node not started") - } - return sn.client, nil -} - -// ServeRPC serves RPC requests over the given connection by creating an -// in-memory client to the node's RPC server. -func (sn *SimNode) ServeRPC(conn *websocket.Conn) error { - handler, err := sn.node.RPCHandler() - if err != nil { - return err - } - codec := rpc.NewFuncCodec(conn, func(v any, _ bool) error { return conn.WriteJSON(v) }, conn.ReadJSON) - handler.ServeCodec(codec, 0) - return nil -} - -// Snapshots creates snapshots of the services by calling the -// simulation_snapshot RPC method -func (sn *SimNode) Snapshots() (map[string][]byte, error) { - sn.lock.RLock() - services := maps.Clone(sn.running) - sn.lock.RUnlock() - if len(services) == 0 { - return nil, errors.New("no running services") - } - snapshots := make(map[string][]byte) - for name, service := range services { - if s, ok := service.(interface { - Snapshot() ([]byte, error) - }); ok { - snap, err := s.Snapshot() - if err != nil { - return nil, err - } - snapshots[name] = snap - } - } - return snapshots, nil -} - -// Start registers the services and starts the underlying devp2p node -func (sn *SimNode) Start(snapshots map[string][]byte) error { - // ensure we only register the services once in the case of the node - // being stopped and then started again - var regErr error - sn.registerOnce.Do(func() { - for _, name := range sn.config.Lifecycles { - ctx := &ServiceContext{ - RPCDialer: sn.adapter, - Config: sn.config, - } - if snapshots != nil { - ctx.Snapshot = snapshots[name] - } - serviceFunc := sn.adapter.lifecycles[name] - service, err := serviceFunc(ctx, sn.node) - if err != nil { - regErr = err - break - } - // if the service has already been registered, don't register it again. - if _, ok := sn.running[name]; ok { - continue - } - sn.running[name] = service - } - }) - if regErr != nil { - return regErr - } - - if err := sn.node.Start(); err != nil { - return err - } - - // create an in-process RPC client - client := sn.node.Attach() - sn.lock.Lock() - sn.client = client - sn.lock.Unlock() - - return nil -} - -// Stop closes the RPC client and stops the underlying devp2p node -func (sn *SimNode) Stop() error { - sn.lock.Lock() - if sn.client != nil { - sn.client.Close() - sn.client = nil - } - sn.lock.Unlock() - return sn.node.Close() -} - -// Service returns a running service by name -func (sn *SimNode) Service(name string) node.Lifecycle { - sn.lock.RLock() - defer sn.lock.RUnlock() - return sn.running[name] -} - -// Services returns a copy of the underlying services -func (sn *SimNode) Services() []node.Lifecycle { - sn.lock.RLock() - defer sn.lock.RUnlock() - services := make([]node.Lifecycle, 0, len(sn.running)) - for _, service := range sn.running { - services = append(services, service) - } - return services -} - -// ServiceMap returns a map by names of the underlying services -func (sn *SimNode) ServiceMap() map[string]node.Lifecycle { - sn.lock.RLock() - defer sn.lock.RUnlock() - return maps.Clone(sn.running) -} - -// Server returns the underlying p2p.Server -func (sn *SimNode) Server() *p2p.Server { - return sn.node.Server() -} - -// SubscribeEvents subscribes the given channel to peer events from the -// underlying p2p.Server -func (sn *SimNode) SubscribeEvents(ch chan *p2p.PeerEvent) event.Subscription { - srv := sn.Server() - if srv == nil { - panic("node not running") - } - return srv.SubscribeEvents(ch) -} - -// NodeInfo returns information about the node -func (sn *SimNode) NodeInfo() *p2p.NodeInfo { - server := sn.Server() - if server == nil { - return &p2p.NodeInfo{ - ID: sn.ID.String(), - Enode: sn.Node().String(), - } - } - return server.NodeInfo() -} diff --git a/p2p/simulations/adapters/inproc_test.go b/p2p/simulations/adapters/inproc_test.go deleted file mode 100644 index d0539ca867..0000000000 --- a/p2p/simulations/adapters/inproc_test.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2018 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 . - -package adapters - -import ( - "bytes" - "encoding/binary" - "fmt" - "sync" - "testing" - - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" -) - -func TestTCPPipe(t *testing.T) { - c1, c2, err := pipes.TCPPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 50 - size := 1024 - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - if _, err := c1.Write(msg); err != nil { - t.Fatal(err) - } - } - - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - out := make([]byte, size) - if _, err := c2.Read(out); err != nil { - t.Fatal(err) - } - if !bytes.Equal(msg, out) { - t.Fatalf("expected %#v, got %#v", msg, out) - } - } -} - -func TestTCPPipeBidirections(t *testing.T) { - c1, c2, err := pipes.TCPPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 50 - size := 7 - for i := 0; i < msgs; i++ { - msg := []byte(fmt.Sprintf("ping %02d", i)) - if _, err := c1.Write(msg); err != nil { - t.Fatal(err) - } - } - - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf("ping %02d", i)) - out := make([]byte, size) - if _, err := c2.Read(out); err != nil { - t.Fatal(err) - } - - if !bytes.Equal(expected, out) { - t.Fatalf("expected %#v, got %#v", expected, out) - } else { - msg := []byte(fmt.Sprintf("pong %02d", i)) - if _, err := c2.Write(msg); err != nil { - t.Fatal(err) - } - } - } - - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf("pong %02d", i)) - out := make([]byte, size) - if _, err := c1.Read(out); err != nil { - t.Fatal(err) - } - if !bytes.Equal(expected, out) { - t.Fatalf("expected %#v, got %#v", expected, out) - } - } -} - -func TestNetPipe(t *testing.T) { - c1, c2, err := pipes.NetPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 50 - size := 1024 - var wg sync.WaitGroup - defer wg.Wait() - - // netPipe is blocking, so writes are emitted asynchronously - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - if _, err := c1.Write(msg); err != nil { - t.Error(err) - } - } - }() - - for i := 0; i < msgs; i++ { - msg := make([]byte, size) - binary.PutUvarint(msg, uint64(i)) - out := make([]byte, size) - if _, err := c2.Read(out); err != nil { - t.Error(err) - } - if !bytes.Equal(msg, out) { - t.Errorf("expected %#v, got %#v", msg, out) - } - } -} - -func TestNetPipeBidirections(t *testing.T) { - c1, c2, err := pipes.NetPipe() - if err != nil { - t.Fatal(err) - } - - msgs := 1000 - size := 8 - pingTemplate := "ping %03d" - pongTemplate := "pong %03d" - var wg sync.WaitGroup - defer wg.Wait() - - // netPipe is blocking, so writes are emitted asynchronously - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - msg := []byte(fmt.Sprintf(pingTemplate, i)) - if _, err := c1.Write(msg); err != nil { - t.Error(err) - } - } - }() - - // netPipe is blocking, so reads for pong are emitted asynchronously - wg.Add(1) - go func() { - defer wg.Done() - - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf(pongTemplate, i)) - out := make([]byte, size) - if _, err := c1.Read(out); err != nil { - t.Error(err) - } - if !bytes.Equal(expected, out) { - t.Errorf("expected %#v, got %#v", expected, out) - } - } - }() - - // expect to read pings, and respond with pongs to the alternate connection - for i := 0; i < msgs; i++ { - expected := []byte(fmt.Sprintf(pingTemplate, i)) - - out := make([]byte, size) - _, err := c2.Read(out) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(expected, out) { - t.Errorf("expected %#v, got %#v", expected, out) - } else { - msg := []byte(fmt.Sprintf(pongTemplate, i)) - if _, err := c2.Write(msg); err != nil { - t.Fatal(err) - } - } - } -} diff --git a/p2p/simulations/adapters/types.go b/p2p/simulations/adapters/types.go deleted file mode 100644 index e18aaacc33..0000000000 --- a/p2p/simulations/adapters/types.go +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2017 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 . - -package adapters - -import ( - "crypto/ecdsa" - "encoding/hex" - "encoding/json" - "fmt" - "log/slog" - "net" - "os" - "strconv" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/internal/reexec" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rpc" - "github.com/gorilla/websocket" -) - -// Node represents a node in a simulation network which is created by a -// NodeAdapter, for example: -// -// - SimNode, an in-memory node in the same process -// - ExecNode, a child process node -type Node interface { - // Addr returns the node's address (e.g. an Enode URL) - Addr() []byte - - // Client returns the RPC client which is created once the node is - // up and running - Client() (*rpc.Client, error) - - // ServeRPC serves RPC requests over the given connection - ServeRPC(*websocket.Conn) error - - // Start starts the node with the given snapshots - Start(snapshots map[string][]byte) error - - // Stop stops the node - Stop() error - - // NodeInfo returns information about the node - NodeInfo() *p2p.NodeInfo - - // Snapshots creates snapshots of the running services - Snapshots() (map[string][]byte, error) -} - -// NodeAdapter is used to create Nodes in a simulation network -type NodeAdapter interface { - // Name returns the name of the adapter for logging purposes - Name() string - - // NewNode creates a new node with the given configuration - NewNode(config *NodeConfig) (Node, error) -} - -// NodeConfig is the configuration used to start a node in a simulation -// network -type NodeConfig struct { - // ID is the node's ID which is used to identify the node in the - // simulation network - ID enode.ID - - // PrivateKey is the node's private key which is used by the devp2p - // stack to encrypt communications - PrivateKey *ecdsa.PrivateKey - - // Enable peer events for Msgs - EnableMsgEvents bool - - // Name is a human friendly name for the node like "node01" - Name string - - // Use an existing database instead of a temporary one if non-empty - DataDir string - - // Lifecycles are the names of the service lifecycles which should be run when - // starting the node (for SimNodes it should be the names of service lifecycles - // contained in SimAdapter.lifecycles, for other nodes it should be - // service lifecycles registered by calling the RegisterLifecycle function) - Lifecycles []string - - // Properties are the names of the properties this node should hold - // within running services (e.g. "bootnode", "lightnode" or any custom values) - // These values need to be checked and acted upon by node Services - Properties []string - - // ExternalSigner specifies an external URI for a clef-type signer - ExternalSigner string - - // Enode - node *enode.Node - - // ENR Record with entries to overwrite - Record enr.Record - - // function to sanction or prevent suggesting a peer - Reachable func(id enode.ID) bool - - Port uint16 - - // LogFile is the log file name of the p2p node at runtime. - // - // The default value is empty so that the default log writer - // is the system standard output. - LogFile string - - // LogVerbosity is the log verbosity of the p2p node at runtime. - // - // The default verbosity is INFO. - LogVerbosity slog.Level -} - -// nodeConfigJSON is used to encode and decode NodeConfig as JSON by encoding -// all fields as strings -type nodeConfigJSON struct { - ID string `json:"id"` - PrivateKey string `json:"private_key"` - Name string `json:"name"` - Lifecycles []string `json:"lifecycles"` - Properties []string `json:"properties"` - EnableMsgEvents bool `json:"enable_msg_events"` - Port uint16 `json:"port"` - LogFile string `json:"logfile"` - LogVerbosity int `json:"log_verbosity"` -} - -// MarshalJSON implements the json.Marshaler interface by encoding the config -// fields as strings -func (n *NodeConfig) MarshalJSON() ([]byte, error) { - confJSON := nodeConfigJSON{ - ID: n.ID.String(), - Name: n.Name, - Lifecycles: n.Lifecycles, - Properties: n.Properties, - Port: n.Port, - EnableMsgEvents: n.EnableMsgEvents, - LogFile: n.LogFile, - LogVerbosity: int(n.LogVerbosity), - } - if n.PrivateKey != nil { - confJSON.PrivateKey = hex.EncodeToString(crypto.FromECDSA(n.PrivateKey)) - } - return json.Marshal(confJSON) -} - -// UnmarshalJSON implements the json.Unmarshaler interface by decoding the json -// string values into the config fields -func (n *NodeConfig) UnmarshalJSON(data []byte) error { - var confJSON nodeConfigJSON - if err := json.Unmarshal(data, &confJSON); err != nil { - return err - } - - if confJSON.ID != "" { - if err := n.ID.UnmarshalText([]byte(confJSON.ID)); err != nil { - return err - } - } - - if confJSON.PrivateKey != "" { - key, err := hex.DecodeString(confJSON.PrivateKey) - if err != nil { - return err - } - privKey, err := crypto.ToECDSA(key) - if err != nil { - return err - } - n.PrivateKey = privKey - } - - n.Name = confJSON.Name - n.Lifecycles = confJSON.Lifecycles - n.Properties = confJSON.Properties - n.Port = confJSON.Port - n.EnableMsgEvents = confJSON.EnableMsgEvents - n.LogFile = confJSON.LogFile - n.LogVerbosity = slog.Level(confJSON.LogVerbosity) - - return nil -} - -// Node returns the node descriptor represented by the config. -func (n *NodeConfig) Node() *enode.Node { - return n.node -} - -// RandomNodeConfig returns node configuration with a randomly generated ID and -// PrivateKey -func RandomNodeConfig() *NodeConfig { - prvkey, err := crypto.GenerateKey() - if err != nil { - panic("unable to generate key") - } - - port, err := assignTCPPort() - if err != nil { - panic("unable to assign tcp port") - } - - enodId := enode.PubkeyToIDV4(&prvkey.PublicKey) - return &NodeConfig{ - PrivateKey: prvkey, - ID: enodId, - Name: fmt.Sprintf("node_%s", enodId.String()), - Port: port, - EnableMsgEvents: true, - LogVerbosity: log.LvlInfo, - } -} - -func assignTCPPort() (uint16, error) { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - return 0, err - } - l.Close() - _, port, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return 0, err - } - p, err := strconv.ParseUint(port, 10, 16) - if err != nil { - return 0, err - } - return uint16(p), nil -} - -// ServiceContext is a collection of options and methods which can be utilised -// when starting services -type ServiceContext struct { - RPCDialer - - Config *NodeConfig - Snapshot []byte -} - -// RPCDialer is used when initialising services which need to connect to -// other nodes in the network (for example a simulated Swarm node which needs -// to connect to a Geth node to resolve ENS names) -type RPCDialer interface { - DialRPC(id enode.ID) (*rpc.Client, error) -} - -// LifecycleConstructor allows a Lifecycle to be constructed during node start-up. -// While the service-specific package usually takes care of Lifecycle creation and registration, -// for testing purposes, it is useful to be able to construct a Lifecycle on spot. -type LifecycleConstructor func(ctx *ServiceContext, stack *node.Node) (node.Lifecycle, error) - -// LifecycleConstructors stores LifecycleConstructor functions to call during node start-up. -type LifecycleConstructors map[string]LifecycleConstructor - -// lifecycleConstructorFuncs is a map of registered services which are used to boot devp2p -// nodes -var lifecycleConstructorFuncs = make(LifecycleConstructors) - -// RegisterLifecycles registers the given Services which can then be used to -// start devp2p nodes using either the Exec or Docker adapters. -// -// It should be called in an init function so that it has the opportunity to -// execute the services before main() is called. -func RegisterLifecycles(lifecycles LifecycleConstructors) { - for name, f := range lifecycles { - if _, exists := lifecycleConstructorFuncs[name]; exists { - panic(fmt.Sprintf("node service already exists: %q", name)) - } - lifecycleConstructorFuncs[name] = f - } - - // now we have registered the services, run reexec.Init() which will - // potentially start one of the services if the current binary has - // been exec'd with argv[0] set to "p2p-node" - if reexec.Init() { - os.Exit(0) - } -} - -// adds the host part to the configuration's ENR, signs it -// creates and adds the corresponding enode object to the configuration -func (n *NodeConfig) initEnode(ip net.IP, tcpport int, udpport int) error { - enrIp := enr.IP(ip) - n.Record.Set(&enrIp) - enrTcpPort := enr.TCP(tcpport) - n.Record.Set(&enrTcpPort) - enrUdpPort := enr.UDP(udpport) - n.Record.Set(&enrUdpPort) - - err := enode.SignV4(&n.Record, n.PrivateKey) - if err != nil { - return fmt.Errorf("unable to generate ENR: %v", err) - } - nod, err := enode.New(enode.V4ID{}, &n.Record) - if err != nil { - return fmt.Errorf("unable to create enode: %v", err) - } - log.Trace("simnode new", "record", n.Record) - n.node = nod - return nil -} - -func (n *NodeConfig) initDummyEnode() error { - return n.initEnode(net.IPv4(127, 0, 0, 1), int(n.Port), 0) -} diff --git a/p2p/simulations/connect.go b/p2p/simulations/connect.go deleted file mode 100644 index ede96b34c1..0000000000 --- a/p2p/simulations/connect.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2018 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 . - -package simulations - -import ( - "errors" - "strings" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -var ( - ErrNodeNotFound = errors.New("node not found") -) - -// ConnectToLastNode connects the node with provided NodeID -// to the last node that is up, and avoiding connection to self. -// It is useful when constructing a chain network topology -// when Network adds and removes nodes dynamically. -func (net *Network) ConnectToLastNode(id enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - ids := net.getUpNodeIDs() - l := len(ids) - if l < 2 { - return nil - } - last := ids[l-1] - if last == id { - last = ids[l-2] - } - return net.connectNotConnected(last, id) -} - -// ConnectToRandomNode connects the node with provided NodeID -// to a random node that is up. -func (net *Network) ConnectToRandomNode(id enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - selected := net.getRandomUpNode(id) - if selected == nil { - return ErrNodeNotFound - } - return net.connectNotConnected(selected.ID(), id) -} - -// ConnectNodesFull connects all nodes one to another. -// It provides a complete connectivity in the network -// which should be rarely needed. -func (net *Network) ConnectNodesFull(ids []enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - if ids == nil { - ids = net.getUpNodeIDs() - } - for i, lid := range ids { - for _, rid := range ids[i+1:] { - if err = net.connectNotConnected(lid, rid); err != nil { - return err - } - } - } - return nil -} - -// ConnectNodesChain connects all nodes in a chain topology. -// If ids argument is nil, all nodes that are up will be connected. -func (net *Network) ConnectNodesChain(ids []enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - return net.connectNodesChain(ids) -} - -func (net *Network) connectNodesChain(ids []enode.ID) (err error) { - if ids == nil { - ids = net.getUpNodeIDs() - } - l := len(ids) - for i := 0; i < l-1; i++ { - if err := net.connectNotConnected(ids[i], ids[i+1]); err != nil { - return err - } - } - return nil -} - -// ConnectNodesRing connects all nodes in a ring topology. -// If ids argument is nil, all nodes that are up will be connected. -func (net *Network) ConnectNodesRing(ids []enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - if ids == nil { - ids = net.getUpNodeIDs() - } - l := len(ids) - if l < 2 { - return nil - } - if err := net.connectNodesChain(ids); err != nil { - return err - } - return net.connectNotConnected(ids[l-1], ids[0]) -} - -// ConnectNodesStar connects all nodes into a star topology -// If ids argument is nil, all nodes that are up will be connected. -func (net *Network) ConnectNodesStar(ids []enode.ID, center enode.ID) (err error) { - net.lock.Lock() - defer net.lock.Unlock() - - if ids == nil { - ids = net.getUpNodeIDs() - } - for _, id := range ids { - if center == id { - continue - } - if err := net.connectNotConnected(center, id); err != nil { - return err - } - } - return nil -} - -func (net *Network) connectNotConnected(oneID, otherID enode.ID) error { - return ignoreAlreadyConnectedErr(net.connect(oneID, otherID)) -} - -func ignoreAlreadyConnectedErr(err error) error { - if err == nil || strings.Contains(err.Error(), "already connected") { - return nil - } - return err -} diff --git a/p2p/simulations/connect_test.go b/p2p/simulations/connect_test.go deleted file mode 100644 index 0154a18b03..0000000000 --- a/p2p/simulations/connect_test.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2018 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 . - -package simulations - -import ( - "testing" - - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -func newTestNetwork(t *testing.T, nodeCount int) (*Network, []enode.ID) { - t.Helper() - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }) - - // create network - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - - // create and start nodes - ids := make([]enode.ID, nodeCount) - for i := range ids { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - t.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - if len(network.Conns) > 0 { - t.Fatal("no connections should exist after just adding nodes") - } - - return network, ids -} - -func TestConnectToLastNode(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - first := ids[0] - if err := net.ConnectToLastNode(first); err != nil { - t.Fatal(err) - } - - last := ids[len(ids)-1] - for i, id := range ids { - if id == first || id == last { - continue - } - - if net.GetConn(first, id) != nil { - t.Errorf("connection must not exist with node(ind: %v, id: %v)", i, id) - } - } - - if net.GetConn(first, last) == nil { - t.Error("first and last node must be connected") - } -} - -func TestConnectToRandomNode(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - err := net.ConnectToRandomNode(ids[0]) - if err != nil { - t.Fatal(err) - } - - var cc int - for i, a := range ids { - for _, b := range ids[i:] { - if net.GetConn(a, b) != nil { - cc++ - } - } - } - - if cc != 1 { - t.Errorf("expected one connection, got %v", cc) - } -} - -func TestConnectNodesFull(t *testing.T) { - tests := []struct { - name string - nodeCount int - }{ - {name: "no node", nodeCount: 0}, - {name: "single node", nodeCount: 1}, - {name: "2 nodes", nodeCount: 2}, - {name: "3 nodes", nodeCount: 3}, - {name: "even number of nodes", nodeCount: 12}, - {name: "odd number of nodes", nodeCount: 13}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - net, ids := newTestNetwork(t, test.nodeCount) - defer net.Shutdown() - - err := net.ConnectNodesFull(ids) - if err != nil { - t.Fatal(err) - } - - VerifyFull(t, net, ids) - }) - } -} - -func TestConnectNodesChain(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - err := net.ConnectNodesChain(ids) - if err != nil { - t.Fatal(err) - } - - VerifyChain(t, net, ids) -} - -func TestConnectNodesRing(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - err := net.ConnectNodesRing(ids) - if err != nil { - t.Fatal(err) - } - - VerifyRing(t, net, ids) -} - -func TestConnectNodesStar(t *testing.T) { - net, ids := newTestNetwork(t, 10) - defer net.Shutdown() - - pivotIndex := 2 - - err := net.ConnectNodesStar(ids, ids[pivotIndex]) - if err != nil { - t.Fatal(err) - } - - VerifyStar(t, net, ids, pivotIndex) -} diff --git a/p2p/simulations/events.go b/p2p/simulations/events.go deleted file mode 100644 index 1131185fb9..0000000000 --- a/p2p/simulations/events.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2017 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 . - -package simulations - -import ( - "fmt" - "time" -) - -// EventType is the type of event emitted by a simulation network -type EventType string - -const ( - // EventTypeNode is the type of event emitted when a node is either - // created, started or stopped - EventTypeNode EventType = "node" - - // EventTypeConn is the type of event emitted when a connection is - // either established or dropped between two nodes - EventTypeConn EventType = "conn" - - // EventTypeMsg is the type of event emitted when a p2p message it - // sent between two nodes - EventTypeMsg EventType = "msg" -) - -// Event is an event emitted by a simulation network -type Event struct { - // Type is the type of the event - Type EventType `json:"type"` - - // Time is the time the event happened - Time time.Time `json:"time"` - - // Control indicates whether the event is the result of a controlled - // action in the network - Control bool `json:"control"` - - // Node is set if the type is EventTypeNode - Node *Node `json:"node,omitempty"` - - // Conn is set if the type is EventTypeConn - Conn *Conn `json:"conn,omitempty"` - - // Msg is set if the type is EventTypeMsg - Msg *Msg `json:"msg,omitempty"` - - //Optionally provide data (currently for simulation frontends only) - Data interface{} `json:"data"` -} - -// NewEvent creates a new event for the given object which should be either a -// Node, Conn or Msg. -// -// The object is copied so that the event represents the state of the object -// when NewEvent is called. -func NewEvent(v interface{}) *Event { - event := &Event{Time: time.Now()} - switch v := v.(type) { - case *Node: - event.Type = EventTypeNode - event.Node = v.copy() - case *Conn: - event.Type = EventTypeConn - conn := *v - event.Conn = &conn - case *Msg: - event.Type = EventTypeMsg - msg := *v - event.Msg = &msg - default: - panic(fmt.Sprintf("invalid event type: %T", v)) - } - return event -} - -// ControlEvent creates a new control event -func ControlEvent(v interface{}) *Event { - event := NewEvent(v) - event.Control = true - return event -} - -// String returns the string representation of the event -func (e *Event) String() string { - switch e.Type { - case EventTypeNode: - return fmt.Sprintf(" id: %s up: %t", e.Node.ID().TerminalString(), e.Node.Up()) - case EventTypeConn: - return fmt.Sprintf(" nodes: %s->%s up: %t", e.Conn.One.TerminalString(), e.Conn.Other.TerminalString(), e.Conn.Up) - case EventTypeMsg: - return fmt.Sprintf(" nodes: %s->%s proto: %s, code: %d, received: %t", e.Msg.One.TerminalString(), e.Msg.Other.TerminalString(), e.Msg.Protocol, e.Msg.Code, e.Msg.Received) - default: - return "" - } -} diff --git a/p2p/simulations/examples/README.md b/p2p/simulations/examples/README.md deleted file mode 100644 index 822a48dcb6..0000000000 --- a/p2p/simulations/examples/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# devp2p simulation examples - -## ping-pong - -`ping-pong.go` implements a simulation network which contains nodes running a -simple "ping-pong" protocol where nodes send a ping message to all their -connected peers every 10s and receive pong messages in return. - -To run the simulation, run `go run ping-pong.go` in one terminal to start the -simulation API and `./ping-pong.sh` in another to start and connect the nodes: - -``` -$ go run ping-pong.go -INFO [08-15|13:53:49] using sim adapter -INFO [08-15|13:53:49] starting simulation server on 0.0.0.0:8888... -``` - -``` -$ ./ping-pong.sh ----> 13:58:12 creating 10 nodes -Created node01 -Started node01 -... -Created node10 -Started node10 ----> 13:58:13 connecting node01 to all other nodes -Connected node01 to node02 -... -Connected node01 to node10 ----> 13:58:14 done -``` - -Use the `--adapter` flag to choose the adapter type: - -``` -$ go run ping-pong.go --adapter exec -INFO [08-15|14:01:14] using exec adapter tmpdir=/var/folders/k6/wpsgfg4n23ddbc6f5cnw5qg00000gn/T/p2p-example992833779 -INFO [08-15|14:01:14] starting simulation server on 0.0.0.0:8888... -``` diff --git a/p2p/simulations/examples/ping-pong.go b/p2p/simulations/examples/ping-pong.go deleted file mode 100644 index b0b8f22fdb..0000000000 --- a/p2p/simulations/examples/ping-pong.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2017 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 . - -package main - -import ( - "flag" - "fmt" - "io" - "net/http" - "os" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim" or "exec")`) - -// main() starts a simulation network which contains nodes running a simple -// ping-pong protocol -func main() { - flag.Parse() - - // set the log level to Trace - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelTrace, false))) - - // register a single ping-pong service - services := map[string]adapters.LifecycleConstructor{ - "ping-pong": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - pps := newPingPongService(ctx.Config.ID) - stack.RegisterProtocols(pps.Protocols()) - return pps, nil - }, - } - adapters.RegisterLifecycles(services) - - // create the NodeAdapter - var adapter adapters.NodeAdapter - - switch *adapterType { - - case "sim": - log.Info("using sim adapter") - adapter = adapters.NewSimAdapter(services) - - case "exec": - tmpdir, err := os.MkdirTemp("", "p2p-example") - if err != nil { - log.Crit("error creating temp dir", "err", err) - } - defer os.RemoveAll(tmpdir) - log.Info("using exec adapter", "tmpdir", tmpdir) - adapter = adapters.NewExecAdapter(tmpdir) - - default: - log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) - } - - // start the HTTP API - log.Info("starting simulation server on 0.0.0.0:8888...") - network := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ - DefaultService: "ping-pong", - }) - if err := http.ListenAndServe(":8888", simulations.NewServer(network)); err != nil { - log.Crit("error starting simulation server", "err", err) - } -} - -// pingPongService runs a ping-pong protocol between nodes where each node -// sends a ping to all its connected peers every 10s and receives a pong in -// return -type pingPongService struct { - id enode.ID - log log.Logger - received atomic.Int64 -} - -func newPingPongService(id enode.ID) *pingPongService { - return &pingPongService{ - id: id, - log: log.New("node.id", id), - } -} - -func (p *pingPongService) Protocols() []p2p.Protocol { - return []p2p.Protocol{{ - Name: "ping-pong", - Version: 1, - Length: 2, - Run: p.Run, - NodeInfo: p.Info, - }} -} - -func (p *pingPongService) Start() error { - p.log.Info("ping-pong service starting") - return nil -} - -func (p *pingPongService) Stop() error { - p.log.Info("ping-pong service stopping") - return nil -} - -func (p *pingPongService) Info() interface{} { - return struct { - Received int64 `json:"received"` - }{ - p.received.Load(), - } -} - -const ( - pingMsgCode = iota - pongMsgCode -) - -// Run implements the ping-pong protocol which sends ping messages to the peer -// at 10s intervals, and responds to pings with pong messages. -func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - log := p.log.New("peer.id", peer.ID()) - - errC := make(chan error, 1) - go func() { - for range time.Tick(10 * time.Second) { - log.Info("sending ping") - if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { - errC <- err - return - } - } - }() - go func() { - for { - msg, err := rw.ReadMsg() - if err != nil { - errC <- err - return - } - payload, err := io.ReadAll(msg.Payload) - if err != nil { - errC <- err - return - } - log.Info("received message", "msg.code", msg.Code, "msg.payload", string(payload)) - p.received.Add(1) - if msg.Code == pingMsgCode { - log.Info("sending pong") - go p2p.Send(rw, pongMsgCode, "PONG") - } - } - }() - return <-errC -} diff --git a/p2p/simulations/examples/ping-pong.sh b/p2p/simulations/examples/ping-pong.sh deleted file mode 100755 index 47936bd9a0..0000000000 --- a/p2p/simulations/examples/ping-pong.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -# -# Boot a ping-pong network simulation using the HTTP API started by ping-pong.go - -set -e - -main() { - if ! which p2psim &>/dev/null; then - fail "missing p2psim binary (you need to build cmd/p2psim and put it in \$PATH)" - fi - - info "creating 10 nodes" - for i in $(seq 1 10); do - p2psim node create --name "$(node_name $i)" - p2psim node start "$(node_name $i)" - done - - info "connecting node01 to all other nodes" - for i in $(seq 2 10); do - p2psim node connect "node01" "$(node_name $i)" - done - - info "done" -} - -node_name() { - local num=$1 - echo "node$(printf '%02d' $num)" -} - -info() { - echo -e "\033[1;32m---> $(date +%H:%M:%S) ${@}\033[0m" -} - -fail() { - echo -e "\033[1;31mERROR: ${@}\033[0m" >&2 - exit 1 -} - -main "$@" diff --git a/p2p/simulations/http.go b/p2p/simulations/http.go deleted file mode 100644 index 34521b4778..0000000000 --- a/p2p/simulations/http.go +++ /dev/null @@ -1,743 +0,0 @@ -// Copyright 2017 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 . - -package simulations - -import ( - "bufio" - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "html" - "io" - "net/http" - "strconv" - "strings" - "sync" - - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - "github.com/gorilla/websocket" - "github.com/julienschmidt/httprouter" -) - -// DefaultClient is the default simulation API client which expects the API -// to be running at http://localhost:8888 -var DefaultClient = NewClient("http://localhost:8888") - -// Client is a client for the simulation HTTP API which supports creating -// and managing simulation networks -type Client struct { - URL string - - client *http.Client -} - -// NewClient returns a new simulation API client -func NewClient(url string) *Client { - return &Client{ - URL: url, - client: http.DefaultClient, - } -} - -// GetNetwork returns details of the network -func (c *Client) GetNetwork() (*Network, error) { - network := &Network{} - return network, c.Get("/", network) -} - -// StartNetwork starts all existing nodes in the simulation network -func (c *Client) StartNetwork() error { - return c.Post("/start", nil, nil) -} - -// StopNetwork stops all existing nodes in a simulation network -func (c *Client) StopNetwork() error { - return c.Post("/stop", nil, nil) -} - -// CreateSnapshot creates a network snapshot -func (c *Client) CreateSnapshot() (*Snapshot, error) { - snap := &Snapshot{} - return snap, c.Get("/snapshot", snap) -} - -// LoadSnapshot loads a snapshot into the network -func (c *Client) LoadSnapshot(snap *Snapshot) error { - return c.Post("/snapshot", snap, nil) -} - -// SubscribeOpts is a collection of options to use when subscribing to network -// events -type SubscribeOpts struct { - // Current instructs the server to send events for existing nodes and - // connections first - Current bool - - // Filter instructs the server to only send a subset of message events - Filter string -} - -// SubscribeNetwork subscribes to network events which are sent from the server -// as a server-sent-events stream, optionally receiving events for existing -// nodes and connections and filtering message events -func (c *Client) SubscribeNetwork(events chan *Event, opts SubscribeOpts) (event.Subscription, error) { - url := fmt.Sprintf("%s/events?current=%t&filter=%s", c.URL, opts.Current, opts.Filter) - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - return nil, err - } - req.Header.Set("Accept", "text/event-stream") - res, err := c.client.Do(req) - if err != nil { - return nil, err - } - if res.StatusCode != http.StatusOK { - response, _ := io.ReadAll(res.Body) - res.Body.Close() - return nil, fmt.Errorf("unexpected HTTP status: %s: %s", res.Status, response) - } - - // define a producer function to pass to event.Subscription - // which reads server-sent events from res.Body and sends - // them to the events channel - producer := func(stop <-chan struct{}) error { - defer res.Body.Close() - - // read lines from res.Body in a goroutine so that we are - // always reading from the stop channel - lines := make(chan string) - errC := make(chan error, 1) - go func() { - s := bufio.NewScanner(res.Body) - for s.Scan() { - select { - case lines <- s.Text(): - case <-stop: - return - } - } - errC <- s.Err() - }() - - // detect any lines which start with "data:", decode the data - // into an event and send it to the events channel - for { - select { - case line := <-lines: - if !strings.HasPrefix(line, "data:") { - continue - } - data := strings.TrimSpace(strings.TrimPrefix(line, "data:")) - event := &Event{} - if err := json.Unmarshal([]byte(data), event); err != nil { - return fmt.Errorf("error decoding SSE event: %s", err) - } - select { - case events <- event: - case <-stop: - return nil - } - case err := <-errC: - return err - case <-stop: - return nil - } - } - } - - return event.NewSubscription(producer), nil -} - -// GetNodes returns all nodes which exist in the network -func (c *Client) GetNodes() ([]*p2p.NodeInfo, error) { - var nodes []*p2p.NodeInfo - return nodes, c.Get("/nodes", &nodes) -} - -// CreateNode creates a node in the network using the given configuration -func (c *Client) CreateNode(config *adapters.NodeConfig) (*p2p.NodeInfo, error) { - node := &p2p.NodeInfo{} - return node, c.Post("/nodes", config, node) -} - -// GetNode returns details of a node -func (c *Client) GetNode(nodeID string) (*p2p.NodeInfo, error) { - node := &p2p.NodeInfo{} - return node, c.Get(fmt.Sprintf("/nodes/%s", nodeID), node) -} - -// StartNode starts a node -func (c *Client) StartNode(nodeID string) error { - return c.Post(fmt.Sprintf("/nodes/%s/start", nodeID), nil, nil) -} - -// StopNode stops a node -func (c *Client) StopNode(nodeID string) error { - return c.Post(fmt.Sprintf("/nodes/%s/stop", nodeID), nil, nil) -} - -// ConnectNode connects a node to a peer node -func (c *Client) ConnectNode(nodeID, peerID string) error { - return c.Post(fmt.Sprintf("/nodes/%s/conn/%s", nodeID, peerID), nil, nil) -} - -// DisconnectNode disconnects a node from a peer node -func (c *Client) DisconnectNode(nodeID, peerID string) error { - return c.Delete(fmt.Sprintf("/nodes/%s/conn/%s", nodeID, peerID)) -} - -// RPCClient returns an RPC client connected to a node -func (c *Client) RPCClient(ctx context.Context, nodeID string) (*rpc.Client, error) { - baseURL := strings.Replace(c.URL, "http", "ws", 1) - return rpc.DialWebsocket(ctx, fmt.Sprintf("%s/nodes/%s/rpc", baseURL, nodeID), "") -} - -// Get performs a HTTP GET request decoding the resulting JSON response -// into "out" -func (c *Client) Get(path string, out interface{}) error { - return c.Send(http.MethodGet, path, nil, out) -} - -// Post performs a HTTP POST request sending "in" as the JSON body and -// decoding the resulting JSON response into "out" -func (c *Client) Post(path string, in, out interface{}) error { - return c.Send(http.MethodPost, path, in, out) -} - -// Delete performs a HTTP DELETE request -func (c *Client) Delete(path string) error { - return c.Send(http.MethodDelete, path, nil, nil) -} - -// Send performs a HTTP request, sending "in" as the JSON request body and -// decoding the JSON response into "out" -func (c *Client) Send(method, path string, in, out interface{}) error { - var body []byte - if in != nil { - var err error - body, err = json.Marshal(in) - if err != nil { - return err - } - } - req, err := http.NewRequest(method, c.URL+path, bytes.NewReader(body)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - res, err := c.client.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated { - response, _ := io.ReadAll(res.Body) - return fmt.Errorf("unexpected HTTP status: %s: %s", res.Status, response) - } - if out != nil { - if err := json.NewDecoder(res.Body).Decode(out); err != nil { - return err - } - } - return nil -} - -// Server is an HTTP server providing an API to manage a simulation network -type Server struct { - router *httprouter.Router - network *Network - mockerStop chan struct{} // when set, stops the current mocker - mockerMtx sync.Mutex // synchronises access to the mockerStop field -} - -// NewServer returns a new simulation API server -func NewServer(network *Network) *Server { - s := &Server{ - router: httprouter.New(), - network: network, - } - - s.OPTIONS("/", s.Options) - s.GET("/", s.GetNetwork) - s.POST("/start", s.StartNetwork) - s.POST("/stop", s.StopNetwork) - s.POST("/mocker/start", s.StartMocker) - s.POST("/mocker/stop", s.StopMocker) - s.GET("/mocker", s.GetMockers) - s.POST("/reset", s.ResetNetwork) - s.GET("/events", s.StreamNetworkEvents) - s.GET("/snapshot", s.CreateSnapshot) - s.POST("/snapshot", s.LoadSnapshot) - s.POST("/nodes", s.CreateNode) - s.GET("/nodes", s.GetNodes) - s.GET("/nodes/:nodeid", s.GetNode) - s.POST("/nodes/:nodeid/start", s.StartNode) - s.POST("/nodes/:nodeid/stop", s.StopNode) - s.POST("/nodes/:nodeid/conn/:peerid", s.ConnectNode) - s.DELETE("/nodes/:nodeid/conn/:peerid", s.DisconnectNode) - s.GET("/nodes/:nodeid/rpc", s.NodeRPC) - - return s -} - -// GetNetwork returns details of the network -func (s *Server) GetNetwork(w http.ResponseWriter, req *http.Request) { - s.JSON(w, http.StatusOK, s.network) -} - -// StartNetwork starts all nodes in the network -func (s *Server) StartNetwork(w http.ResponseWriter, req *http.Request) { - if err := s.network.StartAll(); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusOK) -} - -// StopNetwork stops all nodes in the network -func (s *Server) StopNetwork(w http.ResponseWriter, req *http.Request) { - if err := s.network.StopAll(); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusOK) -} - -// StartMocker starts the mocker node simulation -func (s *Server) StartMocker(w http.ResponseWriter, req *http.Request) { - s.mockerMtx.Lock() - defer s.mockerMtx.Unlock() - if s.mockerStop != nil { - http.Error(w, "mocker already running", http.StatusInternalServerError) - return - } - mockerType := req.FormValue("mocker-type") - mockerFn := LookupMocker(mockerType) - if mockerFn == nil { - http.Error(w, fmt.Sprintf("unknown mocker type %q", html.EscapeString(mockerType)), http.StatusBadRequest) - return - } - nodeCount, err := strconv.Atoi(req.FormValue("node-count")) - if err != nil { - http.Error(w, "invalid node-count provided", http.StatusBadRequest) - return - } - s.mockerStop = make(chan struct{}) - go mockerFn(s.network, s.mockerStop, nodeCount) - - w.WriteHeader(http.StatusOK) -} - -// StopMocker stops the mocker node simulation -func (s *Server) StopMocker(w http.ResponseWriter, req *http.Request) { - s.mockerMtx.Lock() - defer s.mockerMtx.Unlock() - if s.mockerStop == nil { - http.Error(w, "stop channel not initialized", http.StatusInternalServerError) - return - } - close(s.mockerStop) - s.mockerStop = nil - - w.WriteHeader(http.StatusOK) -} - -// GetMockers returns a list of available mockers -func (s *Server) GetMockers(w http.ResponseWriter, req *http.Request) { - list := GetMockerList() - s.JSON(w, http.StatusOK, list) -} - -// ResetNetwork resets all properties of a network to its initial (empty) state -func (s *Server) ResetNetwork(w http.ResponseWriter, req *http.Request) { - s.network.Reset() - - w.WriteHeader(http.StatusOK) -} - -// StreamNetworkEvents streams network events as a server-sent-events stream -func (s *Server) StreamNetworkEvents(w http.ResponseWriter, req *http.Request) { - events := make(chan *Event) - sub := s.network.events.Subscribe(events) - defer sub.Unsubscribe() - - // write writes the given event and data to the stream like: - // - // event: - // data: - // - write := func(event, data string) { - fmt.Fprintf(w, "event: %s\n", event) - fmt.Fprintf(w, "data: %s\n\n", data) - if fw, ok := w.(http.Flusher); ok { - fw.Flush() - } - } - writeEvent := func(event *Event) error { - data, err := json.Marshal(event) - if err != nil { - return err - } - write("network", string(data)) - return nil - } - writeErr := func(err error) { - write("error", err.Error()) - } - - // check if filtering has been requested - var filters MsgFilters - if filterParam := req.URL.Query().Get("filter"); filterParam != "" { - var err error - filters, err = NewMsgFilters(filterParam) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - } - - w.Header().Set("Content-Type", "text/event-stream; charset=utf-8") - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "\n\n") - if fw, ok := w.(http.Flusher); ok { - fw.Flush() - } - - // optionally send the existing nodes and connections - if req.URL.Query().Get("current") == "true" { - snap, err := s.network.Snapshot() - if err != nil { - writeErr(err) - return - } - for _, node := range snap.Nodes { - event := NewEvent(&node.Node) - if err := writeEvent(event); err != nil { - writeErr(err) - return - } - } - for _, conn := range snap.Conns { - conn := conn - event := NewEvent(&conn) - if err := writeEvent(event); err != nil { - writeErr(err) - return - } - } - } - - clientGone := req.Context().Done() - for { - select { - case event := <-events: - // only send message events which match the filters - if event.Msg != nil && !filters.Match(event.Msg) { - continue - } - if err := writeEvent(event); err != nil { - writeErr(err) - return - } - case <-clientGone: - return - } - } -} - -// NewMsgFilters constructs a collection of message filters from a URL query -// parameter. -// -// The parameter is expected to be a dash-separated list of individual filters, -// each having the format ':', where is the name of a -// protocol and is a comma-separated list of message codes. -// -// A message code of '*' or '-1' is considered a wildcard and matches any code. -func NewMsgFilters(filterParam string) (MsgFilters, error) { - filters := make(MsgFilters) - for _, filter := range strings.Split(filterParam, "-") { - proto, codes, found := strings.Cut(filter, ":") - if !found || proto == "" || codes == "" { - return nil, fmt.Errorf("invalid message filter: %s", filter) - } - - for _, code := range strings.Split(codes, ",") { - if code == "*" || code == "-1" { - filters[MsgFilter{Proto: proto, Code: -1}] = struct{}{} - continue - } - n, err := strconv.ParseUint(code, 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid message code: %s", code) - } - filters[MsgFilter{Proto: proto, Code: int64(n)}] = struct{}{} - } - } - return filters, nil -} - -// MsgFilters is a collection of filters which are used to filter message -// events -type MsgFilters map[MsgFilter]struct{} - -// Match checks if the given message matches any of the filters -func (m MsgFilters) Match(msg *Msg) bool { - // check if there is a wildcard filter for the message's protocol - if _, ok := m[MsgFilter{Proto: msg.Protocol, Code: -1}]; ok { - return true - } - - // check if there is a filter for the message's protocol and code - if _, ok := m[MsgFilter{Proto: msg.Protocol, Code: int64(msg.Code)}]; ok { - return true - } - - return false -} - -// MsgFilter is used to filter message events based on protocol and message -// code -type MsgFilter struct { - // Proto is matched against a message's protocol - Proto string - - // Code is matched against a message's code, with -1 matching all codes - Code int64 -} - -// CreateSnapshot creates a network snapshot -func (s *Server) CreateSnapshot(w http.ResponseWriter, req *http.Request) { - snap, err := s.network.Snapshot() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, snap) -} - -// LoadSnapshot loads a snapshot into the network -func (s *Server) LoadSnapshot(w http.ResponseWriter, req *http.Request) { - snap := &Snapshot{} - if err := json.NewDecoder(req.Body).Decode(snap); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - if err := s.network.Load(snap); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, s.network) -} - -// CreateNode creates a node in the network using the given configuration -func (s *Server) CreateNode(w http.ResponseWriter, req *http.Request) { - config := &adapters.NodeConfig{} - - err := json.NewDecoder(req.Body).Decode(config) - if err != nil && !errors.Is(err, io.EOF) { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - node, err := s.network.NewNodeWithConfig(config) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusCreated, node.NodeInfo()) -} - -// GetNodes returns all nodes which exist in the network -func (s *Server) GetNodes(w http.ResponseWriter, req *http.Request) { - nodes := s.network.GetNodes() - - infos := make([]*p2p.NodeInfo, len(nodes)) - for i, node := range nodes { - infos[i] = node.NodeInfo() - } - - s.JSON(w, http.StatusOK, infos) -} - -// GetNode returns details of a node -func (s *Server) GetNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// StartNode starts a node -func (s *Server) StartNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - - if err := s.network.Start(node.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// StopNode stops a node -func (s *Server) StopNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - - if err := s.network.Stop(node.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// ConnectNode connects a node to a peer node -func (s *Server) ConnectNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - peer := req.Context().Value("peer").(*Node) - - if err := s.network.Connect(node.ID(), peer.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// DisconnectNode disconnects a node from a peer node -func (s *Server) DisconnectNode(w http.ResponseWriter, req *http.Request) { - node := req.Context().Value("node").(*Node) - peer := req.Context().Value("peer").(*Node) - - if err := s.network.Disconnect(node.ID(), peer.ID()); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - s.JSON(w, http.StatusOK, node.NodeInfo()) -} - -// Options responds to the OPTIONS HTTP method by returning a 200 OK response -// with the "Access-Control-Allow-Headers" header set to "Content-Type" -func (s *Server) Options(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Access-Control-Allow-Headers", "Content-Type") - w.WriteHeader(http.StatusOK) -} - -var wsUpgrade = websocket.Upgrader{ - CheckOrigin: func(*http.Request) bool { return true }, -} - -// NodeRPC forwards RPC requests to a node in the network via a WebSocket -// connection -func (s *Server) NodeRPC(w http.ResponseWriter, req *http.Request) { - conn, err := wsUpgrade.Upgrade(w, req, nil) - if err != nil { - return - } - defer conn.Close() - node := req.Context().Value("node").(*Node) - node.ServeRPC(conn) -} - -// ServeHTTP implements the http.Handler interface by delegating to the -// underlying httprouter.Router -func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - s.router.ServeHTTP(w, req) -} - -// GET registers a handler for GET requests to a particular path -func (s *Server) GET(path string, handle http.HandlerFunc) { - s.router.GET(path, s.wrapHandler(handle)) -} - -// POST registers a handler for POST requests to a particular path -func (s *Server) POST(path string, handle http.HandlerFunc) { - s.router.POST(path, s.wrapHandler(handle)) -} - -// DELETE registers a handler for DELETE requests to a particular path -func (s *Server) DELETE(path string, handle http.HandlerFunc) { - s.router.DELETE(path, s.wrapHandler(handle)) -} - -// OPTIONS registers a handler for OPTIONS requests to a particular path -func (s *Server) OPTIONS(path string, handle http.HandlerFunc) { - s.router.OPTIONS("/*path", s.wrapHandler(handle)) -} - -// JSON sends "data" as a JSON HTTP response -func (s *Server) JSON(w http.ResponseWriter, status int, data interface{}) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(status) - json.NewEncoder(w).Encode(data) -} - -// wrapHandler returns an httprouter.Handle which wraps an http.HandlerFunc by -// populating request.Context with any objects from the URL params -func (s *Server) wrapHandler(handler http.HandlerFunc) httprouter.Handle { - return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - - ctx := req.Context() - - if id := params.ByName("nodeid"); id != "" { - var nodeID enode.ID - var node *Node - if nodeID.UnmarshalText([]byte(id)) == nil { - node = s.network.GetNode(nodeID) - } else { - node = s.network.GetNodeByName(id) - } - if node == nil { - http.NotFound(w, req) - return - } - ctx = context.WithValue(ctx, "node", node) - } - - if id := params.ByName("peerid"); id != "" { - var peerID enode.ID - var peer *Node - if peerID.UnmarshalText([]byte(id)) == nil { - peer = s.network.GetNode(peerID) - } else { - peer = s.network.GetNodeByName(id) - } - if peer == nil { - http.NotFound(w, req) - return - } - ctx = context.WithValue(ctx, "peer", peer) - } - - handler(w, req.WithContext(ctx)) - } -} diff --git a/p2p/simulations/http_test.go b/p2p/simulations/http_test.go deleted file mode 100644 index cd03e600f3..0000000000 --- a/p2p/simulations/http_test.go +++ /dev/null @@ -1,869 +0,0 @@ -// Copyright 2017 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 . - -package simulations - -import ( - "context" - "flag" - "fmt" - "log/slog" - "math/rand" - "net/http/httptest" - "os" - "reflect" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" - "github.com/ethereum/go-ethereum/rpc" - "github.com/mattn/go-colorable" -) - -func TestMain(m *testing.M) { - loglevel := flag.Int("loglevel", 2, "verbosity of logs") - - flag.Parse() - log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(colorable.NewColorableStderr(), slog.Level(*loglevel), true))) - os.Exit(m.Run()) -} - -// testService implements the node.Service interface and provides protocols -// and APIs which are useful for testing nodes in a simulation network -type testService struct { - id enode.ID - - // peerCount is incremented once a peer handshake has been performed - peerCount int64 - - peers map[enode.ID]*testPeer - peersMtx sync.Mutex - - // state stores []byte which is used to test creating and loading - // snapshots - state atomic.Value -} - -func newTestService(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - svc := &testService{ - id: ctx.Config.ID, - peers: make(map[enode.ID]*testPeer), - } - svc.state.Store(ctx.Snapshot) - - stack.RegisterProtocols(svc.Protocols()) - stack.RegisterAPIs(svc.APIs()) - return svc, nil -} - -type testPeer struct { - testReady chan struct{} - dumReady chan struct{} -} - -func (t *testService) peer(id enode.ID) *testPeer { - t.peersMtx.Lock() - defer t.peersMtx.Unlock() - if peer, ok := t.peers[id]; ok { - return peer - } - peer := &testPeer{ - testReady: make(chan struct{}), - dumReady: make(chan struct{}), - } - t.peers[id] = peer - return peer -} - -func (t *testService) Protocols() []p2p.Protocol { - return []p2p.Protocol{ - { - Name: "test", - Version: 1, - Length: 3, - Run: t.RunTest, - }, - { - Name: "dum", - Version: 1, - Length: 1, - Run: t.RunDum, - }, - { - Name: "prb", - Version: 1, - Length: 1, - Run: t.RunPrb, - }, - } -} - -func (t *testService) APIs() []rpc.API { - return []rpc.API{{ - Namespace: "test", - Version: "1.0", - Service: &TestAPI{ - state: &t.state, - peerCount: &t.peerCount, - }, - }} -} - -func (t *testService) Start() error { - return nil -} - -func (t *testService) Stop() error { - return nil -} - -// handshake performs a peer handshake by sending and expecting an empty -// message with the given code -func (t *testService) handshake(rw p2p.MsgReadWriter, code uint64) error { - errc := make(chan error, 2) - go func() { errc <- p2p.SendItems(rw, code) }() - go func() { errc <- p2p.ExpectMsg(rw, code, struct{}{}) }() - for i := 0; i < 2; i++ { - if err := <-errc; err != nil { - return err - } - } - return nil -} - -func (t *testService) RunTest(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := t.peer(p.ID()) - - // perform three handshakes with three different message codes, - // used to test message sending and filtering - if err := t.handshake(rw, 2); err != nil { - return err - } - if err := t.handshake(rw, 1); err != nil { - return err - } - if err := t.handshake(rw, 0); err != nil { - return err - } - - // close the testReady channel so that other protocols can run - close(peer.testReady) - - // track the peer - atomic.AddInt64(&t.peerCount, 1) - defer atomic.AddInt64(&t.peerCount, -1) - - // block until the peer is dropped - for { - _, err := rw.ReadMsg() - if err != nil { - return err - } - } -} - -func (t *testService) RunDum(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := t.peer(p.ID()) - - // wait for the test protocol to perform its handshake - <-peer.testReady - - // perform a handshake - if err := t.handshake(rw, 0); err != nil { - return err - } - - // close the dumReady channel so that other protocols can run - close(peer.dumReady) - - // block until the peer is dropped - for { - _, err := rw.ReadMsg() - if err != nil { - return err - } - } -} -func (t *testService) RunPrb(p *p2p.Peer, rw p2p.MsgReadWriter) error { - peer := t.peer(p.ID()) - - // wait for the dum protocol to perform its handshake - <-peer.dumReady - - // perform a handshake - if err := t.handshake(rw, 0); err != nil { - return err - } - - // block until the peer is dropped - for { - _, err := rw.ReadMsg() - if err != nil { - return err - } - } -} - -func (t *testService) Snapshot() ([]byte, error) { - return t.state.Load().([]byte), nil -} - -// TestAPI provides a test API to: -// * get the peer count -// * get and set an arbitrary state byte slice -// * get and increment a counter -// * subscribe to counter increment events -type TestAPI struct { - state *atomic.Value - peerCount *int64 - counter int64 - feed event.Feed -} - -func (t *TestAPI) PeerCount() int64 { - return atomic.LoadInt64(t.peerCount) -} - -func (t *TestAPI) Get() int64 { - return atomic.LoadInt64(&t.counter) -} - -func (t *TestAPI) Add(delta int64) { - atomic.AddInt64(&t.counter, delta) - t.feed.Send(delta) -} - -func (t *TestAPI) GetState() []byte { - return t.state.Load().([]byte) -} - -func (t *TestAPI) SetState(state []byte) { - t.state.Store(state) -} - -func (t *TestAPI) Events(ctx context.Context) (*rpc.Subscription, error) { - notifier, supported := rpc.NotifierFromContext(ctx) - if !supported { - return nil, rpc.ErrNotificationsUnsupported - } - - rpcSub := notifier.CreateSubscription() - - go func() { - events := make(chan int64) - sub := t.feed.Subscribe(events) - defer sub.Unsubscribe() - - for { - select { - case event := <-events: - notifier.Notify(rpcSub.ID, event) - case <-sub.Err(): - return - case <-rpcSub.Err(): - return - } - } - }() - - return rpcSub, nil -} - -var testServices = adapters.LifecycleConstructors{ - "test": newTestService, -} - -func testHTTPServer(t *testing.T) (*Network, *httptest.Server) { - t.Helper() - adapter := adapters.NewSimAdapter(testServices) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - return network, httptest.NewServer(NewServer(network)) -} - -// TestHTTPNetwork tests interacting with a simulation network using the HTTP -// API -func TestHTTPNetwork(t *testing.T) { - // start the server - network, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events so we can check them later - client := NewClient(s.URL) - events := make(chan *Event, 100) - var opts SubscribeOpts - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // check we can retrieve details about the network - gotNetwork, err := client.GetNetwork() - if err != nil { - t.Fatalf("error getting network: %s", err) - } - if gotNetwork.ID != network.ID { - t.Fatalf("expected network to have ID %q, got %q", network.ID, gotNetwork.ID) - } - - // start a simulation network - nodeIDs := startTestNetwork(t, client) - - // check we got all the events - x := &expectEvents{t, events, sub} - x.expect( - x.nodeEvent(nodeIDs[0], false), - x.nodeEvent(nodeIDs[1], false), - x.nodeEvent(nodeIDs[0], true), - x.nodeEvent(nodeIDs[1], true), - x.connEvent(nodeIDs[0], nodeIDs[1], false), - x.connEvent(nodeIDs[0], nodeIDs[1], true), - ) - - // reconnect the stream and check we get the current nodes and conns - events = make(chan *Event, 100) - opts.Current = true - sub, err = client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - x = &expectEvents{t, events, sub} - x.expect( - x.nodeEvent(nodeIDs[0], true), - x.nodeEvent(nodeIDs[1], true), - x.connEvent(nodeIDs[0], nodeIDs[1], true), - ) -} - -func startTestNetwork(t *testing.T, client *Client) []string { - // create two nodes - nodeCount := 2 - nodeIDs := make([]string, nodeCount) - for i := 0; i < nodeCount; i++ { - config := adapters.RandomNodeConfig() - node, err := client.CreateNode(config) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - nodeIDs[i] = node.ID - } - - // check both nodes exist - nodes, err := client.GetNodes() - if err != nil { - t.Fatalf("error getting nodes: %s", err) - } - if len(nodes) != nodeCount { - t.Fatalf("expected %d nodes, got %d", nodeCount, len(nodes)) - } - for i, nodeID := range nodeIDs { - if nodes[i].ID != nodeID { - t.Fatalf("expected node %d to have ID %q, got %q", i, nodeID, nodes[i].ID) - } - node, err := client.GetNode(nodeID) - if err != nil { - t.Fatalf("error getting node %d: %s", i, err) - } - if node.ID != nodeID { - t.Fatalf("expected node %d to have ID %q, got %q", i, nodeID, node.ID) - } - } - - // start both nodes - for _, nodeID := range nodeIDs { - if err := client.StartNode(nodeID); err != nil { - t.Fatalf("error starting node %q: %s", nodeID, err) - } - } - - // connect the nodes - for i := 0; i < nodeCount-1; i++ { - peerId := i + 1 - if i == nodeCount-1 { - peerId = 0 - } - if err := client.ConnectNode(nodeIDs[i], nodeIDs[peerId]); err != nil { - t.Fatalf("error connecting nodes: %s", err) - } - } - - return nodeIDs -} - -type expectEvents struct { - *testing.T - - events chan *Event - sub event.Subscription -} - -func (t *expectEvents) nodeEvent(id string, up bool) *Event { - config := &adapters.NodeConfig{ID: enode.HexID(id)} - return &Event{Type: EventTypeNode, Node: newNode(nil, config, up)} -} - -func (t *expectEvents) connEvent(one, other string, up bool) *Event { - return &Event{ - Type: EventTypeConn, - Conn: &Conn{ - One: enode.HexID(one), - Other: enode.HexID(other), - Up: up, - }, - } -} - -func (t *expectEvents) expectMsgs(expected map[MsgFilter]int) { - actual := make(map[MsgFilter]int) - timeout := time.After(10 * time.Second) -loop: - for { - select { - case event := <-t.events: - t.Logf("received %s event: %v", event.Type, event) - - if event.Type != EventTypeMsg || event.Msg.Received { - continue loop - } - if event.Msg == nil { - t.Fatal("expected event.Msg to be set") - } - filter := MsgFilter{ - Proto: event.Msg.Protocol, - Code: int64(event.Msg.Code), - } - actual[filter]++ - if actual[filter] > expected[filter] { - t.Fatalf("received too many msgs for filter: %v", filter) - } - if reflect.DeepEqual(actual, expected) { - return - } - - case err := <-t.sub.Err(): - t.Fatalf("network stream closed unexpectedly: %s", err) - - case <-timeout: - t.Fatal("timed out waiting for expected events") - } - } -} - -func (t *expectEvents) expect(events ...*Event) { - t.Helper() - timeout := time.After(10 * time.Second) - i := 0 - for { - select { - case event := <-t.events: - t.Logf("received %s event: %v", event.Type, event) - - expected := events[i] - if event.Type != expected.Type { - t.Fatalf("expected event %d to have type %q, got %q", i, expected.Type, event.Type) - } - - switch expected.Type { - case EventTypeNode: - if event.Node == nil { - t.Fatal("expected event.Node to be set") - } - if event.Node.ID() != expected.Node.ID() { - t.Fatalf("expected node event %d to have id %q, got %q", i, expected.Node.ID().TerminalString(), event.Node.ID().TerminalString()) - } - if event.Node.Up() != expected.Node.Up() { - t.Fatalf("expected node event %d to have up=%t, got up=%t", i, expected.Node.Up(), event.Node.Up()) - } - - case EventTypeConn: - if event.Conn == nil { - t.Fatal("expected event.Conn to be set") - } - if event.Conn.One != expected.Conn.One { - t.Fatalf("expected conn event %d to have one=%q, got one=%q", i, expected.Conn.One.TerminalString(), event.Conn.One.TerminalString()) - } - if event.Conn.Other != expected.Conn.Other { - t.Fatalf("expected conn event %d to have other=%q, got other=%q", i, expected.Conn.Other.TerminalString(), event.Conn.Other.TerminalString()) - } - if event.Conn.Up != expected.Conn.Up { - t.Fatalf("expected conn event %d to have up=%t, got up=%t", i, expected.Conn.Up, event.Conn.Up) - } - } - - i++ - if i == len(events) { - return - } - - case err := <-t.sub.Err(): - t.Fatalf("network stream closed unexpectedly: %s", err) - - case <-timeout: - t.Fatal("timed out waiting for expected events") - } - } -} - -// TestHTTPNodeRPC tests calling RPC methods on nodes via the HTTP API -func TestHTTPNodeRPC(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // start a node in the network - client := NewClient(s.URL) - - config := adapters.RandomNodeConfig() - node, err := client.CreateNode(config) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := client.StartNode(node.ID); err != nil { - t.Fatalf("error starting node: %s", err) - } - - // create two RPC clients - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - rpcClient1, err := client.RPCClient(ctx, node.ID) - if err != nil { - t.Fatalf("error getting node RPC client: %s", err) - } - rpcClient2, err := client.RPCClient(ctx, node.ID) - if err != nil { - t.Fatalf("error getting node RPC client: %s", err) - } - - // subscribe to events using client 1 - events := make(chan int64, 1) - sub, err := rpcClient1.Subscribe(ctx, "test", events, "events") - if err != nil { - t.Fatalf("error subscribing to events: %s", err) - } - defer sub.Unsubscribe() - - // call some RPC methods using client 2 - if err := rpcClient2.CallContext(ctx, nil, "test_add", 10); err != nil { - t.Fatalf("error calling RPC method: %s", err) - } - var result int64 - if err := rpcClient2.CallContext(ctx, &result, "test_get"); err != nil { - t.Fatalf("error calling RPC method: %s", err) - } - if result != 10 { - t.Fatalf("expected result to be 10, got %d", result) - } - - // check we got an event from client 1 - select { - case event := <-events: - if event != 10 { - t.Fatalf("expected event to be 10, got %d", event) - } - case <-ctx.Done(): - t.Fatal(ctx.Err()) - } -} - -// TestHTTPSnapshot tests creating and loading network snapshots -func TestHTTPSnapshot(t *testing.T) { - // start the server - network, s := testHTTPServer(t) - defer s.Close() - - var eventsDone = make(chan struct{}, 1) - count := 1 - eventsDoneChan := make(chan *Event) - eventSub := network.Events().Subscribe(eventsDoneChan) - go func() { - defer eventSub.Unsubscribe() - for event := range eventsDoneChan { - if event.Type == EventTypeConn && !event.Control { - count-- - if count == 0 { - eventsDone <- struct{}{} - return - } - } - } - }() - - // create a two-node network - client := NewClient(s.URL) - nodeCount := 2 - nodes := make([]*p2p.NodeInfo, nodeCount) - for i := 0; i < nodeCount; i++ { - config := adapters.RandomNodeConfig() - node, err := client.CreateNode(config) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := client.StartNode(node.ID); err != nil { - t.Fatalf("error starting node: %s", err) - } - nodes[i] = node - } - if err := client.ConnectNode(nodes[0].ID, nodes[1].ID); err != nil { - t.Fatalf("error connecting nodes: %s", err) - } - - // store some state in the test services - states := make([]string, nodeCount) - for i, node := range nodes { - rpc, err := client.RPCClient(context.Background(), node.ID) - if err != nil { - t.Fatalf("error getting RPC client: %s", err) - } - defer rpc.Close() - state := fmt.Sprintf("%x", rand.Int()) - if err := rpc.Call(nil, "test_setState", []byte(state)); err != nil { - t.Fatalf("error setting service state: %s", err) - } - states[i] = state - } - <-eventsDone - // create a snapshot - snap, err := client.CreateSnapshot() - if err != nil { - t.Fatalf("error creating snapshot: %s", err) - } - for i, state := range states { - gotState := snap.Nodes[i].Snapshots["test"] - if string(gotState) != state { - t.Fatalf("expected snapshot state %q, got %q", state, gotState) - } - } - - // create another network - network2, s := testHTTPServer(t) - defer s.Close() - client = NewClient(s.URL) - count = 1 - eventSub = network2.Events().Subscribe(eventsDoneChan) - go func() { - defer eventSub.Unsubscribe() - for event := range eventsDoneChan { - if event.Type == EventTypeConn && !event.Control { - count-- - if count == 0 { - eventsDone <- struct{}{} - return - } - } - } - }() - - // subscribe to events so we can check them later - events := make(chan *Event, 100) - var opts SubscribeOpts - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // load the snapshot - if err := client.LoadSnapshot(snap); err != nil { - t.Fatalf("error loading snapshot: %s", err) - } - <-eventsDone - - // check the nodes and connection exists - net, err := client.GetNetwork() - if err != nil { - t.Fatalf("error getting network: %s", err) - } - if len(net.Nodes) != nodeCount { - t.Fatalf("expected network to have %d nodes, got %d", nodeCount, len(net.Nodes)) - } - for i, node := range nodes { - id := net.Nodes[i].ID().String() - if id != node.ID { - t.Fatalf("expected node %d to have ID %s, got %s", i, node.ID, id) - } - } - if len(net.Conns) != 1 { - t.Fatalf("expected network to have 1 connection, got %d", len(net.Conns)) - } - conn := net.Conns[0] - if conn.One.String() != nodes[0].ID { - t.Fatalf("expected connection to have one=%q, got one=%q", nodes[0].ID, conn.One) - } - if conn.Other.String() != nodes[1].ID { - t.Fatalf("expected connection to have other=%q, got other=%q", nodes[1].ID, conn.Other) - } - if !conn.Up { - t.Fatal("should be up") - } - - // check the node states were restored - for i, node := range nodes { - rpc, err := client.RPCClient(context.Background(), node.ID) - if err != nil { - t.Fatalf("error getting RPC client: %s", err) - } - defer rpc.Close() - var state []byte - if err := rpc.Call(&state, "test_getState"); err != nil { - t.Fatalf("error getting service state: %s", err) - } - if string(state) != states[i] { - t.Fatalf("expected snapshot state %q, got %q", states[i], state) - } - } - - // check we got all the events - x := &expectEvents{t, events, sub} - x.expect( - x.nodeEvent(nodes[0].ID, false), - x.nodeEvent(nodes[0].ID, true), - x.nodeEvent(nodes[1].ID, false), - x.nodeEvent(nodes[1].ID, true), - x.connEvent(nodes[0].ID, nodes[1].ID, false), - x.connEvent(nodes[0].ID, nodes[1].ID, true), - ) -} - -// TestMsgFilterPassMultiple tests streaming message events using a filter -// with multiple protocols -func TestMsgFilterPassMultiple(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events with a message filter - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "prb:0-test:0", - } - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // start a simulation network - startTestNetwork(t, client) - - // check we got the expected events - x := &expectEvents{t, events, sub} - x.expectMsgs(map[MsgFilter]int{ - {"test", 0}: 2, - {"prb", 0}: 2, - }) -} - -// TestMsgFilterPassWildcard tests streaming message events using a filter -// with a code wildcard -func TestMsgFilterPassWildcard(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events with a message filter - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "prb:0,2-test:*", - } - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // start a simulation network - startTestNetwork(t, client) - - // check we got the expected events - x := &expectEvents{t, events, sub} - x.expectMsgs(map[MsgFilter]int{ - {"test", 2}: 2, - {"test", 1}: 2, - {"test", 0}: 2, - {"prb", 0}: 2, - }) -} - -// TestMsgFilterPassSingle tests streaming message events using a filter -// with a single protocol and code -func TestMsgFilterPassSingle(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - // subscribe to events with a message filter - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "dum:0", - } - sub, err := client.SubscribeNetwork(events, opts) - if err != nil { - t.Fatalf("error subscribing to network events: %s", err) - } - defer sub.Unsubscribe() - - // start a simulation network - startTestNetwork(t, client) - - // check we got the expected events - x := &expectEvents{t, events, sub} - x.expectMsgs(map[MsgFilter]int{ - {"dum", 0}: 2, - }) -} - -// TestMsgFilterFailBadParams tests streaming message events using an invalid -// filter -func TestMsgFilterFailBadParams(t *testing.T) { - // start the server - _, s := testHTTPServer(t) - defer s.Close() - - client := NewClient(s.URL) - events := make(chan *Event, 10) - opts := SubscribeOpts{ - Filter: "foo:", - } - _, err := client.SubscribeNetwork(events, opts) - if err == nil { - t.Fatalf("expected event subscription to fail but succeeded!") - } - - opts.Filter = "bzz:aa" - _, err = client.SubscribeNetwork(events, opts) - if err == nil { - t.Fatalf("expected event subscription to fail but succeeded!") - } - - opts.Filter = "invalid" - _, err = client.SubscribeNetwork(events, opts) - if err == nil { - t.Fatalf("expected event subscription to fail but succeeded!") - } -} diff --git a/p2p/simulations/mocker.go b/p2p/simulations/mocker.go deleted file mode 100644 index 8763df67ef..0000000000 --- a/p2p/simulations/mocker.go +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2017 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 . - -// Package simulations simulates p2p networks. -// A mocker simulates starting and stopping real nodes in a network. -package simulations - -import ( - "fmt" - "math/rand" - "sync" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -// a map of mocker names to its function -var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){ - "startStop": startStop, - "probabilistic": probabilistic, - "boot": boot, -} - -// LookupMocker looks a mocker by its name, returns the mockerFn -func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) { - return mockerList[mockerType] -} - -// GetMockerList returns a list of mockers (keys of the map) -// Useful for frontend to build available mocker selection -func GetMockerList() []string { - list := make([]string, 0, len(mockerList)) - for k := range mockerList { - list = append(list, k) - } - return list -} - -// The boot mockerFn only connects the node in a ring and doesn't do anything else -func boot(net *Network, quit chan struct{}, nodeCount int) { - _, err := connectNodesInRing(net, nodeCount) - if err != nil { - panic("Could not startup node network for mocker") - } -} - -// The startStop mockerFn stops and starts nodes in a defined period (ticker) -func startStop(net *Network, quit chan struct{}, nodeCount int) { - nodes, err := connectNodesInRing(net, nodeCount) - if err != nil { - panic("Could not startup node network for mocker") - } - var ( - tick = time.NewTicker(10 * time.Second) - timer = time.NewTimer(3 * time.Second) - ) - defer tick.Stop() - defer timer.Stop() - - for { - select { - case <-quit: - log.Info("Terminating simulation loop") - return - case <-tick.C: - id := nodes[rand.Intn(len(nodes))] - log.Info("stopping node", "id", id) - if err := net.Stop(id); err != nil { - log.Error("error stopping node", "id", id, "err", err) - return - } - - timer.Reset(3 * time.Second) - select { - case <-quit: - log.Info("Terminating simulation loop") - return - case <-timer.C: - } - - log.Debug("starting node", "id", id) - if err := net.Start(id); err != nil { - log.Error("error starting node", "id", id, "err", err) - return - } - } - } -} - -// The probabilistic mocker func has a more probabilistic pattern -// (the implementation could probably be improved): -// nodes are connected in a ring, then a varying number of random nodes is selected, -// mocker then stops and starts them in random intervals, and continues the loop -func probabilistic(net *Network, quit chan struct{}, nodeCount int) { - nodes, err := connectNodesInRing(net, nodeCount) - if err != nil { - select { - case <-quit: - //error may be due to abortion of mocking; so the quit channel is closed - return - default: - panic("Could not startup node network for mocker") - } - } - for { - select { - case <-quit: - log.Info("Terminating simulation loop") - return - default: - } - var lowid, highid int - var wg sync.WaitGroup - randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond - rand1 := rand.Intn(nodeCount - 1) - rand2 := rand.Intn(nodeCount - 1) - if rand1 <= rand2 { - lowid = rand1 - highid = rand2 - } else if rand1 > rand2 { - highid = rand1 - lowid = rand2 - } - var steps = highid - lowid - wg.Add(steps) - for i := lowid; i < highid; i++ { - select { - case <-quit: - log.Info("Terminating simulation loop") - return - case <-time.After(randWait): - } - log.Debug(fmt.Sprintf("node %v shutting down", nodes[i])) - err := net.Stop(nodes[i]) - if err != nil { - log.Error("Error stopping node", "node", nodes[i]) - wg.Done() - continue - } - go func(id enode.ID) { - time.Sleep(randWait) - err := net.Start(id) - if err != nil { - log.Error("Error starting node", "node", id) - } - wg.Done() - }(nodes[i]) - } - wg.Wait() - } -} - -// connect nodeCount number of nodes in a ring -func connectNodesInRing(net *Network, nodeCount int) ([]enode.ID, error) { - ids := make([]enode.ID, nodeCount) - for i := 0; i < nodeCount; i++ { - conf := adapters.RandomNodeConfig() - node, err := net.NewNodeWithConfig(conf) - if err != nil { - log.Error("Error creating a node!", "err", err) - return nil, err - } - ids[i] = node.ID() - } - - for _, id := range ids { - if err := net.Start(id); err != nil { - log.Error("Error starting a node!", "err", err) - return nil, err - } - log.Debug(fmt.Sprintf("node %v starting up", id)) - } - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := net.Connect(id, peerID); err != nil { - log.Error("Error connecting a node to a peer!", "err", err) - return nil, err - } - } - - return ids, nil -} diff --git a/p2p/simulations/mocker_test.go b/p2p/simulations/mocker_test.go deleted file mode 100644 index 0112ee5cfd..0000000000 --- a/p2p/simulations/mocker_test.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2017 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 . - -// Package simulations simulates p2p networks. -// A mocker simulates starting and stopping real nodes in a network. -package simulations - -import ( - "encoding/json" - "net/http" - "net/url" - "strconv" - "sync" - "testing" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -func TestMocker(t *testing.T) { - //start the simulation HTTP server - _, s := testHTTPServer(t) - defer s.Close() - - //create a client - client := NewClient(s.URL) - - //start the network - err := client.StartNetwork() - if err != nil { - t.Fatalf("Could not start test network: %s", err) - } - //stop the network to terminate - defer func() { - err = client.StopNetwork() - if err != nil { - t.Fatalf("Could not stop test network: %s", err) - } - }() - - //get the list of available mocker types - resp, err := http.Get(s.URL + "/mocker") - if err != nil { - t.Fatalf("Could not get mocker list: %s", err) - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - t.Fatalf("Invalid Status Code received, expected 200, got %d", resp.StatusCode) - } - - //check the list is at least 1 in size - var mockerlist []string - err = json.NewDecoder(resp.Body).Decode(&mockerlist) - if err != nil { - t.Fatalf("Error decoding JSON mockerlist: %s", err) - } - - if len(mockerlist) < 1 { - t.Fatalf("No mockers available") - } - - nodeCount := 10 - var wg sync.WaitGroup - - events := make(chan *Event, 10) - var opts SubscribeOpts - sub, err := client.SubscribeNetwork(events, opts) - defer sub.Unsubscribe() - - // wait until all nodes are started and connected - // store every node up event in a map (value is irrelevant, mimic Set datatype) - nodemap := make(map[enode.ID]bool) - nodesComplete := false - connCount := 0 - wg.Add(1) - go func() { - defer wg.Done() - - for connCount < (nodeCount-1)*2 { - select { - case event := <-events: - if isNodeUp(event) { - //add the correspondent node ID to the map - nodemap[event.Node.Config.ID] = true - //this means all nodes got a nodeUp event, so we can continue the test - if len(nodemap) == nodeCount { - nodesComplete = true - } - } else if event.Conn != nil && nodesComplete { - connCount += 1 - } - case <-time.After(30 * time.Second): - t.Errorf("Timeout waiting for nodes being started up!") - return - } - } - }() - - //take the last element of the mockerlist as the default mocker-type to ensure one is enabled - mockertype := mockerlist[len(mockerlist)-1] - //still, use hardcoded "probabilistic" one if available ;) - for _, m := range mockerlist { - if m == "probabilistic" { - mockertype = m - break - } - } - //start the mocker with nodeCount number of nodes - resp, err = http.PostForm(s.URL+"/mocker/start", url.Values{"mocker-type": {mockertype}, "node-count": {strconv.Itoa(nodeCount)}}) - if err != nil { - t.Fatalf("Could not start mocker: %s", err) - } - resp.Body.Close() - if resp.StatusCode != 200 { - t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode) - } - - wg.Wait() - - //check there are nodeCount number of nodes in the network - nodesInfo, err := client.GetNodes() - if err != nil { - t.Fatalf("Could not get nodes list: %s", err) - } - - if len(nodesInfo) != nodeCount { - t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodesInfo)) - } - - //stop the mocker - resp, err = http.Post(s.URL+"/mocker/stop", "", nil) - if err != nil { - t.Fatalf("Could not stop mocker: %s", err) - } - resp.Body.Close() - if resp.StatusCode != 200 { - t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode) - } - - //reset the network - resp, err = http.Post(s.URL+"/reset", "", nil) - if err != nil { - t.Fatalf("Could not reset network: %s", err) - } - resp.Body.Close() - - //now the number of nodes in the network should be zero - nodesInfo, err = client.GetNodes() - if err != nil { - t.Fatalf("Could not get nodes list: %s", err) - } - - if len(nodesInfo) != 0 { - t.Fatalf("Expected empty list of nodes, got: %d", len(nodesInfo)) - } -} - -func isNodeUp(event *Event) bool { - return event.Node != nil && event.Node.Up() -} diff --git a/p2p/simulations/network.go b/p2p/simulations/network.go deleted file mode 100644 index 2eb8333cd6..0000000000 --- a/p2p/simulations/network.go +++ /dev/null @@ -1,1093 +0,0 @@ -// Copyright 2017 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 . - -package simulations - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "math/rand" - "sync" - "time" - - "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -var DialBanTimeout = 200 * time.Millisecond - -// NetworkConfig defines configuration options for starting a Network -type NetworkConfig struct { - ID string `json:"id"` - DefaultService string `json:"default_service,omitempty"` -} - -// Network models a p2p simulation network which consists of a collection of -// simulated nodes and the connections which exist between them. -// -// The Network has a single NodeAdapter which is responsible for actually -// starting nodes and connecting them together. -// -// The Network emits events when nodes are started and stopped, when they are -// connected and disconnected, and also when messages are sent between nodes. -type Network struct { - NetworkConfig - - Nodes []*Node `json:"nodes"` - nodeMap map[enode.ID]int - - // Maps a node property string to node indexes of all nodes that hold this property - propertyMap map[string][]int - - Conns []*Conn `json:"conns"` - connMap map[string]int - - nodeAdapter adapters.NodeAdapter - events event.Feed - lock sync.RWMutex - quitc chan struct{} -} - -// NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig -func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network { - return &Network{ - NetworkConfig: *conf, - nodeAdapter: nodeAdapter, - nodeMap: make(map[enode.ID]int), - propertyMap: make(map[string][]int), - connMap: make(map[string]int), - quitc: make(chan struct{}), - } -} - -// Events returns the output event feed of the Network. -func (net *Network) Events() *event.Feed { - return &net.events -} - -// NewNodeWithConfig adds a new node to the network with the given config, -// returning an error if a node with the same ID or name already exists -func (net *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) { - net.lock.Lock() - defer net.lock.Unlock() - - if conf.Reachable == nil { - conf.Reachable = func(otherID enode.ID) bool { - _, err := net.InitConn(conf.ID, otherID) - if err != nil && bytes.Compare(conf.ID.Bytes(), otherID.Bytes()) < 0 { - return false - } - return true - } - } - - // check the node doesn't already exist - if node := net.getNode(conf.ID); node != nil { - return nil, fmt.Errorf("node with ID %q already exists", conf.ID) - } - if node := net.getNodeByName(conf.Name); node != nil { - return nil, fmt.Errorf("node with name %q already exists", conf.Name) - } - - // if no services are configured, use the default service - if len(conf.Lifecycles) == 0 { - conf.Lifecycles = []string{net.DefaultService} - } - - // use the NodeAdapter to create the node - adapterNode, err := net.nodeAdapter.NewNode(conf) - if err != nil { - return nil, err - } - node := newNode(adapterNode, conf, false) - log.Trace("Node created", "id", conf.ID) - - nodeIndex := len(net.Nodes) - net.nodeMap[conf.ID] = nodeIndex - net.Nodes = append(net.Nodes, node) - - // Register any node properties with the network-level propertyMap - for _, property := range conf.Properties { - net.propertyMap[property] = append(net.propertyMap[property], nodeIndex) - } - - // emit a "control" event - net.events.Send(ControlEvent(node)) - - return node, nil -} - -// Config returns the network configuration -func (net *Network) Config() *NetworkConfig { - return &net.NetworkConfig -} - -// StartAll starts all nodes in the network -func (net *Network) StartAll() error { - for _, node := range net.Nodes { - if node.Up() { - continue - } - if err := net.Start(node.ID()); err != nil { - return err - } - } - return nil -} - -// StopAll stops all nodes in the network -func (net *Network) StopAll() error { - for _, node := range net.Nodes { - if !node.Up() { - continue - } - if err := net.Stop(node.ID()); err != nil { - return err - } - } - return nil -} - -// Start starts the node with the given ID -func (net *Network) Start(id enode.ID) error { - return net.startWithSnapshots(id, nil) -} - -// startWithSnapshots starts the node with the given ID using the give -// snapshots -func (net *Network) startWithSnapshots(id enode.ID, snapshots map[string][]byte) error { - net.lock.Lock() - defer net.lock.Unlock() - - node := net.getNode(id) - if node == nil { - return fmt.Errorf("node %v does not exist", id) - } - if node.Up() { - return fmt.Errorf("node %v already up", id) - } - log.Trace("Starting node", "id", id, "adapter", net.nodeAdapter.Name()) - if err := node.Start(snapshots); err != nil { - log.Warn("Node startup failed", "id", id, "err", err) - return err - } - node.SetUp(true) - log.Info("Started node", "id", id) - ev := NewEvent(node) - net.events.Send(ev) - - // subscribe to peer events - client, err := node.Client() - if err != nil { - return fmt.Errorf("error getting rpc client for node %v: %s", id, err) - } - events := make(chan *p2p.PeerEvent) - sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents") - if err != nil { - return fmt.Errorf("error getting peer events for node %v: %s", id, err) - } - go net.watchPeerEvents(id, events, sub) - return nil -} - -// watchPeerEvents reads peer events from the given channel and emits -// corresponding network events -func (net *Network) watchPeerEvents(id enode.ID, events chan *p2p.PeerEvent, sub event.Subscription) { - defer func() { - sub.Unsubscribe() - - // assume the node is now down - net.lock.Lock() - defer net.lock.Unlock() - - node := net.getNode(id) - if node == nil { - return - } - node.SetUp(false) - ev := NewEvent(node) - net.events.Send(ev) - }() - for { - select { - case event, ok := <-events: - if !ok { - return - } - peer := event.Peer - switch event.Type { - case p2p.PeerEventTypeAdd: - net.DidConnect(id, peer) - - case p2p.PeerEventTypeDrop: - net.DidDisconnect(id, peer) - - case p2p.PeerEventTypeMsgSend: - net.DidSend(id, peer, event.Protocol, *event.MsgCode) - - case p2p.PeerEventTypeMsgRecv: - net.DidReceive(peer, id, event.Protocol, *event.MsgCode) - } - - case err := <-sub.Err(): - if err != nil { - log.Error("Error in peer event subscription", "id", id, "err", err) - } - return - } - } -} - -// Stop stops the node with the given ID -func (net *Network) Stop(id enode.ID) error { - // IMPORTANT: node.Stop() must NOT be called under net.lock as - // node.Reachable() closure has a reference to the network and - // calls net.InitConn() what also locks the network. => DEADLOCK - // That holds until the following ticket is not resolved: - - var err error - - node, err := func() (*Node, error) { - net.lock.Lock() - defer net.lock.Unlock() - - node := net.getNode(id) - if node == nil { - return nil, fmt.Errorf("node %v does not exist", id) - } - if !node.Up() { - return nil, fmt.Errorf("node %v already down", id) - } - node.SetUp(false) - return node, nil - }() - if err != nil { - return err - } - - err = node.Stop() // must be called without net.lock - - net.lock.Lock() - defer net.lock.Unlock() - - if err != nil { - node.SetUp(true) - return err - } - log.Info("Stopped node", "id", id, "err", err) - ev := ControlEvent(node) - net.events.Send(ev) - return nil -} - -// Connect connects two nodes together by calling the "admin_addPeer" RPC -// method on the "one" node so that it connects to the "other" node -func (net *Network) Connect(oneID, otherID enode.ID) error { - net.lock.Lock() - defer net.lock.Unlock() - return net.connect(oneID, otherID) -} - -func (net *Network) connect(oneID, otherID enode.ID) error { - log.Debug("Connecting nodes with addPeer", "id", oneID, "other", otherID) - conn, err := net.initConn(oneID, otherID) - if err != nil { - return err - } - client, err := conn.one.Client() - if err != nil { - return err - } - net.events.Send(ControlEvent(conn)) - return client.Call(nil, "admin_addPeer", string(conn.other.Addr())) -} - -// Disconnect disconnects two nodes by calling the "admin_removePeer" RPC -// method on the "one" node so that it disconnects from the "other" node -func (net *Network) Disconnect(oneID, otherID enode.ID) error { - conn := net.GetConn(oneID, otherID) - if conn == nil { - return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID) - } - if !conn.Up { - return fmt.Errorf("%v and %v already disconnected", oneID, otherID) - } - client, err := conn.one.Client() - if err != nil { - return err - } - net.events.Send(ControlEvent(conn)) - return client.Call(nil, "admin_removePeer", string(conn.other.Addr())) -} - -// DidConnect tracks the fact that the "one" node connected to the "other" node -func (net *Network) DidConnect(one, other enode.ID) error { - net.lock.Lock() - defer net.lock.Unlock() - conn, err := net.getOrCreateConn(one, other) - if err != nil { - return fmt.Errorf("connection between %v and %v does not exist", one, other) - } - if conn.Up { - return fmt.Errorf("%v and %v already connected", one, other) - } - conn.Up = true - net.events.Send(NewEvent(conn)) - return nil -} - -// DidDisconnect tracks the fact that the "one" node disconnected from the -// "other" node -func (net *Network) DidDisconnect(one, other enode.ID) error { - net.lock.Lock() - defer net.lock.Unlock() - conn := net.getConn(one, other) - if conn == nil { - return fmt.Errorf("connection between %v and %v does not exist", one, other) - } - if !conn.Up { - return fmt.Errorf("%v and %v already disconnected", one, other) - } - conn.Up = false - conn.initiated = time.Now().Add(-DialBanTimeout) - net.events.Send(NewEvent(conn)) - return nil -} - -// DidSend tracks the fact that "sender" sent a message to "receiver" -func (net *Network) DidSend(sender, receiver enode.ID, proto string, code uint64) error { - msg := &Msg{ - One: sender, - Other: receiver, - Protocol: proto, - Code: code, - Received: false, - } - net.events.Send(NewEvent(msg)) - return nil -} - -// DidReceive tracks the fact that "receiver" received a message from "sender" -func (net *Network) DidReceive(sender, receiver enode.ID, proto string, code uint64) error { - msg := &Msg{ - One: sender, - Other: receiver, - Protocol: proto, - Code: code, - Received: true, - } - net.events.Send(NewEvent(msg)) - return nil -} - -// GetNode gets the node with the given ID, returning nil if the node does not -// exist -func (net *Network) GetNode(id enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getNode(id) -} - -func (net *Network) getNode(id enode.ID) *Node { - i, found := net.nodeMap[id] - if !found { - return nil - } - return net.Nodes[i] -} - -// GetNodeByName gets the node with the given name, returning nil if the node does -// not exist -func (net *Network) GetNodeByName(name string) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getNodeByName(name) -} - -func (net *Network) getNodeByName(name string) *Node { - for _, node := range net.Nodes { - if node.Config.Name == name { - return node - } - } - return nil -} - -// GetNodeIDs returns the IDs of all existing nodes -// Nodes can optionally be excluded by specifying their enode.ID. -func (net *Network) GetNodeIDs(excludeIDs ...enode.ID) []enode.ID { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodeIDs(excludeIDs) -} - -func (net *Network) getNodeIDs(excludeIDs []enode.ID) []enode.ID { - // Get all current nodeIDs - nodeIDs := make([]enode.ID, 0, len(net.nodeMap)) - for id := range net.nodeMap { - nodeIDs = append(nodeIDs, id) - } - - if len(excludeIDs) > 0 { - // Return the difference of nodeIDs and excludeIDs - return filterIDs(nodeIDs, excludeIDs) - } - return nodeIDs -} - -// GetNodes returns the existing nodes. -// Nodes can optionally be excluded by specifying their enode.ID. -func (net *Network) GetNodes(excludeIDs ...enode.ID) []*Node { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodes(excludeIDs) -} - -func (net *Network) getNodes(excludeIDs []enode.ID) []*Node { - if len(excludeIDs) > 0 { - nodeIDs := net.getNodeIDs(excludeIDs) - return net.getNodesByID(nodeIDs) - } - return net.Nodes -} - -// GetNodesByID returns existing nodes with the given enode.IDs. -// If a node doesn't exist with a given enode.ID, it is ignored. -func (net *Network) GetNodesByID(nodeIDs []enode.ID) []*Node { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodesByID(nodeIDs) -} - -func (net *Network) getNodesByID(nodeIDs []enode.ID) []*Node { - nodes := make([]*Node, 0, len(nodeIDs)) - for _, id := range nodeIDs { - node := net.getNode(id) - if node != nil { - nodes = append(nodes, node) - } - } - - return nodes -} - -// GetNodesByProperty returns existing nodes that have the given property string registered in their NodeConfig -func (net *Network) GetNodesByProperty(property string) []*Node { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodesByProperty(property) -} - -func (net *Network) getNodesByProperty(property string) []*Node { - nodes := make([]*Node, 0, len(net.propertyMap[property])) - for _, nodeIndex := range net.propertyMap[property] { - nodes = append(nodes, net.Nodes[nodeIndex]) - } - - return nodes -} - -// GetNodeIDsByProperty returns existing node's enode IDs that have the given property string registered in the NodeConfig -func (net *Network) GetNodeIDsByProperty(property string) []enode.ID { - net.lock.RLock() - defer net.lock.RUnlock() - - return net.getNodeIDsByProperty(property) -} - -func (net *Network) getNodeIDsByProperty(property string) []enode.ID { - nodeIDs := make([]enode.ID, 0, len(net.propertyMap[property])) - for _, nodeIndex := range net.propertyMap[property] { - node := net.Nodes[nodeIndex] - nodeIDs = append(nodeIDs, node.ID()) - } - - return nodeIDs -} - -// GetRandomUpNode returns a random node on the network, which is running. -func (net *Network) GetRandomUpNode(excludeIDs ...enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getRandomUpNode(excludeIDs...) -} - -// getRandomUpNode returns a random node on the network, which is running. -func (net *Network) getRandomUpNode(excludeIDs ...enode.ID) *Node { - return net.getRandomNode(net.getUpNodeIDs(), excludeIDs) -} - -func (net *Network) getUpNodeIDs() (ids []enode.ID) { - for _, node := range net.Nodes { - if node.Up() { - ids = append(ids, node.ID()) - } - } - return ids -} - -// GetRandomDownNode returns a random node on the network, which is stopped. -func (net *Network) GetRandomDownNode(excludeIDs ...enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getRandomNode(net.getDownNodeIDs(), excludeIDs) -} - -func (net *Network) getDownNodeIDs() (ids []enode.ID) { - for _, node := range net.Nodes { - if !node.Up() { - ids = append(ids, node.ID()) - } - } - return ids -} - -// GetRandomNode returns a random node on the network, regardless of whether it is running or not -func (net *Network) GetRandomNode(excludeIDs ...enode.ID) *Node { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getRandomNode(net.getNodeIDs(nil), excludeIDs) // no need to exclude twice -} - -func (net *Network) getRandomNode(ids []enode.ID, excludeIDs []enode.ID) *Node { - filtered := filterIDs(ids, excludeIDs) - - l := len(filtered) - if l == 0 { - return nil - } - return net.getNode(filtered[rand.Intn(l)]) -} - -func filterIDs(ids []enode.ID, excludeIDs []enode.ID) []enode.ID { - exclude := make(map[enode.ID]bool) - for _, id := range excludeIDs { - exclude[id] = true - } - var filtered []enode.ID - for _, id := range ids { - if _, found := exclude[id]; !found { - filtered = append(filtered, id) - } - } - return filtered -} - -// GetConn returns the connection which exists between "one" and "other" -// regardless of which node initiated the connection -func (net *Network) GetConn(oneID, otherID enode.ID) *Conn { - net.lock.RLock() - defer net.lock.RUnlock() - return net.getConn(oneID, otherID) -} - -// GetOrCreateConn is like GetConn but creates the connection if it doesn't -// already exist -func (net *Network) GetOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { - net.lock.Lock() - defer net.lock.Unlock() - return net.getOrCreateConn(oneID, otherID) -} - -func (net *Network) getOrCreateConn(oneID, otherID enode.ID) (*Conn, error) { - if conn := net.getConn(oneID, otherID); conn != nil { - return conn, nil - } - - one := net.getNode(oneID) - if one == nil { - return nil, fmt.Errorf("node %v does not exist", oneID) - } - other := net.getNode(otherID) - if other == nil { - return nil, fmt.Errorf("node %v does not exist", otherID) - } - conn := &Conn{ - One: oneID, - Other: otherID, - one: one, - other: other, - } - label := ConnLabel(oneID, otherID) - net.connMap[label] = len(net.Conns) - net.Conns = append(net.Conns, conn) - return conn, nil -} - -func (net *Network) getConn(oneID, otherID enode.ID) *Conn { - label := ConnLabel(oneID, otherID) - i, found := net.connMap[label] - if !found { - return nil - } - return net.Conns[i] -} - -// InitConn retrieves the connection model for the connection between -// peers 'oneID' and 'otherID', or creates a new one if it does not exist -// the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i) -// it checks if the connection is already up, and if the nodes are running -// NOTE: -// it also checks whether there has been recent attempt to connect the peers -// this is cheating as the simulation is used as an oracle and know about -// remote peers attempt to connect to a node which will then not initiate the connection -func (net *Network) InitConn(oneID, otherID enode.ID) (*Conn, error) { - net.lock.Lock() - defer net.lock.Unlock() - return net.initConn(oneID, otherID) -} - -func (net *Network) initConn(oneID, otherID enode.ID) (*Conn, error) { - if oneID == otherID { - return nil, fmt.Errorf("refusing to connect to self %v", oneID) - } - conn, err := net.getOrCreateConn(oneID, otherID) - if err != nil { - return nil, err - } - if conn.Up { - return nil, fmt.Errorf("%v and %v already connected", oneID, otherID) - } - if time.Since(conn.initiated) < DialBanTimeout { - return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID) - } - - err = conn.nodesUp() - if err != nil { - log.Trace("Nodes not up", "err", err) - return nil, fmt.Errorf("nodes not up: %v", err) - } - log.Debug("Connection initiated", "id", oneID, "other", otherID) - conn.initiated = time.Now() - return conn, nil -} - -// Shutdown stops all nodes in the network and closes the quit channel -func (net *Network) Shutdown() { - for _, node := range net.Nodes { - log.Debug("Stopping node", "id", node.ID()) - if err := node.Stop(); err != nil { - log.Warn("Can't stop node", "id", node.ID(), "err", err) - } - } - close(net.quitc) -} - -// Reset resets all network properties: -// empties the nodes and the connection list -func (net *Network) Reset() { - net.lock.Lock() - defer net.lock.Unlock() - - //re-initialize the maps - net.connMap = make(map[string]int) - net.nodeMap = make(map[enode.ID]int) - net.propertyMap = make(map[string][]int) - - net.Nodes = nil - net.Conns = nil -} - -// Node is a wrapper around adapters.Node which is used to track the status -// of a node in the network -type Node struct { - adapters.Node `json:"-"` - - // Config if the config used to created the node - Config *adapters.NodeConfig `json:"config"` - - // up tracks whether or not the node is running - up bool - upMu *sync.RWMutex -} - -func newNode(an adapters.Node, ac *adapters.NodeConfig, up bool) *Node { - return &Node{Node: an, Config: ac, up: up, upMu: new(sync.RWMutex)} -} - -func (n *Node) copy() *Node { - configCpy := *n.Config - return newNode(n.Node, &configCpy, n.Up()) -} - -// Up returns whether the node is currently up (online) -func (n *Node) Up() bool { - n.upMu.RLock() - defer n.upMu.RUnlock() - return n.up -} - -// SetUp sets the up (online) status of the nodes with the given value -func (n *Node) SetUp(up bool) { - n.upMu.Lock() - defer n.upMu.Unlock() - n.up = up -} - -// ID returns the ID of the node -func (n *Node) ID() enode.ID { - return n.Config.ID -} - -// String returns a log-friendly string -func (n *Node) String() string { - return fmt.Sprintf("Node %v", n.ID().TerminalString()) -} - -// NodeInfo returns information about the node -func (n *Node) NodeInfo() *p2p.NodeInfo { - // avoid a panic if the node is not started yet - if n.Node == nil { - return nil - } - info := n.Node.NodeInfo() - info.Name = n.Config.Name - return info -} - -// MarshalJSON implements the json.Marshaler interface so that the encoded -// JSON includes the NodeInfo -func (n *Node) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Info *p2p.NodeInfo `json:"info,omitempty"` - Config *adapters.NodeConfig `json:"config,omitempty"` - Up bool `json:"up"` - }{ - Info: n.NodeInfo(), - Config: n.Config, - Up: n.Up(), - }) -} - -// UnmarshalJSON implements json.Unmarshaler interface so that we don't lose Node.up -// status. IMPORTANT: The implementation is incomplete; we lose p2p.NodeInfo. -func (n *Node) UnmarshalJSON(raw []byte) error { - // TODO: How should we turn back NodeInfo into n.Node? - // Ticket: https://github.com/ethersphere/go-ethereum/issues/1177 - var node struct { - Config *adapters.NodeConfig `json:"config,omitempty"` - Up bool `json:"up"` - } - if err := json.Unmarshal(raw, &node); err != nil { - return err - } - *n = *newNode(nil, node.Config, node.Up) - return nil -} - -// Conn represents a connection between two nodes in the network -type Conn struct { - // One is the node which initiated the connection - One enode.ID `json:"one"` - - // Other is the node which the connection was made to - Other enode.ID `json:"other"` - - // Up tracks whether or not the connection is active - Up bool `json:"up"` - // Registers when the connection was grabbed to dial - initiated time.Time - - one *Node - other *Node -} - -// nodesUp returns whether both nodes are currently up -func (c *Conn) nodesUp() error { - if !c.one.Up() { - return fmt.Errorf("one %v is not up", c.One) - } - if !c.other.Up() { - return fmt.Errorf("other %v is not up", c.Other) - } - return nil -} - -// String returns a log-friendly string -func (c *Conn) String() string { - return fmt.Sprintf("Conn %v->%v", c.One.TerminalString(), c.Other.TerminalString()) -} - -// Msg represents a p2p message sent between two nodes in the network -type Msg struct { - One enode.ID `json:"one"` - Other enode.ID `json:"other"` - Protocol string `json:"protocol"` - Code uint64 `json:"code"` - Received bool `json:"received"` -} - -// String returns a log-friendly string -func (m *Msg) String() string { - return fmt.Sprintf("Msg(%d) %v->%v", m.Code, m.One.TerminalString(), m.Other.TerminalString()) -} - -// ConnLabel generates a deterministic string which represents a connection -// between two nodes, used to compare if two connections are between the same -// nodes -func ConnLabel(source, target enode.ID) string { - var first, second enode.ID - if bytes.Compare(source.Bytes(), target.Bytes()) > 0 { - first = target - second = source - } else { - first = source - second = target - } - return fmt.Sprintf("%v-%v", first, second) -} - -// Snapshot represents the state of a network at a single point in time and can -// be used to restore the state of a network -type Snapshot struct { - Nodes []NodeSnapshot `json:"nodes,omitempty"` - Conns []Conn `json:"conns,omitempty"` -} - -// NodeSnapshot represents the state of a node in the network -type NodeSnapshot struct { - Node Node `json:"node,omitempty"` - - // Snapshots is arbitrary data gathered from calling node.Snapshots() - Snapshots map[string][]byte `json:"snapshots,omitempty"` -} - -// Snapshot creates a network snapshot -func (net *Network) Snapshot() (*Snapshot, error) { - return net.snapshot(nil, nil) -} - -func (net *Network) SnapshotWithServices(addServices []string, removeServices []string) (*Snapshot, error) { - return net.snapshot(addServices, removeServices) -} - -func (net *Network) snapshot(addServices []string, removeServices []string) (*Snapshot, error) { - net.lock.Lock() - defer net.lock.Unlock() - snap := &Snapshot{ - Nodes: make([]NodeSnapshot, len(net.Nodes)), - } - for i, node := range net.Nodes { - snap.Nodes[i] = NodeSnapshot{Node: *node.copy()} - if !node.Up() { - continue - } - snapshots, err := node.Snapshots() - if err != nil { - return nil, err - } - snap.Nodes[i].Snapshots = snapshots - for _, addSvc := range addServices { - haveSvc := false - for _, svc := range snap.Nodes[i].Node.Config.Lifecycles { - if svc == addSvc { - haveSvc = true - break - } - } - if !haveSvc { - snap.Nodes[i].Node.Config.Lifecycles = append(snap.Nodes[i].Node.Config.Lifecycles, addSvc) - } - } - if len(removeServices) > 0 { - var cleanedServices []string - for _, svc := range snap.Nodes[i].Node.Config.Lifecycles { - haveSvc := false - for _, rmSvc := range removeServices { - if rmSvc == svc { - haveSvc = true - break - } - } - if !haveSvc { - cleanedServices = append(cleanedServices, svc) - } - } - snap.Nodes[i].Node.Config.Lifecycles = cleanedServices - } - } - for _, conn := range net.Conns { - if conn.Up { - snap.Conns = append(snap.Conns, *conn) - } - } - return snap, nil -} - -// longrunning tests may need a longer timeout -var snapshotLoadTimeout = 900 * time.Second - -// Load loads a network snapshot -func (net *Network) Load(snap *Snapshot) error { - // Start nodes. - for _, n := range snap.Nodes { - if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil { - return err - } - if !n.Node.Up() { - continue - } - if err := net.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil { - return err - } - } - - // Prepare connection events counter. - allConnected := make(chan struct{}) // closed when all connections are established - done := make(chan struct{}) // ensures that the event loop goroutine is terminated - defer close(done) - - // Subscribe to event channel. - // It needs to be done outside of the event loop goroutine (created below) - // to ensure that the event channel is blocking before connect calls are made. - events := make(chan *Event) - sub := net.Events().Subscribe(events) - defer sub.Unsubscribe() - - go func() { - // Expected number of connections. - total := len(snap.Conns) - // Set of all established connections from the snapshot, not other connections. - // Key array element 0 is the connection One field value, and element 1 connection Other field. - connections := make(map[[2]enode.ID]struct{}, total) - - for { - select { - case e := <-events: - // Ignore control events as they do not represent - // connect or disconnect (Up) state change. - if e.Control { - continue - } - // Detect only connection events. - if e.Type != EventTypeConn { - continue - } - connection := [2]enode.ID{e.Conn.One, e.Conn.Other} - // Nodes are still not connected or have been disconnected. - if !e.Conn.Up { - // Delete the connection from the set of established connections. - // This will prevent false positive in case disconnections happen. - delete(connections, connection) - log.Warn("load snapshot: unexpected disconnection", "one", e.Conn.One, "other", e.Conn.Other) - continue - } - // Check that the connection is from the snapshot. - for _, conn := range snap.Conns { - if conn.One == e.Conn.One && conn.Other == e.Conn.Other { - // Add the connection to the set of established connections. - connections[connection] = struct{}{} - if len(connections) == total { - // Signal that all nodes are connected. - close(allConnected) - return - } - - break - } - } - case <-done: - // Load function returned, terminate this goroutine. - return - } - } - }() - - // Start connecting. - for _, conn := range snap.Conns { - if !net.GetNode(conn.One).Up() || !net.GetNode(conn.Other).Up() { - //in this case, at least one of the nodes of a connection is not up, - //so it would result in the snapshot `Load` to fail - continue - } - if err := net.Connect(conn.One, conn.Other); err != nil { - return err - } - } - - timeout := time.NewTimer(snapshotLoadTimeout) - defer timeout.Stop() - - select { - // Wait until all connections from the snapshot are established. - case <-allConnected: - // Make sure that we do not wait forever. - case <-timeout.C: - return errors.New("snapshot connections not established") - } - return nil -} - -// Subscribe reads control events from a channel and executes them -func (net *Network) Subscribe(events chan *Event) { - for { - select { - case event, ok := <-events: - if !ok { - return - } - if event.Control { - net.executeControlEvent(event) - } - case <-net.quitc: - return - } - } -} - -func (net *Network) executeControlEvent(event *Event) { - log.Trace("Executing control event", "type", event.Type, "event", event) - switch event.Type { - case EventTypeNode: - if err := net.executeNodeEvent(event); err != nil { - log.Error("Error executing node event", "event", event, "err", err) - } - case EventTypeConn: - if err := net.executeConnEvent(event); err != nil { - log.Error("Error executing conn event", "event", event, "err", err) - } - case EventTypeMsg: - log.Warn("Ignoring control msg event") - } -} - -func (net *Network) executeNodeEvent(e *Event) error { - if !e.Node.Up() { - return net.Stop(e.Node.ID()) - } - - if _, err := net.NewNodeWithConfig(e.Node.Config); err != nil { - return err - } - return net.Start(e.Node.ID()) -} - -func (net *Network) executeConnEvent(e *Event) error { - if e.Conn.Up { - return net.Connect(e.Conn.One, e.Conn.Other) - } - return net.Disconnect(e.Conn.One, e.Conn.Other) -} diff --git a/p2p/simulations/network_test.go b/p2p/simulations/network_test.go deleted file mode 100644 index 4ed1e4e6c3..0000000000 --- a/p2p/simulations/network_test.go +++ /dev/null @@ -1,872 +0,0 @@ -// Copyright 2017 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 . - -package simulations - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "reflect" - "strconv" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/simulations/adapters" -) - -// Tests that a created snapshot with a minimal service only contains the expected connections -// and that a network when loaded with this snapshot only contains those same connections -func TestSnapshot(t *testing.T) { - // PART I - // create snapshot from ring network - - // this is a minimal service, whose protocol will take exactly one message OR close of connection before quitting - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }) - - // create network - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - // \todo consider making a member of network, set to true threadsafe when shutdown - runningOne := true - defer func() { - if runningOne { - network.Shutdown() - } - }() - - // create and start nodes - nodeCount := 20 - ids := make([]enode.ID, nodeCount) - for i := 0; i < nodeCount; i++ { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - t.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - // subscribe to peer events - evC := make(chan *Event) - sub := network.Events().Subscribe(evC) - defer sub.Unsubscribe() - - // connect nodes in a ring - // spawn separate thread to avoid deadlock in the event listeners - connectErr := make(chan error, 1) - go func() { - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := network.Connect(id, peerID); err != nil { - connectErr <- err - return - } - } - }() - - // collect connection events up to expected number - ctx, cancel := context.WithTimeout(context.TODO(), time.Second) - defer cancel() - checkIds := make(map[enode.ID][]enode.ID) - connEventCount := nodeCount -OUTER: - for { - select { - case <-ctx.Done(): - t.Fatal(ctx.Err()) - case err := <-connectErr: - t.Fatal(err) - case ev := <-evC: - if ev.Type == EventTypeConn && !ev.Control { - // fail on any disconnect - if !ev.Conn.Up { - t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) - } - checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other) - checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One) - connEventCount-- - log.Debug("ev", "count", connEventCount) - if connEventCount == 0 { - break OUTER - } - } - } - } - - // create snapshot of current network - snap, err := network.Snapshot() - if err != nil { - t.Fatal(err) - } - j, err := json.Marshal(snap) - if err != nil { - t.Fatal(err) - } - log.Debug("snapshot taken", "nodes", len(snap.Nodes), "conns", len(snap.Conns), "json", string(j)) - - // verify that the snap element numbers check out - if len(checkIds) != len(snap.Conns) || len(checkIds) != len(snap.Nodes) { - t.Fatalf("snapshot wrong node,conn counts %d,%d != %d", len(snap.Nodes), len(snap.Conns), len(checkIds)) - } - - // shut down sim network - runningOne = false - sub.Unsubscribe() - network.Shutdown() - - // check that we have all the expected connections in the snapshot - for nodid, nodConns := range checkIds { - for _, nodConn := range nodConns { - var match bool - for _, snapConn := range snap.Conns { - if snapConn.One == nodid && snapConn.Other == nodConn { - match = true - break - } else if snapConn.Other == nodid && snapConn.One == nodConn { - match = true - break - } - } - if !match { - t.Fatalf("snapshot missing conn %v -> %v", nodid, nodConn) - } - } - } - log.Info("snapshot checked") - - // PART II - // load snapshot and verify that exactly same connections are formed - - adapter = adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }) - network = NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - defer func() { - network.Shutdown() - }() - - // subscribe to peer events - // every node up and conn up event will generate one additional control event - // therefore multiply the count by two - evC = make(chan *Event, (len(snap.Conns)*2)+(len(snap.Nodes)*2)) - sub = network.Events().Subscribe(evC) - defer sub.Unsubscribe() - - // load the snapshot - // spawn separate thread to avoid deadlock in the event listeners - err = network.Load(snap) - if err != nil { - t.Fatal(err) - } - - // collect connection events up to expected number - ctx, cancel = context.WithTimeout(context.TODO(), time.Second*3) - defer cancel() - - connEventCount = nodeCount - -OuterTwo: - for { - select { - case <-ctx.Done(): - t.Fatal(ctx.Err()) - case ev := <-evC: - if ev.Type == EventTypeConn && !ev.Control { - // fail on any disconnect - if !ev.Conn.Up { - t.Fatalf("unexpected disconnect: %v -> %v", ev.Conn.One, ev.Conn.Other) - } - log.Debug("conn", "on", ev.Conn.One, "other", ev.Conn.Other) - checkIds[ev.Conn.One] = append(checkIds[ev.Conn.One], ev.Conn.Other) - checkIds[ev.Conn.Other] = append(checkIds[ev.Conn.Other], ev.Conn.One) - connEventCount-- - log.Debug("ev", "count", connEventCount) - if connEventCount == 0 { - break OuterTwo - } - } - } - } - - // check that we have all expected connections in the network - for _, snapConn := range snap.Conns { - var match bool - for nodid, nodConns := range checkIds { - for _, nodConn := range nodConns { - if snapConn.One == nodid && snapConn.Other == nodConn { - match = true - break - } else if snapConn.Other == nodid && snapConn.One == nodConn { - match = true - break - } - } - } - if !match { - t.Fatalf("network missing conn %v -> %v", snapConn.One, snapConn.Other) - } - } - - // verify that network didn't generate any other additional connection events after the ones we have collected within a reasonable period of time - ctx, cancel = context.WithTimeout(context.TODO(), time.Second) - defer cancel() - select { - case <-ctx.Done(): - case ev := <-evC: - if ev.Type == EventTypeConn { - t.Fatalf("Superfluous conn found %v -> %v", ev.Conn.One, ev.Conn.Other) - } - } - - // This test validates if all connections from the snapshot - // are created in the network. - t.Run("conns after load", func(t *testing.T) { - // Create new network. - n := NewNetwork( - adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - return NewNoopService(nil), nil - }, - }), - &NetworkConfig{ - DefaultService: "noopwoop", - }, - ) - defer n.Shutdown() - - // Load the same snapshot. - err := n.Load(snap) - if err != nil { - t.Fatal(err) - } - - // Check every connection from the snapshot - // if it is in the network, too. - for _, c := range snap.Conns { - if n.GetConn(c.One, c.Other) == nil { - t.Errorf("missing connection: %s -> %s", c.One, c.Other) - } - } - }) -} - -// TestNetworkSimulation creates a multi-node simulation network with each node -// connected in a ring topology, checks that all nodes successfully handshake -// with each other and that a snapshot fully represents the desired topology -func TestNetworkSimulation(t *testing.T) { - // create simulation network with 20 testService nodes - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - nodeCount := 20 - ids := make([]enode.ID, nodeCount) - for i := 0; i < nodeCount; i++ { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - t.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - t.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - // perform a check which connects the nodes in a ring (so each node is - // connected to exactly two peers) and then checks that all nodes - // performed two handshakes by checking their peerCount - action := func(_ context.Context) error { - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := network.Connect(id, peerID); err != nil { - return err - } - } - return nil - } - check := func(ctx context.Context, id enode.ID) (bool, error) { - // check we haven't run out of time - select { - case <-ctx.Done(): - return false, ctx.Err() - default: - } - - // get the node - node := network.GetNode(id) - if node == nil { - return false, fmt.Errorf("unknown node: %s", id) - } - - // check it has exactly two peers - client, err := node.Client() - if err != nil { - return false, err - } - var peerCount int64 - if err := client.CallContext(ctx, &peerCount, "test_peerCount"); err != nil { - return false, err - } - switch { - case peerCount < 2: - return false, nil - case peerCount == 2: - return true, nil - default: - return false, fmt.Errorf("unexpected peerCount: %d", peerCount) - } - } - - timeout := 30 * time.Second - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - - // trigger a check every 100ms - trigger := make(chan enode.ID) - go triggerChecks(ctx, ids, trigger, 100*time.Millisecond) - - result := NewSimulation(network).Run(ctx, &Step{ - Action: action, - Trigger: trigger, - Expect: &Expectation{ - Nodes: ids, - Check: check, - }, - }) - if result.Error != nil { - t.Fatalf("simulation failed: %s", result.Error) - } - - // take a network snapshot and check it contains the correct topology - snap, err := network.Snapshot() - if err != nil { - t.Fatal(err) - } - if len(snap.Nodes) != nodeCount { - t.Fatalf("expected snapshot to contain %d nodes, got %d", nodeCount, len(snap.Nodes)) - } - if len(snap.Conns) != nodeCount { - t.Fatalf("expected snapshot to contain %d connections, got %d", nodeCount, len(snap.Conns)) - } - for i, id := range ids { - conn := snap.Conns[i] - if conn.One != id { - t.Fatalf("expected conn[%d].One to be %s, got %s", i, id, conn.One) - } - peerID := ids[(i+1)%len(ids)] - if conn.Other != peerID { - t.Fatalf("expected conn[%d].Other to be %s, got %s", i, peerID, conn.Other) - } - } -} - -func createTestNodes(count int, network *Network) (nodes []*Node, err error) { - for i := 0; i < count; i++ { - nodeConf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(nodeConf) - if err != nil { - return nil, err - } - if err := network.Start(node.ID()); err != nil { - return nil, err - } - - nodes = append(nodes, node) - } - - return nodes, nil -} - -func createTestNodesWithProperty(property string, count int, network *Network) (propertyNodes []*Node, err error) { - for i := 0; i < count; i++ { - nodeConf := adapters.RandomNodeConfig() - nodeConf.Properties = append(nodeConf.Properties, property) - - node, err := network.NewNodeWithConfig(nodeConf) - if err != nil { - return nil, err - } - if err := network.Start(node.ID()); err != nil { - return nil, err - } - - propertyNodes = append(propertyNodes, node) - } - - return propertyNodes, nil -} - -// TestGetNodeIDs creates a set of nodes and attempts to retrieve their IDs,. -// It then tests again whilst excluding a node ID from being returned. -// If a node ID is not returned, or more node IDs than expected are returned, the test fails. -func TestGetNodeIDs(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 5 - nodes, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Could not create test nodes %v", err) - } - - gotNodeIDs := network.GetNodeIDs() - if len(gotNodeIDs) != numNodes { - t.Fatalf("Expected %d nodes, got %d", numNodes, len(gotNodeIDs)) - } - - for _, node1 := range nodes { - match := false - for _, node2ID := range gotNodeIDs { - if bytes.Equal(node1.ID().Bytes(), node2ID.Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node was not returned by GetNodes(), ID: %s", node1.ID().String()) - } - } - - excludeNodeID := nodes[3].ID() - gotNodeIDsExcl := network.GetNodeIDs(excludeNodeID) - if len(gotNodeIDsExcl) != numNodes-1 { - t.Fatalf("Expected one less node ID to be returned") - } - for _, nodeID := range gotNodeIDsExcl { - if bytes.Equal(excludeNodeID.Bytes(), nodeID.Bytes()) { - t.Fatalf("GetNodeIDs returned the node ID we excluded, ID: %s", nodeID.String()) - } - } -} - -// TestGetNodes creates a set of nodes and attempts to retrieve them again. -// It then tests again whilst excluding a node from being returned. -// If a node is not returned, or more nodes than expected are returned, the test fails. -func TestGetNodes(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 5 - nodes, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Could not create test nodes %v", err) - } - - gotNodes := network.GetNodes() - if len(gotNodes) != numNodes { - t.Fatalf("Expected %d nodes, got %d", numNodes, len(gotNodes)) - } - - for _, node1 := range nodes { - match := false - for _, node2 := range gotNodes { - if bytes.Equal(node1.ID().Bytes(), node2.ID().Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node was not returned by GetNodes(), ID: %s", node1.ID().String()) - } - } - - excludeNodeID := nodes[3].ID() - gotNodesExcl := network.GetNodes(excludeNodeID) - if len(gotNodesExcl) != numNodes-1 { - t.Fatalf("Expected one less node to be returned") - } - for _, node := range gotNodesExcl { - if bytes.Equal(excludeNodeID.Bytes(), node.ID().Bytes()) { - t.Fatalf("GetNodes returned the node we excluded, ID: %s", node.ID().String()) - } - } -} - -// TestGetNodesByID creates a set of nodes and attempts to retrieve a subset of them by ID -// If a node is not returned, or more nodes than expected are returned, the test fails. -func TestGetNodesByID(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 5 - nodes, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Could not create test nodes: %v", err) - } - - numSubsetNodes := 2 - subsetNodes := nodes[0:numSubsetNodes] - var subsetNodeIDs []enode.ID - for _, node := range subsetNodes { - subsetNodeIDs = append(subsetNodeIDs, node.ID()) - } - - gotNodesByID := network.GetNodesByID(subsetNodeIDs) - if len(gotNodesByID) != numSubsetNodes { - t.Fatalf("Expected %d nodes, got %d", numSubsetNodes, len(gotNodesByID)) - } - - for _, node1 := range subsetNodes { - match := false - for _, node2 := range gotNodesByID { - if bytes.Equal(node1.ID().Bytes(), node2.ID().Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node was not returned by GetNodesByID(), ID: %s", node1.ID().String()) - } - } -} - -// TestGetNodesByProperty creates a subset of nodes with a property assigned. -// GetNodesByProperty is then checked for correctness by comparing the nodes returned to those initially created. -// If a node with a property is not found, or more nodes than expected are returned, the test fails. -func TestGetNodesByProperty(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 3 - _, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Failed to create nodes: %v", err) - } - - numPropertyNodes := 3 - propertyTest := "test" - propertyNodes, err := createTestNodesWithProperty(propertyTest, numPropertyNodes, network) - if err != nil { - t.Fatalf("Failed to create nodes with property: %v", err) - } - - gotNodesByProperty := network.GetNodesByProperty(propertyTest) - if len(gotNodesByProperty) != numPropertyNodes { - t.Fatalf("Expected %d nodes with a property, got %d", numPropertyNodes, len(gotNodesByProperty)) - } - - for _, node1 := range propertyNodes { - match := false - for _, node2 := range gotNodesByProperty { - if bytes.Equal(node1.ID().Bytes(), node2.ID().Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("A created node with property was not returned by GetNodesByProperty(), ID: %s", node1.ID().String()) - } - } -} - -// TestGetNodeIDsByProperty creates a subset of nodes with a property assigned. -// GetNodeIDsByProperty is then checked for correctness by comparing the node IDs returned to those initially created. -// If a node ID with a property is not found, or more nodes IDs than expected are returned, the test fails. -func TestGetNodeIDsByProperty(t *testing.T) { - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "test": newTestService, - }) - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "test", - }) - defer network.Shutdown() - - numNodes := 3 - _, err := createTestNodes(numNodes, network) - if err != nil { - t.Fatalf("Failed to create nodes: %v", err) - } - - numPropertyNodes := 3 - propertyTest := "test" - propertyNodes, err := createTestNodesWithProperty(propertyTest, numPropertyNodes, network) - if err != nil { - t.Fatalf("Failed to created nodes with property: %v", err) - } - - gotNodeIDsByProperty := network.GetNodeIDsByProperty(propertyTest) - if len(gotNodeIDsByProperty) != numPropertyNodes { - t.Fatalf("Expected %d nodes with a property, got %d", numPropertyNodes, len(gotNodeIDsByProperty)) - } - - for _, node1 := range propertyNodes { - match := false - id1 := node1.ID() - for _, id2 := range gotNodeIDsByProperty { - if bytes.Equal(id1.Bytes(), id2.Bytes()) { - match = true - break - } - } - - if !match { - t.Fatalf("Not all nodes IDs were returned by GetNodeIDsByProperty(), ID: %s", id1.String()) - } - } -} - -func triggerChecks(ctx context.Context, ids []enode.ID, trigger chan enode.ID, interval time.Duration) { - tick := time.NewTicker(interval) - defer tick.Stop() - for { - select { - case <-tick.C: - for _, id := range ids { - select { - case trigger <- id: - case <-ctx.Done(): - return - } - } - case <-ctx.Done(): - return - } - } -} - -// \todo: refactor to implement snapshots -// and connect configuration methods once these are moved from -// swarm/network/simulations/connect.go -func BenchmarkMinimalService(b *testing.B) { - b.Run("ring/32", benchmarkMinimalServiceTmp) -} - -func benchmarkMinimalServiceTmp(b *testing.B) { - // stop timer to discard setup time pollution - args := strings.Split(b.Name(), "/") - nodeCount, err := strconv.ParseInt(args[2], 10, 16) - if err != nil { - b.Fatal(err) - } - - for i := 0; i < b.N; i++ { - // this is a minimal service, whose protocol will close a channel upon run of protocol - // making it possible to bench the time it takes for the service to start and protocol actually to be run - protoCMap := make(map[enode.ID]map[enode.ID]chan struct{}) - adapter := adapters.NewSimAdapter(adapters.LifecycleConstructors{ - "noopwoop": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { - protoCMap[ctx.Config.ID] = make(map[enode.ID]chan struct{}) - svc := NewNoopService(protoCMap[ctx.Config.ID]) - return svc, nil - }, - }) - - // create network - network := NewNetwork(adapter, &NetworkConfig{ - DefaultService: "noopwoop", - }) - defer network.Shutdown() - - // create and start nodes - ids := make([]enode.ID, nodeCount) - for i := 0; i < int(nodeCount); i++ { - conf := adapters.RandomNodeConfig() - node, err := network.NewNodeWithConfig(conf) - if err != nil { - b.Fatalf("error creating node: %s", err) - } - if err := network.Start(node.ID()); err != nil { - b.Fatalf("error starting node: %s", err) - } - ids[i] = node.ID() - } - - // ready, set, go - b.ResetTimer() - - // connect nodes in a ring - for i, id := range ids { - peerID := ids[(i+1)%len(ids)] - if err := network.Connect(id, peerID); err != nil { - b.Fatal(err) - } - } - - // wait for all protocols to signal to close down - ctx, cancel := context.WithTimeout(context.TODO(), time.Second) - defer cancel() - for nodid, peers := range protoCMap { - for peerid, peerC := range peers { - log.Debug("getting ", "node", nodid, "peer", peerid) - select { - case <-ctx.Done(): - b.Fatal(ctx.Err()) - case <-peerC: - } - } - } - } -} - -func TestNode_UnmarshalJSON(t *testing.T) { - t.Run("up_field", func(t *testing.T) { - runNodeUnmarshalJSON(t, casesNodeUnmarshalJSONUpField()) - }) - t.Run("config_field", func(t *testing.T) { - runNodeUnmarshalJSON(t, casesNodeUnmarshalJSONConfigField()) - }) -} - -func runNodeUnmarshalJSON(t *testing.T, tests []nodeUnmarshalTestCase) { - t.Helper() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var got *Node - if err := json.Unmarshal([]byte(tt.marshaled), &got); err != nil { - expectErrorMessageToContain(t, err, tt.wantErr) - got = nil - } - expectNodeEquality(t, got, tt.want) - }) - } -} - -type nodeUnmarshalTestCase struct { - name string - marshaled string - want *Node - wantErr string -} - -func expectErrorMessageToContain(t *testing.T, got error, want string) { - t.Helper() - if got == nil && want == "" { - return - } - - if got == nil && want != "" { - t.Errorf("error was expected, got: nil, want: %v", want) - return - } - - if !strings.Contains(got.Error(), want) { - t.Errorf( - "unexpected error message, got %v, want: %v", - want, - got, - ) - } -} - -func expectNodeEquality(t *testing.T, got, want *Node) { - t.Helper() - if !reflect.DeepEqual(got, want) { - t.Errorf("Node.UnmarshalJSON() = %v, want %v", got, want) - } -} - -func casesNodeUnmarshalJSONUpField() []nodeUnmarshalTestCase { - return []nodeUnmarshalTestCase{ - { - name: "empty json", - marshaled: "{}", - want: newNode(nil, nil, false), - }, - { - name: "a stopped node", - marshaled: "{\"up\": false}", - want: newNode(nil, nil, false), - }, - { - name: "a running node", - marshaled: "{\"up\": true}", - want: newNode(nil, nil, true), - }, - { - name: "invalid JSON value on valid key", - marshaled: "{\"up\": foo}", - wantErr: "invalid character", - }, - { - name: "invalid JSON key and value", - marshaled: "{foo: bar}", - wantErr: "invalid character", - }, - { - name: "bool value expected but got something else (string)", - marshaled: "{\"up\": \"true\"}", - wantErr: "cannot unmarshal string into Go struct", - }, - } -} - -func casesNodeUnmarshalJSONConfigField() []nodeUnmarshalTestCase { - // Don't do a big fuss around testing, as adapters.NodeConfig should - // handle it's own serialization. Just do a sanity check. - return []nodeUnmarshalTestCase{ - { - name: "Config field is omitted", - marshaled: "{}", - want: newNode(nil, nil, false), - }, - { - name: "Config field is nil", - marshaled: "{\"config\": null}", - want: newNode(nil, nil, false), - }, - { - name: "a non default Config field", - marshaled: "{\"config\":{\"name\":\"node_ecdd0\",\"port\":44665}}", - want: newNode(nil, &adapters.NodeConfig{Name: "node_ecdd0", Port: 44665}, false), - }, - } -} diff --git a/p2p/simulations/simulation.go b/p2p/simulations/simulation.go deleted file mode 100644 index ae62c42b9c..0000000000 --- a/p2p/simulations/simulation.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2017 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 . - -package simulations - -import ( - "context" - "time" - - "github.com/ethereum/go-ethereum/p2p/enode" -) - -// Simulation provides a framework for running actions in a simulated network -// and then waiting for expectations to be met -type Simulation struct { - network *Network -} - -// NewSimulation returns a new simulation which runs in the given network -func NewSimulation(network *Network) *Simulation { - return &Simulation{ - network: network, - } -} - -// Run performs a step of the simulation by performing the step's action and -// then waiting for the step's expectation to be met -func (s *Simulation) Run(ctx context.Context, step *Step) (result *StepResult) { - result = newStepResult() - - result.StartedAt = time.Now() - defer func() { result.FinishedAt = time.Now() }() - - // watch network events for the duration of the step - stop := s.watchNetwork(result) - defer stop() - - // perform the action - if err := step.Action(ctx); err != nil { - result.Error = err - return - } - - // wait for all node expectations to either pass, error or timeout - nodes := make(map[enode.ID]struct{}, len(step.Expect.Nodes)) - for _, id := range step.Expect.Nodes { - nodes[id] = struct{}{} - } - for len(result.Passes) < len(nodes) { - select { - case id := <-step.Trigger: - // skip if we aren't checking the node - if _, ok := nodes[id]; !ok { - continue - } - - // skip if the node has already passed - if _, ok := result.Passes[id]; ok { - continue - } - - // run the node expectation check - pass, err := step.Expect.Check(ctx, id) - if err != nil { - result.Error = err - return - } - if pass { - result.Passes[id] = time.Now() - } - case <-ctx.Done(): - result.Error = ctx.Err() - return - } - } - - return -} - -func (s *Simulation) watchNetwork(result *StepResult) func() { - stop := make(chan struct{}) - done := make(chan struct{}) - events := make(chan *Event) - sub := s.network.Events().Subscribe(events) - go func() { - defer close(done) - defer sub.Unsubscribe() - for { - select { - case event := <-events: - result.NetworkEvents = append(result.NetworkEvents, event) - case <-stop: - return - } - } - }() - return func() { - close(stop) - <-done - } -} - -type Step struct { - // Action is the action to perform for this step - Action func(context.Context) error - - // Trigger is a channel which receives node ids and triggers an - // expectation check for that node - Trigger chan enode.ID - - // Expect is the expectation to wait for when performing this step - Expect *Expectation -} - -type Expectation struct { - // Nodes is a list of nodes to check - Nodes []enode.ID - - // Check checks whether a given node meets the expectation - Check func(context.Context, enode.ID) (bool, error) -} - -func newStepResult() *StepResult { - return &StepResult{ - Passes: make(map[enode.ID]time.Time), - } -} - -type StepResult struct { - // Error is the error encountered whilst running the step - Error error - - // StartedAt is the time the step started - StartedAt time.Time - - // FinishedAt is the time the step finished - FinishedAt time.Time - - // Passes are the timestamps of the successful node expectations - Passes map[enode.ID]time.Time - - // NetworkEvents are the network events which occurred during the step - NetworkEvents []*Event -} diff --git a/p2p/simulations/test.go b/p2p/simulations/test.go deleted file mode 100644 index 0edb07b127..0000000000 --- a/p2p/simulations/test.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2018 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 . - -package simulations - -import ( - "testing" - - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/p2p/enode" - "github.com/ethereum/go-ethereum/p2p/enr" - "github.com/ethereum/go-ethereum/rpc" -) - -// NoopService is the service that does not do anything -// but implements node.Service interface. -type NoopService struct { - c map[enode.ID]chan struct{} -} - -func NewNoopService(ackC map[enode.ID]chan struct{}) *NoopService { - return &NoopService{ - c: ackC, - } -} - -func (t *NoopService) Protocols() []p2p.Protocol { - return []p2p.Protocol{ - { - Name: "noop", - Version: 666, - Length: 0, - Run: func(peer *p2p.Peer, rw p2p.MsgReadWriter) error { - if t.c != nil { - t.c[peer.ID()] = make(chan struct{}) - close(t.c[peer.ID()]) - } - rw.ReadMsg() - return nil - }, - NodeInfo: func() interface{} { - return struct{}{} - }, - PeerInfo: func(id enode.ID) interface{} { - return struct{}{} - }, - Attributes: []enr.Entry{}, - }, - } -} - -func (t *NoopService) APIs() []rpc.API { - return []rpc.API{} -} - -func (t *NoopService) Start() error { - return nil -} - -func (t *NoopService) Stop() error { - return nil -} - -func VerifyRing(t *testing.T, net *Network, ids []enode.ID) { - t.Helper() - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := net.GetConn(ids[i], ids[j]) - if i == j-1 || (i == 0 && j == n-1) { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func VerifyChain(t *testing.T, net *Network, ids []enode.ID) { - t.Helper() - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := net.GetConn(ids[i], ids[j]) - if i == j-1 { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} - -func VerifyFull(t *testing.T, net *Network, ids []enode.ID) { - t.Helper() - n := len(ids) - var connections int - for i, lid := range ids { - for _, rid := range ids[i+1:] { - if net.GetConn(lid, rid) != nil { - connections++ - } - } - } - - want := n * (n - 1) / 2 - if connections != want { - t.Errorf("wrong number of connections, got: %v, want: %v", connections, want) - } -} - -func VerifyStar(t *testing.T, net *Network, ids []enode.ID, centerIndex int) { - t.Helper() - n := len(ids) - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - c := net.GetConn(ids[i], ids[j]) - if i == centerIndex || j == centerIndex { - if c == nil { - t.Errorf("nodes %v and %v are not connected, but they should be", i, j) - } - } else { - if c != nil { - t.Errorf("nodes %v and %v are connected, but they should not be", i, j) - } - } - } - } -} diff --git a/p2p/transport_test.go b/p2p/transport_test.go index 24e06c5a06..01695cd3af 100644 --- a/p2p/transport_test.go +++ b/p2p/transport_test.go @@ -24,7 +24,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/p2p/simulations/pipes" + "github.com/ethereum/go-ethereum/p2p/pipes" ) func TestProtocolHandshake(t *testing.T) { From 5adf4adc8ec2c497eddd3b1ff20d2d35d65ec5fc Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 12 Aug 2024 16:43:54 +0800 Subject: [PATCH 181/196] eth/protocols/snap: cleanup dangling account trie nodes due to incomplete storage (#30258) This pull request fixes #30229. During snap sync, large storage will be split into several pieces and synchronized concurrently. Unfortunately, the tradeoff is that the respective merkle trie of each storage chunk will be incomplete due to the incomplete boundaries. The trie nodes on these boundaries will be discarded, and any dangling nodes on disk will also be removed if they fall on these paths, ensuring the state healer won't be blocked. However, the dangling account trie nodes on the path from the root to the associated account are left untouched. This means the dangling account trie nodes could potentially stop the state healing and break the assumption that the entire subtrie should exist if the subtrie root exists. We should consider the account trie node as the ancestor of the corresponding storage trie node. In the scenarios described in the above ticket, the state corruption could occur if there is a dangling account trie node while some storage trie nodes are removed due to synchronization redo. The fixing idea is pretty straightforward, the trie nodes on the path from root to account should all be explicitly removed if an incomplete storage trie occurs. Therefore, a `delete` operation has been added into `gentrie` to explicitly clear the account along with all nodes on this path. The special thing is that it's a cross-trie clearing. In theory, there may be a dangling node at any position on this account key and we have to clear all of them. --- eth/protocols/snap/gentrie.go | 44 ++++++++- eth/protocols/snap/gentrie_test.go | 142 +++++++++++++++++++++++++++++ eth/protocols/snap/sync.go | 11 ++- trie/stacktrie.go | 10 +- 4 files changed, 198 insertions(+), 9 deletions(-) diff --git a/eth/protocols/snap/gentrie.go b/eth/protocols/snap/gentrie.go index 6255fb221d..5126d26777 100644 --- a/eth/protocols/snap/gentrie.go +++ b/eth/protocols/snap/gentrie.go @@ -31,6 +31,9 @@ type genTrie interface { // update inserts the state item into generator trie. update(key, value []byte) error + // delete removes the state item from the generator trie. + delete(key []byte) error + // commit flushes the right boundary nodes if complete flag is true. This // function must be called before flushing the associated database batch. commit(complete bool) common.Hash @@ -113,7 +116,7 @@ func (t *pathTrie) onTrieNode(path []byte, hash common.Hash, blob []byte) { // removed because it's a sibling of the nodes we want to commit, not // the parent or ancestor. for i := 0; i < len(path); i++ { - t.delete(path[:i], false) + t.deleteNode(path[:i], false) } } return @@ -136,7 +139,7 @@ func (t *pathTrie) onTrieNode(path []byte, hash common.Hash, blob []byte) { // byte key. In either case, no gaps will be left in the path. if t.last != nil && bytes.HasPrefix(t.last, path) && len(t.last)-len(path) > 1 { for i := len(path) + 1; i < len(t.last); i++ { - t.delete(t.last[:i], true) + t.deleteNode(t.last[:i], true) } } t.write(path, blob) @@ -192,8 +195,8 @@ func (t *pathTrie) deleteStorageNode(path []byte, inner bool) { rawdb.DeleteStorageTrieNode(t.batch, t.owner, path) } -// delete commits the node deletion to provided database batch in path mode. -func (t *pathTrie) delete(path []byte, inner bool) { +// deleteNode commits the node deletion to provided database batch in path mode. +func (t *pathTrie) deleteNode(path []byte, inner bool) { if t.owner == (common.Hash{}) { t.deleteAccountNode(path, inner) } else { @@ -207,6 +210,34 @@ func (t *pathTrie) update(key, value []byte) error { return t.tr.Update(key, value) } +// delete implements genTrie interface, deleting the item from the stack trie. +func (t *pathTrie) delete(key []byte) error { + // Commit the trie since the right boundary is incomplete because + // of the deleted item. This will implicitly discard the last inserted + // item and clean some ancestor trie nodes of the last committed + // item in the database. + t.commit(false) + + // Reset the trie and all the internal trackers + t.first = nil + t.last = nil + t.tr.Reset() + + // Explicitly mark the left boundary as incomplete, as the left-side + // item of the next one has been deleted. Be aware that the next item + // to be inserted will be ignored from committing as well as it's on + // the left boundary. + t.skipLeftBoundary = true + + // Explicitly delete the potential leftover nodes on the specific + // path from the database. + tkey := t.tr.TrieKey(key) + for i := 0; i <= len(tkey); i++ { + t.deleteNode(tkey[:i], false) + } + return nil +} + // commit implements genTrie interface, flushing the right boundary if it's // considered as complete. Otherwise, the nodes on the right boundary are // discarded and cleaned up. @@ -255,7 +286,7 @@ func (t *pathTrie) commit(complete bool) common.Hash { // with no issues as they are actually complete. Also, from a database // perspective, first deleting and then rewriting is a valid data update. for i := 0; i < len(t.last); i++ { - t.delete(t.last[:i], false) + t.deleteNode(t.last[:i], false) } return common.Hash{} // the hash is meaningless for incomplete commit } @@ -278,6 +309,9 @@ func (t *hashTrie) update(key, value []byte) error { return t.tr.Update(key, value) } +// delete implements genTrie interface, ignoring the state item for deleting. +func (t *hashTrie) delete(key []byte) error { return nil } + // commit implements genTrie interface, committing the nodes on right boundary. func (t *hashTrie) commit(complete bool) common.Hash { if !complete { diff --git a/eth/protocols/snap/gentrie_test.go b/eth/protocols/snap/gentrie_test.go index 1fb2dbce75..2da4f3c866 100644 --- a/eth/protocols/snap/gentrie_test.go +++ b/eth/protocols/snap/gentrie_test.go @@ -551,3 +551,145 @@ func TestTinyPartialTree(t *testing.T) { } } } + +func TestTrieDelete(t *testing.T) { + var entries []*kv + for i := 0; i < 1024; i++ { + entries = append(entries, &kv{ + k: testrand.Bytes(32), + v: testrand.Bytes(32), + }) + } + slices.SortFunc(entries, (*kv).cmp) + + nodes := make(map[string]common.Hash) + tr := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { + nodes[string(path)] = hash + }) + for i := 0; i < len(entries); i++ { + tr.Update(entries[i].k, entries[i].v) + } + tr.Hash() + + check := func(index []int) { + var ( + db = rawdb.NewMemoryDatabase() + batch = db.NewBatch() + marks = map[int]struct{}{} + neighbors = map[int]struct{}{} + ) + for _, n := range index { + marks[n] = struct{}{} + } + for _, n := range index { + if n != 0 { + if _, ok := marks[n-1]; !ok { + neighbors[n-1] = struct{}{} + } + } + if n != len(entries)-1 { + if _, ok := neighbors[n+1]; !ok { + neighbors[n+1] = struct{}{} + } + } + } + // Write the junk nodes as the dangling + var injects []string + for _, n := range index { + nibbles := byteToHex(entries[n].k) + for i := 0; i <= len(nibbles); i++ { + injects = append(injects, string(nibbles[:i])) + } + } + for _, path := range injects { + rawdb.WriteAccountTrieNode(db, []byte(path), testrand.Bytes(32)) + } + tr := newPathTrie(common.Hash{}, false, db, batch) + for i := 0; i < len(entries); i++ { + if _, ok := marks[i]; ok { + tr.delete(entries[i].k) + } else { + tr.update(entries[i].k, entries[i].v) + } + } + tr.commit(true) + + r := newBatchReplay() + batch.Replay(r) + batch.Write() + + for _, path := range injects { + if rawdb.HasAccountTrieNode(db, []byte(path)) { + t.Fatalf("Unexpected leftover node %v", []byte(path)) + } + } + + // ensure all the written nodes match with the complete tree + set := make(map[string]common.Hash) + for path, hash := range r.modifies() { + if hash == (common.Hash{}) { + continue + } + n, ok := nodes[path] + if !ok { + t.Fatalf("Unexpected trie node: %v", []byte(path)) + } + if n != hash { + t.Fatalf("Unexpected trie node content: %v, want: %x, got: %x", []byte(path), n, hash) + } + set[path] = hash + } + + // ensure all the missing nodes either on the deleted path, or + // on the neighbor paths. + isMissing := func(path []byte) bool { + for n := range marks { + key := byteToHex(entries[n].k) + if bytes.HasPrefix(key, path) { + return true + } + } + for n := range neighbors { + key := byteToHex(entries[n].k) + if bytes.HasPrefix(key, path) { + return true + } + } + return false + } + for path := range nodes { + if _, ok := set[path]; ok { + continue + } + if !isMissing([]byte(path)) { + t.Fatalf("Missing node %v", []byte(path)) + } + } + } + var cases = []struct { + index []int + }{ + // delete the first + {[]int{0}}, + + // delete the last + {[]int{len(entries) - 1}}, + + // delete the first two + {[]int{0, 1}}, + + // delete the last two + {[]int{len(entries) - 2, len(entries) - 1}}, + + {[]int{ + 0, 2, 4, 6, + len(entries) - 1, + len(entries) - 3, + len(entries) - 5, + len(entries) - 7, + }}, + } + for _, c := range cases { + check(c.index) + } +} diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 88d7d34dcc..cdd03e6a0c 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2424,14 +2424,21 @@ func (s *Syncer) forwardAccountTask(task *accountTask) { slim := types.SlimAccountRLP(*res.accounts[i]) rawdb.WriteAccountSnapshot(batch, hash, slim) - // If the task is complete, drop it into the stack trie to generate - // account trie nodes for it if !task.needHeal[i] { + // If the storage task is complete, drop it into the stack trie + // to generate account trie nodes for it full, err := types.FullAccountRLP(slim) // TODO(karalabe): Slim parsing can be omitted if err != nil { panic(err) // Really shouldn't ever happen } task.genTrie.update(hash[:], full) + } else { + // If the storage task is incomplete, explicitly delete the corresponding + // account item from the account trie to ensure that all nodes along the + // path to the incomplete storage trie are cleaned up. + if err := task.genTrie.delete(hash[:]); err != nil { + panic(err) // Really shouldn't ever happen + } } } // Flush anything written just now and update the stats diff --git a/trie/stacktrie.go b/trie/stacktrie.go index 9c574db0bf..d194cbf0ae 100644 --- a/trie/stacktrie.go +++ b/trie/stacktrie.go @@ -64,8 +64,7 @@ func (t *StackTrie) Update(key, value []byte) error { if len(value) == 0 { return errors.New("trying to insert empty (deletion)") } - k := keybytesToHex(key) - k = k[:len(k)-1] // chop the termination flag + k := t.TrieKey(key) if bytes.Compare(t.last, k) >= 0 { return errors.New("non-ascending key order") } @@ -84,6 +83,13 @@ func (t *StackTrie) Reset() { t.last = nil } +// TrieKey returns the internal key representation for the given user key. +func (t *StackTrie) TrieKey(key []byte) []byte { + k := keybytesToHex(key) + k = k[:len(k)-1] // chop the termination flag + return k +} + // stNode represents a node within a StackTrie type stNode struct { typ uint8 // node type (as in branch, ext, leaf) From 880511dc39e5d4788a07313a1289c928c8b7c7b7 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 12 Aug 2024 14:15:30 +0200 Subject: [PATCH 182/196] params: release go-ethereum v1.14.8 stable --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 852f9fd1e1..050b2122f7 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor 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 + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 8 // Patch version component of the current release + VersionMeta = "stable" // Version metadata to append to the version string ) // Version holds the textual version string. From 1cf3b5d38ac64921819b8e999d194047c84c4126 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 12 Aug 2024 14:19:35 +0200 Subject: [PATCH 183/196] params: begin v1.14.9 release cycle --- params/version.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/params/version.go b/params/version.go index 050b2122f7..22e59d6838 100644 --- a/params/version.go +++ b/params/version.go @@ -21,10 +21,10 @@ import ( ) const ( - VersionMajor = 1 // Major version component of the current release - VersionMinor = 14 // Minor version component of the current release - VersionPatch = 8 // Patch version component of the current release - VersionMeta = "stable" // Version metadata to append to the version string + VersionMajor = 1 // Major version component of the current release + VersionMinor = 14 // Minor version component of the current release + VersionPatch = 9 // Patch version component of the current release + VersionMeta = "unstable" // Version metadata to append to the version string ) // Version holds the textual version string. From ab03c5746c040be2336a0efa0e2dcc43871435f0 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Tue, 13 Aug 2024 02:42:36 +0800 Subject: [PATCH 184/196] go.mod: remove github.com/julienschmidt/httprouter (#30290) --- go.mod | 1 - go.sum | 1 - 2 files changed, 2 deletions(-) diff --git a/go.mod b/go.mod index 763210decd..ae6b12c0b8 100644 --- a/go.mod +++ b/go.mod @@ -44,7 +44,6 @@ require ( github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c github.com/jackpal/go-nat-pmp v1.0.2 github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 - github.com/julienschmidt/httprouter v1.3.0 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 github.com/kilic/bls12-381 v0.1.0 github.com/kylelemons/godebug v1.1.0 diff --git a/go.sum b/go.sum index 562362dee6..4dadd40a75 100644 --- a/go.sum +++ b/go.sum @@ -339,7 +339,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= From bc95452e024b91c238ef3e43f3573eb179a762d2 Mon Sep 17 00:00:00 2001 From: jwasinger Date: Mon, 12 Aug 2024 11:46:15 -0700 Subject: [PATCH 185/196] build: run 'go mod tidy' check as part of lint (#30291) --- build/ci.go | 68 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/build/ci.go b/build/ci.go index db57633704..009d69e6e4 100644 --- a/build/ci.go +++ b/build/ci.go @@ -349,10 +349,10 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { return filepath.Join(cachedir, base) } -// hashSourceFiles iterates all files under the top-level project directory +// hashAllSourceFiles iterates all files under the top-level project directory // computing the hash of each file (excluding files within the tests // subrepo) -func hashSourceFiles() (map[string]common.Hash, error) { +func hashAllSourceFiles() (map[string]common.Hash, error) { res := make(map[string]common.Hash) err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error { if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) { @@ -379,6 +379,56 @@ func hashSourceFiles() (map[string]common.Hash, error) { return res, nil } +// hashSourceFiles iterates the provided set of filepaths (relative to the top-level geth project directory) +// computing the hash of each file. +func hashSourceFiles(files []string) (map[string]common.Hash, error) { + res := make(map[string]common.Hash) + for _, filePath := range files { + f, err := os.OpenFile(filePath, os.O_RDONLY, 0666) + if err != nil { + return nil, err + } + hasher := sha256.New() + if _, err := io.Copy(hasher, f); err != nil { + return nil, err + } + res[filePath] = common.Hash(hasher.Sum(nil)) + } + return res, nil +} + +// compareHashedFilesets compares two maps (key is relative file path to top-level geth directory, value is its hash) +// and returns the list of file paths whose hashes differed. +func compareHashedFilesets(preHashes map[string]common.Hash, postHashes map[string]common.Hash) []string { + updates := []string{} + for path, postHash := range postHashes { + preHash, ok := preHashes[path] + if !ok || preHash != postHash { + updates = append(updates, path) + } + } + return updates +} + +func doGoModTidy() { + targetFiles := []string{"go.mod", "go.sum"} + preHashes, err := hashSourceFiles(targetFiles) + if err != nil { + log.Fatal("failed to hash go.mod/go.sum", "err", err) + } + tc := new(build.GoToolchain) + c := tc.Go("mod", "tidy") + build.MustRun(c) + postHashes, err := hashSourceFiles(targetFiles) + updates := compareHashedFilesets(preHashes, postHashes) + for _, updatedFile := range updates { + fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) + } + if len(updates) != 0 { + log.Fatal("go.sum and/or go.mod were updated by running 'go mod tidy'") + } +} + // doGenerate ensures that re-generating generated files does not cause // any mutations in the source file tree: i.e. all generated files were // updated and committed. Any stale generated files are updated. @@ -395,7 +445,7 @@ func doGenerate() { var preHashes map[string]common.Hash if *verify { var err error - preHashes, err = hashSourceFiles() + preHashes, err = hashAllSourceFiles() if err != nil { log.Fatal("failed to compute map of source hashes", "err", err) } @@ -410,17 +460,11 @@ func doGenerate() { return } // Check if files were changed. - postHashes, err := hashSourceFiles() + postHashes, err := hashAllSourceFiles() if err != nil { log.Fatal("error computing source tree file hashes", "err", err) } - updates := []string{} - for path, postHash := range postHashes { - preHash, ok := preHashes[path] - if !ok || preHash != postHash { - updates = append(updates, path) - } - } + updates := compareHashedFilesets(preHashes, postHashes) for _, updatedFile := range updates { fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile) } @@ -443,6 +487,8 @@ func doLint(cmdline []string) { linter := downloadLinter(*cachedir) lflags := []string{"run", "--config", ".golangci.yml"} build.MustRunCommandWithOutput(linter, append(lflags, packages...)...) + + doGoModTidy() fmt.Println("You have achieved perfection.") } From bd57f35f8d1e920ef2b234ea6cd1aa18715b358f Mon Sep 17 00:00:00 2001 From: Zoo Date: Tue, 13 Aug 2024 19:49:31 +0800 Subject: [PATCH 186/196] core/txpool/blobpool: fix error message (#30247) the validation process only checks for 'less than', which is inconsistent with the error output --- core/txpool/blobpool/blobpool.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index cb266fd10a..d66a08aa17 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -1155,11 +1155,11 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error { ) switch { case tx.GasFeeCapIntCmp(minGasFeeCap.ToBig()) < 0: - return fmt.Errorf("%w: new tx gas fee cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap, p.config.PriceBump) + return fmt.Errorf("%w: new tx gas fee cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasFeeCap(), prev.execFeeCap, p.config.PriceBump) case tx.GasTipCapIntCmp(minGasTipCap.ToBig()) < 0: - return fmt.Errorf("%w: new tx gas tip cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap, p.config.PriceBump) + return fmt.Errorf("%w: new tx gas tip cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.GasTipCap(), prev.execTipCap, p.config.PriceBump) case tx.BlobGasFeeCapIntCmp(minBlobGasFeeCap.ToBig()) < 0: - return fmt.Errorf("%w: new tx blob gas fee cap %v <= %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap, p.config.PriceBump) + return fmt.Errorf("%w: new tx blob gas fee cap %v < %v queued + %d%% replacement penalty", txpool.ErrReplaceUnderpriced, tx.BlobGasFeeCap(), prev.blobFeeCap, p.config.PriceBump) } } return nil From 2b9d19870646140c4dc90645cf7c828cc76860aa Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Wed, 14 Aug 2024 19:45:51 +1000 Subject: [PATCH 187/196] go.mod: upgrade to pebble v1.1.2 (#30297) Includes a fix for MIPS32 support. Pebble release: https://github.com/cockroachdb/pebble/releases/tag/v1.1.2 Key fix for mips32: https://github.com/cockroachdb/pebble/commit/9f3904a705d60b9832febb6c6494183d92c8f556 (also the only change from v1.1.1. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ae6b12c0b8..909add8be6 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/cespare/cp v0.1.0 github.com/cloudflare/cloudflare-go v0.79.0 - github.com/cockroachdb/pebble v1.1.1 + github.com/cockroachdb/pebble v1.1.2 github.com/consensys/gnark-crypto v0.12.1 github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c github.com/crate-crypto/go-kzg-4844 v1.0.0 diff --git a/go.sum b/go.sum index 4dadd40a75..089c05c2ec 100644 --- a/go.sum +++ b/go.sum @@ -122,8 +122,8 @@ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/e github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= -github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= From c686485a062d0addddf40c3808de7fe90793ed18 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 15 Aug 2024 09:16:23 +0200 Subject: [PATCH 188/196] core: only compute state root once (#30299) This PR refactors the genesis initialization a bit, s.th. we only compute the blockhash once instead of twice as before (during hashAlloc and flushAlloc) This will significantly reduce the amount of memory allocated during genesis init --------- Co-authored-by: Gary Rong --- core/genesis.go | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index 4ca24807fc..9e213e5163 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -145,13 +145,12 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { return statedb.Commit(0, false) } -// flushAlloc is very similar with hash, but the main difference is all the generated -// states will be persisted into the given database. Also, the genesis state -// specification will be flushed as well. -func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database, blockhash common.Hash) error { +// flushAlloc is very similar with hash, but the main difference is all the +// generated states will be persisted into the given database. +func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Database) (common.Hash, error) { statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil) if err != nil { - return err + return common.Hash{}, err } for addr, account := range *ga { if account.Balance != nil { @@ -167,21 +166,15 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa } root, err := statedb.Commit(0, false) if err != nil { - return err + return common.Hash{}, err } // Commit newly generated states into disk if it's not empty. if root != types.EmptyRootHash { if err := triedb.Commit(root, true); err != nil { - return err + return common.Hash{}, err } } - // Marshal the genesis state specification and persist. - blob, err := json.Marshal(ga) - if err != nil { - return err - } - rawdb.WriteGenesisStateSpec(db, blockhash, blob) - return nil + return root, nil } func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) { @@ -426,6 +419,11 @@ func (g *Genesis) ToBlock() *types.Block { if err != nil { panic(err) } + return g.toBlockWithRoot(root) +} + +// toBlockWithRoot constructs the genesis block with the given genesis state root. +func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block { head := &types.Header{ Number: new(big.Int).SetUint64(g.Number), Nonce: types.EncodeNonce(g.Nonce), @@ -482,8 +480,7 @@ func (g *Genesis) ToBlock() *types.Block { // Commit writes the block and state of a genesis specification to the database. // The block is committed as the canonical head block. func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Block, error) { - block := g.ToBlock() - if block.Number().Sign() != 0 { + if g.Number != 0 { return nil, errors.New("can't commit genesis block with number > 0") } config := g.Config @@ -493,15 +490,22 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo if err := config.CheckConfigForkOrder(); err != nil { return nil, err } - if config.Clique != nil && len(block.Extra()) < 32+crypto.SignatureLength { + if config.Clique != nil && len(g.ExtraData) < 32+crypto.SignatureLength { return nil, errors.New("can't start clique chain without signers") } - // All the checks has passed, flushAlloc the states derived from the genesis - // specification as well as the specification itself into the provided - // database. - if err := flushAlloc(&g.Alloc, db, triedb, block.Hash()); err != nil { + // flush the data to disk and compute the state root + root, err := flushAlloc(&g.Alloc, db, triedb) + if err != nil { return nil, err } + block := g.toBlockWithRoot(root) + + // Marshal the genesis state specification and persist. + blob, err := json.Marshal(g.Alloc) + if err != nil { + return nil, err + } + rawdb.WriteGenesisStateSpec(db, block.Hash(), blob) rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty()) rawdb.WriteBlock(db, block) rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil) From 2f2e5b088a08ff164fb20f704d04d67ddd6edbf5 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 10:11:03 +0200 Subject: [PATCH 189/196] .golangci.yml: remove lint warning for TxLookupLimit --- .golangci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index 75452472d0..d3b8535cfb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -60,6 +60,8 @@ issues: - path: crypto/bn256/ linters: - revive + - path: cmd/utils/flags.go + text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead." - path: internal/build/pgp.go text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go From c4b01d80b94820abeea52504c661e2a2ca8739d7 Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Thu, 15 Aug 2024 17:35:16 +0800 Subject: [PATCH 190/196] eth/fetcher: always expect transaction metadata in announcement (#30288) This pull request drops the legacy transaction retrieval support from before eth68, adding the restrictions that transaction metadata must be provided along with the transaction announment. --- eth/fetcher/tx_fetcher.go | 23 +- eth/fetcher/tx_fetcher_test.go | 981 ++++++++++++++++++--------------- 2 files changed, 547 insertions(+), 457 deletions(-) diff --git a/eth/fetcher/tx_fetcher.go b/eth/fetcher/tx_fetcher.go index 18c5ff007a..a113155009 100644 --- a/eth/fetcher/tx_fetcher.go +++ b/eth/fetcher/tx_fetcher.go @@ -114,7 +114,7 @@ var errTerminated = errors.New("terminated") type txAnnounce struct { origin string // Identifier of the peer originating the notification hashes []common.Hash // Batch of transaction hashes being announced - metas []*txMetadata // Batch of metadatas associated with the hashes (nil before eth/68) + metas []*txMetadata // Batch of metadata associated with the hashes } // txMetadata is a set of extra data transmitted along the announcement for better @@ -137,7 +137,7 @@ type txRequest struct { type txDelivery struct { origin string // Identifier of the peer originating the notification hashes []common.Hash // Batch of transaction hashes having been delivered - metas []txMetadata // Batch of metadatas associated with the delivered hashes + metas []txMetadata // Batch of metadata associated with the delivered hashes direct bool // Whether this is a direct reply or a broadcast } @@ -260,11 +260,11 @@ func (f *TxFetcher) Notify(peer string, types []byte, sizes []uint32, hashes []c underpriced++ default: unknownHashes = append(unknownHashes, hash) - if types == nil { - unknownMetas = append(unknownMetas, nil) - } else { - unknownMetas = append(unknownMetas, &txMetadata{kind: types[i], size: sizes[i]}) - } + + // Transaction metadata has been available since eth68, and all + // legacy eth protocols (prior to eth68) have been deprecated. + // Therefore, metadata is always expected in the announcement. + unknownMetas = append(unknownMetas, &txMetadata{kind: types[i], size: sizes[i]}) } } txAnnounceKnownMeter.Mark(duplicate) @@ -892,13 +892,8 @@ func (f *TxFetcher) scheduleFetches(timer *mclock.Timer, timeout chan struct{}, if len(hashes) >= maxTxRetrievals { return false // break in the for-each } - if meta != nil { // Only set eth/68 and upwards - bytes += uint64(meta.size) - if bytes >= maxTxRetrievalSize { - return false - } - } - return true // scheduled, try to add more + bytes += uint64(meta.size) + return bytes < maxTxRetrievalSize }) // If any hashes were allocated, request them from the peer if len(hashes) > 0 { diff --git a/eth/fetcher/tx_fetcher_test.go b/eth/fetcher/tx_fetcher_test.go index 3d3ef81ede..0b47646669 100644 --- a/eth/fetcher/tx_fetcher_test.go +++ b/eth/fetcher/tx_fetcher_test.go @@ -45,13 +45,10 @@ var ( type announce struct { hash common.Hash - kind *byte - size *uint32 + kind byte + size uint32 } -func typeptr(t byte) *byte { return &t } -func sizeptr(n uint32) *uint32 { return &n } - type doTxNotify struct { peer string hashes []common.Hash @@ -70,16 +67,10 @@ type doWait struct { type doDrop string type doFunc func() -type isWaitingWithMeta map[string][]announce -type isWaiting map[string][]common.Hash +type isWaiting map[string][]announce -type isScheduledWithMeta struct { - tracking map[string][]announce - fetching map[string][]common.Hash - dangling map[string][]common.Hash -} type isScheduled struct { - tracking map[string][]common.Hash + tracking map[string][]announce fetching map[string][]common.Hash dangling map[string][]common.Hash } @@ -92,104 +83,13 @@ type txFetcherTest struct { steps []interface{} } -// Tests that transaction announcements are added to a waitlist, and none -// of them are scheduled for retrieval until the wait expires. +// Tests that transaction announcements with associated metadata are added to a +// waitlist, and none of them are scheduled for retrieval until the wait expires. +// +// This test is an extended version of TestTransactionFetcherWaiting. It's mostly +// to cover the metadata checks without bloating up the basic behavioral tests +// with all the useless extra fields. func TestTransactionFetcherWaiting(t *testing.T) { - testTransactionFetcherParallel(t, txFetcherTest{ - init: func() *TxFetcher { - return NewTxFetcher( - func(common.Hash) bool { return false }, - nil, - func(string, []common.Hash) error { return nil }, - nil, - ) - }, - steps: []interface{}{ - // Initial announcement to get something into the waitlist - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - }), - // Announce from a new peer to check that no overwrite happens - doTxNotify{peer: "B", hashes: []common.Hash{{0x03}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x03}, {0x04}}, - }), - // Announce clashing hashes but unique new peer - doTxNotify{peer: "C", hashes: []common.Hash{{0x01}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}}, - }), - // Announce existing and clashing hashes from existing peer - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x03}, {0x05}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}}, - }), - isScheduled{tracking: nil, fetching: nil}, - - // Wait for the arrival timeout which should move all expired items - // from the wait list to the scheduler - doWait{time: txArriveTimeout, step: true}, - isWaiting(nil), - isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}}, - }, - fetching: map[string][]common.Hash{ // Depends on deterministic test randomizer - "A": {{0x02}, {0x03}, {0x05}}, - "C": {{0x01}, {0x04}}, - }, - }, - // Queue up a non-fetchable transaction and then trigger it with a new - // peer (weird case to test 1 line in the fetcher) - doTxNotify{peer: "C", hashes: []common.Hash{{0x06}, {0x07}}}, - isWaiting(map[string][]common.Hash{ - "C": {{0x06}, {0x07}}, - }), - doWait{time: txArriveTimeout, step: true}, - isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}, {0x06}, {0x07}}, - }, - fetching: map[string][]common.Hash{ - "A": {{0x02}, {0x03}, {0x05}}, - "C": {{0x01}, {0x04}}, - }, - }, - doTxNotify{peer: "D", hashes: []common.Hash{{0x06}, {0x07}}}, - isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x05}}, - "B": {{0x03}, {0x04}}, - "C": {{0x01}, {0x04}, {0x06}, {0x07}}, - "D": {{0x06}, {0x07}}, - }, - fetching: map[string][]common.Hash{ - "A": {{0x02}, {0x03}, {0x05}}, - "C": {{0x01}, {0x04}}, - "D": {{0x06}, {0x07}}, - }, - }, - }, - }) -} - -// Tests that transaction announcements with associated metadata are added to a -// waitlist, and none of them are scheduled for retrieval until the wait expires. -// -// This test is an extended version of TestTransactionFetcherWaiting. It's mostly -// to cover the metadata checks without bloating up the basic behavioral tests -// with all the useless extra fields. -func TestTransactionFetcherWaitingWithMeta(t *testing.T) { testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { return NewTxFetcher( @@ -202,80 +102,80 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { steps: []interface{}{ // Initial announcement to get something into the waitlist doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, }, }), // Announce from a new peer to check that no overwrite happens doTxNotify{peer: "B", hashes: []common.Hash{{0x03}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{333, 444}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, }), // Announce clashing hashes but unique new peer doTxNotify{peer: "C", hashes: []common.Hash{{0x01}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 444}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, }), // Announce existing and clashing hashes from existing peer. Clashes // should not overwrite previous announcements. doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x03}, {0x05}}, types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{999, 333, 555}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, }), // Announce clashing hashes with conflicting metadata. Somebody will // be in the wrong, but we don't know yet who. doTxNotify{peer: "D", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.BlobTxType}, sizes: []uint32{999, 222}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, }), isScheduled{tracking: nil, fetching: nil}, @@ -284,25 +184,25 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { // from the wait list to the scheduler doWait{time: txArriveTimeout, step: true}, isWaiting(nil), - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, }, fetching: map[string][]common.Hash{ // Depends on deterministic test randomizer @@ -314,34 +214,34 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { // Queue up a non-fetchable transaction and then trigger it with a new // peer (weird case to test 1 line in the fetcher) doTxNotify{peer: "C", hashes: []common.Hash{{0x06}, {0x07}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{666, 777}}, - isWaitingWithMeta(map[string][]announce{ + isWaiting(map[string][]announce{ "C": { - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, }), doWait{time: txArriveTimeout, step: true}, - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, }, fetching: map[string][]common.Hash{ @@ -351,31 +251,31 @@ func TestTransactionFetcherWaitingWithMeta(t *testing.T) { }, }, doTxNotify{peer: "E", hashes: []common.Hash{{0x06}, {0x07}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{666, 777}}, - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(222)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(555)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x05}, types.LegacyTxType, 555}, }, "B": { - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(333)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, }, "C": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(111)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(444)}, - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, "D": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(999)}, - {common.Hash{0x02}, typeptr(types.BlobTxType), sizeptr(222)}, + {common.Hash{0x01}, types.LegacyTxType, 999}, + {common.Hash{0x02}, types.BlobTxType, 222}, }, "E": { - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(666)}, - {common.Hash{0x07}, typeptr(types.LegacyTxType), sizeptr(777)}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + {common.Hash{0x07}, types.LegacyTxType, 777}, }, }, fetching: map[string][]common.Hash{ @@ -403,17 +303,28 @@ func TestTransactionFetcherSkipWaiting(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{{0x01}, {0x02}}, + types: []byte{types.LegacyTxType, types.LegacyTxType}, + sizes: []uint32{111, 222}, + }, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -421,13 +332,18 @@ func TestTransactionFetcherSkipWaiting(t *testing.T) { }, // Announce overlaps from the same peer, ensure the new ones end up // in stage one, and clashing ones don't get double tracked - doTxNotify{peer: "A", hashes: []common.Hash{{0x02}, {0x03}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x02}, {0x03}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{222, 333}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -435,15 +351,25 @@ func TestTransactionFetcherSkipWaiting(t *testing.T) { }, // Announce overlaps from a new peer, ensure new transactions end up // in stage one and clashing ones get tracked for the new peer - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}}, - "B": {{0x03}, {0x04}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{222, 333, 444}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, + "B": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -467,17 +393,23 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -485,13 +417,19 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { }, // Announce a new set of transactions from the same peer and ensure // they do not start fetching since the peer is already busy - doTxNotify{peer: "A", hashes: []common.Hash{{0x03}, {0x04}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}, {0x04}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x03}, {0x04}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{333, 444}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -500,8 +438,13 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x04}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -509,14 +452,25 @@ func TestTransactionFetcherSingletonRequesting(t *testing.T) { }, // Announce a duplicate set of transactions from a new peer and ensure // uniquely new ones start downloading, even if clashing. - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x05}, {0x06}}}, - isWaiting(map[string][]common.Hash{ - "B": {{0x05}, {0x06}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}, {0x03}, {0x05}, {0x06}}, types: []byte{types.LegacyTxType, types.LegacyTxType, types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{222, 333, 555, 666}}, + isWaiting(map[string][]announce{ + "B": { + {common.Hash{0x05}, types.LegacyTxType, 555}, + {common.Hash{0x06}, types.LegacyTxType, 666}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}, {0x03}, {0x04}}, - "B": {{0x02}, {0x03}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + {common.Hash{0x04}, types.LegacyTxType, 444}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -547,17 +501,23 @@ func TestTransactionFetcherFailedRescheduling(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}, {0x02}}, types: []byte{types.LegacyTxType, types.LegacyTxType}, sizes: []uint32{111, 222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -565,12 +525,17 @@ func TestTransactionFetcherFailedRescheduling(t *testing.T) { }, // While the original peer is stuck in the request, push in an second // data source. - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, - "B": {{0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}, {0x02}}, @@ -584,8 +549,10 @@ func TestTransactionFetcherFailedRescheduling(t *testing.T) { doWait{time: 0, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "B": {{0x02}}, + tracking: map[string][]announce{ + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "B": {{0x02}}, @@ -617,17 +584,21 @@ func TestTransactionFetcherCleanup(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -657,17 +628,21 @@ func TestTransactionFetcherCleanupEmpty(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -696,17 +671,29 @@ func TestTransactionFetcherMissingRescheduling(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type(), testTxs[2].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size()), uint32(testTxs[2].Size())}, + }, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, @@ -716,8 +703,10 @@ func TestTransactionFetcherMissingRescheduling(t *testing.T) { // should be dropped and the one after re-requested. doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}, direct: true}, // This depends on the deterministic random isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[2]}, @@ -743,17 +732,27 @@ func TestTransactionFetcherMissingCleanup(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0], testTxsHashes[1]}, @@ -782,18 +781,23 @@ func TestTransactionFetcherBroadcasts(t *testing.T) { }, steps: []interface{}{ // Set up three transactions to be in different stats, waiting, queued and fetching - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}, types: []byte{testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[1].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}, types: []byte{testTxs[2].Type()}, sizes: []uint32{uint32(testTxs[2].Size())}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -830,29 +834,40 @@ func TestTransactionFetcherWaitTimerResets(t *testing.T) { ) }, steps: []interface{}{ - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, }), isScheduled{nil, nil, nil}, doWait{time: txArriveTimeout / 2, step: false}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, }), isScheduled{nil, nil, nil}, - doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{nil, nil, nil}, doWait{time: txArriveTimeout / 2, step: true}, - isWaiting(map[string][]common.Hash{ - "A": {{0x02}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -862,8 +877,11 @@ func TestTransactionFetcherWaitTimerResets(t *testing.T) { doWait{time: txArriveTimeout / 2, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -889,17 +907,22 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) { }, steps: []interface{}{ // Push an initial announcement through to the scheduled stage - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[0]}, + types: []byte{testTxs[0].Type()}, + sizes: []uint32{uint32(testTxs[0].Size())}, + }, + isWaiting(map[string][]announce{ + "A": {{testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}}, }), isScheduled{tracking: nil, fetching: nil}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": {{testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}}, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -916,11 +939,16 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) { }, }, // Ensure that followup announcements don't get scheduled - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[1]}, + types: []byte{testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[1].Size())}, + }, doWait{time: txArriveTimeout, step: true}, isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": {{testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}}, }, fetching: nil, dangling: map[string][]common.Hash{ @@ -931,8 +959,8 @@ func TestTransactionFetcherTimeoutRescheduling(t *testing.T) { doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}, direct: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": {{testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}}, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[1]}, @@ -954,16 +982,20 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { ) }, steps: []interface{}{ - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}}, - "B": {{0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + }, + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -972,8 +1004,10 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { }, doWait{time: txFetchTimeout - txArriveTimeout, step: true}, isScheduled{ - tracking: map[string][]common.Hash{ - "B": {{0x02}}, + tracking: map[string][]announce{ + "B": { + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "B": {{0x02}}, @@ -999,9 +1033,22 @@ func TestTransactionFetcherTimeoutTimerResets(t *testing.T) { // number of them will be requested at a time. func TestTransactionFetcherRateLimiting(t *testing.T) { // Create a slew of transactions and announce them - var hashes []common.Hash + var ( + hashes []common.Hash + ts []byte + sizes []uint32 + announces []announce + ) for i := 0; i < maxTxAnnounces; i++ { - hashes = append(hashes, common.Hash{byte(i / 256), byte(i % 256)}) + hash := common.Hash{byte(i / 256), byte(i % 256)} + hashes = append(hashes, hash) + ts = append(ts, types.LegacyTxType) + sizes = append(sizes, 111) + announces = append(announces, announce{ + hash: hash, + kind: types.LegacyTxType, + size: 111, + }) } testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { @@ -1015,12 +1062,12 @@ func TestTransactionFetcherRateLimiting(t *testing.T) { steps: []interface{}{ // Announce all the transactions, wait a bit and ensure only a small // percentage gets requested - doTxNotify{peer: "A", hashes: hashes}, + doTxNotify{peer: "A", hashes: hashes, types: ts, sizes: sizes}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashes, + tracking: map[string][]announce{ + "A": announces, }, fetching: map[string][]common.Hash{ "A": hashes[1643 : 1643+maxTxRetrievals], @@ -1065,21 +1112,21 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { }, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), - isScheduledWithMeta{ + isScheduled{ tracking: map[string][]announce{ "A": { - {common.Hash{0x01}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, - {common.Hash{0x02}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, - {common.Hash{0x03}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, - {common.Hash{0x04}, typeptr(types.LegacyTxType), sizeptr(48 * 1024)}, + {common.Hash{0x01}, types.LegacyTxType, 48 * 1024}, + {common.Hash{0x02}, types.LegacyTxType, 48 * 1024}, + {common.Hash{0x03}, types.LegacyTxType, 48 * 1024}, + {common.Hash{0x04}, types.LegacyTxType, 48 * 1024}, }, "B": { - {common.Hash{0x05}, typeptr(types.LegacyTxType), sizeptr(maxTxRetrievalSize)}, - {common.Hash{0x06}, typeptr(types.LegacyTxType), sizeptr(maxTxRetrievalSize)}, + {common.Hash{0x05}, types.LegacyTxType, maxTxRetrievalSize}, + {common.Hash{0x06}, types.LegacyTxType, maxTxRetrievalSize}, }, "C": { - {common.Hash{0x07}, typeptr(types.BlobTxType), sizeptr(params.MaxBlobGasPerBlock)}, - {common.Hash{0x08}, typeptr(types.BlobTxType), sizeptr(params.MaxBlobGasPerBlock)}, + {common.Hash{0x07}, types.BlobTxType, params.MaxBlobGasPerBlock}, + {common.Hash{0x08}, types.BlobTxType, params.MaxBlobGasPerBlock}, }, }, fetching: map[string][]common.Hash{ @@ -1096,13 +1143,41 @@ func TestTransactionFetcherBandwidthLimiting(t *testing.T) { // request at the same time is hard capped. func TestTransactionFetcherDoSProtection(t *testing.T) { // Create a slew of transactions and to announce them - var hashesA []common.Hash + var ( + hashesA []common.Hash + typesA []byte + sizesA []uint32 + announceA []announce + ) for i := 0; i < maxTxAnnounces+1; i++ { - hashesA = append(hashesA, common.Hash{0x01, byte(i / 256), byte(i % 256)}) + hash := common.Hash{0x01, byte(i / 256), byte(i % 256)} + hashesA = append(hashesA, hash) + typesA = append(typesA, types.LegacyTxType) + sizesA = append(sizesA, 111) + + announceA = append(announceA, announce{ + hash: hash, + kind: types.LegacyTxType, + size: 111, + }) } - var hashesB []common.Hash + var ( + hashesB []common.Hash + typesB []byte + sizesB []uint32 + announceB []announce + ) for i := 0; i < maxTxAnnounces+1; i++ { - hashesB = append(hashesB, common.Hash{0x02, byte(i / 256), byte(i % 256)}) + hash := common.Hash{0x02, byte(i / 256), byte(i % 256)} + hashesB = append(hashesB, hash) + typesB = append(typesB, types.LegacyTxType) + sizesB = append(sizesB, 111) + + announceB = append(announceB, announce{ + hash: hash, + kind: types.LegacyTxType, + size: 111, + }) } testTransactionFetcherParallel(t, txFetcherTest{ init: func() *TxFetcher { @@ -1115,23 +1190,23 @@ func TestTransactionFetcherDoSProtection(t *testing.T) { }, steps: []interface{}{ // Announce half of the transaction and wait for them to be scheduled - doTxNotify{peer: "A", hashes: hashesA[:maxTxAnnounces/2]}, - doTxNotify{peer: "B", hashes: hashesB[:maxTxAnnounces/2-1]}, + doTxNotify{peer: "A", hashes: hashesA[:maxTxAnnounces/2], types: typesA[:maxTxAnnounces/2], sizes: sizesA[:maxTxAnnounces/2]}, + doTxNotify{peer: "B", hashes: hashesB[:maxTxAnnounces/2-1], types: typesB[:maxTxAnnounces/2-1], sizes: sizesB[:maxTxAnnounces/2-1]}, doWait{time: txArriveTimeout, step: true}, // Announce the second half and keep them in the wait list - doTxNotify{peer: "A", hashes: hashesA[maxTxAnnounces/2 : maxTxAnnounces]}, - doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces/2-1 : maxTxAnnounces-1]}, + doTxNotify{peer: "A", hashes: hashesA[maxTxAnnounces/2 : maxTxAnnounces], types: typesA[maxTxAnnounces/2 : maxTxAnnounces], sizes: sizesA[maxTxAnnounces/2 : maxTxAnnounces]}, + doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces/2-1 : maxTxAnnounces-1], types: typesB[maxTxAnnounces/2-1 : maxTxAnnounces-1], sizes: sizesB[maxTxAnnounces/2-1 : maxTxAnnounces-1]}, // Ensure the hashes are split half and half - isWaiting(map[string][]common.Hash{ - "A": hashesA[maxTxAnnounces/2 : maxTxAnnounces], - "B": hashesB[maxTxAnnounces/2-1 : maxTxAnnounces-1], + isWaiting(map[string][]announce{ + "A": announceA[maxTxAnnounces/2 : maxTxAnnounces], + "B": announceB[maxTxAnnounces/2-1 : maxTxAnnounces-1], }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashesA[:maxTxAnnounces/2], - "B": hashesB[:maxTxAnnounces/2-1], + tracking: map[string][]announce{ + "A": announceA[:maxTxAnnounces/2], + "B": announceB[:maxTxAnnounces/2-1], }, fetching: map[string][]common.Hash{ "A": hashesA[1643 : 1643+maxTxRetrievals], @@ -1139,17 +1214,17 @@ func TestTransactionFetcherDoSProtection(t *testing.T) { }, }, // Ensure that adding even one more hash results in dropping the hash - doTxNotify{peer: "A", hashes: []common.Hash{hashesA[maxTxAnnounces]}}, - doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces-1 : maxTxAnnounces+1]}, + doTxNotify{peer: "A", hashes: []common.Hash{hashesA[maxTxAnnounces]}, types: []byte{typesA[maxTxAnnounces]}, sizes: []uint32{sizesA[maxTxAnnounces]}}, + doTxNotify{peer: "B", hashes: hashesB[maxTxAnnounces-1 : maxTxAnnounces+1], types: typesB[maxTxAnnounces-1 : maxTxAnnounces+1], sizes: sizesB[maxTxAnnounces-1 : maxTxAnnounces+1]}, - isWaiting(map[string][]common.Hash{ - "A": hashesA[maxTxAnnounces/2 : maxTxAnnounces], - "B": hashesB[maxTxAnnounces/2-1 : maxTxAnnounces], + isWaiting(map[string][]announce{ + "A": announceA[maxTxAnnounces/2 : maxTxAnnounces], + "B": announceB[maxTxAnnounces/2-1 : maxTxAnnounces], }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashesA[:maxTxAnnounces/2], - "B": hashesB[:maxTxAnnounces/2-1], + tracking: map[string][]announce{ + "A": announceA[:maxTxAnnounces/2], + "B": announceB[:maxTxAnnounces/2-1], }, fetching: map[string][]common.Hash{ "A": hashesA[1643 : 1643+maxTxRetrievals], @@ -1183,15 +1258,23 @@ func TestTransactionFetcherUnderpricedDedup(t *testing.T) { }, steps: []interface{}{ // Deliver a transaction through the fetcher, but reject as underpriced - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0], testTxs[1]}, direct: true}, isScheduled{nil, nil, nil}, // Try to announce the transaction again, ensure it's not scheduled back - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}}, // [2] is needed to force a step in the fetcher - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + doTxNotify{peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1], testTxsHashes[2]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type(), testTxs[2].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size()), uint32(testTxs[2].Size())}, + }, // [2] is needed to force a step in the fetcher + isWaiting(map[string][]announce{ + "A": {{testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}}, }), isScheduled{nil, nil, nil}, }, @@ -1211,21 +1294,38 @@ func TestTransactionFetcherUnderpricedDoSProtection(t *testing.T) { for i := 0; i < maxTxUnderpricedSetSize+1; i++ { txs = append(txs, types.NewTransaction(rand.Uint64(), common.Address{byte(rand.Intn(256))}, new(big.Int), 0, new(big.Int), nil)) } - hashes := make([]common.Hash, len(txs)) - for i, tx := range txs { - hashes[i] = tx.Hash() + var ( + hashes []common.Hash + ts []byte + sizes []uint32 + annos []announce + ) + for _, tx := range txs { + hashes = append(hashes, tx.Hash()) + ts = append(ts, tx.Type()) + sizes = append(sizes, uint32(tx.Size())) + annos = append(annos, announce{ + hash: tx.Hash(), + kind: tx.Type(), + size: uint32(tx.Size()), + }) } // Generate a set of steps to announce and deliver the entire set of transactions var steps []interface{} for i := 0; i < maxTxUnderpricedSetSize/maxTxRetrievals; i++ { - steps = append(steps, doTxNotify{peer: "A", hashes: hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals]}) - steps = append(steps, isWaiting(map[string][]common.Hash{ - "A": hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + steps = append(steps, doTxNotify{ + peer: "A", + hashes: hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + types: ts[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + sizes: sizes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + }) + steps = append(steps, isWaiting(map[string][]announce{ + "A": annos[i*maxTxRetrievals : (i+1)*maxTxRetrievals], })) steps = append(steps, doWait{time: txArriveTimeout, step: true}) steps = append(steps, isScheduled{ - tracking: map[string][]common.Hash{ - "A": hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], + tracking: map[string][]announce{ + "A": annos[i*maxTxRetrievals : (i+1)*maxTxRetrievals], }, fetching: map[string][]common.Hash{ "A": hashes[i*maxTxRetrievals : (i+1)*maxTxRetrievals], @@ -1253,7 +1353,12 @@ func TestTransactionFetcherUnderpricedDoSProtection(t *testing.T) { }, steps: append(steps, []interface{}{ // The preparation of the test has already been done in `steps`, add the last check - doTxNotify{peer: "A", hashes: []common.Hash{hashes[maxTxUnderpricedSetSize]}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{hashes[maxTxUnderpricedSetSize]}, + types: []byte{ts[maxTxUnderpricedSetSize]}, + sizes: []uint32{sizes[maxTxUnderpricedSetSize]}, + }, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{txs[maxTxUnderpricedSetSize]}, direct: true}, isUnderpriced(maxTxUnderpricedSetSize), @@ -1283,18 +1388,23 @@ func TestTransactionFetcherOutOfBoundDeliveries(t *testing.T) { isScheduled{nil, nil, nil}, // Set up a few hashes into various stages - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[1]}, types: []byte{testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[1].Size())}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[2]}, types: []byte{testTxs[2].Type()}, sizes: []uint32{uint32(testTxs[2].Size())}}, - isWaiting(map[string][]common.Hash{ - "A": {testTxsHashes[2]}, + isWaiting(map[string][]announce{ + "A": { + {testTxsHashes[2], testTxs[2].Type(), uint32(testTxs[2].Size())}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0], testTxsHashes[1]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -1330,18 +1440,23 @@ func TestTransactionFetcherDrop(t *testing.T) { }, steps: []interface{}{ // Set up a few hashes into various stages - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x02}}, types: []byte{types.LegacyTxType}, sizes: []uint32{222}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "A", hashes: []common.Hash{{0x03}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x03}}, types: []byte{types.LegacyTxType}, sizes: []uint32{333}}, - isWaiting(map[string][]common.Hash{ - "A": {{0x03}}, + isWaiting(map[string][]announce{ + "A": { + {common.Hash{0x03}, types.LegacyTxType, 333}, + }, }), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}, {0x02}}, + tracking: map[string][]announce{ + "A": { + {common.Hash{0x01}, types.LegacyTxType, 111}, + {common.Hash{0x02}, types.LegacyTxType, 222}, + }, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -1353,12 +1468,14 @@ func TestTransactionFetcherDrop(t *testing.T) { isScheduled{nil, nil, nil}, // Push the node into a dangling (timeout) state - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {testTxsHashes[0]}, + tracking: map[string][]announce{ + "A": { + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + }, }, fetching: map[string][]common.Hash{ "A": {testTxsHashes[0]}, @@ -1397,15 +1514,15 @@ func TestTransactionFetcherDropRescheduling(t *testing.T) { }, steps: []interface{}{ // Set up a few hashes into various stages - doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "A", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, doWait{time: txArriveTimeout, step: true}, - doTxNotify{peer: "B", hashes: []common.Hash{{0x01}}}, + doTxNotify{peer: "B", hashes: []common.Hash{{0x01}}, types: []byte{types.LegacyTxType}, sizes: []uint32{111}}, isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "A": {{0x01}}, - "B": {{0x01}}, + tracking: map[string][]announce{ + "A": {{common.Hash{0x01}, types.LegacyTxType, 111}}, + "B": {{common.Hash{0x01}, types.LegacyTxType, 111}}, }, fetching: map[string][]common.Hash{ "A": {{0x01}}, @@ -1415,8 +1532,8 @@ func TestTransactionFetcherDropRescheduling(t *testing.T) { doDrop("A"), isWaiting(nil), isScheduled{ - tracking: map[string][]common.Hash{ - "B": {{0x01}}, + tracking: map[string][]announce{ + "B": {{common.Hash{0x01}, types.LegacyTxType, 111}}, }, fetching: map[string][]common.Hash{ "B": {{0x01}}, @@ -1443,42 +1560,57 @@ func TestInvalidAnnounceMetadata(t *testing.T) { }, steps: []interface{}{ // Initial announcement to get something into the waitlist - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, types: []byte{testTxs[0].Type(), testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}}, - isWaitingWithMeta(map[string][]announce{ + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, + isWaiting(map[string][]announce{ "A": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(uint32(testTxs[0].Size()))}, - {testTxsHashes[1], typeptr(testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, }, }), // Announce from new peers conflicting transactions - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{1024 + uint32(testTxs[0].Size())}}, - doTxNotify{peer: "C", hashes: []common.Hash{testTxsHashes[1]}, types: []byte{1 + testTxs[1].Type()}, sizes: []uint32{uint32(testTxs[1].Size())}}, - isWaitingWithMeta(map[string][]announce{ + doTxNotify{ + peer: "B", + hashes: []common.Hash{testTxsHashes[0]}, + types: []byte{testTxs[0].Type()}, + sizes: []uint32{1024 + uint32(testTxs[0].Size())}, + }, + doTxNotify{ + peer: "C", + hashes: []common.Hash{testTxsHashes[1]}, + types: []byte{1 + testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[1].Size())}, + }, + isWaiting(map[string][]announce{ "A": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(uint32(testTxs[0].Size()))}, - {testTxsHashes[1], typeptr(testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, }, "B": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(1024 + uint32(testTxs[0].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), 1024 + uint32(testTxs[0].Size())}, }, "C": { - {testTxsHashes[1], typeptr(1 + testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[1], 1 + testTxs[1].Type(), uint32(testTxs[1].Size())}, }, }), // Schedule all the transactions for retrieval doWait{time: txArriveTimeout, step: true}, - isWaitingWithMeta(nil), - isScheduledWithMeta{ + isWaiting(nil), + isScheduled{ tracking: map[string][]announce{ "A": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(uint32(testTxs[0].Size()))}, - {testTxsHashes[1], typeptr(testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), uint32(testTxs[0].Size())}, + {testTxsHashes[1], testTxs[1].Type(), uint32(testTxs[1].Size())}, }, "B": { - {testTxsHashes[0], typeptr(testTxs[0].Type()), sizeptr(1024 + uint32(testTxs[0].Size()))}, + {testTxsHashes[0], testTxs[0].Type(), 1024 + uint32(testTxs[0].Size())}, }, "C": { - {testTxsHashes[1], typeptr(1 + testTxs[1].Type()), sizeptr(uint32(testTxs[1].Size()))}, + {testTxsHashes[1], 1 + testTxs[1].Type(), uint32(testTxs[1].Size())}, }, }, fetching: map[string][]common.Hash{ @@ -1511,12 +1643,12 @@ func TestTransactionFetcherFuzzCrash01(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}}, // Notify the dangling transaction once more and crash via a timeout - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txFetchTimeout, step: true}, }, }) @@ -1539,12 +1671,12 @@ func TestTransactionFetcherFuzzCrash02(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}}, // Notify the dangling transaction once more, re-fetch, and crash via a drop and timeout - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doDrop("A"), doWait{time: txFetchTimeout, step: true}, @@ -1569,12 +1701,17 @@ func TestTransactionFetcherFuzzCrash03(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}}, + doTxNotify{ + peer: "A", + hashes: []common.Hash{testTxsHashes[0], testTxsHashes[1]}, + types: []byte{testTxs[0].Type(), testTxs[1].Type()}, + sizes: []uint32{uint32(testTxs[0].Size()), uint32(testTxs[1].Size())}, + }, doWait{time: txFetchTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0], testTxs[1]}}, // Notify the dangling transaction once more, partially deliver, clash&crash with a timeout - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[1]}, direct: true}, @@ -1606,12 +1743,12 @@ func TestTransactionFetcherFuzzCrash04(t *testing.T) { }, steps: []interface{}{ // Get a transaction into fetching mode and make it dangling with a broadcast - doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "A", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doTxEnqueue{peer: "A", txs: []*types.Transaction{testTxs[0]}}, // Notify the dangling transaction once more, re-fetch, and crash via an in-flight disconnect - doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}}, + doTxNotify{peer: "B", hashes: []common.Hash{testTxsHashes[0]}, types: []byte{testTxs[0].Type()}, sizes: []uint32{uint32(testTxs[0].Size())}}, doWait{time: txArriveTimeout, step: true}, doFunc(func() { proceed <- struct{}{} // Allow peer A to return the failure @@ -1652,30 +1789,6 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { // Crunch through all the test steps and execute them for i, step := range tt.steps { - // Auto-expand certain steps to ones with metadata - switch old := step.(type) { - case isWaiting: - new := make(isWaitingWithMeta) - for peer, hashes := range old { - for _, hash := range hashes { - new[peer] = append(new[peer], announce{hash, nil, nil}) - } - } - step = new - - case isScheduled: - new := isScheduledWithMeta{ - tracking: make(map[string][]announce), - fetching: old.fetching, - dangling: old.dangling, - } - for peer, hashes := range old.tracking { - for _, hash := range hashes { - new.tracking[peer] = append(new.tracking[peer], announce{hash, nil, nil}) - } - } - step = new - } // Process the original or expanded steps switch step := step.(type) { case doTxNotify: @@ -1710,7 +1823,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { case doFunc: step() - case isWaitingWithMeta: + case isWaiting: // We need to check that the waiting list (stage 1) internals // match with the expected set. Check the peer->hash mappings // first. @@ -1724,18 +1837,13 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { if meta, ok := waiting[ann.hash]; !ok { t.Errorf("step %d, peer %s: hash %x missing from waitslots", i, peer, ann.hash) } else { - if (meta == nil && (ann.kind != nil || ann.size != nil)) || - (meta != nil && (ann.kind == nil || ann.size == nil)) || - (meta != nil && (meta.kind != *ann.kind || meta.size != *ann.size)) { - t.Errorf("step %d, peer %s, hash %x: waitslot metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, *ann.kind, *ann.size) + if meta.kind != ann.kind || meta.size != ann.size { + t.Errorf("step %d, peer %s, hash %x: waitslot metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, ann.kind, ann.size) } } } for hash, meta := range waiting { - ann := announce{hash: hash} - if meta != nil { - ann.kind, ann.size = &meta.kind, &meta.size - } + ann := announce{hash: hash, kind: meta.kind, size: meta.size} if !containsAnnounce(announces, ann) { t.Errorf("step %d, peer %s: announce %v extra in waitslots", i, peer, ann) } @@ -1780,7 +1888,7 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { } } - case isScheduledWithMeta: + case isScheduled: // Check that all scheduled announces are accounted for and no // extra ones are present. for peer, announces := range step.tracking { @@ -1793,18 +1901,13 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { if meta, ok := scheduled[ann.hash]; !ok { t.Errorf("step %d, peer %s: hash %x missing from announces", i, peer, ann.hash) } else { - if (meta == nil && (ann.kind != nil || ann.size != nil)) || - (meta != nil && (ann.kind == nil || ann.size == nil)) || - (meta != nil && (meta.kind != *ann.kind || meta.size != *ann.size)) { - t.Errorf("step %d, peer %s, hash %x: announce metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, *ann.kind, *ann.size) + if meta.kind != ann.kind || meta.size != ann.size { + t.Errorf("step %d, peer %s, hash %x: announce metadata mismatch: want %v, have %v/%v", i, peer, ann.hash, meta, ann.kind, ann.size) } } } for hash, meta := range scheduled { - ann := announce{hash: hash} - if meta != nil { - ann.kind, ann.size = &meta.kind, &meta.size - } + ann := announce{hash: hash, kind: meta.kind, size: meta.size} if !containsAnnounce(announces, ann) { t.Errorf("step %d, peer %s: announce %x extra in announces", i, peer, hash) } @@ -1954,18 +2057,10 @@ func testTransactionFetcher(t *testing.T, tt txFetcherTest) { func containsAnnounce(slice []announce, ann announce) bool { for _, have := range slice { if have.hash == ann.hash { - if have.kind == nil || ann.kind == nil { - if have.kind != ann.kind { - return false - } - } else if *have.kind != *ann.kind { + if have.kind != ann.kind { return false } - if have.size == nil || ann.size == nil { - if have.size != ann.size { - return false - } - } else if *have.size != *ann.size { + if have.size != ann.size { return false } return true From c35684709c8c71da78d5abbc6c38a501dd05b58a Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 11:42:39 +0200 Subject: [PATCH 191/196] eth/ethconfig: remove LES server config (#30298) --- .golangci.yml | 2 ++ cmd/geth/config.go | 32 +++++++++++++++----------------- cmd/utils/flags_legacy.go | 4 ---- eth/backend.go | 12 ++---------- eth/ethconfig/config.go | 15 ++++----------- eth/ethconfig/gen_config.go | 36 ------------------------------------ 6 files changed, 23 insertions(+), 78 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d3b8535cfb..adb59f318f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -62,6 +62,8 @@ issues: - revive - path: cmd/utils/flags.go text: "SA1019: cfg.TxLookupLimit is deprecated: use 'TransactionHistory' instead." + - path: cmd/utils/flags.go + text: "SA1019: ethconfig.Defaults.TxLookupLimit is deprecated: use 'TransactionHistory' instead." - path: internal/build/pgp.go text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.' - path: core/vm/contracts.go diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 522e5e22f2..fd57ff40de 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -75,8 +75,8 @@ var tomlSettings = toml.Config{ }, MissingField: func(rt reflect.Type, field string) error { id := fmt.Sprintf("%s.%s", rt.String(), field) - if deprecated(id) { - log.Warn("Config field is deprecated and won't have an effect", "name", id) + if deprecatedConfigFields[id] { + log.Warn(fmt.Sprintf("Config field '%s' is deprecated and won't have any effect.", id)) return nil } var link string @@ -87,6 +87,19 @@ var tomlSettings = toml.Config{ }, } +var deprecatedConfigFields = map[string]bool{ + "ethconfig.Config.EVMInterpreter": true, + "ethconfig.Config.EWASMInterpreter": true, + "ethconfig.Config.TrieCleanCacheJournal": true, + "ethconfig.Config.TrieCleanCacheRejournal": true, + "ethconfig.Config.LightServ": true, + "ethconfig.Config.LightIngress": true, + "ethconfig.Config.LightEgress": true, + "ethconfig.Config.LightPeers": true, + "ethconfig.Config.LightNoPrune": true, + "ethconfig.Config.LightNoSyncServe": true, +} + type ethstatsConfig struct { URL string `toml:",omitempty"` } @@ -314,21 +327,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { } } -func deprecated(field string) bool { - switch field { - case "ethconfig.Config.EVMInterpreter": - return true - case "ethconfig.Config.EWASMInterpreter": - return true - case "ethconfig.Config.TrieCleanCacheJournal": - return true - case "ethconfig.Config.TrieCleanCacheRejournal": - return true - default: - return false - } -} - func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error { scryptN := keystore.StandardScryptN scryptP := keystore.StandardScryptP diff --git a/cmd/utils/flags_legacy.go b/cmd/utils/flags_legacy.go index 1dfd1a5f89..f145f605d6 100644 --- a/cmd/utils/flags_legacy.go +++ b/cmd/utils/flags_legacy.go @@ -92,25 +92,21 @@ var ( LightServeFlag = &cli.IntFlag{ Name: "light.serve", Usage: "Maximum percentage of time allowed for serving LES requests (deprecated)", - Value: ethconfig.Defaults.LightServ, Category: flags.DeprecatedCategory, } LightIngressFlag = &cli.IntFlag{ Name: "light.ingress", Usage: "Incoming bandwidth limit for serving light clients (deprecated)", - Value: ethconfig.Defaults.LightIngress, Category: flags.DeprecatedCategory, } LightEgressFlag = &cli.IntFlag{ Name: "light.egress", Usage: "Outgoing bandwidth limit for serving light clients (deprecated)", - Value: ethconfig.Defaults.LightEgress, Category: flags.DeprecatedCategory, } LightMaxPeersFlag = &cli.IntFlag{ Name: "light.maxpeers", Usage: "Maximum number of light clients to serve, or light servers to attach to (deprecated)", - Value: ethconfig.Defaults.LightPeers, Category: flags.DeprecatedCategory, } LightNoPruneFlag = &cli.BoolFlag{ diff --git a/eth/backend.go b/eth/backend.go index 8679018dab..442d408bb0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -377,16 +377,8 @@ func (s *Ethereum) Start() error { // Regularly update shutdown marker s.shutdownTracker.Start() - // Figure out a max peers count based on the server limits - maxPeers := s.p2pServer.MaxPeers - if s.config.LightServ > 0 { - if s.config.LightPeers >= s.p2pServer.MaxPeers { - return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) - } - maxPeers -= s.config.LightPeers - } - // Start the networking layer and the light server if requested - s.handler.Start(maxPeers) + // Start the networking layer + s.handler.Start(s.p2pServer.MaxPeers) return nil } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 7453fb1efd..5a955d9bbf 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -53,7 +53,6 @@ var Defaults = Config{ TxLookupLimit: 2350000, TransactionHistory: 2350000, StateHistory: params.FullImmutabilityThreshold, - LightPeers: 100, DatabaseCache: 512, TrieCleanCache: 154, TrieDirtyCache: 256, @@ -87,11 +86,13 @@ type Config struct { EthDiscoveryURLs []string SnapDiscoveryURLs []string + // State options. NoPruning bool // Whether to disable pruning and flush everything to disk NoPrefetch bool // Whether to disable prefetching and only load state on demand - // Deprecated, use 'TransactionHistory' instead. - TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. + // Deprecated: use 'TransactionHistory' instead. + TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. + TransactionHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved. StateHistory uint64 `toml:",omitempty"` // The maximum number of blocks from head whose state histories are reserved. @@ -105,14 +106,6 @@ type Config struct { // presence of these blocks for every new peer connection. RequiredBlocks map[uint64]common.Hash `toml:"-"` - // Light client options - LightServ int `toml:",omitempty"` // Maximum percentage of time allowed for serving LES requests - LightIngress int `toml:",omitempty"` // Incoming bandwidth limit for light servers - LightEgress int `toml:",omitempty"` // Outgoing bandwidth limit for light servers - LightPeers int `toml:",omitempty"` // Maximum number of LES client peers - LightNoPrune bool `toml:",omitempty"` // Whether to disable light chain pruning - LightNoSyncServe bool `toml:",omitempty"` // Whether to serve light clients before syncing - // Database options SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 147a559984..2854c87097 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -29,12 +29,6 @@ func (c Config) MarshalTOML() (interface{}, error) { StateHistory uint64 `toml:",omitempty"` StateScheme string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ int `toml:",omitempty"` - LightIngress int `toml:",omitempty"` - LightEgress int `toml:",omitempty"` - LightPeers int `toml:",omitempty"` - LightNoPrune bool `toml:",omitempty"` - LightNoSyncServe bool `toml:",omitempty"` SkipBcVersionCheck bool `toml:"-"` DatabaseHandles int `toml:"-"` DatabaseCache int @@ -73,12 +67,6 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.StateHistory = c.StateHistory enc.StateScheme = c.StateScheme enc.RequiredBlocks = c.RequiredBlocks - enc.LightServ = c.LightServ - enc.LightIngress = c.LightIngress - enc.LightEgress = c.LightEgress - enc.LightPeers = c.LightPeers - enc.LightNoPrune = c.LightNoPrune - enc.LightNoSyncServe = c.LightNoSyncServe enc.SkipBcVersionCheck = c.SkipBcVersionCheck enc.DatabaseHandles = c.DatabaseHandles enc.DatabaseCache = c.DatabaseCache @@ -121,12 +109,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { StateHistory *uint64 `toml:",omitempty"` StateScheme *string `toml:",omitempty"` RequiredBlocks map[uint64]common.Hash `toml:"-"` - LightServ *int `toml:",omitempty"` - LightIngress *int `toml:",omitempty"` - LightEgress *int `toml:",omitempty"` - LightPeers *int `toml:",omitempty"` - LightNoPrune *bool `toml:",omitempty"` - LightNoSyncServe *bool `toml:",omitempty"` SkipBcVersionCheck *bool `toml:"-"` DatabaseHandles *int `toml:"-"` DatabaseCache *int @@ -192,24 +174,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { if dec.RequiredBlocks != nil { c.RequiredBlocks = dec.RequiredBlocks } - if dec.LightServ != nil { - c.LightServ = *dec.LightServ - } - if dec.LightIngress != nil { - c.LightIngress = *dec.LightIngress - } - if dec.LightEgress != nil { - c.LightEgress = *dec.LightEgress - } - if dec.LightPeers != nil { - c.LightPeers = *dec.LightPeers - } - if dec.LightNoPrune != nil { - c.LightNoPrune = *dec.LightNoPrune - } - if dec.LightNoSyncServe != nil { - c.LightNoSyncServe = *dec.LightNoSyncServe - } if dec.SkipBcVersionCheck != nil { c.SkipBcVersionCheck = *dec.SkipBcVersionCheck } From 7a149a159a609f5c0a1eb0cc76dc27a944a1007b Mon Sep 17 00:00:00 2001 From: Dylan Vassallo Date: Thu, 15 Aug 2024 16:36:35 +0200 Subject: [PATCH 192/196] eth/tracers/js: add coinbase addr to ctx (#30231) Add coinbase address to javascript tracer context. This PR adds the `coinbase` address to `jsTracer.ctx`, allowing access to the coinbase address (fee receipient) in custom JavaScript tracers. Example usage: ```javascript result: function(ctx) { return toAddress(ctx.coinbase); } ``` This change enables custom tracers to access coinbase address, previously unavailable, enhancing their capabilities to match built-in tracers. --- eth/tracers/js/goja.go | 6 ++++++ eth/tracers/js/tracer_test.go | 3 +++ 2 files changed, 9 insertions(+) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 5290d4f709..fd8f74fc54 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -254,6 +254,12 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from return } t.ctx["gasPrice"] = gasPriceBig + coinbase, err := t.toBuf(t.vm, env.Coinbase.Bytes()) + if err != nil { + t.err = err + return + } + t.ctx["coinbase"] = t.vm.ToValue(coinbase) } // OnTxEnd implements the Tracer interface and is invoked at the end of diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 05adedf265..7122b3c90e 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -154,6 +154,9 @@ func TestTracer(t *testing.T) { want: "", fail: "reached limit for padding memory slice: 1049568 at step (:1:83(20)) in server-side tracer function 'step'", contract: []byte{byte(vm.PUSH1), byte(0xff), byte(vm.PUSH1), byte(0x00), byte(vm.MSTORE8), byte(vm.STOP)}, + }, { // tests ctx.coinbase + code: "{lengths: [], step: function(log) { }, fault: function() {}, result: function(ctx) { var coinbase = ctx.coinbase; return toAddress(coinbase); }}", + want: `{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0}`, }, } { if have, err := execTracer(tt.code, tt.contract); tt.want != string(have) || tt.fail != err { From 6eb42a6b4f9a07a4a11a9ac706b6a738212de210 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Aug 2024 22:14:42 +0200 Subject: [PATCH 193/196] eth: dial nodes from discv5 (#30302) Here I am adding a discv5 nodes source into the p2p dial iterator. It's an improved version of #29533. Unlike discv4, the discv5 random nodes iterator will always provide full ENRs. This means we can apply filtering to the results and will only try dialing nodes which explictly opt into the eth protocol with a matching chain. I have also removed the dial iterator from snap. We don't have an official DNS list for snap anymore, and I doubt anyone else is running one. While we could potentially filter for snap on discv5, there will be very few nodes announcing it, and the extra iterator would just stall the dialer. --------- Co-authored-by: lightclient --- eth/backend.go | 67 ++++++++++++++++++++++------------ eth/protocols/eth/discovery.go | 14 +++++++ eth/protocols/eth/handler.go | 3 +- eth/protocols/snap/handler.go | 11 +----- 4 files changed, 60 insertions(+), 35 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 442d408bb0..51011ed0b2 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -64,15 +64,13 @@ type Config = ethconfig.Config // Ethereum implements the Ethereum full node service. type Ethereum struct { - config *ethconfig.Config + // core protocol objects + config *ethconfig.Config + txPool *txpool.TxPool + blockchain *core.BlockChain - // Handlers - txPool *txpool.TxPool - - blockchain *core.BlockChain - handler *handler - ethDialCandidates enode.Iterator - snapDialCandidates enode.Iterator + handler *handler + discmix *enode.FairMix // DB interfaces chainDb ethdb.Database // Block chain database @@ -162,6 +160,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { bloomRequests: make(chan chan *bloombits.Retrieval), bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), p2pServer: stack.Server(), + discmix: enode.NewFairMix(0), shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), } bcVersion := rawdb.ReadDatabaseVersion(chainDb) @@ -266,17 +265,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { } eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, config.GPO, config.Miner.GasPrice) - // Setup DNS discovery iterators. - dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) - eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) - if err != nil { - return nil, err - } - eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...) - if err != nil { - return nil, err - } - // Start the RPC service eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, networkID) @@ -359,9 +347,9 @@ func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } // Protocols returns all the currently configured // network protocols to start. func (s *Ethereum) Protocols() []p2p.Protocol { - protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) + protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.discmix) if s.config.SnapshotCache > 0 { - protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) + protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler))...) } return protos } @@ -369,7 +357,7 @@ func (s *Ethereum) Protocols() []p2p.Protocol { // Start implements node.Lifecycle, starting all internal goroutines needed by the // Ethereum protocol implementation. func (s *Ethereum) Start() error { - eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) + s.setupDiscovery() // Start the bloom bits servicing goroutines s.startBloomHandlers(params.BloomBitsBlocks) @@ -382,12 +370,43 @@ func (s *Ethereum) Start() error { return nil } +func (s *Ethereum) setupDiscovery() error { + eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) + + // Add eth nodes from DNS. + dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) + if len(s.config.EthDiscoveryURLs) > 0 { + iter, err := dnsclient.NewIterator(s.config.EthDiscoveryURLs...) + if err != nil { + return err + } + s.discmix.AddSource(iter) + } + + // Add snap nodes from DNS. + if len(s.config.SnapDiscoveryURLs) > 0 { + iter, err := dnsclient.NewIterator(s.config.SnapDiscoveryURLs...) + if err != nil { + return err + } + s.discmix.AddSource(iter) + } + + // Add DHT nodes from discv5. + if s.p2pServer.DiscoveryV5() != nil { + filter := eth.NewNodeFilter(s.blockchain) + iter := enode.Filter(s.p2pServer.DiscoveryV5().RandomNodes(), filter) + s.discmix.AddSource(iter) + } + + return nil +} + // Stop implements node.Lifecycle, terminating all internal goroutines used by the // Ethereum protocol. func (s *Ethereum) Stop() error { // Stop all the peer-related stuff first. - s.ethDialCandidates.Close() - s.snapDialCandidates.Close() + s.discmix.Close() s.handler.Stop() // Then stop everything else. diff --git a/eth/protocols/eth/discovery.go b/eth/protocols/eth/discovery.go index a7bdd47daf..075a85b69c 100644 --- a/eth/protocols/eth/discovery.go +++ b/eth/protocols/eth/discovery.go @@ -64,3 +64,17 @@ func currentENREntry(chain *core.BlockChain) *enrEntry { ForkID: forkid.NewID(chain.Config(), chain.Genesis(), head.Number.Uint64(), head.Time), } } + +// NewNodeFilter returns a filtering function that returns whether the provided +// enode advertises a forkid compatible with the current chain. +func NewNodeFilter(chain *core.BlockChain) func(*enode.Node) bool { + filter := forkid.NewFilter(chain) + return func(n *enode.Node) bool { + var entry enrEntry + if err := n.Load(entry); err != nil { + return false + } + err := filter(entry.ForkID) + return err == nil + } +} diff --git a/eth/protocols/eth/handler.go b/eth/protocols/eth/handler.go index 2d69ecdc83..ecf07b6a2c 100644 --- a/eth/protocols/eth/handler.go +++ b/eth/protocols/eth/handler.go @@ -113,8 +113,7 @@ func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2 PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{currentENREntry(backend.Chain())}, - DialCandidates: dnsdisc, + Attributes: []enr.Entry{currentENREntry(backend.Chain())}, }) } return protocols diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 5cbe9d1270..a6c60bc075 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -82,13 +82,7 @@ type Backend interface { } // MakeProtocols constructs the P2P protocol definitions for `snap`. -func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { - // Filter the discovery iterator for nodes advertising snap support. - dnsdisc = enode.Filter(dnsdisc, func(n *enode.Node) bool { - var snap enrEntry - return n.Load(&snap) == nil - }) - +func MakeProtocols(backend Backend) []p2p.Protocol { protocols := make([]p2p.Protocol, len(ProtocolVersions)) for i, version := range ProtocolVersions { version := version // Closure @@ -108,8 +102,7 @@ func MakeProtocols(backend Backend, dnsdisc enode.Iterator) []p2p.Protocol { PeerInfo: func(id enode.ID) interface{} { return backend.PeerInfo(id) }, - Attributes: []enr.Entry{&enrEntry{}}, - DialCandidates: dnsdisc, + Attributes: []enr.Entry{&enrEntry{}}, } } return protocols From 43640f12d8576cf5e27a99f34280b3e20fb900d3 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Fri, 16 Aug 2024 14:39:57 +0200 Subject: [PATCH 194/196] beacon/light: handle endpoint URL more gracefully (#30306) blsync was failing if the light endpoint it was provided ended with a `/`. This change should handle the joining more gracefully. --- beacon/light/api/light_api.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/beacon/light/api/light_api.go b/beacon/light/api/light_api.go index 6f60fc0cc6..45b425164f 100755 --- a/beacon/light/api/light_api.go +++ b/beacon/light/api/light_api.go @@ -23,6 +23,7 @@ import ( "fmt" "io" "net/http" + "net/url" "sync" "time" @@ -121,7 +122,11 @@ func NewBeaconLightApi(url string, customHeaders map[string]string) *BeaconLight } func (api *BeaconLightApi) httpGet(path string) ([]byte, error) { - req, err := http.NewRequest("GET", api.url+path, nil) + uri, err := api.buildURL(path, nil) + if err != nil { + return nil, err + } + req, err := http.NewRequest("GET", uri, nil) if err != nil { return nil, err } @@ -545,9 +550,13 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func() // established. It can only return nil when the context is canceled. func (api *BeaconLightApi) startEventStream(ctx context.Context, listener *HeadEventListener) *eventsource.Stream { for retry := true; retry; retry = ctxSleep(ctx, 5*time.Second) { - path := "/eth/v1/events?topics=head&topics=light_client_finality_update&topics=light_client_optimistic_update" log.Trace("Sending event subscription request") - req, err := http.NewRequestWithContext(ctx, "GET", api.url+path, nil) + uri, err := api.buildURL("/eth/v1/events", map[string][]string{"topics": {"head", "light_client_finality_update", "light_client_optimistic_update"}}) + if err != nil { + listener.OnError(fmt.Errorf("error creating event subscription URL: %v", err)) + continue + } + req, err := http.NewRequestWithContext(ctx, "GET", uri, nil) if err != nil { listener.OnError(fmt.Errorf("error creating event subscription request: %v", err)) continue @@ -576,3 +585,15 @@ func ctxSleep(ctx context.Context, timeout time.Duration) (ok bool) { return false } } + +func (api *BeaconLightApi) buildURL(path string, params url.Values) (string, error) { + uri, err := url.Parse(api.url) + if err != nil { + return "", err + } + uri = uri.JoinPath(path) + if params != nil { + uri.RawQuery = params.Encode() + } + return uri.String(), nil +} From 09d889d2e3405f3c15d0b92fc0f027bed232a6e1 Mon Sep 17 00:00:00 2001 From: Shude Li Date: Fri, 16 Aug 2024 22:33:41 +0800 Subject: [PATCH 195/196] core: remove withdrawal length check for state processor (#30286) The withdrawal length is already verified by the beacon consensus package, so the check in the state processor is a duplicate. --- core/state_processor.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index c21f644f98..cc41583165 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,7 +17,6 @@ package core import ( - "errors" "fmt" "math/big" @@ -93,11 +92,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } - // Fail if Shanghai not enabled and len(withdrawals) is non-zero. - withdrawals := block.Withdrawals() - if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) { - return nil, nil, 0, errors.New("withdrawals before shanghai") - } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.chain.engine.Finalize(p.chain, header, statedb, block.Body()) From 710c3f32ac8e4e5829a6a631dcfb1e0e13a49220 Mon Sep 17 00:00:00 2001 From: Arran Schlosberg <519948+ARR4N@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:41:44 +0100 Subject: [PATCH 196/196] vm: simplify error handling in `vm.EVM.create()` (#30292) To allow all error paths in `vm.EVM.create()` to consume the necessary gas, there is currently a pattern of gating code on `if err == nil` instead of returning as soon as the error occurs. The same behaviour can be achieved by abstracting the gated code into a method that returns immediately on error, improving readability and thus making it easier to understand and maintain. --- core/vm/evm.go | 97 ++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 1944189b5d..7617d843c7 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -510,66 +510,61 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, contract.SetCodeOptionalHash(&address, codeAndHash) contract.IsDeployment = true - // Charge the contract creation init gas in verkle mode - if evm.chainRules.IsEIP4762 { - if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { - err = ErrOutOfGas - } - } - - if err == nil { - ret, err = evm.interpreter.Run(contract, nil, false) - } - - // Check whether the max code size has been exceeded, assign err if the case. - if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { - err = ErrMaxCodeSizeExceeded - } - - // Reject code starting with 0xEF if EIP-3541 is enabled. - if err == nil && len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon { - err = ErrInvalidCode - } - - // if the contract creation ran successfully and no errors were returned - // calculate the gas required to store the code. If the code could not - // be stored due to not enough gas set an error and let it be handled - // by the error checking condition below. - if err == nil { - if !evm.chainRules.IsEIP4762 { - createDataGas := uint64(len(ret)) * params.CreateDataGas - if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { - err = ErrCodeStoreOutOfGas - } - } else { - // Contract creation completed, touch the missing fields in the contract - if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { - err = ErrCodeStoreOutOfGas - } - - if err == nil && len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { - err = ErrCodeStoreOutOfGas - } - } - - if err == nil { - evm.StateDB.SetCode(address, ret) - } - } - - // When an error was returned by the EVM or when setting the creation code - // above we revert to the snapshot and consume any gas remaining. Additionally, - // when we're in homestead this also counts for code storage gas errors. + ret, err = evm.initNewContract(contract, address, value) if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) } } - return ret, address, contract.Gas, err } +// initNewContract runs a new contract's creation code, performs checks on the +// resulting code that is to be deployed, and consumes necessary gas. +func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) { + // Charge the contract creation init gas in verkle mode + if evm.chainRules.IsEIP4762 { + if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) { + return nil, ErrOutOfGas + } + } + + ret, err := evm.interpreter.Run(contract, nil, false) + if err != nil { + return ret, err + } + + // Check whether the max code size has been exceeded, assign err if the case. + if evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { + return ret, ErrMaxCodeSizeExceeded + } + + // Reject code starting with 0xEF if EIP-3541 is enabled. + if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon { + return ret, ErrInvalidCode + } + + if !evm.chainRules.IsEIP4762 { + createDataGas := uint64(len(ret)) * params.CreateDataGas + if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + return ret, ErrCodeStoreOutOfGas + } + } else { + // Contract creation completed, touch the missing fields in the contract + if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) { + return ret, ErrCodeStoreOutOfGas + } + + if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) { + return ret, ErrCodeStoreOutOfGas + } + } + + evm.StateDB.SetCode(address, ret) + return ret, nil +} + // Create creates a new contract using code as deployment code. func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))