Browse Source

remove PoW from ID

pull/1048/head
Ethan Buchman 7 years ago
parent
commit
9670519a21
3 changed files with 44 additions and 59 deletions
  1. +2
    -6
      node/node.go
  2. +26
    -38
      p2p/key.go
  3. +16
    -15
      p2p/key_test.go

+ 2
- 6
node/node.go View File

@ -368,11 +368,8 @@ func (n *Node) OnStart() error {
n.sw.AddListener(l) n.sw.AddListener(l)
// Generate node PrivKey // Generate node PrivKey
// TODO: both the loading function and the target
// will need to be configurable
difficulty := uint8(16) // number of leading 0s in bitstring
target := p2p.MakePoWTarget(difficulty)
nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile(), target)
// TODO: the loading function will need to be configurable
nodeKey, err := p2p.LoadOrGenNodeKey(n.config.NodeKeyFile())
if err != nil { if err != nil {
return err return err
} }
@ -381,7 +378,6 @@ func (n *Node) OnStart() error {
// Start the switch // Start the switch
n.sw.SetNodeInfo(n.makeNodeInfo(nodeKey.PubKey())) n.sw.SetNodeInfo(n.makeNodeInfo(nodeKey.PubKey()))
n.sw.SetNodeKey(nodeKey) n.sw.SetNodeKey(nodeKey)
n.sw.SetPeerIDTarget(target)
err = n.sw.Start() err = n.sw.Start()
if err != nil { if err != nil {
return err return err


+ 26
- 38
p2p/key.go View File

@ -6,7 +6,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common" cmn "github.com/tendermint/tmlibs/common"
@ -42,35 +41,18 @@ func (nodeKey *NodeKey) SatisfiesTarget(target []byte) bool {
return bytes.Compare(nodeKey.id(), target) < 0 return bytes.Compare(nodeKey.id(), target) < 0
} }
// LoadOrGenNodeKey attempts to load the NodeKey from the given filePath,
// and checks that the corresponding ID is less than the target.
// If the file does not exist, it generates and saves a new NodeKey
// with ID less than target.
func LoadOrGenNodeKey(filePath string, target []byte) (*NodeKey, error) {
// LoadOrGenNodeKey attempts to load the NodeKey from the given filePath.
// If the file does not exist, it generates and saves a new NodeKey.
func LoadOrGenNodeKey(filePath string) (*NodeKey, error) {
if cmn.FileExists(filePath) { if cmn.FileExists(filePath) {
nodeKey, err := loadNodeKey(filePath) nodeKey, err := loadNodeKey(filePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if !nodeKey.SatisfiesTarget(target) {
return nil, fmt.Errorf("Loaded ID (%s) does not satisfy target (%X)", nodeKey.ID(), target)
}
return nodeKey, nil return nodeKey, nil
} else { } else {
return genNodeKey(filePath, target)
}
}
// MakePoWTarget returns a 20 byte target byte array.
func MakePoWTarget(difficulty uint8) []byte {
zeroPrefixLen := (int(difficulty) / 8)
prefix := bytes.Repeat([]byte{0}, zeroPrefixLen)
mod := (difficulty % 8)
if mod > 0 {
nonZeroPrefix := byte(1 << (8 - mod))
prefix = append(prefix, nonZeroPrefix)
return genNodeKey(filePath)
} }
return append(prefix, bytes.Repeat([]byte{255}, 20-len(prefix))...)
} }
func loadNodeKey(filePath string) (*NodeKey, error) { func loadNodeKey(filePath string) (*NodeKey, error) {
@ -86,8 +68,8 @@ func loadNodeKey(filePath string) (*NodeKey, error) {
return nodeKey, nil return nodeKey, nil
} }
func genNodeKey(filePath string, target []byte) (*NodeKey, error) {
privKey := genPrivKeyEd25519PoW(target).Wrap()
func genNodeKey(filePath string) (*NodeKey, error) {
privKey := crypto.GenPrivKeyEd25519().Wrap()
nodeKey := &NodeKey{ nodeKey := &NodeKey{
PrivKey: privKey, PrivKey: privKey,
} }
@ -103,20 +85,26 @@ func genNodeKey(filePath string, target []byte) (*NodeKey, error) {
return nodeKey, nil return nodeKey, nil
} }
// generate key with address satisfying the difficult target
func genPrivKeyEd25519PoW(target []byte) crypto.PrivKeyEd25519 {
secret := crypto.CRandBytes(32)
var privKey crypto.PrivKeyEd25519
for i := 0; ; i++ {
privKey = crypto.GenPrivKeyEd25519FromSecret(secret)
if bytes.Compare(privKey.PubKey().Address(), target) < 0 {
break
}
z := new(big.Int)
z.SetBytes(secret)
z = z.Add(z, big.NewInt(1))
secret = z.Bytes()
//------------------------------------------------------------------------------
// MakePoWTarget returns the big-endian encoding of 2^(targetBits - difficulty) - 1.
// It can be used as a Proof of Work target.
// NOTE: targetBits must be a multiple of 8 and difficulty must be less than targetBits.
func MakePoWTarget(difficulty, targetBits uint) []byte {
if targetBits%8 != 0 {
panic(fmt.Sprintf("targetBits (%d) not a multiple of 8", targetBits))
}
if difficulty >= targetBits {
panic(fmt.Sprintf("difficulty (%d) >= targetBits (%d)", difficulty, targetBits))
}
targetBytes := targetBits / 8
zeroPrefixLen := (int(difficulty) / 8)
prefix := bytes.Repeat([]byte{0}, zeroPrefixLen)
mod := (difficulty % 8)
if mod > 0 {
nonZeroPrefix := byte(1<<(8-mod) - 1)
prefix = append(prefix, nonZeroPrefix)
} }
return privKey
tailLen := int(targetBytes) - len(prefix)
return append(prefix, bytes.Repeat([]byte{0xFF}, tailLen)...)
} }

+ 16
- 15
p2p/key_test.go View File

@ -13,37 +13,38 @@ import (
func TestLoadOrGenNodeKey(t *testing.T) { func TestLoadOrGenNodeKey(t *testing.T) {
filePath := filepath.Join(os.TempDir(), cmn.RandStr(12)+"_peer_id.json") filePath := filepath.Join(os.TempDir(), cmn.RandStr(12)+"_peer_id.json")
target := MakePoWTarget(2)
nodeKey, err := LoadOrGenNodeKey(filePath, target)
nodeKey, err := LoadOrGenNodeKey(filePath)
assert.Nil(t, err) assert.Nil(t, err)
nodeKey2, err := LoadOrGenNodeKey(filePath, target)
nodeKey2, err := LoadOrGenNodeKey(filePath)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, nodeKey, nodeKey2) assert.Equal(t, nodeKey, nodeKey2)
} }
func repeatBytes(val byte, n int) []byte {
return bytes.Repeat([]byte{val}, n)
//----------------------------------------------------------
func padBytes(bz []byte, targetBytes int) []byte {
return append(bz, bytes.Repeat([]byte{0xFF}, targetBytes-len(bz))...)
} }
func TestPoWTarget(t *testing.T) { func TestPoWTarget(t *testing.T) {
targetBytes := 20
cases := []struct { cases := []struct {
difficulty uint8
difficulty uint
target []byte target []byte
}{ }{
{0, bytes.Repeat([]byte{255}, 20)},
{1, append([]byte{128}, repeatBytes(255, 19)...)},
{8, append([]byte{0}, repeatBytes(255, 19)...)},
{9, append([]byte{0, 128}, repeatBytes(255, 18)...)},
{10, append([]byte{0, 64}, repeatBytes(255, 18)...)},
{16, append([]byte{0, 0}, repeatBytes(255, 18)...)},
{17, append([]byte{0, 0, 128}, repeatBytes(255, 17)...)},
{0, padBytes([]byte{}, targetBytes)},
{1, padBytes([]byte{127}, targetBytes)},
{8, padBytes([]byte{0}, targetBytes)},
{9, padBytes([]byte{0, 127}, targetBytes)},
{10, padBytes([]byte{0, 63}, targetBytes)},
{16, padBytes([]byte{0, 0}, targetBytes)},
{17, padBytes([]byte{0, 0, 127}, targetBytes)},
} }
for _, c := range cases { for _, c := range cases {
assert.Equal(t, MakePoWTarget(c.difficulty), c.target)
assert.Equal(t, MakePoWTarget(c.difficulty, 20*8), c.target)
} }
} }

Loading…
Cancel
Save