Skip to content

Commit

Permalink
cmd/geth: drop support for goerli network (#653)
Browse files Browse the repository at this point in the history
  • Loading branch information
ziogaschr authored Jan 20, 2025
1 parent 91708c9 commit 912b6dd
Show file tree
Hide file tree
Showing 27 changed files with 20 additions and 179 deletions.
20 changes: 0 additions & 20 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,6 @@ pipeline {
unsuccessful { githubNotify context: 'Mordor Regression', description: "${GITHUB_NOTIFY_DESCRIPTION}", status: 'FAILURE', account: "${GITHUB_OWNER_NAME}", repo: "${GITHUB_REPO_NAME}", credentialsId: 'meowsbits-github-jenkins', sha: "${GIT_COMMIT}" }
}
}
stage('Goerli') {
agent { label "aws-slave-m5-xlarge" }
steps {
sh "curl -L -O https://go.dev/dl/go1.22.4.linux-amd64.tar.gz"
sh "sudo rm -rf /usr/bin/go && sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz"
sh "export GOROOT=/usr/local/go"
sh "/usr/local/go/bin/go version"
sh "mkdir -p ./build/bin && /usr/local/go/bin/go build -o ./build/bin/geth ./cmd/geth && sudo chmod +x ./build/bin/geth"
sh "sudo cp ./build/bin/geth /usr/bin/ && which geth"
sh "geth version"
sh "rm -rf ${GETH_DATADIR}-goerli"
sh "shasum -a 256 -c ./tests/regression/shasums/goerli.0-2000000.rlp.gz.sha256"
sh "geth --goerli --cache=2048 --nocompaction --nousb --txlookuplimit=1 --datadir=${GETH_DATADIR}-goerli import ${GETH_EXPORTS}/goerli.0-2000000.rlp.gz"
}
post {
always { sh "rm -rf ${GETH_DATADIR}-goerli" }
success { githubNotify context: 'Goerli Regression', description: "${GITHUB_NOTIFY_DESCRIPTION}", status: 'SUCCESS', account: "${GITHUB_OWNER_NAME}", repo: "${GITHUB_REPO_NAME}", credentialsId: 'meowsbits-github-jenkins', sha: "${GIT_COMMIT}" }
unsuccessful { githubNotify context: 'Goerli Regression', description: "${GITHUB_NOTIFY_DESCRIPTION}", status: 'FAILURE', account: "${GITHUB_OWNER_NAME}", repo: "${GITHUB_REPO_NAME}", credentialsId: 'meowsbits-github-jenkins', sha: "${GIT_COMMIT}" }
}
}
// Commented now because these take a looong time.
// One way of approaching a solution is to break each chain into a "stepladder" of imports, eg. 0-1150000, 1150000-1920000, 1920000-2500000, etc...
// This would allow further parallelization at the cost of duplicated base chaindata stores.
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ Networks supported by the respective go-ethereum packaged `geth` program.
| | :zap: | Morden (Geth+Parity ETH PoW Testnet) | | |
| | :zap: | Ropsten (Geth+Parity ETH PoW Testnet) | :heavy_check_mark: | :heavy_check_mark: |
| | :handshake: | Rinkeby (Geth-only ETH PoA Testnet) | :heavy_check_mark: | :heavy_check_mark: |
| | :handshake: | Goerli (Geth+Parity ETH PoA Testnet) | :heavy_check_mark: | :heavy_check_mark: |
| | :handshake: | Kovan (Parity-only ETH PoA Testnet) | | |
| | | Tobalaba (EWF Testnet) | | |
| | | Ephemeral development PoA network | :heavy_check_mark: | :heavy_check_mark: |
Expand Down
2 changes: 1 addition & 1 deletion cmd/clef/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ GLOBAL OPTIONS:
--loglevel value log level to emit to the screen (default: 4)
--keystore value Directory for the keystore (default: "$HOME/.ethereum/keystore")
--configdir value Directory for Clef configuration (default: "$HOME/.clef")
--chainid value Chain id to use for signing (1=foundation, 5=Goerli, 61=classic, 63=Mordor) (default: 1)
--chainid value Chain id to use for signing (1=foundation, 61=classic, 63=Mordor) (default: 1)
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
--nousb Disables monitoring for and managing USB hardware wallets
--pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm")
Expand Down
2 changes: 1 addition & 1 deletion cmd/clef/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ var (
chainIdFlag = &cli.Int64Flag{
Name: "chainid",
Value: params.MainnetChainConfig.ChainID.Int64(),
Usage: "Chain id to use for signing (1=foundation, 61=classic, 5=Goerli, 63=Mordor, 133519467574834=Yolo)",
Usage: "Chain id to use for signing (1=foundation, 61=classic, 63=Mordor, 133519467574834=Yolo)",
}
rpcPortFlag = &cli.IntFlag{
Name: "http.port",
Expand Down
2 changes: 1 addition & 1 deletion cmd/devp2p/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ set to standard output. The following filters are supported:
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score
- `-ip <CIDR>` filters nodes by IP subnet
- `-min-age <duration>` filters nodes by 'first seen' time
- `-eth-network <classic/mordor/mainnet/goerli/sepolia/holesky>` filters nodes by "eth" ENR entry
- `-eth-network <classic/mordor/mainnet/sepolia/holesky>` filters nodes by "eth" ENR entry
- `-les-server` filters nodes by LES server support
- `-snap` filters nodes by snap protocol support

Expand Down
3 changes: 0 additions & 3 deletions cmd/devp2p/nodesetcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@ func ethFilter(args []string) (nodeFilter, error) {
case "mainnet":
gb := core.GenesisToBlock(params.DefaultGenesisBlock(), nil)
filter = forkid.NewStaticFilter(params.MainnetChainConfig, gb)
case "goerli":
gb := core.GenesisToBlock(params.DefaultGoerliGenesisBlock(), nil)
filter = forkid.NewStaticFilter(params.GoerliChainConfig, gb)
case "sepolia":
gb := core.GenesisToBlock(params.DefaultSepoliaGenesisBlock(), nil)
filter = forkid.NewStaticFilter(params.SepoliaChainConfig, gb)
Expand Down
1 change: 0 additions & 1 deletion cmd/echainspec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ var defaultChainspecValues = map[string]ctypes.Configurator{
"mordor": params.DefaultMordorGenesisBlock(),

"foundation": params.DefaultGenesisBlock(),
"goerli": params.DefaultGoerliGenesisBlock(),
"sepolia": params.DefaultSepoliaGenesisBlock(),

"mintme": params.DefaultMintMeGenesisBlock(),
Expand Down
2 changes: 0 additions & 2 deletions cmd/geth/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,6 @@ func importHistory(ctx *cli.Context) error {
network = "mainnet"
case ctx.Bool(utils.SepoliaFlag.Name):
network = "sepolia"
case ctx.Bool(utils.GoerliFlag.Name):
network = "goerli"
}
} else {
// No network flag set, try to determine network based on files
Expand Down
1 change: 0 additions & 1 deletion cmd/geth/consolecmd_cg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ func TestConsoleCmdNetworkIdentities(t *testing.T) {
// All other possible --<chain> values.
{[]string{"--mainnet"}, 1, 1, params.MainnetGenesisHash.Hex()},
{[]string{"--sepolia"}, 11155111, 11155111, params.SepoliaGenesisHash.Hex()},
{[]string{"--goerli"}, 5, 5, params.GoerliGenesisHash.Hex()},
{[]string{"--mordor"}, 7, 63, params.MordorGenesisHash.Hex()},
{[]string{"--mintme"}, 37480, 24734, params.MintMeGenesisHash.Hex()},
{[]string{"--dev"}, 1337, 1337, "0x0"},
Expand Down
9 changes: 4 additions & 5 deletions cmd/geth/consolecmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,17 @@ import (
)

const (
ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 trace:1.0 txpool:1.0 web3:1.0"
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 rpc:1.0 trace:1.0 txpool:1.0 web3:1.0"
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
)

// spawns geth with the given command line args, using a set of flags to minimise
// memory and disk IO. If the args don't set --datadir, the
// child g gets a temporary data directory.
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
// --goerli to make the 'writing genesis to disk' faster (no accounts)
// --networkid=1337 to avoid cache bump
// --syncmode=full to avoid allocating fast sync bloom
allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
allArgs := []string{"--mordor", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
"--datadir.minfreedisk", "0"}
return runGeth(t, append(allArgs, args...)...)
Expand Down Expand Up @@ -71,7 +70,7 @@ func TestConsoleWelcome(t *testing.T) {
geth.SetTemplateFunc("gover", runtime.Version)
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
geth.SetTemplateFunc("niltime", func() string {
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
return time.Unix(1570141915, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
})
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })

Expand Down Expand Up @@ -151,7 +150,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
attach.SetTemplateFunc("niltime", func() string {
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
return time.Unix(1570141915, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
})
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
Expand Down
3 changes: 0 additions & 3 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,6 @@ func checkMainnet(ctx *cli.Context) bool {
isMainnet := false

switch {
case ctx.IsSet(utils.GoerliFlag.Name):
log.Info("Starting Geth on Görli testnet...")

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

Expand Down
22 changes: 3 additions & 19 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ var (
}
NetworkIdFlag = &cli.Uint64Flag{
Name: "networkid",
Usage: "Explicitly set network id (integer)(For testnets: use --goerli, --sepolia, --holesky instead)",
Usage: "Explicitly set network id (integer)(For testnets: use --sepolia, --holesky instead)",
Value: ethconfig.Defaults.NetworkId,
Category: flags.EthCategory,
}
Expand Down Expand Up @@ -182,11 +182,6 @@ var (
Usage: "Mordor network: Ethereum Classic's cross-client proof-of-work test network",
Category: flags.EthCategory,
}
GoerliFlag = &cli.BoolFlag{
Name: "goerli",
Usage: "Görli network: pre-configured proof-of-authority test network",
Category: flags.EthCategory,
}
SepoliaFlag = &cli.BoolFlag{
Name: "sepolia",
Usage: "Sepolia network: pre-configured proof-of-work test network",
Expand Down Expand Up @@ -1127,7 +1122,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
var (
// TestnetFlags is the flag group of all built-in supported testnets.
TestnetFlags = []cli.Flag{
GoerliFlag,
SepoliaFlag,
MordorFlag,
HoleskyFlag,
Expand Down Expand Up @@ -1200,7 +1194,7 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
//
// 1. --bootnodes flag
// 2. Config file
// 3. Network preset flags (e.g. --goerli)
// 3. Network preset flags (e.g. --classic)
// 4. default to mainnet nodes
func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls := params.MainnetBootnodes
Expand All @@ -1219,8 +1213,6 @@ func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
urls = params.MordorBootnodes
case ctx.Bool(SepoliaFlag.Name):
urls = params.SepoliaBootnodes
case ctx.Bool(GoerliFlag.Name):
urls = params.GoerliBootnodes
case ctx.Bool(HoleskyFlag.Name):
urls = params.HoleskyBootnodes
}
Expand Down Expand Up @@ -1254,8 +1246,6 @@ func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
urls = params.ClassicBootnodes
case ctx.IsSet(MordorFlag.Name):
urls = params.MordorBootnodes
case ctx.Bool(GoerliFlag.Name):
urls = params.GoerliBootnodes
case ctx.Bool(MintMeFlag.Name):
urls = params.MintMeBootnodes
case cfg.BootstrapNodesV5 != nil:
Expand Down Expand Up @@ -1699,8 +1689,6 @@ func dataDirPathForCtxChainConfig(ctx *cli.Context, baseDataDirPath string) stri
return filepath.Join(baseDataDirPath, "classic")
case ctx.Bool(MordorFlag.Name):
return filepath.Join(baseDataDirPath, "mordor")
case ctx.Bool(GoerliFlag.Name):
return filepath.Join(baseDataDirPath, "goerli")
case ctx.Bool(SepoliaFlag.Name):
return filepath.Join(baseDataDirPath, "sepolia")
case ctx.Bool(MintMeFlag.Name):
Expand Down Expand Up @@ -1957,7 +1945,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, DeveloperPoWFlag, GoerliFlag, SepoliaFlag, ClassicFlag, MordorFlag, MintMeFlag, HoleskyFlag)
CheckExclusive(ctx, MainnetFlag, DeveloperFlag, DeveloperPoWFlag, SepoliaFlag, ClassicFlag, MordorFlag, MintMeFlag, HoleskyFlag)
CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light")
CheckExclusive(ctx, DeveloperFlag, DeveloperPoWFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer

Expand Down Expand Up @@ -2191,8 +2179,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
case ctx.Bool(SepoliaFlag.Name):
cfg.Genesis = params.DefaultSepoliaGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.SepoliaGenesisHash)
case ctx.Bool(GoerliFlag.Name):
SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash)
case ctx.Bool(ClassicFlag.Name):
SetDNSDiscoveryDefaults2(cfg, params.ClassicDNSNetwork1)
case ctx.Bool(MordorFlag.Name):
Expand Down Expand Up @@ -2522,8 +2508,6 @@ func genesisForCtxChainConfig(ctx *cli.Context) *genesisT.Genesis {
genesis = params.DefaultMordorGenesisBlock()
case ctx.Bool(SepoliaFlag.Name):
genesis = params.DefaultSepoliaGenesisBlock()
case ctx.Bool(GoerliFlag.Name):
genesis = params.DefaultGoerliGenesisBlock()
case ctx.Bool(MintMeFlag.Name):
genesis = params.DefaultMintMeGenesisBlock()
case ctx.Bool(HoleskyFlag.Name):
Expand Down
26 changes: 0 additions & 26 deletions core/forkid/forkid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,26 +90,6 @@ func TestCreation(t *testing.T) {
{50000000, 2000000000, ID{Hash: checksumToBytes(0x9f3d2254), Next: 0}}, // Future Cancun block
},
},
// Goerli test cases
{
"goerli",
params.GoerliChainConfig,
core.GenesisToBlock(params.DefaultGoerliGenesisBlock(), nil),
[]testcase{
{0, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Unsynced, last Frontier, Homestead, Tangerine, Spurious, Byzantium, Constantinople and first Petersburg block
{1561650, 0, ID{Hash: checksumToBytes(0xa3f5ab08), Next: 1561651}}, // Last Petersburg block
{1561651, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // First Istanbul block
{4460643, 0, ID{Hash: checksumToBytes(0xc25efa5c), Next: 4460644}}, // Last Istanbul block
{4460644, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // First Berlin block
{5000000, 0, ID{Hash: checksumToBytes(0x757a1c47), Next: 5062605}}, // Last Berlin block
{5062605, 0, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // First London block
{6000000, 1678832735, ID{Hash: checksumToBytes(0xB8C6299D), Next: 1678832736}}, // Last London block
{6000001, 1678832736, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // First Shanghai block
{6500002, 1705473119, ID{Hash: checksumToBytes(0xf9843abf), Next: 1705473120}}, // Last Shanghai block
{6500003, 1705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // First Cancun block
{6500003, 2705473120, ID{Hash: checksumToBytes(0x70cc14e2), Next: 0}}, // Future Cancun block
},
},
// Sepolia test cases
{
"sepolia",
Expand Down Expand Up @@ -509,12 +489,6 @@ func TestGatherForks(t *testing.T) {
[]uint64{1150000, 1920000, 2463000, 2675000, 4370000, 7280000, 9069000, 9200000, 12_244_000, 12_965_000, 13_773_000, 15050000},
[]uint64{1681338455 /* ShanghaiTime */, 1710338135 /* Cancun */},
},
{
"goerli",
params.GoerliChainConfig,
[]uint64{1_561_651, 4_460_644, 5_062_605},
[]uint64{1678832736 /* ShanghaiTime */, 1705473120 /* Cancun */},
},
{
"sepolia",
params.SepoliaChainConfig,
Expand Down
4 changes: 0 additions & 4 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,6 @@ func configOrDefault(g *genesisT.Genesis, ghash common.Hash) ctypes.ChainConfigu
return params.HoleskyChainConfig
case ghash == params.SepoliaGenesisHash:
return params.SepoliaChainConfig
case ghash == params.GoerliGenesisHash:
return params.GoerliChainConfig
case ghash == params.MordorGenesisHash:
return params.MordorChainConfig
case ghash == params.SepoliaGenesisHash:
Expand Down Expand Up @@ -427,8 +425,6 @@ func CommitGenesisState(db ethdb.Database, triedb *triedb.Database, blockhash co
switch blockhash {
case params.MainnetGenesisHash:
genesis = params.DefaultGenesisBlock()
case params.GoerliGenesisHash:
genesis = params.DefaultGoerliGenesisBlock()
case params.SepoliaGenesisHash:
genesis = params.DefaultSepoliaGenesisBlock()
case params.MordorGenesisHash:
Expand Down
22 changes: 6 additions & 16 deletions core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,6 @@ func TestSetupGenesisBlock(t *testing.T) {
}
}

func TestInvalidCliqueConfig(t *testing.T) {
db := rawdb.NewMemoryDatabase()
gspec := params.DefaultGoerliGenesisBlock()
gspec.ExtraData = []byte{}

if _, err := CommitGenesis(gspec, db, triedb.NewDatabase(db, nil)); err == nil {
t.Fatal("Expected error on invalid clique config")
}
}

func TestSetupGenesis(t *testing.T) {
testSetupGenesis(t, rawdb.HashScheme)
testSetupGenesis(t, rawdb.PathScheme)
Expand Down Expand Up @@ -143,15 +133,15 @@ func testSetupGenesis(t *testing.T, scheme string) {
wantConfig: customg.Config,
},
{
name: "custom block in DB, genesis == goerli",
name: "custom block in DB, genesis == mordor",
fn: func(db ethdb.Database) (ctypes.ChainConfigurator, common.Hash, error) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
MustCommitGenesis(db, tdb, &customg)
return SetupGenesisBlock(db, tdb, params.DefaultGoerliGenesisBlock())
return SetupGenesisBlock(db, tdb, params.DefaultMordorGenesisBlock())
},
wantErr: &genesisT.GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
wantHash: params.GoerliGenesisHash,
wantConfig: params.GoerliChainConfig,
wantErr: &genesisT.GenesisMismatchError{Stored: customghash, New: params.MordorGenesisHash},
wantHash: params.MordorGenesisHash,
wantConfig: params.MordorChainConfig,
},
{
name: "compatible config in DB",
Expand Down Expand Up @@ -222,7 +212,7 @@ func TestGenesisHashes(t *testing.T) {
want common.Hash
}{
{params.DefaultGenesisBlock(), params.MainnetGenesisHash},
{params.DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
{params.DefaultMordorGenesisBlock(), params.MordorGenesisHash},
{params.DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
} {
// Test via MustCommit
Expand Down
3 changes: 1 addition & 2 deletions core/state/pruner/pruner.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,7 @@ func (p *Pruner) Prune(root common.Hash) error {
// is the presence of root can indicate the presence of the
// entire trie.
if !rawdb.HasLegacyTrieNode(p.db, root) {
// The special case is for clique based networks(goerli
// and some other private networks), it's possible that two
// The special case is for clique based networks (private networks), it's possible that two
// consecutive blocks will have same root. In this case snapshot
// difflayer won't be created. So HEAD-127 may not paired with
// head-127 layer. Instead the paired layer is higher than the
Expand Down
Loading

0 comments on commit 912b6dd

Please sign in to comment.