diff options
author | gary rong <garyrong0905@gmail.com> | 2019-06-28 15:34:02 +0800 |
---|---|---|
committer | Péter Szilágyi <peterke@gmail.com> | 2019-06-28 15:34:02 +0800 |
commit | f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9 (patch) | |
tree | b463c8dd42547edceb778d946927d2c363303324 /cmd | |
parent | 702f52fb99d60b4b6bab05799c14dafdd8648854 (diff) | |
download | go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.tar go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.tar.gz go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.tar.bz2 go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.tar.lz go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.tar.xz go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.tar.zst go-tangerine-f7cdea2bdcd7ff3cec99731cb912cde0b233d6c9.zip |
all: on-chain oracle checkpoint syncing (#19543)
* all: implement simple checkpoint syncing
cmd, les, node: remove callback mechanism
cmd, node: remove callback definition
les: simplify the registrar
les: expose checkpoint rpc services in the light client
les, light: don't store untrusted receipt
cmd, contracts, les: discard stale checkpoint
cmd, contracts/registrar: loose restriction of registeration
cmd, contracts: add replay-protection
all: off-chain multi-signature contract
params: deploy checkpoint contract for rinkeby
cmd/registrar: add raw signing mode for registrar
cmd/registrar, contracts/registrar, les: fixed messages
* cmd/registrar, contracts/registrar: fix lints
* accounts/abi/bind, les: address comments
* cmd, contracts, les, light, params: minor checkpoint sync cleanups
* cmd, eth, les, light: move checkpoint config to config file
* cmd, eth, les, params: address comments
* eth, les, params: address comments
* cmd: polish up the checkpoint admin CLI
* cmd, contracts, params: deploy new version contract
* cmd/checkpoint-admin: add another flag for clef mode signing
* cmd, contracts, les: rename and regen checkpoint oracle with abigen
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/checkpoint-admin/common.go | 166 | ||||
-rw-r--r-- | cmd/checkpoint-admin/exec.go | 335 | ||||
-rw-r--r-- | cmd/checkpoint-admin/main.go | 124 | ||||
-rw-r--r-- | cmd/checkpoint-admin/status.go | 61 | ||||
-rw-r--r-- | cmd/geth/main.go | 35 | ||||
-rw-r--r-- | cmd/puppeth/wizard_genesis.go | 17 |
6 files changed, 722 insertions, 16 deletions
diff --git a/cmd/checkpoint-admin/common.go b/cmd/checkpoint-admin/common.go new file mode 100644 index 000000000..1f4a34a41 --- /dev/null +++ b/cmd/checkpoint-admin/common.go @@ -0,0 +1,166 @@ +// Copyright 2018 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "io/ioutil" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/console" + "github.com/ethereum/go-ethereum/contracts/checkpointoracle" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + "gopkg.in/urfave/cli.v1" +) + +// newClient creates a client with specified remote URL. +func newClient(ctx *cli.Context) *ethclient.Client { + client, err := ethclient.Dial(ctx.GlobalString(nodeURLFlag.Name)) + if err != nil { + utils.Fatalf("Failed to connect to Ethereum node: %v", err) + } + return client +} + +// newRPCClient creates a rpc client with specified node URL. +func newRPCClient(url string) *rpc.Client { + client, err := rpc.Dial(url) + if err != nil { + utils.Fatalf("Failed to connect to Ethereum node: %v", err) + } + return client +} + +// getContractAddr retrieves the register contract address through +// rpc request. +func getContractAddr(client *rpc.Client) common.Address { + var addr string + if err := client.Call(&addr, "les_getCheckpointContractAddress"); err != nil { + utils.Fatalf("Failed to fetch checkpoint oracle address: %v", err) + } + return common.HexToAddress(addr) +} + +// getCheckpoint retrieves the specified checkpoint or the latest one +// through rpc request. +func getCheckpoint(ctx *cli.Context, client *rpc.Client) *params.TrustedCheckpoint { + var checkpoint *params.TrustedCheckpoint + + if ctx.GlobalIsSet(indexFlag.Name) { + var result [3]string + index := uint64(ctx.GlobalInt64(indexFlag.Name)) + if err := client.Call(&result, "les_getCheckpoint", index); err != nil { + utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err) + } + checkpoint = ¶ms.TrustedCheckpoint{ + SectionIndex: index, + SectionHead: common.HexToHash(result[0]), + CHTRoot: common.HexToHash(result[1]), + BloomRoot: common.HexToHash(result[2]), + } + } else { + var result [4]string + err := client.Call(&result, "les_latestCheckpoint") + if err != nil { + utils.Fatalf("Failed to get local checkpoint %v, please ensure the les API is exposed", err) + } + index, err := strconv.ParseUint(result[0], 0, 64) + if err != nil { + utils.Fatalf("Failed to parse checkpoint index %v", err) + } + checkpoint = ¶ms.TrustedCheckpoint{ + SectionIndex: index, + SectionHead: common.HexToHash(result[1]), + CHTRoot: common.HexToHash(result[2]), + BloomRoot: common.HexToHash(result[3]), + } + } + return checkpoint +} + +// newContract creates a registrar contract instance with specified +// contract address or the default contracts for mainnet or testnet. +func newContract(client *rpc.Client) (common.Address, *checkpointoracle.CheckpointOracle) { + addr := getContractAddr(client) + if addr == (common.Address{}) { + utils.Fatalf("No specified registrar contract address") + } + contract, err := checkpointoracle.NewCheckpointOracle(addr, ethclient.NewClient(client)) + if err != nil { + utils.Fatalf("Failed to setup registrar contract %s: %v", addr, err) + } + return addr, contract +} + +// promptPassphrase prompts the user for a passphrase. +// Set confirmation to true to require the user to confirm the passphrase. +func promptPassphrase(confirmation bool) string { + passphrase, err := console.Stdin.PromptPassword("Passphrase: ") + if err != nil { + utils.Fatalf("Failed to read passphrase: %v", err) + } + + if confirmation { + confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ") + if err != nil { + utils.Fatalf("Failed to read passphrase confirmation: %v", err) + } + if passphrase != confirm { + utils.Fatalf("Passphrases do not match") + } + } + return passphrase +} + +// getPassphrase obtains a passphrase given by the user. It first checks the +// --password command line flag and ultimately prompts the user for a +// passphrase. +func getPassphrase(ctx *cli.Context) string { + passphraseFile := ctx.String(utils.PasswordFileFlag.Name) + if passphraseFile != "" { + content, err := ioutil.ReadFile(passphraseFile) + if err != nil { + utils.Fatalf("Failed to read passphrase file '%s': %v", + passphraseFile, err) + } + return strings.TrimRight(string(content), "\r\n") + } + // Otherwise prompt the user for the passphrase. + return promptPassphrase(false) +} + +// getKey retrieves the user key through specified key file. +func getKey(ctx *cli.Context) *keystore.Key { + // Read key from file. + keyFile := ctx.GlobalString(keyFileFlag.Name) + keyJson, err := ioutil.ReadFile(keyFile) + if err != nil { + utils.Fatalf("Failed to read the keyfile at '%s': %v", keyFile, err) + } + // Decrypt key with passphrase. + passphrase := getPassphrase(ctx) + key, err := keystore.DecryptKey(keyJson, passphrase) + if err != nil { + utils.Fatalf("Failed to decrypt user key '%s': %v", keyFile, err) + } + return key +} diff --git a/cmd/checkpoint-admin/exec.go b/cmd/checkpoint-admin/exec.go new file mode 100644 index 000000000..02c4f35cc --- /dev/null +++ b/cmd/checkpoint-admin/exec.go @@ -0,0 +1,335 @@ +// Copyright 2018 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/contracts/checkpointoracle" + "github.com/ethereum/go-ethereum/contracts/checkpointoracle/contract" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + "gopkg.in/urfave/cli.v1" +) + +var commandDeploy = cli.Command{ + Name: "deploy", + Usage: "Deploy a new checkpoint oracle contract", + Flags: []cli.Flag{ + nodeURLFlag, + clefURLFlag, + signersFlag, + thresholdFlag, + keyFileFlag, + utils.PasswordFileFlag, + }, + Action: utils.MigrateFlags(deploy), +} + +var commandSign = cli.Command{ + Name: "sign", + Usage: "Sign the checkpoint with the specified key", + Flags: []cli.Flag{ + nodeURLFlag, + clefURLFlag, + indexFlag, + hashFlag, + oracleFlag, + keyFileFlag, + signerFlag, + utils.PasswordFileFlag, + }, + Action: utils.MigrateFlags(sign), +} + +var commandPublish = cli.Command{ + Name: "publish", + Usage: "Publish a checkpoint into the oracle", + Flags: []cli.Flag{ + nodeURLFlag, + indexFlag, + signaturesFlag, + keyFileFlag, + utils.PasswordFileFlag, + }, + Action: utils.MigrateFlags(publish), +} + +// deploy deploys the checkpoint registrar contract. +// +// Note the network where the contract is deployed depends on +// the network where the connected node is located. +func deploy(ctx *cli.Context) error { + // Gather all the addresses that should be permitted to sign + var addrs []common.Address + for _, account := range strings.Split(ctx.String(signersFlag.Name), ",") { + if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { + utils.Fatalf("Invalid account in --signers: '%s'", trimmed) + } + addrs = append(addrs, common.HexToAddress(account)) + } + // Retrieve and validate the signing threshold + needed := ctx.Int(thresholdFlag.Name) + if needed == 0 || needed > len(addrs) { + utils.Fatalf("Invalid signature threshold %d", needed) + } + // Print a summary to ensure the user understands what they're signing + fmt.Printf("Deploying new checkpoint oracle:\n\n") + for i, addr := range addrs { + fmt.Printf("Admin %d => %s\n", i+1, addr.Hex()) + } + fmt.Printf("\nSignatures needed to publish: %d\n", needed) + + // Retrieve the private key, create an abigen transactor and an RPC client + transactor := bind.NewKeyedTransactor(getKey(ctx).PrivateKey) + client := newClient(ctx) + + // Deploy the checkpoint oracle + oracle, tx, _, err := contract.DeployCheckpointOracle(transactor, client, addrs, big.NewInt(int64(params.CheckpointFrequency)), + big.NewInt(int64(params.CheckpointProcessConfirmations)), big.NewInt(int64(needed))) + if err != nil { + utils.Fatalf("Failed to deploy checkpoint oracle %v", err) + } + log.Info("Deployed checkpoint oracle", "address", oracle, "tx", tx.Hash().Hex()) + + return nil +} + +// sign creates the signature for specific checkpoint +// with local key. Only contract admins have the permission to +// sign checkpoint. +func sign(ctx *cli.Context) error { + var ( + offline bool // The indicator whether we sign checkpoint by offline. + chash common.Hash + cindex uint64 + address common.Address + + node *rpc.Client + oracle *checkpointoracle.CheckpointOracle + ) + if !ctx.GlobalIsSet(nodeURLFlag.Name) { + // Offline mode signing + offline = true + if !ctx.IsSet(hashFlag.Name) { + utils.Fatalf("Please specify the checkpoint hash (--hash) to sign in offline mode") + } + chash = common.HexToHash(ctx.String(hashFlag.Name)) + + if !ctx.IsSet(indexFlag.Name) { + utils.Fatalf("Please specify checkpoint index (--index) to sign in offline mode") + } + cindex = ctx.Uint64(indexFlag.Name) + + if !ctx.IsSet(oracleFlag.Name) { + utils.Fatalf("Please specify oracle address (--oracle) to sign in offline mode") + } + address = common.HexToAddress(ctx.String(oracleFlag.Name)) + } else { + // Interactive mode signing, retrieve the data from the remote node + node = newRPCClient(ctx.GlobalString(nodeURLFlag.Name)) + + checkpoint := getCheckpoint(ctx, node) + chash = checkpoint.Hash() + cindex = checkpoint.SectionIndex + address = getContractAddr(node) + + // Check the validity of checkpoint + reqCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second) + defer cancelFn() + + head, err := ethclient.NewClient(node).HeaderByNumber(reqCtx, nil) + if err != nil { + return err + } + num := head.Number.Uint64() + if num < ((cindex+1)*params.CheckpointFrequency + params.CheckpointProcessConfirmations) { + utils.Fatalf("Invalid future checkpoint") + } + _, oracle = newContract(node) + latest, _, h, err := oracle.Contract().GetLatestCheckpoint(nil) + if err != nil { + return err + } + if cindex < latest { + utils.Fatalf("Checkpoint is too old") + } + if cindex == latest && (latest != 0 || h.Uint64() != 0) { + utils.Fatalf("Stale checkpoint, latest registered %d, given %d", latest, cindex) + } + } + var ( + signature string + signer string + ) + // isAdmin checks whether the specified signer is admin. + isAdmin := func(addr common.Address) error { + signers, err := oracle.Contract().GetAllAdmin(nil) + if err != nil { + return err + } + for _, s := range signers { + if s == addr { + return nil + } + } + return fmt.Errorf("signer %v is not the admin", addr.Hex()) + } + // Print to the user the data thy are about to sign + fmt.Printf("Oracle => %s\n", address.Hex()) + fmt.Printf("Index %4d => %s\n", cindex, chash.Hex()) + + switch { + case ctx.GlobalIsSet(clefURLFlag.Name): + // Sign checkpoint in clef mode. + signer = ctx.String(signerFlag.Name) + + if !offline { + if err := isAdmin(common.HexToAddress(signer)); err != nil { + return err + } + } + clef := newRPCClient(ctx.GlobalString(clefURLFlag.Name)) + p := make(map[string]string) + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, cindex) + p["address"] = address.Hex() + p["message"] = hexutil.Encode(append(buf, chash.Bytes()...)) + if err := clef.Call(&signature, "account_signData", accounts.MimetypeDataWithValidator, signer, p); err != nil { + utils.Fatalf("Failed to sign checkpoint, err %v", err) + } + case ctx.GlobalIsSet(keyFileFlag.Name): + // Sign checkpoint in raw private key file mode. + key := getKey(ctx) + signer = key.Address.Hex() + + if !offline { + if err := isAdmin(key.Address); err != nil { + return err + } + } + sig, err := crypto.Sign(sighash(cindex, address, chash), key.PrivateKey) + if err != nil { + utils.Fatalf("Failed to sign checkpoint, err %v", err) + } + sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper + signature = common.Bytes2Hex(sig) + default: + utils.Fatalf("Please specify clef URL or private key file path to sign checkpoint") + } + fmt.Printf("Signer => %s\n", signer) + fmt.Printf("Signature => %s\n", signature) + return nil +} + +// sighash calculates the hash of the data to sign for the checkpoint oracle. +func sighash(index uint64, oracle common.Address, hash common.Hash) []byte { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, index) + + data := append([]byte{0x19, 0x00}, append(oracle[:], append(buf, hash[:]...)...)...) + return crypto.Keccak256(data) +} + +// ecrecover calculates the sender address from a sighash and signature combo. +func ecrecover(sighash []byte, sig []byte) common.Address { + sig[64] -= 27 + defer func() { sig[64] += 27 }() + + signer, err := crypto.SigToPub(sighash, sig) + if err != nil { + utils.Fatalf("Failed to recover sender from signature %x: %v", sig, err) + } + return crypto.PubkeyToAddress(*signer) +} + +// publish registers the specified checkpoint which generated by connected node +// with a authorised private key. +func publish(ctx *cli.Context) error { + // Print the checkpoint oracle's current status to make sure we're interacting + // with the correct network and contract. + status(ctx) + + // Gather the signatures from the CLI + var sigs [][]byte + for _, sig := range strings.Split(ctx.String(signaturesFlag.Name), ",") { + trimmed := strings.TrimPrefix(strings.TrimSpace(sig), "0x") + if len(trimmed) != 130 { + utils.Fatalf("Invalid signature in --signature: '%s'", trimmed) + } else { + sigs = append(sigs, common.Hex2Bytes(trimmed)) + } + } + // Retrieve the checkpoint we want to sign to sort the signatures + var ( + client = newRPCClient(ctx.GlobalString(nodeURLFlag.Name)) + addr, oracle = newContract(client) + checkpoint = getCheckpoint(ctx, client) + sighash = sighash(checkpoint.SectionIndex, addr, checkpoint.Hash()) + ) + for i := 0; i < len(sigs); i++ { + for j := i + 1; j < len(sigs); j++ { + signerA := ecrecover(sighash, sigs[i]) + signerB := ecrecover(sighash, sigs[j]) + if bytes.Compare(signerA.Bytes(), signerB.Bytes()) > 0 { + sigs[i], sigs[j] = sigs[j], sigs[i] + } + } + } + // Retrieve recent header info to protect replay attack + reqCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second) + defer cancelFn() + + head, err := ethclient.NewClient(client).HeaderByNumber(reqCtx, nil) + if err != nil { + return err + } + num := head.Number.Uint64() + recent, err := ethclient.NewClient(client).HeaderByNumber(reqCtx, big.NewInt(int64(num-128))) + if err != nil { + return err + } + // Print a summary of the operation that's going to be performed + fmt.Printf("Publishing %d => %s:\n\n", checkpoint.SectionIndex, checkpoint.Hash().Hex()) + for i, sig := range sigs { + fmt.Printf("Signer %d => %s\n", i+1, ecrecover(sighash, sig).Hex()) + } + fmt.Println() + fmt.Printf("Sentry number => %d\nSentry hash => %s\n", recent.Number, recent.Hash().Hex()) + + // Publish the checkpoint into the oracle + tx, err := oracle.RegisterCheckpoint(getKey(ctx).PrivateKey, checkpoint.SectionIndex, checkpoint.Hash().Bytes(), recent.Number, recent.Hash(), sigs) + if err != nil { + utils.Fatalf("Register contract failed %v", err) + } + log.Info("Successfully registered checkpoint", "tx", tx.Hash().Hex()) + return nil +} diff --git a/cmd/checkpoint-admin/main.go b/cmd/checkpoint-admin/main.go new file mode 100644 index 000000000..39eae6878 --- /dev/null +++ b/cmd/checkpoint-admin/main.go @@ -0,0 +1,124 @@ +// Copyright 2018 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 <http://www.gnu.org/licenses/>. + +// checkpoint-admin is a utility that can be used to query checkpoint information +// and register stable checkpoints into an oracle contract. +package main + +import ( + "fmt" + "os" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common/fdlimit" + "github.com/ethereum/go-ethereum/log" + "gopkg.in/urfave/cli.v1" +) + +const ( + commandHelperTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...] +{{if .Description}}{{.Description}} +{{end}}{{if .Subcommands}} +SUBCOMMANDS: + {{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{end}}{{end}}{{if .Flags}} +OPTIONS: +{{range $.Flags}}{{"\t"}}{{.}} +{{end}} +{{end}}` +) + +var ( + // Git SHA1 commit hash of the release (set via linker flags) + gitCommit = "" + gitDate = "" +) + +var app *cli.App + +func init() { + app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") + app.Commands = []cli.Command{ + commandStatus, + commandDeploy, + commandSign, + commandPublish, + } + app.Flags = []cli.Flag{ + oracleFlag, + keyFileFlag, + nodeURLFlag, + clefURLFlag, + utils.PasswordFileFlag, + } + cli.CommandHelpTemplate = commandHelperTemplate +} + +// Commonly used command line flags. +var ( + indexFlag = cli.Int64Flag{ + Name: "index", + Usage: "Checkpoint index (query latest from remote node if not specified)", + } + hashFlag = cli.StringFlag{ + Name: "hash", + Usage: "Checkpoint hash (query latest from remote node if not specified)", + } + oracleFlag = cli.StringFlag{ + Name: "oracle", + Usage: "Checkpoint oracle address (query from remote node if not specified)", + } + thresholdFlag = cli.Int64Flag{ + Name: "threshold", + Usage: "Minimal number of signatures required to approve a checkpoint", + } + keyFileFlag = cli.StringFlag{ + Name: "keyfile", + Usage: "The private key file (keyfile signature is not recommended)", + } + nodeURLFlag = cli.StringFlag{ + Name: "rpc", + Value: "http://localhost:8545", + Usage: "The rpc endpoint of a local or remote geth node", + } + clefURLFlag = cli.StringFlag{ + Name: "clef", + Value: "http://localhost:8550", + Usage: "The rpc endpoint of clef", + } + signerFlag = cli.StringFlag{ + Name: "signer", + Usage: "Signer address for clef mode signing", + } + signersFlag = cli.StringFlag{ + Name: "signers", + Usage: "Comma separated accounts of trusted checkpoint signers", + } + signaturesFlag = cli.StringFlag{ + Name: "signatures", + Usage: "Comma separated checkpoint signatures to submit", + } +) + +func main() { + log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) + fdlimit.Raise(2048) + + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/checkpoint-admin/status.go b/cmd/checkpoint-admin/status.go new file mode 100644 index 000000000..c134ec090 --- /dev/null +++ b/cmd/checkpoint-admin/status.go @@ -0,0 +1,61 @@ +// Copyright 2018 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 <http://www.gnu.org/licenses/>. + +package main + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "gopkg.in/urfave/cli.v1" +) + +var commandStatus = cli.Command{ + Name: "status", + Usage: "Fetches the signers and checkpoint status of the oracle contract", + Flags: []cli.Flag{ + nodeURLFlag, + }, + Action: utils.MigrateFlags(status), +} + +// status fetches the admin list of specified registrar contract. +func status(ctx *cli.Context) error { + // Create a wrapper around the checkpoint oracle contract + addr, oracle := newContract(newRPCClient(ctx.GlobalString(nodeURLFlag.Name))) + fmt.Printf("Oracle => %s\n", addr.Hex()) + fmt.Println() + + // Retrieve the list of authorized signers (admins) + admins, err := oracle.Contract().GetAllAdmin(nil) + if err != nil { + return err + } + for i, admin := range admins { + fmt.Printf("Admin %d => %s\n", i+1, admin.Hex()) + } + fmt.Println() + + // Retrieve the latest checkpoint + index, checkpoint, height, err := oracle.Contract().GetLatestCheckpoint(nil) + if err != nil { + return err + } + fmt.Printf("Checkpoint (published at #%d) %d => %s\n", height, index, common.Hash(checkpoint).Hex()) + + return nil +} diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 00809e2e1..7e94da1f5 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" @@ -323,14 +324,33 @@ func startNode(ctx *cli.Context, stack *node.Node) { events := make(chan accounts.WalletEvent, 16) stack.AccountManager().Subscribe(events) - go func() { - // Create a chain state reader for self-derivation - rpcClient, err := stack.Attach() - if err != nil { - utils.Fatalf("Failed to attach to self: %v", err) + // Create a client to interact with local geth node. + rpcClient, err := stack.Attach() + if err != nil { + utils.Fatalf("Failed to attach to self: %v", err) + } + ethClient := ethclient.NewClient(rpcClient) + + // Set contract backend for ethereum service if local node + // is serving LES requests. + if ctx.GlobalInt(utils.LightServFlag.Name) > 0 { + var ethService *eth.Ethereum + if err := stack.Service(ðService); err != nil { + utils.Fatalf("Failed to retrieve ethereum service: %v", err) + } + ethService.SetContractBackend(ethClient) + } + // Set contract backend for les service if local node is + // running as a light client. + if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" { + var lesService *les.LightEthereum + if err := stack.Service(&lesService); err != nil { + utils.Fatalf("Failed to retrieve light ethereum service: %v", err) } - stateReader := ethclient.NewClient(rpcClient) + lesService.SetContractBackend(ethClient) + } + go func() { // Open any wallets already attached for _, wallet := range stack.AccountManager().Wallets() { if err := wallet.Open(""); err != nil { @@ -354,7 +374,7 @@ func startNode(ctx *cli.Context, stack *node.Node) { } derivationPaths = append(derivationPaths, accounts.DefaultBaseDerivationPath) - event.Wallet.SelfDerive(derivationPaths, stateReader) + event.Wallet.SelfDerive(derivationPaths, ethClient) case accounts.WalletDropped: log.Info("Old wallet dropped", "url", event.Wallet.URL()) @@ -383,7 +403,6 @@ func startNode(ctx *cli.Context, stack *node.Node) { "age", common.PrettyAge(timestamp)) stack.Stop() } - } }() } diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 6aed09f14..499f320f6 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -44,12 +44,13 @@ func (w *wizard) makeGenesis() { Difficulty: big.NewInt(524288), Alloc: make(core.GenesisAlloc), Config: ¶ms.ChainConfig{ - HomesteadBlock: big.NewInt(1), - EIP150Block: big.NewInt(2), - EIP155Block: big.NewInt(3), - EIP158Block: big.NewInt(3), - ByzantiumBlock: big.NewInt(4), - ConstantinopleBlock: big.NewInt(5), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), }, } // Figure out which consensus engine to choose @@ -191,7 +192,7 @@ func (w *wizard) importGenesis() { func (w *wizard) manageGenesis() { // Figure out whether to modify or export the genesis fmt.Println() - fmt.Println(" 1. Modify existing fork rules") + fmt.Println(" 1. Modify existing configurations") fmt.Println(" 2. Export genesis configurations") fmt.Println(" 3. Remove genesis configuration") @@ -226,7 +227,7 @@ func (w *wizard) manageGenesis() { w.conf.Genesis.Config.PetersburgBlock = w.conf.Genesis.Config.ConstantinopleBlock } fmt.Println() - fmt.Printf("Which block should Constantinople-Fix (remove EIP-1283) come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) + fmt.Printf("Which block should Petersburg come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock) out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") |