Skip to content

Commit 27675ad

Browse files
qizhouQi Zhou
and
Qi Zhou
authored
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 <[email protected]>
1 parent 8800def commit 27675ad

24 files changed

+5109
-185
lines changed

cmd/tendermint/default_block_store.go

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package main
2+
3+
import (
4+
"encoding/binary"
5+
"fmt"
6+
7+
"github.com/ethereum/go-ethereum/consensus/tendermint/consensus"
8+
"github.com/ethereum/go-ethereum/rlp"
9+
"github.com/syndtr/goleveldb/leveldb"
10+
)
11+
12+
type DefaultBlockStore struct {
13+
db *leveldb.DB
14+
}
15+
16+
func NewDefaultBlockStore(db *leveldb.DB) consensus.BlockStore {
17+
return &DefaultBlockStore{
18+
db: db,
19+
}
20+
}
21+
22+
func (bs *DefaultBlockStore) Height() uint64 {
23+
data, err := bs.db.Get([]byte("height"), nil)
24+
if err != nil {
25+
return 0
26+
}
27+
28+
if len(data) != 8 {
29+
return 0
30+
}
31+
32+
return binary.BigEndian.Uint64(data)
33+
}
34+
35+
func (bs *DefaultBlockStore) Base() uint64 {
36+
return 0
37+
}
38+
39+
func (bs *DefaultBlockStore) Size() uint64 {
40+
height := bs.Height()
41+
if height == 0 {
42+
return 0
43+
}
44+
return height + 1 - bs.Base()
45+
}
46+
47+
func (bs *DefaultBlockStore) LoadBlock(height uint64) *consensus.FullBlock {
48+
hd := make([]byte, 8)
49+
binary.BigEndian.PutUint64(hd, height)
50+
bk := []byte("block")
51+
bk = append(bk, hd...)
52+
53+
blockData, err := bs.db.Get(bk, nil)
54+
if err != nil {
55+
return nil
56+
}
57+
58+
b := &consensus.FullBlock{}
59+
if rlp.DecodeBytes(blockData, b) != nil {
60+
panic(fmt.Errorf("error from block: %w", err))
61+
}
62+
return b
63+
}
64+
65+
func (bs *DefaultBlockStore) LoadBlockCommit(height uint64) *consensus.Commit {
66+
hd := make([]byte, 8)
67+
binary.BigEndian.PutUint64(hd, height)
68+
ck := []byte("commit")
69+
ck = append(ck, hd...)
70+
71+
commitData, err := bs.db.Get(ck, nil)
72+
if err != nil {
73+
return nil
74+
}
75+
76+
c := &consensus.Commit{}
77+
if rlp.DecodeBytes(commitData, c) != nil {
78+
panic(fmt.Errorf("error from block: %w", err))
79+
}
80+
return c
81+
}
82+
83+
func (bs *DefaultBlockStore) SaveBlock(b *consensus.FullBlock, c *consensus.Commit) {
84+
// sanity check?
85+
if b.NumberU64() != bs.Height()+1 {
86+
panic(fmt.Sprintf("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.Height()+1, b.NumberU64()))
87+
}
88+
89+
hd := make([]byte, 8)
90+
binary.BigEndian.PutUint64(hd, b.NumberU64())
91+
bk := []byte("block")
92+
bk = append(bk, hd...)
93+
94+
blockData, err := rlp.EncodeToBytes(b)
95+
if err != nil {
96+
// error?
97+
return
98+
}
99+
100+
if err := bs.db.Put(bk, blockData, nil); err != nil {
101+
return
102+
}
103+
104+
commitData, err := rlp.EncodeToBytes(c)
105+
if err != nil {
106+
return
107+
}
108+
109+
ck := []byte("commit")
110+
ck = append(ck, hd...)
111+
if err := bs.db.Put(ck, commitData, nil); err != nil {
112+
return
113+
}
114+
115+
data := make([]byte, 8)
116+
binary.BigEndian.PutUint64(data, b.NumberU64())
117+
if err := bs.db.Put([]byte("height"), data, nil); err != nil {
118+
return
119+
}
120+
}
121+
122+
// LoadSeenCommit returns the last locally seen Commit before being
123+
// cannonicalized. This is useful when we've seen a commit, but there
124+
// has not yet been a new block at `height + 1` that includes this
125+
// commit in its block.LastCommit.
126+
func (bs *DefaultBlockStore) LoadSeenCommit() *consensus.Commit {
127+
commitData, err := bs.db.Get([]byte("seen_commit"), nil)
128+
if err != nil {
129+
return nil
130+
}
131+
132+
c := &consensus.Commit{}
133+
if rlp.DecodeBytes(commitData, c) != nil {
134+
panic(fmt.Errorf("error from block: %w", err))
135+
}
136+
return c
137+
}

cmd/tendermint/keygen.go

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"crypto/ecdsa"
6+
"errors"
7+
"fmt"
8+
"io/ioutil"
9+
"os"
10+
11+
"github.com/ethereum/go-ethereum/consensus/tendermint/consensus"
12+
"github.com/ethereum/go-ethereum/crypto"
13+
"github.com/ethereum/go-ethereum/log"
14+
"github.com/spf13/cobra"
15+
)
16+
17+
var keyDescription *string
18+
var nolock *bool
19+
20+
const (
21+
ValidatorKeyArmoredBlock = "VALIDATOR PRIVATE KEY"
22+
)
23+
24+
var KeygenCmd = &cobra.Command{
25+
Use: "keygen [KEYFILE]",
26+
Short: "Create validator key at the specified path",
27+
Run: runKeygen,
28+
Args: cobra.ExactArgs(1),
29+
}
30+
31+
func init() {
32+
keyDescription = KeygenCmd.Flags().String("desc", "", "Human-readable key description (optional)")
33+
nolock = KeygenCmd.Flags().Bool("nolock", false, "Do not lock memory (less safer)")
34+
}
35+
36+
func runKeygen(cmd *cobra.Command, args []string) {
37+
if !*nolock {
38+
lockMemory()
39+
} else {
40+
log.Info("Skipping lockMemory()")
41+
}
42+
setRestrictiveUmask()
43+
44+
log.Info("Creating new key", "location", args[0])
45+
46+
gk := consensus.GeneratePrivValidatorLocal().(*consensus.PrivValidatorLocal)
47+
pk, err := gk.GetPubKey(context.Background())
48+
if err != nil {
49+
log.Error("Failed to get pub key", "err", err)
50+
return
51+
}
52+
53+
log.Info("Key generated", "address", pk.Address())
54+
55+
err = writeValidatorKey(gk.PrivKey, *keyDescription, args[0], false)
56+
if err != nil {
57+
log.Error("Failed to write key", "err", err)
58+
return
59+
}
60+
}
61+
62+
// loadValidatorKey loads a serialized guardian key from disk.
63+
func loadValidatorKey(filename string) (*ecdsa.PrivateKey, error) {
64+
b, err := ioutil.ReadFile(filename)
65+
if err != nil {
66+
return nil, fmt.Errorf("failed to open file: %w", err)
67+
}
68+
69+
gk, err := crypto.ToECDSA(b)
70+
if err != nil {
71+
return nil, fmt.Errorf("failed to deserialize raw key data: %w", err)
72+
}
73+
74+
return gk, nil
75+
}
76+
77+
// writeValidatorKey serializes a guardian key and writes it to disk.
78+
func writeValidatorKey(key *ecdsa.PrivateKey, description string, filename string, unsafe bool) error {
79+
if _, err := os.Stat(filename); !os.IsNotExist(err) {
80+
return errors.New("refusing to override existing key")
81+
}
82+
83+
b := crypto.FromECDSA(key)
84+
85+
err := ioutil.WriteFile(filename, b, 0600)
86+
if err != nil {
87+
return fmt.Errorf("failed to write file: %w", err)
88+
}
89+
return nil
90+
}

cmd/tendermint/main.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"syscall"
7+
8+
"github.com/spf13/cobra"
9+
"github.com/spf13/viper"
10+
"golang.org/x/sys/unix"
11+
12+
homedir "github.com/mitchellh/go-homedir"
13+
)
14+
15+
var cfgFile string
16+
17+
// rootCmd represents the base command when called without any subcommands
18+
var rootCmd = &cobra.Command{
19+
Use: "mpbft",
20+
Short: "Minimal PBFT node server",
21+
}
22+
23+
func init() {
24+
cobra.OnInitialize(initConfig)
25+
26+
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.guardiand.yaml)")
27+
rootCmd.AddCommand(NodeCmd)
28+
rootCmd.AddCommand(KeygenCmd)
29+
}
30+
31+
// initConfig reads in config file and ENV variables if set.
32+
func initConfig() {
33+
if cfgFile != "" {
34+
// Use config file from the flag.
35+
viper.SetConfigFile(cfgFile)
36+
} else {
37+
// Find home directory.
38+
home, err := homedir.Dir()
39+
if err != nil {
40+
fmt.Println(err)
41+
os.Exit(1)
42+
}
43+
44+
// Search config in home directory with name ".guardiand" (without extension).
45+
viper.AddConfigPath(home)
46+
viper.SetConfigName(".guardiand.yaml")
47+
}
48+
49+
viper.AutomaticEnv() // read in environment variables that match
50+
51+
// If a config file is found, read it in.
52+
if err := viper.ReadInConfig(); err == nil {
53+
fmt.Println("Using config file:", viper.ConfigFileUsed())
54+
}
55+
}
56+
57+
// lockMemory locks current and future pages in memory to protect secret keys from being swapped out to disk.
58+
// It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever
59+
// stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK.
60+
func lockMemory() {
61+
err := unix.Mlockall(syscall.MCL_CURRENT | syscall.MCL_FUTURE)
62+
if err != nil {
63+
fmt.Printf("Failed to lock memory: %v (CAP_IPC_LOCK missing?)\n", err)
64+
os.Exit(1)
65+
}
66+
}
67+
68+
// setRestrictiveUmask masks the group and world bits. This ensures that key material
69+
// and sockets we create aren't accidentally group- or world-readable.
70+
func setRestrictiveUmask() {
71+
syscall.Umask(0077) // cannot fail
72+
}
73+
74+
func main() {
75+
if err := rootCmd.Execute(); err != nil {
76+
fmt.Println(err)
77+
os.Exit(1)
78+
}
79+
}

0 commit comments

Comments
 (0)