Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add --classic: ETC treads lightly (v. master, retesteth) #13

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d0dc349
graphql: return correct logs for tx (#25612)
s1na Aug 31, 2022
3b41be6
graphql: fixes missing tx logs (#25745)
s1na Sep 13, 2022
972007a
Release Geth v1.10.24
karalabe Sep 14, 2022
593b4e6
params: init basic ETC config vals
meowsbits Oct 27, 2022
697ee77
core/forkid,core,core/types,core/vm,miner,params: mystique/london, ei…
meowsbits Oct 27, 2022
93495c0
common,consensus/ethash,internal/ethapi: install etcash support at et…
meowsbits Oct 27, 2022
c9f8495
cmd/geth,cmd/utils,core,eth/catalyst,eth/ethconfig,params: install --…
meowsbits Oct 27, 2022
7416843
cmd/utils: [squashme] install --classic flag decl
meowsbits Oct 27, 2022
10a70c8
eth,les: skip checkpoint assignment in case of colliding ETC/ETH gene…
meowsbits Oct 27, 2022
f732600
.gitmodules,tests: add tests/testdata-etc submodule (from etclabscore…
meowsbits Oct 27, 2022
0e8201e
tests: init state tests, failing
meowsbits Oct 27, 2022
a3c71c5
params: move eip155,160 and mystique blocks to chainconfig struct
meowsbits Oct 27, 2022
fb16d9d
params,tests: [squashme] finish ETC_ fork fields impl in test configs
meowsbits Oct 27, 2022
7211c73
params,tests: fix fork/test configurations, fixes (most) tests
meowsbits Oct 27, 2022
5ffbebd
params: comments!
meowsbits Oct 27, 2022
dada559
tests: bump testdata-etc submodule to latest core-geth generated
meowsbits Oct 28, 2022
03fc698
tests: rename file for sensible alphabetic sorting
meowsbits Nov 1, 2022
09b3feb
tests: skip loading the config files, they are not tests
meowsbits Nov 1, 2022
d95b8af
go.mod,go.sum: bump github.com/VictoriaMetrics/fastcache to latest (v…
meowsbits Nov 1, 2022
100bf8e
core: panic: panic at sender_cacher.go
meowsbits Nov 1, 2022
898e7fd
Merge branch 'foundation-master' into etc-treads-lightly-retests
meowsbits Nov 1, 2022
6c9aea5
eth/ethconfig: whitespace
meowsbits Nov 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
[submodule "tests"]
[submodule "tests/testdata"]
path = tests/testdata
url = https://github.com/ethereum/tests
shallow = true
[submodule "evm-benchmarks"]
[submodule "tests/evm-benchmarks"]
path = tests/evm-benchmarks
url = https://github.com/ipsilon/evm-benchmarks
shallow = true
[submodule "tests/testdata-etc"]
path = tests/testdata-etc
url = https://github.com/etclabscore/tests-etc.git
3 changes: 3 additions & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ func main() {
func prepare(ctx *cli.Context) {
// If we're running a known preset, log it for convenience.
switch {
case ctx.IsSet(utils.ClassicFlag.Name):
log.Info("Starting Geth on Ethereum Classic (ETC) mainnet...")

case ctx.IsSet(utils.RopstenFlag.Name):
log.Info("Starting Geth on Ropsten testnet...")

Expand Down
32 changes: 30 additions & 2 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ var (
KilnFlag,
}
// NetworkFlags is the flag group of all built-in supported networks.
NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...)
NetworkFlags = append([]cli.Flag{MainnetFlag, ClassicFlag}, TestnetFlags...)

// DatabasePathFlags is the flag group of all database path flags.
DatabasePathFlags = []cli.Flag{
Expand All @@ -1031,6 +1031,9 @@ var (
// then a subdirectory of the specified datadir will be used.
func MakeDataDir(ctx *cli.Context) string {
if path := ctx.String(DataDirFlag.Name); path != "" {
if ctx.Bool(ClassicFlag.Name) {
return filepath.Join(path, "classic")
}
if ctx.Bool(RopstenFlag.Name) {
// Maintain compatibility with older Geth configurations storing the
// Ropsten database in `testnet` instead of `ropsten`.
Expand Down Expand Up @@ -1094,6 +1097,8 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
switch {
case ctx.IsSet(BootnodesFlag.Name):
urls = SplitAndTrim(ctx.String(BootnodesFlag.Name))
case ctx.Bool(ClassicFlag.Name):
urls = params.ClassicBootnodes
case ctx.Bool(RopstenFlag.Name):
urls = params.RopstenBootnodes
case ctx.Bool(SepoliaFlag.Name):
Expand Down Expand Up @@ -1554,6 +1559,8 @@ func SetDataDir(ctx *cli.Context, cfg *node.Config) {
}

cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten")
case ctx.Bool(ClassicFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "classic")
case ctx.Bool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
case ctx.Bool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
Expand Down Expand Up @@ -1752,7 +1759,7 @@ func CheckExclusive(ctx *cli.Context, args ...interface{}) {
// SetEthConfig applies eth-related command line flags to the config.
func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// Avoid conflicting network flags
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag, KilnFlag)
CheckExclusive(ctx, MainnetFlag, ClassicFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag, SepoliaFlag, KilnFlag)
CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
if ctx.String(GCModeFlag.Name) == "archive" && ctx.Uint64(TxLookupLimitFlag.Name) != 0 {
Expand Down Expand Up @@ -1912,6 +1919,25 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
}
cfg.Genesis = core.DefaultGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash)
case ctx.Bool(ClassicFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 1
}
cfg.Genesis = core.DefaultClassicGenesisBlock()

// Only configure if not already established through flags/config
if cfg.EthDiscoveryURLs == nil {
url := params.ClassicDNS
if cfg.SyncMode == downloader.LightSync {
url = strings.ReplaceAll(url, "all", "les")
}
cfg.EthDiscoveryURLs = []string{url}
cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs
}

// Set ECIP-1099 block number for Ethash config.
u := params.ECIP1099Block_Classic.Uint64()
cfg.Ethash.ECIP1099Block = &u
case ctx.Bool(RopstenFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 3
Expand Down Expand Up @@ -2238,6 +2264,8 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis {
switch {
case ctx.Bool(MainnetFlag.Name):
genesis = core.DefaultGenesisBlock()
case ctx.Bool(ClassicFlag.Name):
genesis = core.DefaultClassicGenesisBlock()
case ctx.Bool(RopstenFlag.Name):
genesis = core.DefaultRopstenGenesisBlock()
case ctx.Bool(SepoliaFlag.Name):
Expand Down
14 changes: 14 additions & 0 deletions cmd/utils/flags_classic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package utils

import (
"github.com/ethereum/go-ethereum/internal/flags"
"github.com/urfave/cli/v2"
)

var (
ClassicFlag = &cli.BoolFlag{
Name: "classic",
Usage: "Ethereum Classic (ETC) mainnet",
Category: flags.EthCategory,
}
)
58 changes: 58 additions & 0 deletions common/hasher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package common

import (
"fmt"
"hash"

"golang.org/x/crypto/sha3"
)

// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
type keccakState interface {
hash.Hash
Read([]byte) (int, error)
}

type Hasher struct {
Sha keccakState
}

var hasherPool = make(chan *Hasher, 128)

func NewHasher() *Hasher {
var h *Hasher
select {
case h = <-hasherPool:
default:
h = &Hasher{Sha: sha3.NewLegacyKeccak256().(keccakState)}
}
return h
}

func ReturnHasherToPool(h *Hasher) {
select {
case hasherPool <- h:
default:
fmt.Printf("Allowing Hasher to be garbage collected, pool is full\n")
}
}

func HashData(data []byte) (Hash, error) {
h := NewHasher()
defer ReturnHasherToPool(h)
h.Sha.Reset()

_, err := h.Sha.Write(data)
if err != nil {
return Hash{}, err
}

var buf Hash
_, err = h.Sha.Read(buf[:])
if err != nil {
return Hash{}, err
}
return buf, nil
}
64 changes: 45 additions & 19 deletions consensus/ethash/algorithm.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,18 @@ const (

// cacheSize returns the size of the ethash verification cache that belongs to a certain
// block number.
func cacheSize(block uint64) uint64 {
epoch := int(block / epochLength)
func cacheSize(epoch uint64) uint64 {
if epoch < maxEpoch {
return cacheSizes[epoch]
return cacheSizes[int(epoch)]
}
return calcCacheSize(epoch)
}

// calcCacheSize calculates the cache size for epoch. The cache size grows linearly,
// however, we always take the highest prime below the linearly growing threshold in order
// to reduce the risk of accidental regularities leading to cyclic behavior.
func calcCacheSize(epoch int) uint64 {
size := cacheInitBytes + cacheGrowthBytes*uint64(epoch) - hashBytes
func calcCacheSize(epoch uint64) uint64 {
size := cacheInitBytes + cacheGrowthBytes*epoch - hashBytes
for !new(big.Int).SetUint64(size / hashBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
size -= 2 * hashBytes
}
Expand All @@ -71,19 +70,18 @@ func calcCacheSize(epoch int) uint64 {

// datasetSize returns the size of the ethash mining dataset that belongs to a certain
// block number.
func datasetSize(block uint64) uint64 {
epoch := int(block / epochLength)
func datasetSize(epoch uint64) uint64 {
if epoch < maxEpoch {
return datasetSizes[epoch]
return datasetSizes[int(epoch)]
}
return calcDatasetSize(epoch)
}

// calcDatasetSize calculates the dataset size for epoch. The dataset size grows linearly,
// however, we always take the highest prime below the linearly growing threshold in order
// to reduce the risk of accidental regularities leading to cyclic behavior.
func calcDatasetSize(epoch int) uint64 {
size := datasetInitBytes + datasetGrowthBytes*uint64(epoch) - mixBytes
func calcDatasetSize(epoch uint64) uint64 {
size := datasetInitBytes + datasetGrowthBytes*epoch - mixBytes
for !new(big.Int).SetUint64(size / mixBytes).ProbablyPrime(1) { // Always accurate for n < 2^64
size -= 2 * mixBytes
}
Expand Down Expand Up @@ -118,13 +116,41 @@ func makeHasher(h hash.Hash) hasher {

// seedHash is the seed to use for generating a verification cache and the mining
// dataset.
func seedHash(block uint64) []byte {
func seedHash(epoch uint64, epochLength uint64) []byte {
block := calcEpochBlock(epoch, epochLength)
seed := make([]byte, 32)
if block < epochLength {
if block < epochLengthDefault {
return seed
}

h := common.NewHasher()

for i := 0; i < int(block/epochLengthDefault); i++ {
h.Sha.Reset()
//nolint:errcheck
_, writeErr := h.Sha.Write(seed)
if writeErr != nil {
log.Warn("Failed to write data", "err", writeErr)
}
//nolint:errcheck
_, readErr := h.Sha.Read(seed)
if readErr != nil {
log.Warn("Failed to read data", "err", readErr)
}
}

common.ReturnHasherToPool(h)

return seed
}

func seedHashOld(block uint64) []byte {
seed := make([]byte, 32)
if block < epochLengthDefault {
return seed
}
keccak256 := makeHasher(sha3.NewLegacyKeccak256())
for i := 0; i < int(block/epochLength); i++ {
for i := 0; i < int(block/epochLengthDefault); i++ {
keccak256(seed, seed)
}
return seed
Expand All @@ -136,7 +162,7 @@ func seedHash(block uint64) []byte {
// algorithm from Strict Memory Hard Hashing Functions (2014). The output is a
// set of 524288 64-byte values.
// This method places the result into dest in machine byte order.
func generateCache(dest []uint32, epoch uint64, seed []byte) {
func generateCache(dest []uint32, epoch uint64, epochLength uint64, seed []byte) {
// Print some debug logs to allow analysis on low end devices
logger := log.New("epoch", epoch)

Expand All @@ -148,7 +174,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
if elapsed > 3*time.Second {
logFn = logger.Info
}
logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed))
logFn("Generated ethash verification cache", "epochLength", epochLength, "elapsed", common.PrettyDuration(elapsed))
}()
// Convert our destination slice to a byte buffer
var cache []byte
Expand All @@ -174,7 +200,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) {
case <-done:
return
case <-time.After(3 * time.Second):
logger.Info("Generating ethash verification cache", "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start)))
logger.Info("Generating ethash verification cache", "epochLength", epochLength, "percentage", atomic.LoadUint32(&progress)*100/uint32(rows)/(cacheRounds+1), "elapsed", common.PrettyDuration(time.Since(start)))
}
}
}()
Expand Down Expand Up @@ -266,7 +292,7 @@ func generateDatasetItem(cache []uint32, index uint32, keccak512 hasher) []byte

// generateDataset generates the entire ethash dataset for mining.
// This method places the result into dest in machine byte order.
func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
func generateDataset(dest []uint32, epoch uint64, epochLength uint64, cache []uint32) {
// Print some debug logs to allow analysis on low end devices
logger := log.New("epoch", epoch)

Expand All @@ -278,7 +304,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
if elapsed > 3*time.Second {
logFn = logger.Info
}
logFn("Generated ethash verification cache", "elapsed", common.PrettyDuration(elapsed))
logFn("Generated ethash verification dataset", "epochLength", epochLength, "elapsed", common.PrettyDuration(elapsed))
}()

// Figure out whether the bytes need to be swapped for the machine
Expand Down Expand Up @@ -324,7 +350,7 @@ func generateDataset(dest []uint32, epoch uint64, cache []uint32) {
copy(dataset[index*hashBytes:], item)

if status := atomic.AddUint64(&progress, 1); status%percent == 0 {
logger.Info("Generating DAG in progress", "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start)))
logger.Info("Generating DAG in progress", "epochLength", epochLength, "percentage", (status*100)/(size/hashBytes), "elapsed", common.PrettyDuration(time.Since(start)))
}
}
}(i)
Expand Down
Loading