Merge pull request #62 from simple-rules/idc

Identity Chain [Testing in Progress]
pull/69/head
alajko 6 years ago committed by GitHub
commit 23f953492d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      identitychain/identityblock.go
  2. 40
      identitychain/identitychain.go
  3. 72
      identitychain/identitychain_handler.go
  4. 43
      identitymanage/identitymanage.go
  5. 106
      node/node.go
  6. 15
      node/node_handler.go
  7. 21
      pow/LICENSE
  8. 57
      pow/README.md
  9. 131
      pow/api.go
  10. 56
      pow/api_test.go
  11. 25
      pow/example_test.go
  12. 81
      pow/pow.go
  13. 78
      pow/sha2bday.go
  14. 4
      proto/identity/identity.go
  15. 34
      runwait/run_wait.go
  16. 82
      waitnode/wait_node.go
  17. 18
      waitnode/wait_node_test.go

@ -7,8 +7,8 @@ import (
"log"
"time"
"github.com/simple-rules/harmony-benchmark/node"
"github.com/simple-rules/harmony-benchmark/utils"
"github.com/simple-rules/harmony-benchmark/waitnode"
)
// IdentityBlock has the information of one node
@ -16,7 +16,7 @@ type IdentityBlock struct {
Timestamp int64
PrevBlockHash [32]byte
NumIdentities int32
Identities []*waitnode.WaitNode
Identities []*node.Node
}
// Serialize serializes the block
@ -31,7 +31,7 @@ func (b *IdentityBlock) Serialize() []byte {
}
//Get Identities
func (b *IdentityBlock) GetIdentities() []*waitnode.WaitNode {
func (b *IdentityBlock) GetIdentities() []*node.Node {
return b.Identities
}
@ -47,7 +47,7 @@ func DeserializeBlock(d []byte) *IdentityBlock {
}
// NewBlock creates and returns a new block.
func NewBlock(Identities []*waitnode.WaitNode, prevBlockHash [32]byte) *IdentityBlock {
func NewBlock(Identities []*node.Node, prevBlockHash [32]byte) *IdentityBlock {
block := &IdentityBlock{Timestamp: time.Now().Unix(), PrevBlockHash: prevBlockHash, NumIdentities: int32(len(Identities)), Identities: Identities}
return block
}
@ -59,7 +59,7 @@ func (b *IdentityBlock) CalculateBlockHash() [32]byte {
hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(b.Timestamp))
hashes = append(hashes, b.PrevBlockHash[:])
for _, id := range b.Identities {
hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(id.ID))
hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(id))
}
hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(b.NumIdentities))
blockHash = sha256.Sum256(bytes.Join(hashes, []byte{}))
@ -68,7 +68,7 @@ func (b *IdentityBlock) CalculateBlockHash() [32]byte {
// NewGenesisBlock creates and returns genesis Block.
func NewGenesisBlock() *IdentityBlock {
var Ids []*waitnode.WaitNode
var Ids []*node.Node
block := &IdentityBlock{Timestamp: time.Now().Unix(), PrevBlockHash: [32]byte{}, NumIdentities: 1, Identities: Ids}
return block
}

@ -9,8 +9,8 @@ import (
"sync"
"github.com/simple-rules/harmony-benchmark/log"
"github.com/simple-rules/harmony-benchmark/node"
"github.com/simple-rules/harmony-benchmark/p2p"
"github.com/simple-rules/harmony-benchmark/waitnode"
)
var mutex sync.Mutex
@ -19,20 +19,21 @@ var identityPerBlock = 100000
// IdentityChain (Blockchain) keeps Identities per epoch, currently centralized!
type IdentityChain struct {
Identities []*IdentityBlock
PendingIdentities []*waitnode.WaitNode
PendingIdentities []*node.Node
log log.Logger
Peer p2p.Peer
SelectedIdentitites []*waitnode.WaitNode
SelectedIdentitites []*node.Node
EpochNum int
PeerToShardMap map[*waitnode.WaitNode]int
ShardLeaderMap map[int]*waitnode.WaitNode
PeerToShardMap map[*node.Node]int
ShardLeaderMap map[int]*node.Node
PubKey string
CurrentEpochStartTime int64
NumberOfShards int
NumberOfNodesInShard int
PowMap map[p2p.Peer]string
}
func seekRandomNumber(EpochNum int, SelectedIdentitites []*waitnode.WaitNode) int {
func seekRandomNumber(EpochNum int, SelectedIdentitites []*node.Node) int {
// Broadcast message to all nodes and collect back their numbers, do consensus and get a leader.
// Use leader to generate a random number.
//all here mocked
@ -50,38 +51,46 @@ type GlobalBlockchainConfig struct {
//Shard
func (IDC *IdentityChain) Shard() {
num := seekRandomNumber(IDC.EpochNum, IDC.SelectedIdentitites)
IDC.CreateShardAssignment(num)
IDC.CreateShardAssignment()
IDC.ElectLeaders()
IDC.BroadCastNewConfiguration()
}
//
func (IDC *IdentityChain) ElectLeaders() {
}
func (IDC *IdentityChain) BroadCastNewConfiguration() {
// allPeers := make([]p2p.Peer, len(IDC.SelectedIdentitites))
// msgToSend := proto.
// p2p.BroadCastMessage(allPeers, msgToSend)
}
//CreateShardAssignment
func (IDC *IdentityChain) CreateShardAssignment(num int) {
func (IDC *IdentityChain) CreateShardAssignment() {
num := seekRandomNumber(IDC.EpochNum, IDC.SelectedIdentitites)
IDC.NumberOfShards = IDC.NumberOfShards + needNewShards()
IDC.SelectedIdentitites = generateRandomPermutations(num, IDC.SelectedIdentitites)
IDC.PeerToShardMap = make(map[*waitnode.WaitNode]int)
IDC.PeerToShardMap = make(map[*node.Node]int)
numberInOneShard := len(IDC.SelectedIdentitites) / IDC.NumberOfShards
for peerNum := 1; peerNum <= len(IDC.SelectedIdentitites); peerNum++ {
IDC.PeerToShardMap[IDC.SelectedIdentitites[peerNum]] = peerNum / numberInOneShard
}
}
func generateRandomPermutations(num int, SelectedIdentitites []*waitnode.WaitNode) []*waitnode.WaitNode {
func generateRandomPermutations(num int, SelectedIdentitites []*node.Node) []*node.Node {
src := rand.NewSource(int64(num))
rnd := rand.New(src)
perm := rnd.Perm(len(SelectedIdentitites))
SelectedIdentititesCopy := make([]*waitnode.WaitNode, len(SelectedIdentitites))
SelectedIdentititesCopy := make([]*node.Node, len(SelectedIdentitites))
for j, i := range perm {
SelectedIdentititesCopy[j] = SelectedIdentitites[i]
}
return SelectedIdentititesCopy
}
// SelectIds
// SelectIds as
func (IDC *IdentityChain) SelectIds() {
selectNumber := IDC.NumberOfNodesInShard - len(IDC.Identities)
IB := IDC.GetLatestBlock()
@ -89,7 +98,7 @@ func (IDC *IdentityChain) SelectIds() {
selectNumber = int(math.Min(float64(len(IDC.PendingIdentities)), float64(selectNumber)))
pending := IDC.PendingIdentities[:selectNumber]
IDC.SelectedIdentitites = append(currentIDS, pending...)
IDC.PendingIdentities = []*waitnode.WaitNode{}
IDC.PendingIdentities = []*node.Node{}
}
//Checks how many new shards we need. Currently we say 0.
@ -120,7 +129,7 @@ func (IDC *IdentityChain) UpdateIdentityChain() {
prevBlock := IDC.GetLatestBlock()
prevBlockHash := prevBlock.CalculateBlockHash()
NewIdentities := IDC.PendingIdentities[:identityPerBlock]
IDC.PendingIdentities = []*waitnode.WaitNode{}
IDC.PendingIdentities = []*node.Node{}
//All other blocks are dropped, we need to inform them that they are dropped?
IDBlock := NewBlock(NewIdentities, prevBlockHash)
IDC.Identities = append(IDC.Identities, IDBlock)
@ -162,5 +171,6 @@ func New(Peer p2p.Peer) *IdentityChain {
IDC := IdentityChain{}
IDC.Peer = Peer
IDC.log = log.New()
IDC.PowMap = make(map[p2p.Peer]string)
return &IDC
}

@ -1,14 +1,19 @@
package identitychain
import (
"bytes"
"fmt"
"math/rand"
"net"
"os"
"strconv"
"time"
"github.com/simple-rules/harmony-benchmark/node"
"github.com/simple-rules/harmony-benchmark/p2p"
"github.com/simple-rules/harmony-benchmark/pow"
"github.com/simple-rules/harmony-benchmark/proto"
proto_identity "github.com/simple-rules/harmony-benchmark/proto/identity"
"github.com/simple-rules/harmony-benchmark/waitnode"
)
//IdentityChainHandler handles registration of new Identities
@ -27,6 +32,8 @@ func (IDC *IdentityChain) IdentityChainHandler(conn net.Conn) {
if msgCategory != proto.IDENTITY {
IDC.log.Error("Identity Chain Recieved incorrect protocol message")
os.Exit(1)
} else {
fmt.Println("Message category is correct")
}
msgType, err := proto.GetMessageType(content)
if err != nil {
@ -43,20 +50,73 @@ func (IDC *IdentityChain) IdentityChainHandler(conn net.Conn) {
actionType := proto_identity.IdentityMessageType(msgType)
switch actionType {
case proto_identity.IDENTITY:
IDC.registerIdentity(msgPayload)
idMsgType, err := proto_identity.GetIdentityMessageType(msgPayload)
if err != nil {
fmt.Println("Error finding the identity message type")
}
switch idMsgType {
case proto_identity.REGISTER:
IDC.registerIdentity(msgPayload)
case proto_identity.ANNOUNCE:
IDC.acceptNewConnection(msgPayload)
}
}
}
}
func (IDC *IdentityChain) registerIdentity(msgPayload []byte) {
identityPayload, err := proto_identity.GetIdentityMessagePayload(msgPayload)
payload, err := proto_identity.GetIdentityMessagePayload(msgPayload)
if err != nil {
IDC.log.Error("identity payload not read")
} else {
fmt.Println("identity payload read")
}
NewWaitNode := waitnode.DeserializeWaitNode(identityPayload)
IDC.PendingIdentities = append(IDC.PendingIdentities, NewWaitNode)
fmt.Println(len(IDC.PendingIdentities))
fmt.Println("we are now registering identities")
//reconstruct the challenge and check whether its correct
offset := 0
proof := payload[offset : offset+32]
offset = offset + 32
Node := node.DeserializeWaitNode(payload[offset:])
req := IDC.PowMap[Node.Self]
ok, err := pow.Check(req, string(proof), []byte(""))
fmt.Println(err)
if ok {
fmt.Println("Proof of work accepted")
IDC.PendingIdentities = append(IDC.PendingIdentities, Node)
fmt.Println(len(IDC.PendingIdentities)) //Fix why IDC does not have log working.
} else {
fmt.Println("identity proof of work not accepted")
}
}
func (IDC *IdentityChain) acceptNewConnection(msgPayload []byte) {
identityPayload, err := proto_identity.GetIdentityMessagePayload(msgPayload)
if err != nil {
fmt.Println("There was a error in reading the identity payload")
} else {
fmt.Println("accepted new connection")
}
fmt.Println("Sleeping for 2 secs ...")
time.Sleep(2 * time.Second)
Node := node.DeserializeWaitNode(identityPayload)
buffer := bytes.NewBuffer([]byte{})
src := rand.NewSource(time.Now().UnixNano())
rnd := rand.New(src)
challengeNonce := int((rnd.Int31()))
req := pow.NewRequest(5, []byte(strconv.Itoa(challengeNonce)))
IDC.PowMap[Node.Self] = req
fmt.Println(req)
buffer.Write([]byte(req))
// 32 byte block hash
// buffer.Write(prevBlockHash)
// The message is missing previous BlockHash, this is because we don't actively maintain a identitychain
// This canbe included in the fulfill request.
// Message should be encrypted and then signed to follow PKE.
//IDC should accept node publickey, encrypt the nonce and blockhash
// Then sign the message by own private key and send the message back.
msgToSend := proto_identity.ConstructIdentityMessage(proto_identity.REGISTER, buffer.Bytes())
p2p.SendMessage(Node.Self, msgToSend)
}

@ -1,43 +0,0 @@
package identitymanage
// import (
// "bytes"
// "encoding/binary"
// "log"
// "github.com/dedis/kyber"
// )
// // Consensus data containing all info related to one round of consensus process
// type Identity struct {
// priKey kyber.Scalar
// pubKey kyber.Point
// Log log.Logger
// }
// // Construct the response message to send to leader (assumption the consensus data is already verified)
// func (identity *Identity) registerIdentity(msgType proto_consensus.MessageType, response kyber.Scalar) []byte {
// buffer := bytes.NewBuffer([]byte{})
// // 4 byte consensus id
// fourBytes := make([]byte, 4)
// binary.BigEndian.PutUint32(fourBytes, consensus.consensusId)
// buffer.Write(fourBytes)
// // 32 byte block hash
// buffer.Write(consensus.blockHash[:32])
// // 2 byte validator id
// twoBytes := make([]byte, 2)
// binary.BigEndian.PutUint16(twoBytes, consensus.nodeId)
// buffer.Write(twoBytes)
// // 32 byte of response
// response.MarshalTo(buffer)
// // 64 byte of signature on previous data
// signature := consensus.signMessage(buffer.Bytes())
// buffer.Write(signature)
// return proto_identity.ConstructIdentityMessage(msgType, buffer.Bytes())
// }

@ -1,10 +1,15 @@
package node
import (
"bytes"
"encoding/gob"
"fmt"
"net"
"sync"
"github.com/simple-rules/harmony-benchmark/crypto/pki"
"github.com/simple-rules/harmony-benchmark/pow"
"github.com/simple-rules/harmony-benchmark/proto/identity"
"github.com/simple-rules/harmony-benchmark/blockchain"
"github.com/simple-rules/harmony-benchmark/client"
@ -33,6 +38,9 @@ type Node struct {
doneSyncing chan struct{}
ClientPeer *p2p.Peer // The peer for the benchmark tx generator client, used for leaders to return proof-of-accept
Client *client.Client // The presence of a client object means this node will also act as a client
IsWaiting bool
Self p2p.Peer
IDCPeer p2p.Peer
}
// Add new crossTx and proofs to the list of crossTx that needs to be sent back to client
@ -64,6 +72,7 @@ func (node *Node) getTransactionsForNewBlock(maxNumTxs int) ([]*blockchain.Trans
// Start a server and process the request by a handler.
func (node *Node) StartServer(port string) {
fmt.Println("Hello in server now")
node.log.Debug("Starting server", "node", node, "port", port)
node.listenOnPort(port)
@ -110,6 +119,103 @@ func (node *Node) countNumTransactionsInBlockchain() int {
return count
}
//ConnectIdentityChain connects to identity chain
func (node *Node) ConnectIdentityChain() {
IDCPeer := node.IDCPeer
p2p.SendMessage(IDCPeer, identity.ConstructIdentityMessage(identity.ANNOUNCE, node.SerializeWaitNode()))
return
}
//NewWaitNode is a way to initiate a waiting no
func NewWaitNode(peer, IDCPeer p2p.Peer) Node {
node := Node{}
node.Self = peer
node.IDCPeer = IDCPeer
node.log = log.New()
return node
}
//NewNodefromIDC
func NewNodefromIDC(node Node, consensus *consensus.Consensus, db *db.LDBDatabase) *Node {
if consensus != nil {
// Consensus and associated channel to communicate blocks
node.Consensus = consensus
node.BlockChannel = make(chan blockchain.Block)
// Genesis Block
// TODO(minh): Use or implement new function in blockchain package for this.
genesisBlock := &blockchain.Blockchain{}
genesisBlock.Blocks = make([]*blockchain.Block, 0)
// TODO(RJ): use miner's address as coinbase address
coinbaseTx := blockchain.NewCoinbaseTX(pki.GetAddressFromInt(1), "0", node.Consensus.ShardID)
genesisBlock.Blocks = append(genesisBlock.Blocks, blockchain.NewGenesisBlock(coinbaseTx, node.Consensus.ShardID))
node.blockchain = genesisBlock
// UTXO pool from Genesis block
//node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain)
// Initialize level db.
node.db = db
}
// Logger
node.log = log.New()
return &node
}
func (node *Node) processPOWMessage(message []byte) {
payload, err := identity.GetIdentityMessagePayload(message)
if err != nil {
fmt.Println("Could not read payload")
}
IDCPeer := node.IDCPeer
// 4 byte challengeNonce id
req := string(payload)
fmt.Println(req)
proof, _ := pow.Fulfil(req, []byte("")) //"This could be blockhasdata"
buffer := bytes.NewBuffer([]byte{})
proofBytes := make([]byte, 32) //proof seems to be 32 byte here
copy(proofBytes[:], proof)
buffer.Write(proofBytes)
buffer.Write(node.SerializeWaitNode())
msgPayload := buffer.Bytes()
p2p.SendMessage(IDCPeer, identity.ConstructIdentityMessage(identity.REGISTER, msgPayload))
}
//https://stackoverflow.com/questions/12854125/how-do-i-dump-the-struct-into-the-byte-array-without-reflection/12854659#12854659
//SerializeWaitNode serializes the node
func (node *Node) SerializeWaitNode() []byte {
//Needs to escape the serialization of unexported fields
result := new(bytes.Buffer)
encoder := gob.NewEncoder(result)
err := encoder.Encode(node.Self)
if err != nil {
fmt.Println("Could not serialize node")
fmt.Println("ERROR", err)
//node.log.Error("Could not serialize node")
}
err = encoder.Encode(node.IDCPeer)
return result.Bytes()
}
// DeserializeWaitNode deserializes the node
func DeserializeWaitNode(d []byte) *Node {
var wn Node
r := bytes.NewBuffer(d)
decoder := gob.NewDecoder(r)
err := decoder.Decode(&wn.Self)
if err != nil {
log.Error("Could not de-serialize node")
}
err = decoder.Decode(&wn.IDCPeer)
if err != nil {
log.Error("Could not de-serialize node")
}
return &wn
}
// Create a new Node
func New(consensus *consensus.Consensus, db *db.LDBDatabase) *Node {
node := Node{}

@ -3,6 +3,7 @@ package node
import (
"bytes"
"encoding/gob"
"fmt"
"net"
"os"
"strconv"
@ -13,6 +14,7 @@ import (
"github.com/simple-rules/harmony-benchmark/proto"
"github.com/simple-rules/harmony-benchmark/proto/client"
"github.com/simple-rules/harmony-benchmark/proto/consensus"
proto_identity "github.com/simple-rules/harmony-benchmark/proto/identity"
proto_node "github.com/simple-rules/harmony-benchmark/proto/node"
)
@ -55,6 +57,19 @@ func (node *Node) NodeHandler(conn net.Conn) {
}
switch msgCategory {
case proto.IDENTITY:
actionType := proto_identity.IdentityMessageType(msgType)
switch actionType {
case proto_identity.IDENTITY:
messageType := proto_identity.MessageType(msgPayload[0])
switch messageType {
case proto_identity.REGISTER:
fmt.Println("received a identity message")
node.processPOWMessage(msgPayload)
case proto_identity.ANNOUNCE:
node.log.Error("Announce message should be sent to IdentityChain")
}
}
case proto.CONSENSUS:
actionType := consensus.ConsensusMessageType(msgType)
switch actionType {

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Bas Westerbaan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,57 @@
go-pow
======
`go-pow` is a simple Go package to add (asymmetric) *Proof of Work* to your service.
To create a Proof-of-Work request (with difficulty 5), use `pow.NewRequest`:
```go
req := pow.NewRequest(5, someRandomNonce)
```
This returns a string like `sha2bday-5-c29tZSByYW5kb20gbm9uY2U`,
which can be passed on to the client.
The client fulfils the proof of work by running `pow.Fulfil`:
```go
proof, _ := pow.Fulfil(req, []byte("some bound data"))
```
The client returns the proof (in this case `AAAAAAAAAAMAAAAAAAAADgAAAAAAAAAb`)
to the server, which can check it is indeed a valid proof of work, by running:
``` go
ok, _ := pow.Check(req, proof, []byte("some bound data"))
```
Notes
-----
1. There should be at least sufficient randomness in either the `nonce` passed to
`NewRequest` or the `data` passed to `Fulfil` and `Check`.
Thus it is fine to use the same bound `data` for every client, if every client
get a different `nonce` in its proof-of-work request.
It is also fine to use the same `nonce` in the proof-of-work request,
if every client is (by the encapsulating protocol) forced to use
different bound `data`.
2. The work to fulfil a request scales exponentially in the difficulty parameter.
The work to check it proof is correct remains constant:
```
Check on Difficulty=5 500000 2544 ns/op
Check on Difficulty=10 500000 2561 ns/op
Check on Difficulty=15 500000 2549 ns/op
Check on Difficulty=20 500000 2525 ns/op
Fulfil on Difficulty=5 100000 15725 ns/op
Fulfil on Difficulty=10 30000 46808 ns/op
Fulfil on Difficulty=15 2000 955606 ns/op
Fulfil on Difficulty=20 200 6887722 ns/op
```
To do
-----
- Support for [equihash](https://www.cryptolux.org/index.php/Equihash) would be nice.
- Port to Python, Java, Javascript, ...
- Parallelize.

@ -0,0 +1,131 @@
// Create and fulfill proof of work requests.
package pow
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
)
type Algorithm string
const (
Sha2BDay Algorithm = "sha2bday"
)
// Represents a proof-of-work request.
type Request struct {
// The requested algorithm
Alg Algorithm
// The requested difficulty
Difficulty uint32
// Nonce to diversify the request
Nonce []byte
}
// Represents a completed proof-of-work
type Proof struct {
buf []byte
}
// Convenience function to create a new sha3bday proof-of-work request
// as a string
func NewRequest(difficulty uint32, nonce []byte) string {
req := Request{
Difficulty: difficulty,
Nonce: nonce,
Alg: Sha2BDay,
}
s, _ := req.MarshalText()
return string(s)
}
func (proof Proof) MarshalText() ([]byte, error) {
return []byte(base64.RawStdEncoding.EncodeToString(proof.buf)), nil
}
func (proof *Proof) UnmarshalText(buf []byte) error {
var err error
proof.buf, err = base64.RawStdEncoding.DecodeString(string(buf))
return err
}
func (req Request) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%s-%d-%s",
req.Alg,
req.Difficulty,
string(base64.RawStdEncoding.EncodeToString(req.Nonce)))), nil
}
func (req *Request) UnmarshalText(buf []byte) error {
bits := strings.SplitN(string(buf), "-", 3)
if len(bits) != 3 {
return fmt.Errorf("There should be two dashes in a PoW request")
}
alg := Algorithm(bits[0])
if alg != Sha2BDay {
return fmt.Errorf("%s: unsupported algorithm", bits[0])
}
req.Alg = alg
diff, err := strconv.Atoi(bits[1])
if err != nil {
return err
}
req.Difficulty = uint32(diff)
req.Nonce, err = base64.RawStdEncoding.DecodeString(bits[2])
if err != nil {
return err
}
return nil
}
// Convenience function to check whether a proof of work is fulfilled
func Check(request, proof string, data []byte) (bool, error) {
var req Request
var prf Proof
err := req.UnmarshalText([]byte(request))
if err != nil {
return false, err
}
err = prf.UnmarshalText([]byte(proof))
if err != nil {
return false, err
}
return prf.Check(req, data), nil
}
// Fulfil the proof-of-work request.
func (req *Request) Fulfil(data []byte) Proof {
switch req.Alg {
case Sha2BDay:
return Proof{fulfilSha2BDay(req.Nonce, req.Difficulty, data)}
default:
panic("No such algorithm")
}
}
// Convenience function to fulfil the proof of work request
func Fulfil(request string, data []byte) (string, error) {
var req Request
err := req.UnmarshalText([]byte(request))
if err != nil {
return "", err
}
proof := req.Fulfil(data)
s, _ := proof.MarshalText()
return string(s), nil
}
// Check whether the proof is ok
func (proof *Proof) Check(req Request, data []byte) bool {
switch req.Alg {
case Sha2BDay:
return checkSha2BDay(proof.buf, req.Nonce, data, req.Difficulty)
default:
panic("No such algorithm")
}
}

@ -0,0 +1,56 @@
package pow
import (
"testing"
)
func TestSha2BDay(t *testing.T) {
nonce := []byte{1, 2, 3, 4, 5}
data := []byte{2, 2, 3, 4, 5}
r := NewRequest(5, nonce)
proof, err := Fulfil(r, data)
if err != nil {
t.Fatalf("Fulfil: %v", err)
}
ok, err := Check(r, proof, data)
if err != nil {
t.Fatalf("Check: %v", err)
}
if !ok {
t.Fatalf("Proof of work should be ok")
}
ok, err = Check(r, proof, nonce)
if err != nil {
t.Fatalf("Check: %v", err)
}
if ok {
t.Fatalf("Proof of work should not be ok")
}
}
func BenchmarkCheck5(b *testing.B) { benchmarkCheck(5, b) }
func BenchmarkCheck10(b *testing.B) { benchmarkCheck(10, b) }
func BenchmarkCheck15(b *testing.B) { benchmarkCheck(15, b) }
func BenchmarkCheck20(b *testing.B) { benchmarkCheck(20, b) }
func benchmarkCheck(diff uint32, b *testing.B) {
req := NewRequest(diff, []byte{1, 2, 3, 4, 5})
prf, _ := Fulfil(req, []byte{6, 7, 8, 9})
b.ResetTimer()
for n := 0; n < b.N; n++ {
Check(req, prf, []byte{6, 7, 8, 9})
}
}
func BenchmarkFulfil5(b *testing.B) { benchmarkFulfil(5, b) }
func BenchmarkFulfil10(b *testing.B) { benchmarkFulfil(10, b) }
func BenchmarkFulfil15(b *testing.B) { benchmarkFulfil(15, b) }
func BenchmarkFulfil20(b *testing.B) { benchmarkFulfil(20, b) }
func benchmarkFulfil(diff uint32, b *testing.B) {
req := NewRequest(diff, []byte{1, 2, 3, 4, 5})
b.ResetTimer()
for n := 0; n < b.N; n++ {
Fulfil(req, []byte{6, 7, 8, 9})
}
}

@ -0,0 +1,25 @@
package pow_test
import (
"fmt" // imported as pow
"github.com/simple-rules/harmony-benchmark/pow"
)
func Example() {
// Create a proof of work request with difficulty 5
req := pow.NewRequest(5, []byte("some random nonce"))
fmt.Printf("req: %s\n", req)
// Fulfil the proof of work
proof, _ := pow.Fulfil(req, []byte("some bound data"))
fmt.Printf("proof: %s\n", proof)
// Check if the proof is correct
ok, _ := pow.Check(req, proof, []byte("some bound data"))
fmt.Printf("check: %v", ok)
// Output: req: sha2bday-5-c29tZSByYW5kb20gbm9uY2U
// proof: AAAAAAAAAAMAAAAAAAAADgAAAAAAAAAb
// check: true
}

@ -1,81 +0,0 @@
package pow
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"math"
"math/big"
)
var (
maxNonce = math.MaxUint32
)
const targetBits = 24
// ProofOfWork represents a proof-of-work
type ProofOfWork struct {
Challenge uint32
target *big.Int
FinalNonce uint32
}
// NewProofOfWork builds and returns a ProofOfWork
func NewProofOfWork(c uint32) *ProofOfWork {
target := big.NewInt(1)
target.Lsh(target, uint(256-targetBits))
pow := &ProofOfWork{Challenge: c, target: target, FinalNonce: 0}
return pow
}
func (pow *ProofOfWork) prepareData(nonce uint32) []byte {
challenge := make([]byte, 4)
binary.LittleEndian.PutUint32(challenge, pow.Challenge)
nonceB := make([]byte, 4)
binary.LittleEndian.PutUint32(nonceB, nonce)
data := bytes.Join(
[][]byte{
challenge,
nonceB,
},
[]byte{},
)
return data
}
// Run performs a proof-of-work
func (pow *ProofOfWork) Run() int {
var hashInt big.Int
var hash [32]byte
nonce := 0
for nonce < maxNonce {
data := pow.prepareData(uint32(nonce))
hash = sha256.Sum256(data)
fmt.Printf("\r%x", hash)
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.target) == -1 {
pow.FinalNonce = uint32(nonce)
break
} else {
nonce++
}
}
fmt.Print("\n\n")
return nonce
}
// Validate validates block's PoW
func (pow *ProofOfWork) Validate(nonce uint32) bool {
var hashInt big.Int
data := pow.prepareData(nonce)
hash := sha256.Sum256(data)
hashInt.SetBytes(hash[:])
isValid := hashInt.Cmp(pow.target) == -1
return isValid
}

@ -0,0 +1,78 @@
package pow
import (
"bytes"
"crypto/sha256"
"encoding/binary"
)
func checkSha2BDay(proof []byte, nonce, data []byte, diff uint32) bool {
if len(proof) != 24 {
return false
}
prefix1 := proof[:8]
prefix2 := proof[8:16]
prefix3 := proof[16:]
if bytes.Equal(prefix1, prefix2) || bytes.Equal(prefix2, prefix3) ||
bytes.Equal(prefix1, prefix3) {
return false
}
resBuf := make([]byte, 32)
h := sha256.New()
h.Write(prefix1)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res1 := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
h.Reset()
h.Write(prefix2)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res2 := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
h.Reset()
h.Write(prefix3)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res3 := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
return res1 == res2 && res2 == res3
}
func fulfilSha2BDay(nonce []byte, diff uint32, data []byte) []byte {
// TODO make multithreaded if the difficulty is high enough.
// For light proof-of-work requests, the overhead of parallelizing is
// not worth it.
type Pair struct {
First, Second uint64
}
var i uint64 = 1
prefix := make([]byte, 8)
resBuf := make([]byte, 32)
lut := make(map[uint64]Pair)
h := sha256.New()
for {
binary.BigEndian.PutUint64(prefix, i)
h.Write(prefix)
h.Write(data)
h.Write(nonce)
h.Sum(resBuf[:0])
res := binary.BigEndian.Uint64(resBuf) & ((1 << diff) - 1)
pair, ok := lut[res]
if ok {
if pair.Second != 0 {
ret := make([]byte, 24)
binary.BigEndian.PutUint64(ret, pair.First)
binary.BigEndian.PutUint64(ret[8:], pair.Second)
copy(ret[16:], prefix)
return ret
}
lut[res] = Pair{First: pair.First, Second: i}
} else {
lut[res] = Pair{First: i}
}
h.Reset()
i++
}
}

@ -21,15 +21,17 @@ type MessageType int
const (
REGISTER MessageType = iota
ANNOUNCE
)
// Returns string name for the MessageType enum
func (msgType MessageType) String() string {
names := [...]string{
"REGISTER",
"ANNOUNCE",
}
if msgType < REGISTER || msgType > REGISTER {
if msgType < REGISTER || msgType > ANNOUNCE {
return "Unknown"
}
return names[msgType]

@ -1,21 +1,25 @@
package main
import "fmt"
import (
"flag"
"fmt"
// import (
// "flag"
// "github.com/simple-rules/harmony-benchmark/p2p"
// "github.com/simple-rules/harmony-benchmark/waitnode"
// )
"github.com/simple-rules/harmony-benchmark/node"
"github.com/simple-rules/harmony-benchmark/p2p"
)
func main() {
fmt.Println("hello")
// ip := flag.String("ip", "127.0.0.0", "IP of the node")
// port := flag.String("port", "8080", "port of the node")
// flag.Parse()
// peer := p2p.Peer{Ip: *ip, Port: *port}
// idcpeer := p2p.Peer{Ip: "localhost", Port: "9000"} //Hardcoded here.
// node := waitnode.New(peer)
// node.ConnectIdentityChain(idcpeer)
ip := flag.String("ip", "localhost", "IP of the node")
port := flag.String("port", "8080", "port of the node")
flag.Parse()
peer := p2p.Peer{Ip: *ip, Port: *port}
idcpeer := p2p.Peer{Ip: "localhost", Port: "9000"} //Hardcoded here.
node := node.NewWaitNode(peer, idcpeer)
go func() {
node.ConnectIdentityChain()
}()
fmt.Println("control is back with me")
node.StartServer(*port)
fmt.Println("starting the server")
}

@ -1,82 +0,0 @@
package waitnode
import (
"bytes"
"crypto/sha256"
"encoding/gob"
"log"
"github.com/simple-rules/harmony-benchmark/p2p"
"github.com/simple-rules/harmony-benchmark/utils"
)
//WaitNode is for nodes waiting to join consensus
type WaitNode struct {
Peer p2p.Peer
ID uint16
SeedPeers p2p.Peer
}
// StartServer a server and process the request by a handler.
func (node *WaitNode) StartServer() {
log.Printf("Starting waitnode on server %s and port %s", node.Peer.Ip, node.Peer.Port)
}
// //ConnectIdentityChain connects to identity chain
// func (node *WaitNode) ConnectIdentityChain(peer p2p.Peer) {
// pow := NewProofOfWork(10)
// nonce := pow.Run()
// if pow.FinalNonce != uint32(nonce) {
// fmt.Println("Something wrong with POW")
// }
// p2p.SendMessage(peer, identity.ConstructIdentityMessage(identity.REGISTER, node.SerializeWaitNode()))
// }
//Constructs node-id by hashing the IP.
func calculateHash(num string) []byte {
var hashes [][]byte
hashes = append(hashes, utils.ConvertFixedDataIntoByteArray(num))
hash := sha256.Sum256(bytes.Join(hashes, []byte{}))
return hash[:]
}
// //SerializePOW serializes the node
// func SerializePOW(pow ProofOfWork) []byte {
// var result bytes.Buffer
// encoder := gob.NewEncoder(&pow)
// err := encoder.Encode(pow)
// if err != nil {
// log.Panic(err.Error())
// }
// return pow.Bytes()
// }
//SerializeWaitNode serializes the node
func (node *WaitNode) SerializeWaitNode() []byte {
var result bytes.Buffer
encoder := gob.NewEncoder(&result)
err := encoder.Encode(node)
if err != nil {
log.Panic(err.Error())
}
return result.Bytes()
}
// DeserializeWaitNode deserializes the node
func DeserializeWaitNode(d []byte) *WaitNode {
var wn WaitNode
decoder := gob.NewDecoder(bytes.NewReader(d))
err := decoder.Decode(&wn)
if err != nil {
log.Panic(err)
}
return &wn
}
// New Create a new Node
func New(Peer p2p.Peer) *WaitNode {
node := WaitNode{}
node.Peer = Peer
node.ID = utils.GetUniqueIdFromPeer(Peer)
return &node
}

@ -1,18 +0,0 @@
package waitnode
import (
"testing"
"github.com/simple-rules/harmony-benchmark/p2p"
)
func TestNewNode(test *testing.T) {
p := p2p.Peer{Ip: "127.0.0.1", Port: "8080"}
wn := New(p)
b := wn.SerializeWaitNode()
wnd := DeserializeWaitNode(b)
if *wn != *wnd {
test.Error("Serialization is not working")
}
}
Loading…
Cancel
Save