forked from ethereum/go-ethereum
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge go-minimial-pbft code (ethereum#51)
* add tendermint code * add node.go * use old topics * remove unused proposerReptition in MakeChainState() Co-authored-by: Qi Zhou <qzhou64@gmail.com>
- Loading branch information
Showing
24 changed files
with
5,109 additions
and
185 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/binary" | ||
"fmt" | ||
|
||
"github.com/ethereum/go-ethereum/consensus/tendermint/consensus" | ||
"github.com/ethereum/go-ethereum/rlp" | ||
"github.com/syndtr/goleveldb/leveldb" | ||
) | ||
|
||
type DefaultBlockStore struct { | ||
db *leveldb.DB | ||
} | ||
|
||
func NewDefaultBlockStore(db *leveldb.DB) consensus.BlockStore { | ||
return &DefaultBlockStore{ | ||
db: db, | ||
} | ||
} | ||
|
||
func (bs *DefaultBlockStore) Height() uint64 { | ||
data, err := bs.db.Get([]byte("height"), nil) | ||
if err != nil { | ||
return 0 | ||
} | ||
|
||
if len(data) != 8 { | ||
return 0 | ||
} | ||
|
||
return binary.BigEndian.Uint64(data) | ||
} | ||
|
||
func (bs *DefaultBlockStore) Base() uint64 { | ||
return 0 | ||
} | ||
|
||
func (bs *DefaultBlockStore) Size() uint64 { | ||
height := bs.Height() | ||
if height == 0 { | ||
return 0 | ||
} | ||
return height + 1 - bs.Base() | ||
} | ||
|
||
func (bs *DefaultBlockStore) LoadBlock(height uint64) *consensus.FullBlock { | ||
hd := make([]byte, 8) | ||
binary.BigEndian.PutUint64(hd, height) | ||
bk := []byte("block") | ||
bk = append(bk, hd...) | ||
|
||
blockData, err := bs.db.Get(bk, nil) | ||
if err != nil { | ||
return nil | ||
} | ||
|
||
b := &consensus.FullBlock{} | ||
if rlp.DecodeBytes(blockData, b) != nil { | ||
panic(fmt.Errorf("error from block: %w", err)) | ||
} | ||
return b | ||
} | ||
|
||
func (bs *DefaultBlockStore) LoadBlockCommit(height uint64) *consensus.Commit { | ||
hd := make([]byte, 8) | ||
binary.BigEndian.PutUint64(hd, height) | ||
ck := []byte("commit") | ||
ck = append(ck, hd...) | ||
|
||
commitData, err := bs.db.Get(ck, nil) | ||
if err != nil { | ||
return nil | ||
} | ||
|
||
c := &consensus.Commit{} | ||
if rlp.DecodeBytes(commitData, c) != nil { | ||
panic(fmt.Errorf("error from block: %w", err)) | ||
} | ||
return c | ||
} | ||
|
||
func (bs *DefaultBlockStore) SaveBlock(b *consensus.FullBlock, c *consensus.Commit) { | ||
// sanity check? | ||
if b.NumberU64() != bs.Height()+1 { | ||
panic(fmt.Sprintf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.Height()+1, b.NumberU64())) | ||
} | ||
|
||
hd := make([]byte, 8) | ||
binary.BigEndian.PutUint64(hd, b.NumberU64()) | ||
bk := []byte("block") | ||
bk = append(bk, hd...) | ||
|
||
blockData, err := rlp.EncodeToBytes(b) | ||
if err != nil { | ||
// error? | ||
return | ||
} | ||
|
||
if err := bs.db.Put(bk, blockData, nil); err != nil { | ||
return | ||
} | ||
|
||
commitData, err := rlp.EncodeToBytes(c) | ||
if err != nil { | ||
return | ||
} | ||
|
||
ck := []byte("commit") | ||
ck = append(ck, hd...) | ||
if err := bs.db.Put(ck, commitData, nil); err != nil { | ||
return | ||
} | ||
|
||
data := make([]byte, 8) | ||
binary.BigEndian.PutUint64(data, b.NumberU64()) | ||
if err := bs.db.Put([]byte("height"), data, nil); err != nil { | ||
return | ||
} | ||
} | ||
|
||
// LoadSeenCommit returns the last locally seen Commit before being | ||
// cannonicalized. This is useful when we've seen a commit, but there | ||
// has not yet been a new block at `height + 1` that includes this | ||
// commit in its block.LastCommit. | ||
func (bs *DefaultBlockStore) LoadSeenCommit() *consensus.Commit { | ||
commitData, err := bs.db.Get([]byte("seen_commit"), nil) | ||
if err != nil { | ||
return nil | ||
} | ||
|
||
c := &consensus.Commit{} | ||
if rlp.DecodeBytes(commitData, c) != nil { | ||
panic(fmt.Errorf("error from block: %w", err)) | ||
} | ||
return c | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"crypto/ecdsa" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
|
||
"github.com/ethereum/go-ethereum/consensus/tendermint/consensus" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/log" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var keyDescription *string | ||
var nolock *bool | ||
|
||
const ( | ||
ValidatorKeyArmoredBlock = "VALIDATOR PRIVATE KEY" | ||
) | ||
|
||
var KeygenCmd = &cobra.Command{ | ||
Use: "keygen [KEYFILE]", | ||
Short: "Create validator key at the specified path", | ||
Run: runKeygen, | ||
Args: cobra.ExactArgs(1), | ||
} | ||
|
||
func init() { | ||
keyDescription = KeygenCmd.Flags().String("desc", "", "Human-readable key description (optional)") | ||
nolock = KeygenCmd.Flags().Bool("nolock", false, "Do not lock memory (less safer)") | ||
} | ||
|
||
func runKeygen(cmd *cobra.Command, args []string) { | ||
if !*nolock { | ||
lockMemory() | ||
} else { | ||
log.Info("Skipping lockMemory()") | ||
} | ||
setRestrictiveUmask() | ||
|
||
log.Info("Creating new key", "location", args[0]) | ||
|
||
gk := consensus.GeneratePrivValidatorLocal().(*consensus.PrivValidatorLocal) | ||
pk, err := gk.GetPubKey(context.Background()) | ||
if err != nil { | ||
log.Error("Failed to get pub key", "err", err) | ||
return | ||
} | ||
|
||
log.Info("Key generated", "address", pk.Address()) | ||
|
||
err = writeValidatorKey(gk.PrivKey, *keyDescription, args[0], false) | ||
if err != nil { | ||
log.Error("Failed to write key", "err", err) | ||
return | ||
} | ||
} | ||
|
||
// loadValidatorKey loads a serialized guardian key from disk. | ||
func loadValidatorKey(filename string) (*ecdsa.PrivateKey, error) { | ||
b, err := ioutil.ReadFile(filename) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to open file: %w", err) | ||
} | ||
|
||
gk, err := crypto.ToECDSA(b) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to deserialize raw key data: %w", err) | ||
} | ||
|
||
return gk, nil | ||
} | ||
|
||
// writeValidatorKey serializes a guardian key and writes it to disk. | ||
func writeValidatorKey(key *ecdsa.PrivateKey, description string, filename string, unsafe bool) error { | ||
if _, err := os.Stat(filename); !os.IsNotExist(err) { | ||
return errors.New("refusing to override existing key") | ||
} | ||
|
||
b := crypto.FromECDSA(key) | ||
|
||
err := ioutil.WriteFile(filename, b, 0600) | ||
if err != nil { | ||
return fmt.Errorf("failed to write file: %w", err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"syscall" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
"golang.org/x/sys/unix" | ||
|
||
homedir "github.com/mitchellh/go-homedir" | ||
) | ||
|
||
var cfgFile string | ||
|
||
// rootCmd represents the base command when called without any subcommands | ||
var rootCmd = &cobra.Command{ | ||
Use: "mpbft", | ||
Short: "Minimal PBFT node server", | ||
} | ||
|
||
func init() { | ||
cobra.OnInitialize(initConfig) | ||
|
||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.guardiand.yaml)") | ||
rootCmd.AddCommand(NodeCmd) | ||
rootCmd.AddCommand(KeygenCmd) | ||
} | ||
|
||
// initConfig reads in config file and ENV variables if set. | ||
func initConfig() { | ||
if cfgFile != "" { | ||
// Use config file from the flag. | ||
viper.SetConfigFile(cfgFile) | ||
} else { | ||
// Find home directory. | ||
home, err := homedir.Dir() | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
|
||
// Search config in home directory with name ".guardiand" (without extension). | ||
viper.AddConfigPath(home) | ||
viper.SetConfigName(".guardiand.yaml") | ||
} | ||
|
||
viper.AutomaticEnv() // read in environment variables that match | ||
|
||
// If a config file is found, read it in. | ||
if err := viper.ReadInConfig(); err == nil { | ||
fmt.Println("Using config file:", viper.ConfigFileUsed()) | ||
} | ||
} | ||
|
||
// lockMemory locks current and future pages in memory to protect secret keys from being swapped out to disk. | ||
// It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever | ||
// stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK. | ||
func lockMemory() { | ||
err := unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE) | ||
if err != nil { | ||
fmt.Printf("Failed to lock memory: %v (CAP_IPC_LOCK missing?)\n", err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
// setRestrictiveUmask masks the group and world bits. This ensures that key material | ||
// and sockets we create aren't accidentally group- or world-readable. | ||
func setRestrictiveUmask() { | ||
syscall.Umask(0077) // cannot fail | ||
} | ||
|
||
func main() { | ||
if err := rootCmd.Execute(); err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
} |
Oops, something went wrong.