diff --git a/accounts/usbwallet/hub.go b/accounts/usbwallet/hub.go index 2a01e0a91f..81457b7da2 100644 --- a/accounts/usbwallet/hub.go +++ b/accounts/usbwallet/hub.go @@ -19,7 +19,6 @@ package usbwallet import ( "errors" "runtime" - "slices" "sync" "sync/atomic" "time" @@ -49,7 +48,7 @@ type Hub struct { scheme string // Protocol scheme prefixing account and wallet URLs. vendorID uint16 // USB vendor identifier used for device discovery productIDs []uint16 // USB product identifiers used for device discovery - usageIDs []uint16 // USB usage page identifier used for macOS device discovery + usageID uint16 // USB usage page identifier used for macOS device discovery endpointID int // USB endpoint identifier used for non-macOS device discovery makeDriver func(log.Logger) driver // Factory method to construct a vendor specific driver @@ -90,22 +89,22 @@ func NewLedgerHub() (*Hub, error) { 0x5000, /* WebUSB Ledger Nano S Plus */ 0x6000, /* WebUSB Ledger Nano FTS */ 0x7000, /* WebUSB Ledger Flex */ - }, []uint16{0xffa0, 0}, 2, newLedgerDriver) + }, 0xffa0, 0, newLedgerDriver) } // NewTrezorHubWithHID creates a new hardware wallet manager for Trezor devices. func NewTrezorHubWithHID() (*Hub, error) { - return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor HID */}, []uint16{0xff00}, 0, newTrezorDriver) + return newHub(TrezorScheme, 0x534c, []uint16{0x0001 /* Trezor HID */}, 0xff00, 0, newTrezorDriver) } // NewTrezorHubWithWebUSB creates a new hardware wallet manager for Trezor devices with // firmware version > 1.8.0 func NewTrezorHubWithWebUSB() (*Hub, error) { - return newHub(TrezorScheme, 0x1209, []uint16{0x53c1 /* Trezor WebUSB */}, []uint16{0xffff} /* No usage id on webusb, don't match unset (0) */, 0, newTrezorDriver) + return newHub(TrezorScheme, 0x1209, []uint16{0x53c1 /* Trezor WebUSB */}, 0xffff /* No usage id on webusb, don't match unset (0) */, 0, newTrezorDriver) } // newHub creates a new hardware wallet manager for generic USB devices. -func newHub(scheme string, vendorID uint16, productIDs []uint16, usageIDs []uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) { +func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) { if !hid.Supported() { return nil, errors.New("unsupported platform") } @@ -113,7 +112,7 @@ func newHub(scheme string, vendorID uint16, productIDs []uint16, usageIDs []uint scheme: scheme, vendorID: vendorID, productIDs: productIDs, - usageIDs: usageIDs, + usageID: usageID, endpointID: endpointID, makeDriver: makeDriver, quit: make(chan chan error), @@ -186,10 +185,7 @@ func (hub *Hub) refreshWallets() { // uses `MMII`, encoding a model (MM) and an interface bitfield (II) mmOnly := info.ProductID & 0xff00 // Windows and Macos use UsageID matching, Linux uses Interface matching - if (info.ProductID == id || mmOnly == id) && - // TODO: we had the following check in op-geth only, ok to remove? - // info.Path != "" && - (slices.Contains(hub.usageIDs, info.UsagePage) || info.Interface == hub.endpointID) { + if (info.ProductID == id || mmOnly == id) && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) { devices = append(devices, info) break } diff --git a/core/blockchain.go b/core/blockchain.go index f57b6f2e6f..61d41ce7ac 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -467,6 +467,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis rawdb.WriteChainConfig(db, genesisHash, chainConfig) } + // OP-Stack diff: deliberately only check header after reorg handling, to get un-stuck of degenerate reorg cases. // The first thing the node will do is reconstruct the verification data for // the head block (ethash cache or clique voting snapshot). Might as well do // it in advance. diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index cf72e98cb2..65b85417c1 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -350,6 +350,16 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte { return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash) } +// ContractCode retrieves a blob of data associated with a contract hash +// either from ephemeral in-memory cache, or from persistent storage. +// OP-Stack diff: this is a legacy-method, replaced by ContractCodeWithPrefix in upstream, +// but required for old databases to serve snap-sync. +// It tries prefix-style contract-code retrieval first, then falls back to legacy code storage. +// Returns nil if not found. +func (bc *BlockChain) ContractCode(hash common.Hash) []byte { + return bc.statedb.ContractCode(common.Address{}, hash) +} + // State returns a new mutable state based on the current HEAD block. func (bc *BlockChain) State() (*state.StateDB, error) { return bc.StateAt(bc.CurrentBlock().Root) diff --git a/core/genesis.go b/core/genesis.go index e23f6440b6..c0c86ad392 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -403,19 +403,18 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g return chainCfg, block.Hash(), nil, nil } - // TODO: Reinstate transitioned network check. Not sure where exactly to put it after this refactor. - // If the bedrock block is not 0, that implies that the network was migrated at the bedrock block. - // In this case the genesis state may not be in the state database (e.g. op-geth is performing a snap - // sync without an existing datadir) & even if it were, would not be useful as op-geth is not able to - // execute the pre-bedrock STF. - // transitionedNetwork := genesis != nil && genesis.Config != nil && genesis.Config.BedrockBlock != nil && genesis.Config.BedrockBlock.Uint64() != 0 + // OP-Stack note: if it's a bedrock-transition genesis, + // then only commit to DB if it has a StateHash to work with, + // as the genesis config accounts map will not be usable. + transitionedNetwork := genesis != nil && genesis.Config != nil && genesis.Config.BedrockBlock != nil && genesis.Config.BedrockBlock.Uint64() != 0 + canCommitGenesis := !transitionedNetwork || genesis.StateHash != nil // Commit the genesis if the genesis block exists in the ancient database // but the key-value database is empty without initializing the genesis // fields. This scenario can occur when the node is created from scratch // with an existing ancient store. storedCfg := rawdb.ReadChainConfig(db, ghash) - if storedCfg == nil { + if storedCfg == nil && canCommitGenesis { // Ensure the stored genesis block matches with the given genesis. Private // networks must explicitly specify the genesis in the config file, mainnet // genesis will be used as default and the initialization will always fail. @@ -440,7 +439,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g } return chainCfg, block.Hash(), nil, nil } - log.Info("Stored config", "cfg", storedCfg, "genesis-nil", genesis == nil) // The genesis block has already been committed previously. Verify that the // provided genesis with chain overrides matches the existing one, and update // the stored chain config if necessary. @@ -455,20 +453,34 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash} } } + // Check config compatibility and write the config. Compatibility errors // are returned to the caller unless we're already at block zero. head := rawdb.ReadHeadHeader(db) if head == nil { return nil, common.Hash{}, nil, errors.New("missing head header") } + + // OP-Stack warning: tricky upstream code: method with nil-receiver case. + // Returns genesis.Config if genesis is not nil. Falls back to storedCfg otherwise. And some special L1 cases. newCfg := genesis.chainConfigOrDefault(ghash, storedCfg) + // OP-Stack note: geth used to have a "Special case" for private networks, + // where it would set newCfg to storedCfg if genesis was nil. That is implied now in chainConfigOrDefault. + // However, a possible upstream bug means that overrides are not always applied to this new config. + // Always apply overrides. + chainCfg, err := overrides.apply(newCfg) + if err != nil { + return nil, common.Hash{}, nil, err + } + newCfg = chainCfg + log.Info("New config", "cfg", newCfg, "genesis-nil", genesis == nil) var genesisTimestamp *uint64 if genesis != nil { genesisTimestamp = &genesis.Timestamp } - + // OP-Stack diff: provide genesis timestamp (may be nil), to check bedrock-migration compat with config. // TODO(rjl493456442) better to define the comparator of chain config // and short circuit if the chain config is not changed. compatErr := storedCfg.CheckCompatible(newCfg, head.Number.Uint64(), head.Time, genesisTimestamp) @@ -480,10 +492,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g // for the scenarios that database is opened in the read-only mode. storedData, _ := json.Marshal(storedCfg) if newData, _ := json.Marshal(newCfg); !bytes.Equal(storedData, newData) { - log.Info("Configs differ") + log.Info("Chain configs differ, overwriting stored config with new config.") + log.Info("Previously stored chain config", "json", string(storedData)) + log.Info("New chain config", "json", string(newData), "genesis-nil", genesis == nil) rawdb.WriteChainConfig(db, ghash, newCfg) } else { - log.Info("Configs equal") + log.Info("Configured chain config matches existing chain config in storage.") } return newCfg, ghash, nil, nil } diff --git a/core/state/database.go b/core/state/database.go index faf4954650..4ca475a189 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -235,6 +235,22 @@ func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre return tr, nil } +// ContractCode retrieves a particular contract's code. Returns nil if not found. +// OP-Stack diff: used to serve snap-sync from legacy DB code storage scheme. +func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) []byte { + code, _ := db.codeCache.Get(codeHash) + if len(code) > 0 { + return code + } + code = rawdb.ReadCode(db.disk, codeHash) // tries prefix first, then reads non-prefixed key if not found + if len(code) > 0 { + db.codeCache.Add(codeHash, code) + db.codeSizeCache.Add(codeHash, len(code)) + return code + } + return nil +} + // ContractCodeWithPrefix retrieves a particular contract's code. If the // code can't be found in the cache, then check the existence with **new** // db scheme. diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 4266426cc2..7d48bbcd5b 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -206,7 +206,6 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.Nonce = (*hexutil.Uint64)(&itx.EffectiveNonce) // other fields will show up as null. } - return json.Marshal(&enc) } @@ -591,7 +590,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { if dec.Nonce != nil { inner = &depositTxWithNonce{DepositTx: itx, EffectiveNonce: uint64(*dec.Nonce)} } - default: return ErrTxTypeNotSupported } diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index a4e206a969..bfbea8df14 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -40,7 +40,7 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer { var signer Signer switch { - case config.IsPrague(blockNumber, blockTime): + case config.IsPrague(blockNumber, blockTime) && !config.IsOptimism(): signer = NewPragueSigner(config.ChainID) case config.IsCancun(blockNumber, blockTime) && !config.IsOptimism(): signer = NewCancunSigner(config.ChainID) @@ -69,7 +69,7 @@ func LatestSigner(config *params.ChainConfig) Signer { var signer Signer if config.ChainID != nil { switch { - case config.PragueTime != nil: + case config.PragueTime != nil && !config.IsOptimism(): signer = NewPragueSigner(config.ChainID) case config.CancunTime != nil && !config.IsOptimism(): signer = NewCancunSigner(config.ChainID) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 924aff7ac9..ab469b4ce9 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -454,7 +454,8 @@ func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [ // Peers should not request the empty code, but if they do, at // least sent them back a correct response without db lookups codes = append(codes, []byte{}) - } else if blob := chain.ContractCodeWithPrefix(hash); len(blob) > 0 { + } else if blob := chain.ContractCode(hash); len(blob) > 0 { + // OP-Stack diff: above contract-code is fetched with support for legacy DB. codes = append(codes, blob) bytes += uint64(len(blob)) } diff --git a/fork.yaml b/fork.yaml index 07684614f1..3fae33f3f6 100644 --- a/fork.yaml +++ b/fork.yaml @@ -329,13 +329,6 @@ def: not updated to handle the newly added `withdrawalsRoot` field in the block header. globs: - "cmd/evm/internal/t8ntool/block.go" - - title: "Hardware wallet support" - description: Extend Ledger wallet support for newer devices on Macos - sub: - - title: Fix Ledger discoverability - # upstream PR: https://github.com/ethereum/go-ethereum/pull/28863/ - globs: - - "accounts/usbwallet/hub.go" - title: "Testing" description: Additional or modified tests, not already captured by the above diff ignore: diff --git a/miner/miner_test.go b/miner/miner_test.go index 10f6e4b123..7df5a642b6 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -152,7 +152,6 @@ func createMiner(t *testing.T) *Miner { if err != nil { t.Fatalf("can't create new chain config: %v", err) } - // Create consensus engine engine := clique.New(chainConfig.Clique, chainDB) // Create Ethereum backend