From 9d597754d2921f6b9d841cf9684041a1e2862929 Mon Sep 17 00:00:00 2001 From: ak Date: Tue, 4 Sep 2018 14:37:57 -0700 Subject: [PATCH 01/17] WIP commit --- identitychain/identitychain.go | 17 +++- identitychain/identitychain_handler.go | 64 ++++++++++-- identitymanage/identitymanage.go | 43 -------- node/node.go | 94 +++++++++++++++++- node/node_handler.go | 16 ++- pow/LICENSE | 21 ++++ pow/README.md | 57 +++++++++++ pow/api.go | 131 +++++++++++++++++++++++++ pow/api_test.go | 56 +++++++++++ pow/example_test.go | 25 +++++ pow/pow.go | 81 --------------- pow/sha2bday.go | 78 +++++++++++++++ proto/identity/identity.go | 4 +- runwait/run_wait.go | 27 +++-- 14 files changed, 562 insertions(+), 152 deletions(-) delete mode 100644 identitymanage/identitymanage.go create mode 100755 pow/LICENSE create mode 100755 pow/README.md create mode 100755 pow/api.go create mode 100755 pow/api_test.go create mode 100755 pow/example_test.go delete mode 100644 pow/pow.go create mode 100755 pow/sha2bday.go diff --git a/identitychain/identitychain.go b/identitychain/identitychain.go index ffd9e1372..0af4ba361 100644 --- a/identitychain/identitychain.go +++ b/identitychain/identitychain.go @@ -30,6 +30,7 @@ type IdentityChain struct { CurrentEpochStartTime int64 NumberOfShards int NumberOfNodesInShard int + PowMap map[p2p.Peer]uint32 } func seekRandomNumber(EpochNum int, SelectedIdentitites []*waitnode.WaitNode) int { @@ -50,17 +51,25 @@ 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) @@ -81,7 +90,7 @@ func generateRandomPermutations(num int, SelectedIdentitites []*waitnode.WaitNod return SelectedIdentititesCopy } -// SelectIds +// SelectIds as func (IDC *IdentityChain) SelectIds() { selectNumber := IDC.NumberOfNodesInShard - len(IDC.Identities) IB := IDC.GetLatestBlock() diff --git a/identitychain/identitychain_handler.go b/identitychain/identitychain_handler.go index 4ac1b6c3f..eb9d46326 100644 --- a/identitychain/identitychain_handler.go +++ b/identitychain/identitychain_handler.go @@ -1,14 +1,17 @@ package identitychain import ( + "bytes" + "encoding/binary" "fmt" + "math/rand" "net" "os" + "github.com/simple-rules/harmony-benchmark/node" "github.com/simple-rules/harmony-benchmark/p2p" "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 @@ -40,23 +43,70 @@ func (IDC *IdentityChain) IdentityChainHandler(conn net.Conn) { } switch msgCategory { case proto.IDENTITY: - actionType := proto_identity.IdentityMessageType(msgType) + actionType := proto_identity.MessageType(msgType) switch actionType { - case proto_identity.IDENTITY: + 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)) + //reconstruct the challenge and check whether its correct + offset := 0 + //proof := payload[offset : offset+64] + + offset = offset + 64 + Node := node.DeserializeNode(payload[offset:]) + fmt.Println(Node.Self) + os.Exit(1) + // id := []byte(IDC.PowMap[Node.Self]) + // req := pow.NewRequest(5, id) + // ok, _ := pow.Check(req, string(proof), []byte("This is blockchash data")) + // if ok { + // 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") + } + Node := node.DeserializeNode(identityPayload) + buffer := bytes.NewBuffer([]byte{}) + challengeNonce := uint32(rand.Intn(1000)) + IDC.PowMap[Node.Self] = challengeNonce + + // 64 byte length of challenge + fourBytes := make([]byte, 64) + binary.BigEndian.PutUint32(fourBytes, challengeNonce) + buffer.Write(fourBytes) + + sendMsgPayload := buffer.Bytes() + + // 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, sendMsgPayload) + p2p.SendMessage(Node.Self, msgToSend) } diff --git a/identitymanage/identitymanage.go b/identitymanage/identitymanage.go deleted file mode 100644 index aaef5dfa3..000000000 --- a/identitymanage/identitymanage.go +++ /dev/null @@ -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()) -// } diff --git a/node/node.go b/node/node.go index 895e76413..ef0d9819e 100644 --- a/node/node.go +++ b/node/node.go @@ -1,11 +1,16 @@ package node import ( - "github.com/simple-rules/harmony-benchmark/crypto/pki" + "bytes" + "encoding/gob" "net" "os" "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" "github.com/simple-rules/harmony-benchmark/consensus" @@ -31,6 +36,9 @@ type Node struct { crossTxToReturnMutex sync.Mutex 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 @@ -96,6 +104,90 @@ 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.SerializeNode())) +} + +//NewWaitNode is a way to initiate a waiting no +func NewWaitNode(peer, IDCPeer p2p.Peer) Node { + node := Node{} + node.Self = peer + node.IDCPeer = IDCPeer + 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(payload []byte) { + IDCPeer := node.IDCPeer + offset := 0 + // 4 byte challenge nonce id + req := pow.NewRequest(5, payload[offset:offset+64]) + proof, _ := pow.Fulfil(req, []byte("This is blockchash data")) //"some bound dat" + + proofBytes := make([]byte, 64) + copy(proofBytes[:], proof) + buffer := bytes.NewBuffer([]byte{}) + buffer.Write(proofBytes) + + buffer.Write(node.SerializeNode()) + + msgPayload := buffer.Bytes() + p2p.SendMessage(IDCPeer, identity.ConstructIdentityMessage(identity.REGISTER, msgPayload)) +} + +//SerializeWaitNode serializes the node +func (node *Node) SerializeNode() []byte { + var result bytes.Buffer + encoder := gob.NewEncoder(&result) + err := encoder.Encode(node) + if err != nil { + node.log.Error("Could not serialize node") + } + return result.Bytes() +} + +// DeserializeWaitNode deserializes the node +func DeserializeNode(d []byte) *Node { + var wn Node + decoder := gob.NewDecoder(bytes.NewReader(d)) + err := decoder.Decode(&wn) + 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{} diff --git a/node/node_handler.go b/node/node_handler.go index 7d86ca873..f403bccf1 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -3,17 +3,19 @@ package node import ( "bytes" "encoding/gob" - "github.com/simple-rules/harmony-benchmark/log" "net" "os" "strconv" "time" + "github.com/simple-rules/harmony-benchmark/log" + "github.com/simple-rules/harmony-benchmark/blockchain" "github.com/simple-rules/harmony-benchmark/p2p" "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" ) @@ -54,6 +56,18 @@ 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: + 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 { diff --git a/pow/LICENSE b/pow/LICENSE new file mode 100755 index 000000000..bd93e247d --- /dev/null +++ b/pow/LICENSE @@ -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. diff --git a/pow/README.md b/pow/README.md new file mode 100755 index 000000000..5f7c83c17 --- /dev/null +++ b/pow/README.md @@ -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. + diff --git a/pow/api.go b/pow/api.go new file mode 100755 index 000000000..f4e5ba906 --- /dev/null +++ b/pow/api.go @@ -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") + } +} diff --git a/pow/api_test.go b/pow/api_test.go new file mode 100755 index 000000000..2361288f7 --- /dev/null +++ b/pow/api_test.go @@ -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}) + } +} diff --git a/pow/example_test.go b/pow/example_test.go new file mode 100755 index 000000000..cca46eb42 --- /dev/null +++ b/pow/example_test.go @@ -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 +} diff --git a/pow/pow.go b/pow/pow.go deleted file mode 100644 index a8c31b3d5..000000000 --- a/pow/pow.go +++ /dev/null @@ -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 -} diff --git a/pow/sha2bday.go b/pow/sha2bday.go new file mode 100755 index 000000000..4fdd03134 --- /dev/null +++ b/pow/sha2bday.go @@ -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++ + } +} diff --git a/proto/identity/identity.go b/proto/identity/identity.go index 5458f348c..a3ab381f9 100644 --- a/proto/identity/identity.go +++ b/proto/identity/identity.go @@ -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] diff --git a/runwait/run_wait.go b/runwait/run_wait.go index b2a953adb..3abebccc4 100644 --- a/runwait/run_wait.go +++ b/runwait/run_wait.go @@ -1,21 +1,20 @@ 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", "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 := node.NewWaitNode(peer, idcpeer) + node.ConnectIdentityChain() } From c7b63df577f616fbb64f302dcde56d55dc3e9d4e Mon Sep 17 00:00:00 2001 From: ak Date: Tue, 4 Sep 2018 14:42:30 -0700 Subject: [PATCH 02/17] corrected node handler --- node/node_handler.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/node/node_handler.go b/node/node_handler.go index 84c97d323..186c46a45 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -8,8 +8,6 @@ import ( "strconv" "time" - "github.com/simple-rules/harmony-benchmark/log" - "github.com/simple-rules/harmony-benchmark/blockchain" "github.com/simple-rules/harmony-benchmark/p2p" "github.com/simple-rules/harmony-benchmark/proto" From b56bc830c2771a643ae3e1c21bde1c7850add86f Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Wed, 5 Sep 2018 22:20:04 +0000 Subject: [PATCH 03/17] fix null pointer segfault on soldier when config file is empty Got a null pointer error of the soldier when I run "init" command on 2k nodes. panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x8376cc] goroutine 7 [running]: main.handleInitCommand(0xc42001c740, 0x4, 0x4, 0xc42004bed0) /Users/ricl/GoPath/src/github.com/simple-rules/experiment-deploy/experiment/soldier/main.go:160 +0x43c main.handleCommand(0xc4200642a0, 0x5b, 0xc420050ed0) /Users/ricl/GoPath/src/github.com/simple-rules/experiment-deploy/experiment/soldier/main.go:121 +0xe6 main.handler(0x9ec220, 0xc42000c0a8) /Users/ricl/GoPath/src/github.com/simple-rules/experiment-deploy/experiment/soldier/main.go:96 +0x289 created by main.socketServer /Users/ricl/GoPath/src/github.com/simple-rules/experiment-deploy/experiment/soldier/main.go:72 +0x320 Signed-off-by: Leo Chen --- utils/distribution_config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/distribution_config.go b/utils/distribution_config.go index dd034efbc..f5c6f72e8 100644 --- a/utils/distribution_config.go +++ b/utils/distribution_config.go @@ -148,6 +148,9 @@ func (config *DistributionConfig) GetConfigEntries() []ConfigEntry { } func (config *DistributionConfig) GetMyConfigEntry(ip string, port string) *ConfigEntry { + if config.config == nil { + return nil + } for _, entry := range config.config { if entry.IP == ip && entry.Port == port { return &entry From e809eb1e5963b37dd60de9c6274159c8f3494145 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 6 Sep 2018 04:05:12 +0000 Subject: [PATCH 04/17] add -version support to benchmark/txgen Signed-off-by: Leo Chen --- benchmark.go | 19 +++++++++++++++++++ client/txgen/main.go | 19 +++++++++++++++++++ go_executable_build.sh | 10 ++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/benchmark.go b/benchmark.go index 249944b26..6015d89f5 100644 --- a/benchmark.go +++ b/benchmark.go @@ -5,6 +5,7 @@ import ( "fmt" "math/rand" "os" + "path" "time" "github.com/simple-rules/harmony-benchmark/attack" @@ -16,6 +17,13 @@ import ( "github.com/simple-rules/harmony-benchmark/utils" ) +var ( + version string + builtBy string + builtAt string + commit string +) + const ( AttackProbability = 20 ) @@ -42,6 +50,11 @@ func InitLDBDatabase(ip string, port string) (*db.LDBDatabase, error) { return db.NewLDBDatabase(dbFileName, 0, 0) } +func printVersion(me string) { + fmt.Fprintf(os.Stderr, "Harmony (C) 2018. %v, version %v-%v (%v %v)\n", path.Base(me), version, commit, builtBy, builtAt) + os.Exit(0) +} + func main() { ip := flag.String("ip", "127.0.0.1", "IP of the node") port := flag.String("port", "9000", "port of the node.") @@ -51,8 +64,14 @@ func main() { dbSupported := flag.Bool("db_supported", false, "false means not db_supported, true means db_supported") profile := flag.Bool("profile", false, "Turn on profiling (CPU, Memory).") metricsReportURL := flag.String("metrics_profile_url", "", "If set, reports metrics to this URL.") + versionFlag := flag.Bool("version", false, "Output version info") + flag.Parse() + if *versionFlag { + printVersion(os.Args[0]) + } + // Set up randomization seed. rand.Seed(int64(time.Now().Nanosecond())) diff --git a/client/txgen/main.go b/client/txgen/main.go index 4944f0184..aa5601422 100644 --- a/client/txgen/main.go +++ b/client/txgen/main.go @@ -6,6 +6,8 @@ import ( "flag" "fmt" "math/rand" + "os" + "path" "sync" "time" @@ -20,6 +22,13 @@ import ( proto_node "github.com/simple-rules/harmony-benchmark/proto/node" ) +var ( + version string + builtBy string + builtAt string + commit string +) + type txGenSettings struct { numOfAddress int crossShard bool @@ -238,14 +247,24 @@ func countNumOfUtxos(utxoPool *blockchain.UTXOPool) int { return countAll } +func printVersion(me string) { + fmt.Fprintf(os.Stderr, "Harmony (C) 2018. %v, version %v-%v (%v %v)\n", path.Base(me), version, commit, builtBy, builtAt) + os.Exit(0) +} + func main() { configFile := flag.String("config_file", "local_config.txt", "file containing all ip addresses and config") maxNumTxsPerBatch := flag.Int("max_num_txs_per_batch", 100000, "number of transactions to send per message") logFolder := flag.String("log_folder", "latest", "the folder collecting the logs of this execution") numSubset := flag.Int("numSubset", 3, "the number of subsets of utxos to process separately") duration := flag.Int("duration", 60, "duration of the tx generation in second") + versionFlag := flag.Bool("version", false, "Output version info") flag.Parse() + if *versionFlag { + printVersion(os.Args[0]) + } + // Read the configs config := client_config.NewConfig() config.ReadConfigFile(*configFile) diff --git a/go_executable_build.sh b/go_executable_build.sh index c90532e0d..50adc1c42 100755 --- a/go_executable_build.sh +++ b/go_executable_build.sh @@ -2,8 +2,14 @@ GOOS=linux GOARCH=amd64 -env GOOS=$GOOS GOARCH=$GOARCH go build -o bin/benchmark benchmark.go -env GOOS=$GOOS GOARCH=$GOARCH go build -o bin/txgen client/txgen/main.go + +VERSION=$(git rev-list --all --count) +COMMIT=$(git describe --always --long --dirty) +BUILTAT=$(date +%FT%T%z) +BUILTBY=${USER}@ + +env GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.builtAt=${BUILTAT} -X main.builtBy=${BUILTBY}" -o bin/benchmark benchmark.go +env GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.builtAt=${BUILTAT} -X main.builtBy=${BUILTBY}" -o bin/txgen client/txgen/main.go AWSCLI=aws if [ "$1" != "" ]; then From e15e04a219d6551d0afeb422773c9fa13afb7c4c Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 6 Sep 2018 04:49:27 +0000 Subject: [PATCH 05/17] support windows build and extra parameters Usage: go_executable_build.sh [OPTIONS] ACTION OPTIONS: -h print this help message -p profile aws profile name -a arch set build arch (default: amd64) -o os set build OS (default: linux, windows is supported) -b bucket set the upload bucket name (default: unique-bucket-bin) ACTION: build build binaries only (default action) upload upload binaries to s3 Signed-off-by: Leo Chen --- go_executable_build.sh | 103 +++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 13 deletions(-) diff --git a/go_executable_build.sh b/go_executable_build.sh index 50adc1c42..c7501739b 100755 --- a/go_executable_build.sh +++ b/go_executable_build.sh @@ -1,20 +1,97 @@ -#!/usr/bin/env bash +#!/bin/bash +# this script is used to generate the binary of benchmark/txgen +# TODO: add error and parameter checking +declare -A SRC +SRC[benchmark]=benchmark.go +SRC[txgen]=client/txgen/main.go + +BINDIR=bin +BUCKET=unique-bucket-bin GOOS=linux GOARCH=amd64 -VERSION=$(git rev-list --all --count) -COMMIT=$(git describe --always --long --dirty) -BUILTAT=$(date +%FT%T%z) -BUILTBY=${USER}@ +function usage +{ + ME=$(basename $0) + cat< $BINDIR/md5sum.txt +} + +function upload +{ + AWSCLI=aws + + if [ -n "$PROFILE" ]; then + AWSCLI+=" --profile $PROFILE" + fi + + for bin in "${!SRC[@]}"; do + [ -e $BINDIR/$bin ] && $AWSCLI s3 cp $BINDIR/$bin s3://$BUCKET/$bin --acl public-read + done + [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://$BUCKET/$bin --acl public-read +} + +################################ MAIN FUNCTION ############################## +while getopts "hp:a:o:b:" option; do + case $option in + h) usage ;; + p) PROFILE=$OPTARG ;; + a) GOARCH=$OPTARG ;; + o) GOOS=$OPTARG ;; + b) BUCKET=$OPTARG ;; + esac +done + +mkdir -p $BINDIR -env GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.builtAt=${BUILTAT} -X main.builtBy=${BUILTBY}" -o bin/benchmark benchmark.go -env GOOS=$GOOS GOARCH=$GOARCH go build -ldflags="-X main.version=v${VERSION} -X main.commit=${COMMIT} -X main.builtAt=${BUILTAT} -X main.builtBy=${BUILTBY}" -o bin/txgen client/txgen/main.go +shift $(($OPTIND-1)) -AWSCLI=aws -if [ "$1" != "" ]; then - AWSCLI+=" --profile $1" -fi +ACTION=${1:-build} -$AWSCLI s3 cp bin/benchmark s3://unique-bucket-bin/benchmark --acl public-read-write -$AWSCLI s3 cp bin/txgen s3://unique-bucket-bin/txgen --acl public-read-write +case "$ACTION" in + "build") build_only ;; + "upload") upload ;; + *) usage ;; +esac From 7455c3f4b86fb1a228e017c14b0ec7c093dab7b0 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 6 Sep 2018 05:18:47 +0000 Subject: [PATCH 06/17] fix a typo in go_executable_build.sh Signed-off-by: Leo Chen --- go_executable_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go_executable_build.sh b/go_executable_build.sh index c7501739b..f6fe973e4 100755 --- a/go_executable_build.sh +++ b/go_executable_build.sh @@ -70,7 +70,7 @@ function upload for bin in "${!SRC[@]}"; do [ -e $BINDIR/$bin ] && $AWSCLI s3 cp $BINDIR/$bin s3://$BUCKET/$bin --acl public-read done - [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://$BUCKET/$bin --acl public-read + [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://$BUCKET/md5sum.txt --acl public-read } ################################ MAIN FUNCTION ############################## From 945f25c65be5cc07b0fb49dddfaa48e207cfd400 Mon Sep 17 00:00:00 2001 From: Rongjian Lan Date: Wed, 5 Sep 2018 22:51:21 -0700 Subject: [PATCH 07/17] Update utxo with state block; refactor utxo counter func --- blockchain/block.go | 4 +-- blockchain/blockchain_test.go | 4 +-- blockchain/utxopool.go | 47 ++++++++++++++++++++++++----------- blockchain/utxopool_test.go | 6 ++--- client/txgen/main.go | 27 ++------------------ node/node.go | 2 +- node/node_handler.go | 39 +++++++++++++++-------------- 7 files changed, 64 insertions(+), 65 deletions(-) diff --git a/blockchain/block.go b/blockchain/block.go index 42ab919f6..d5f84d0f2 100644 --- a/blockchain/block.go +++ b/blockchain/block.go @@ -133,7 +133,7 @@ func NewStateBlock(utxoPool *UTXOPool, numBlocks, numTxs int32) *Block { stateTransactions := []*Transaction{} stateTransactionIds := [][32]byte{} for address, txHash2Vout2AmountMap := range utxoPool.UtxoMap { - stateTransaction := Transaction{} + stateTransaction := &Transaction{} for txHash, vout2AmountMap := range txHash2Vout2AmountMap { for index, amount := range vout2AmountMap { txHashBytes, err := utils.Get32BytesFromString(txHash) @@ -148,7 +148,7 @@ func NewStateBlock(utxoPool *UTXOPool, numBlocks, numTxs int32) *Block { if len(stateTransaction.TxOutput) != 0 { stateTransaction.SetID() stateTransactionIds = append(stateTransactionIds, stateTransaction.ID) - stateTransactions = append(stateTransactions, &stateTransaction) + stateTransactions = append(stateTransactions, stateTransaction) } } newBlock := NewBlock(stateTransactions, [32]byte{}, utxoPool.ShardID) diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index 7d2f14128..bccf9fee0 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -58,7 +58,7 @@ func TestFindUTXO(t *testing.T) { func TestAddNewUserTransfer(t *testing.T) { bc := CreateBlockchain(TestAddressOne, 0) - utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) + utxoPool := CreateUTXOPoolFromGenesisBlock(bc.Blocks[0]) if !bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0) { t.Error("Failed to add new transfer to alok.") @@ -75,7 +75,7 @@ func TestAddNewUserTransfer(t *testing.T) { func TestVerifyNewBlock(t *testing.T) { bc := CreateBlockchain(TestAddressOne, 0) - utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) + utxoPool := CreateUTXOPoolFromGenesisBlock(bc.Blocks[0]) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0) diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 54252feb3..831b602cf 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -363,28 +363,31 @@ func (utxoPool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool { return false } -// CreateUTXOPoolFromTransaction a Utxo pool from a genesis transaction. -func CreateUTXOPoolFromTransaction(tx *Transaction, shardId uint32) *UTXOPool { +// CreateUTXOPoolFromGenesisBlock a Utxo pool from a genesis block. +func CreateUTXOPoolFromGenesisBlock(block *Block) *UTXOPool { + shardId := block.ShardId var utxoPool UTXOPool - txID := hex.EncodeToString(tx.ID[:]) utxoPool.UtxoMap = make(UtxoMap) utxoPool.LockedUtxoMap = make(UtxoMap) - for index, out := range tx.TxOutput { - utxoPool.UtxoMap[out.Address] = make(TXHash2Vout2AmountMap) - utxoPool.UtxoMap[out.Address][txID] = make(Vout2AmountMap) - utxoPool.UtxoMap[out.Address][txID][uint32(index)] = out.Amount + for _, tx := range block.Transactions { + txID := hex.EncodeToString(tx.ID[:]) + for index, out := range tx.TxOutput { + _, ok := utxoPool.UtxoMap[out.Address] + if !ok { + utxoPool.UtxoMap[out.Address] = make(TXHash2Vout2AmountMap) + } + + _, ok = utxoPool.UtxoMap[out.Address][txID] + if !ok { + utxoPool.UtxoMap[out.Address][txID] = make(Vout2AmountMap) + } + utxoPool.UtxoMap[out.Address][txID][uint32(index)] = out.Amount + } } utxoPool.ShardID = shardId return &utxoPool } -// CreateUTXOPoolFromGenesisBlockChain a Utxo pool from a genesis blockchain. -func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { - tx := bc.Blocks[0].Transactions[0] - shardId := bc.Blocks[0].ShardId - return CreateUTXOPoolFromTransaction(tx, shardId) -} - // SelectTransactionsForNewBlock returns a list of index of valid transactions for the new block. func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transaction, maxNumTxs int) ([]*Transaction, []*Transaction, []*Transaction, []*CrossShardTxAndProof) { selected, unselected, invalid, crossShardTxs := []*Transaction{}, []*Transaction{}, []*Transaction{}, []*CrossShardTxAndProof{} @@ -484,3 +487,19 @@ func (utxoPool *UTXOPool) GetSizeInByteOfUtxoMap() int { encoder.Encode(utxoPool.UtxoMap) return len(byteBuffer.Bytes()) } + +// A utility func that counts the total number of utxos in a pool. +func (utxoPool *UTXOPool) CountNumOfUtxos() int { + countAll := 0 + for _, utxoMap := range utxoPool.UtxoMap { + for txIdStr, val := range utxoMap { + _, err := hex.DecodeString(txIdStr) + if err != nil { + continue + } + + countAll += len(val) + } + } + return countAll +} diff --git a/blockchain/utxopool_test.go b/blockchain/utxopool_test.go index 69eb8a9ef..314eb3965 100644 --- a/blockchain/utxopool_test.go +++ b/blockchain/utxopool_test.go @@ -6,7 +6,7 @@ import ( func TestVerifyOneTransactionAndUpdate(t *testing.T) { bc := CreateBlockchain(TestAddressOne, 0) - utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) + utxoPool := CreateUTXOPoolFromGenesisBlock(bc.Blocks[0]) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0) @@ -24,7 +24,7 @@ func TestVerifyOneTransactionAndUpdate(t *testing.T) { func TestVerifyOneTransactionFail(t *testing.T) { bc := CreateBlockchain(TestAddressOne, 0) - utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) + utxoPool := CreateUTXOPoolFromGenesisBlock(bc.Blocks[0]) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressTwo, 100, 0) @@ -42,7 +42,7 @@ func TestVerifyOneTransactionFail(t *testing.T) { func TestDeleteOneBalanceItem(t *testing.T) { bc := CreateBlockchain(TestAddressOne, 0) - utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) + utxoPool := CreateUTXOPoolFromGenesisBlock(bc.Blocks[0]) bc.AddNewUserTransfer(utxoPool, PriKeyOne, TestAddressOne, TestAddressThree, 3, 0) bc.AddNewUserTransfer(utxoPool, PriKeyThree, TestAddressThree, TestAddressTwo, 3, 0) diff --git a/client/txgen/main.go b/client/txgen/main.go index 4944f0184..b464554ff 100644 --- a/client/txgen/main.go +++ b/client/txgen/main.go @@ -119,7 +119,6 @@ UTXOLOOP: } } utxoPoolMutex.Unlock() - log.Debug("[Generator] generated transations", "single-shard", len(txInfo.txs), "cross-shard", len(txInfo.crossTxs)) return txInfo.txs, txInfo.crossTxs } @@ -216,28 +215,6 @@ func generateSingleShardTx(txInfo *TxInfo) { txInfo.txCount++ } -// A utility func that counts the total number of utxos in a pool. -func countNumOfUtxos(utxoPool *blockchain.UTXOPool) int { - countAll := 0 - for _, utxoMap := range utxoPool.UtxoMap { - for txIdStr, val := range utxoMap { - _ = val - id, err := hex.DecodeString(txIdStr) - if err != nil { - continue - } - - txId := [32]byte{} - copy(txId[:], id[:]) - for _, utxo := range val { - _ = utxo - countAll++ - } - } - } - return countAll -} - func main() { configFile := flag.String("config_file", "local_config.txt", "file containing all ip addresses and config") maxNumTxsPerBatch := flag.Int("max_num_txs_per_batch", 100000, "number of transactions to send per message") @@ -290,8 +267,8 @@ func main() { if node.Consensus.ShardID == block.ShardId { log.Debug("Adding block from leader", "shardId", block.ShardId) // Add it to blockchain - utxoPoolMutex.Lock() node.AddNewBlock(block) + utxoPoolMutex.Lock() node.UpdateUtxoAndState(block) utxoPoolMutex.Unlock() } else { @@ -324,7 +301,7 @@ func main() { constructAndSendTransaction(batchCounter, *numSubset, shardId, leaders, nodes, clientNode, clientPort) } batchCounter++ - time.Sleep(1000 * time.Millisecond) + time.Sleep(2000 * time.Millisecond) } // Send a stop message to stop the nodes at the end diff --git a/node/node.go b/node/node.go index ee93c64a7..1120c8fa2 100644 --- a/node/node.go +++ b/node/node.go @@ -129,7 +129,7 @@ func New(consensus *consensus.Consensus, db *db.LDBDatabase) *Node { node.blockchain = genesisBlock // UTXO pool from Genesis block - node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain) + node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlock(node.blockchain.Blocks[0]) // Initialize level db. node.db = db diff --git a/node/node_handler.go b/node/node_handler.go index f19fb48e8..76433d8a2 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -304,27 +304,25 @@ func (node *Node) PostConsensusProcessing(newBlock *blockchain.Block) { } } node.blockchain.Blocks = []*blockchain.Block{} - node.AddNewBlock(newBlock) - } else { - node.AddNewBlock(newBlock) - node.UpdateUtxoAndState(newBlock) - - if node.Consensus.IsLeader { - // Move crossTx-in-consensus into the list to be returned to client - for _, crossTxAndProof := range node.CrossTxsInConsensus { - crossTxAndProof.Proof.BlockHash = newBlock.Hash - // TODO: fill in the signature proofs - } - if len(node.CrossTxsInConsensus) != 0 { - node.addCrossTxsToReturn(node.CrossTxsInConsensus) - node.CrossTxsInConsensus = []*blockchain.CrossShardTxAndProof{} - } + } - node.SendBackProofOfAcceptOrReject() - node.BroadcastNewBlock(newBlock) + if node.Consensus.IsLeader { + // Move crossTx-in-consensus into the list to be returned to client + for _, crossTxAndProof := range node.CrossTxsInConsensus { + crossTxAndProof.Proof.BlockHash = newBlock.Hash + // TODO: fill in the signature proofs + } + if len(node.CrossTxsInConsensus) != 0 { + node.addCrossTxsToReturn(node.CrossTxsInConsensus) + node.CrossTxsInConsensus = []*blockchain.CrossShardTxAndProof{} } + + node.SendBackProofOfAcceptOrReject() + node.BroadcastNewBlock(newBlock) } + node.AddNewBlock(newBlock) + node.UpdateUtxoAndState(newBlock) } func (node *Node) AddNewBlock(newBlock *blockchain.Block) { @@ -339,7 +337,12 @@ func (node *Node) AddNewBlock(newBlock *blockchain.Block) { func (node *Node) UpdateUtxoAndState(newBlock *blockchain.Block) { // Update UTXO pool - node.UtxoPool.Update(newBlock.Transactions) + if newBlock.IsStateBlock() { + newUtxoPool := blockchain.CreateUTXOPoolFromGenesisBlock(newBlock) + node.UtxoPool.UtxoMap = newUtxoPool.UtxoMap + } else { + node.UtxoPool.Update(newBlock.Transactions) + } // Clear transaction-in-Consensus list node.transactionInConsensus = []*blockchain.Transaction{} } From 6632cea6de4e0832833b24dc385ad525ccc29139 Mon Sep 17 00:00:00 2001 From: ak Date: Wed, 5 Sep 2018 23:37:14 -0700 Subject: [PATCH 08/17] working pow --- identitychain/identityblock.go | 12 ++-- identitychain/identitychain.go | 23 ++++---- identitychain/identitychain_handler.go | 77 +++++++++++++++--------- node/node.go | 58 ++++++++++++------ node/node_handler.go | 2 + waitnode/wait_node.go | 82 -------------------------- waitnode/wait_node_test.go | 18 ------ 7 files changed, 107 insertions(+), 165 deletions(-) delete mode 100644 waitnode/wait_node.go delete mode 100644 waitnode/wait_node_test.go diff --git a/identitychain/identityblock.go b/identitychain/identityblock.go index 46be703fe..7a438979e 100644 --- a/identitychain/identityblock.go +++ b/identitychain/identityblock.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 } diff --git a/identitychain/identitychain.go b/identitychain/identitychain.go index 0af4ba361..d1a9fa012 100644 --- a/identitychain/identitychain.go +++ b/identitychain/identitychain.go @@ -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,13 +19,13 @@ 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 @@ -33,7 +33,7 @@ type IdentityChain struct { PowMap map[p2p.Peer]uint32 } -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 @@ -72,18 +72,18 @@ 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] } @@ -98,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. @@ -129,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) @@ -171,5 +171,6 @@ func New(Peer p2p.Peer) *IdentityChain { IDC := IdentityChain{} IDC.Peer = Peer IDC.log = log.New() + IDC.PowMap = make(map[p2p.Peer]uint32) return &IDC } diff --git a/identitychain/identitychain_handler.go b/identitychain/identitychain_handler.go index eb9d46326..4e8ac8820 100644 --- a/identitychain/identitychain_handler.go +++ b/identitychain/identitychain_handler.go @@ -7,9 +7,12 @@ import ( "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" ) @@ -30,6 +33,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,12 +48,20 @@ func (IDC *IdentityChain) IdentityChainHandler(conn net.Conn) { } switch msgCategory { case proto.IDENTITY: - actionType := proto_identity.MessageType(msgType) + actionType := proto_identity.IdentityMessageType(msgType) switch actionType { - case proto_identity.REGISTER: - IDC.registerIdentity(msgPayload) - case proto_identity.ANNOUNCE: - IDC.acceptNewConnection(msgPayload) + case proto_identity.IDENTITY: + 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) + } + } } @@ -61,23 +74,23 @@ func (IDC *IdentityChain) registerIdentity(msgPayload []byte) { } else { fmt.Println("identity payload read") } + fmt.Println("we are now registering identities") //reconstruct the challenge and check whether its correct offset := 0 - //proof := payload[offset : offset+64] - - offset = offset + 64 - Node := node.DeserializeNode(payload[offset:]) - fmt.Println(Node.Self) - os.Exit(1) - // id := []byte(IDC.PowMap[Node.Self]) - // req := pow.NewRequest(5, id) - // ok, _ := pow.Check(req, string(proof), []byte("This is blockchash data")) - // if ok { - // 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") - // } + proof := payload[offset : offset+32] + offset = offset + 32 + Node := node.DeserializeWaitNode(payload[offset:]) + id := int(IDC.PowMap[Node.Self]) + req := pow.NewRequest(5, []byte(strconv.Itoa(id))) + 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) { @@ -85,19 +98,25 @@ 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") } - Node := node.DeserializeNode(identityPayload) + fmt.Println("Sleeping for 2 secs ...") + time.Sleep(5 * time.Second) + Node := node.DeserializeWaitNode(identityPayload) buffer := bytes.NewBuffer([]byte{}) - challengeNonce := uint32(rand.Intn(1000)) + src := rand.NewSource(time.Now().UnixNano()) + rnd := rand.New(src) + challengeNonce := uint32(rnd.Int31()) + //challengeNonce := uint32(rand.Intn(1000)) //fix so that different nonce is sent everytime. + fmt.Println("Challenge Nonce Sent:") + fmt.Println(challengeNonce) IDC.PowMap[Node.Self] = challengeNonce + // 4 byte length of challengeNonce - // 64 byte length of challenge - fourBytes := make([]byte, 64) + fourBytes := make([]byte, 4) binary.BigEndian.PutUint32(fourBytes, challengeNonce) buffer.Write(fourBytes) - - sendMsgPayload := buffer.Bytes() - // 32 byte block hash // buffer.Write(prevBlockHash) // The message is missing previous BlockHash, this is because we don't actively maintain a identitychain @@ -106,7 +125,7 @@ func (IDC *IdentityChain) acceptNewConnection(msgPayload []byte) { // 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, sendMsgPayload) + fmt.Println("Done sleeping. Ready or not here i come!") + msgToSend := proto_identity.ConstructIdentityMessage(proto_identity.REGISTER, buffer.Bytes()) p2p.SendMessage(Node.Self, msgToSend) } diff --git a/node/node.go b/node/node.go index aad7a9893..f408aa120 100644 --- a/node/node.go +++ b/node/node.go @@ -2,8 +2,11 @@ package node import ( "bytes" + "encoding/binary" "encoding/gob" + "fmt" "net" + "strconv" "sync" "github.com/simple-rules/harmony-benchmark/crypto/pki" @@ -68,6 +71,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) @@ -111,7 +115,8 @@ func (node *Node) countNumTransactionsInBlockchain() int { //ConnectIdentityChain connects to identity chain func (node *Node) ConnectIdentityChain() { IDCPeer := node.IDCPeer - p2p.SendMessage(IDCPeer, identity.ConstructIdentityMessage(identity.ANNOUNCE, node.SerializeNode())) + p2p.SendMessage(IDCPeer, identity.ConstructIdentityMessage(identity.ANNOUNCE, node.SerializeWaitNode())) + return } //NewWaitNode is a way to initiate a waiting no @@ -119,6 +124,7 @@ func NewWaitNode(peer, IDCPeer p2p.Peer) Node { node := Node{} node.Self = peer node.IDCPeer = IDCPeer + node.log = log.New() return node } @@ -152,40 +158,54 @@ func NewNodefromIDC(node Node, consensus *consensus.Consensus, db *db.LDBDatabas return &node } -func (node *Node) processPOWMessage(payload []byte) { +func (node *Node) processPOWMessage(message []byte) { + payload, err := identity.GetIdentityMessagePayload(message) + if err != nil { + fmt.Println("Could not read payload") + } IDCPeer := node.IDCPeer offset := 0 - // 4 byte challenge nonce id - req := pow.NewRequest(5, payload[offset:offset+64]) - proof, _ := pow.Fulfil(req, []byte("This is blockchash data")) //"some bound dat" - - proofBytes := make([]byte, 64) - copy(proofBytes[:], proof) + // 4 byte challengeNonce id + challengeNonce := int(binary.BigEndian.Uint32(payload[offset : offset+4])) + offset += 4 + fmt.Println(challengeNonce) + req := pow.NewRequest(5, []byte(strconv.Itoa(challengeNonce))) + 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.SerializeNode()) - + 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) SerializeNode() []byte { - var result bytes.Buffer - encoder := gob.NewEncoder(&result) - err := encoder.Encode(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 { - node.log.Error("Could not serialize node") + 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 DeserializeNode(d []byte) *Node { +func DeserializeWaitNode(d []byte) *Node { var wn Node - decoder := gob.NewDecoder(bytes.NewReader(d)) - err := decoder.Decode(&wn) + 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") } diff --git a/node/node_handler.go b/node/node_handler.go index 186c46a45..7696241ca 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -3,6 +3,7 @@ package node import ( "bytes" "encoding/gob" + "fmt" "net" "os" "strconv" @@ -63,6 +64,7 @@ func (node *Node) NodeHandler(conn net.Conn) { 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") diff --git a/waitnode/wait_node.go b/waitnode/wait_node.go deleted file mode 100644 index c66cbe2c9..000000000 --- a/waitnode/wait_node.go +++ /dev/null @@ -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 -} diff --git a/waitnode/wait_node_test.go b/waitnode/wait_node_test.go deleted file mode 100644 index b7f89ef7d..000000000 --- a/waitnode/wait_node_test.go +++ /dev/null @@ -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") - } - -} From 1da4bd06eaa7c6352d2eee54997176ab9bfecaa2 Mon Sep 17 00:00:00 2001 From: ak Date: Wed, 5 Sep 2018 23:38:16 -0700 Subject: [PATCH 09/17] working pow 2 --- runwait/run_wait.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/runwait/run_wait.go b/runwait/run_wait.go index 3abebccc4..62431c679 100644 --- a/runwait/run_wait.go +++ b/runwait/run_wait.go @@ -9,12 +9,17 @@ import ( ) func main() { - fmt.Println("hello") - ip := flag.String("ip", "127.0.0.0", "IP of the node") + 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) - node.ConnectIdentityChain() + go func() { + node.ConnectIdentityChain() + }() + fmt.Println("control is back with me") + node.StartServer(*port) + fmt.Println("starting the server") + } From c2eb7020c119b6a10a790a405dc501e5615e5753 Mon Sep 17 00:00:00 2001 From: ak Date: Thu, 6 Sep 2018 00:02:38 -0700 Subject: [PATCH 10/17] working pow --- identitychain/identitychain.go | 4 ++-- identitychain/identitychain_handler.go | 23 +++++++---------------- node/node.go | 11 +++-------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/identitychain/identitychain.go b/identitychain/identitychain.go index d1a9fa012..c84cb412d 100644 --- a/identitychain/identitychain.go +++ b/identitychain/identitychain.go @@ -30,7 +30,7 @@ type IdentityChain struct { CurrentEpochStartTime int64 NumberOfShards int NumberOfNodesInShard int - PowMap map[p2p.Peer]uint32 + PowMap map[p2p.Peer]string } func seekRandomNumber(EpochNum int, SelectedIdentitites []*node.Node) int { @@ -171,6 +171,6 @@ func New(Peer p2p.Peer) *IdentityChain { IDC := IdentityChain{} IDC.Peer = Peer IDC.log = log.New() - IDC.PowMap = make(map[p2p.Peer]uint32) + IDC.PowMap = make(map[p2p.Peer]string) return &IDC } diff --git a/identitychain/identitychain_handler.go b/identitychain/identitychain_handler.go index 4e8ac8820..7b004fd2e 100644 --- a/identitychain/identitychain_handler.go +++ b/identitychain/identitychain_handler.go @@ -2,7 +2,6 @@ package identitychain import ( "bytes" - "encoding/binary" "fmt" "math/rand" "net" @@ -80,8 +79,7 @@ func (IDC *IdentityChain) registerIdentity(msgPayload []byte) { proof := payload[offset : offset+32] offset = offset + 32 Node := node.DeserializeWaitNode(payload[offset:]) - id := int(IDC.PowMap[Node.Self]) - req := pow.NewRequest(5, []byte(strconv.Itoa(id))) + req := IDC.PowMap[Node.Self] ok, err := pow.Check(req, string(proof), []byte("")) fmt.Println(err) if ok { @@ -102,30 +100,23 @@ func (IDC *IdentityChain) acceptNewConnection(msgPayload []byte) { fmt.Println("accepted new connection") } fmt.Println("Sleeping for 2 secs ...") - time.Sleep(5 * time.Second) + time.Sleep(2 * time.Second) Node := node.DeserializeWaitNode(identityPayload) buffer := bytes.NewBuffer([]byte{}) src := rand.NewSource(time.Now().UnixNano()) rnd := rand.New(src) - challengeNonce := uint32(rnd.Int31()) - //challengeNonce := uint32(rand.Intn(1000)) //fix so that different nonce is sent everytime. - fmt.Println("Challenge Nonce Sent:") - fmt.Println(challengeNonce) - IDC.PowMap[Node.Self] = challengeNonce - // 4 byte length of challengeNonce - - fourBytes := make([]byte, 4) - binary.BigEndian.PutUint32(fourBytes, challengeNonce) - buffer.Write(fourBytes) + 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. - fmt.Println("Done sleeping. Ready or not here i come!") msgToSend := proto_identity.ConstructIdentityMessage(proto_identity.REGISTER, buffer.Bytes()) p2p.SendMessage(Node.Self, msgToSend) } diff --git a/node/node.go b/node/node.go index 3676725c0..35fc1f7a6 100644 --- a/node/node.go +++ b/node/node.go @@ -2,11 +2,9 @@ package node import ( "bytes" - "encoding/binary" "encoding/gob" "fmt" "net" - "strconv" "sync" "github.com/simple-rules/harmony-benchmark/crypto/pki" @@ -155,7 +153,7 @@ func NewNodefromIDC(node Node, consensus *consensus.Consensus, db *db.LDBDatabas node.blockchain = genesisBlock // UTXO pool from Genesis block - node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain) + //node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain) // Initialize level db. node.db = db @@ -173,12 +171,9 @@ func (node *Node) processPOWMessage(message []byte) { fmt.Println("Could not read payload") } IDCPeer := node.IDCPeer - offset := 0 // 4 byte challengeNonce id - challengeNonce := int(binary.BigEndian.Uint32(payload[offset : offset+4])) - offset += 4 - fmt.Println(challengeNonce) - req := pow.NewRequest(5, []byte(strconv.Itoa(challengeNonce))) + 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 From 32bbd1a7dd8f91408d22d834a6b6637e527a1f91 Mon Sep 17 00:00:00 2001 From: ak Date: Thu, 6 Sep 2018 11:02:48 -0700 Subject: [PATCH 11/17] deleting pow.txt --- waitnode/pow.txt | 82 ------------------------------------------------ 1 file changed, 82 deletions(-) delete mode 100644 waitnode/pow.txt diff --git a/waitnode/pow.txt b/waitnode/pow.txt deleted file mode 100644 index e1ae54168..000000000 --- a/waitnode/pow.txt +++ /dev/null @@ -1,82 +0,0 @@ -package waitnode - -import ( - "bytes" - "crypto/sha256" - "fmt" - "math" - "math/big" -) - -var ( - maxNonce = math.MaxInt64 -) - -const targetBits = 24 - -// ProofOfWork represents a proof-of-work -type ProofOfWork struct { - Challenge int32 - target *big.Int -} - -// NewProofOfWork builds and returns a ProofOfWork -func NewProofOfWork(c int32) *ProofOfWork { - target := big.NewInt(1) - target.Lsh(target, uint(256-targetBits)) - - pow := &ProofOfWork{c, target} - - return pow -} - -func (pow *ProofOfWork) prepareData(nonce int) []byte { - data := bytes.Join( - [][]byte{ - pow.Challenge., - IntToHex(int64(targetBits)), - IntToHex(int64(nonce)), - }, - []byte{}, - ) - - return data -} - -// Run performs a proof-of-work -func (pow *ProofOfWork) Run() (int, []byte) { - var hashInt big.Int - var hash [32]byte - nonce := 0 - - fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data) - for nonce < maxNonce { - data := pow.prepareData(nonce) - - hash = sha256.Sum256(data) - fmt.Printf("\r%x", hash) - hashInt.SetBytes(hash[:]) - - if hashInt.Cmp(pow.target) == -1 { - break - } else { - nonce++ - } - } - fmt.Print("\n\n") - - return nonce, hash[:] -} - -// Validate validates block's PoW -func (pow *ProofOfWork) Validate() bool { - var hashInt big.Int - - data := pow.prepareData(pow.challenge.Nonce) - hash := sha256.Sum256(data) - hashInt.SetBytes(hash[:]) - - isValid := hashInt.Cmp(pow.target) == -1 - - return isValid -} From 85d91ef63e3f17f5d0dbd4eca8fd6e5d35ac5255 Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 6 Sep 2018 18:46:42 +0000 Subject: [PATCH 12/17] add folder support Signed-off-by: Leo Chen --- go_executable_build.sh | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/go_executable_build.sh b/go_executable_build.sh index f6fe973e4..927fcaca3 100755 --- a/go_executable_build.sh +++ b/go_executable_build.sh @@ -10,6 +10,7 @@ BINDIR=bin BUCKET=unique-bucket-bin GOOS=linux GOARCH=amd64 +FOLDER= function usage { @@ -19,11 +20,12 @@ function usage Usage: $ME [OPTIONS] ACTION OPTIONS: - -h print this help message - -p profile aws profile name - -a arch set build arch (default: $GOARCH) - -o os set build OS (default: $GOOS, windows is supported) - -b bucket set the upload bucket name (default: $BUCKET) + -h print this help message + -p profile aws profile name + -a arch set build arch (default: $GOARCH) + -o os set build OS (default: $GOOS, windows is supported) + -b bucket set the upload bucket name (default: $BUCKET) + -f folder set the upload folder name in the bucket (default: $FOLDER) ACTION: build build binaries only (default action) @@ -31,14 +33,14 @@ ACTION: EXAMPLES: -# build linux binaries by default +# build linux binaries only by default $ME # build windows binaries $ME -o windows -# upload binaries to my s3 bucket - $ME -b mybucket upload +# upload binaries to my s3 bucket, 0908 folder + $ME -b mybucket -f 0908 upload EOF exit 1 @@ -68,19 +70,20 @@ function upload fi for bin in "${!SRC[@]}"; do - [ -e $BINDIR/$bin ] && $AWSCLI s3 cp $BINDIR/$bin s3://$BUCKET/$bin --acl public-read + [ -e $BINDIR/$bin ] && $AWSCLI s3 cp $BINDIR/$bin s3://$BUCKET/$FOLDER/$bin --acl public-read done - [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://$BUCKET/md5sum.txt --acl public-read + [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://$BUCKET/$FOLDER/md5sum.txt --acl public-read } ################################ MAIN FUNCTION ############################## -while getopts "hp:a:o:b:" option; do +while getopts "hp:a:o:b:f:" option; do case $option in h) usage ;; p) PROFILE=$OPTARG ;; a) GOARCH=$OPTARG ;; o) GOOS=$OPTARG ;; b) BUCKET=$OPTARG ;; + f) FOLDER=$OPTARG ;; esac done From 3a83d4d0f82d6905263636b2a08e3353bcb3179c Mon Sep 17 00:00:00 2001 From: Leo Chen Date: Thu, 6 Sep 2018 22:33:56 +0000 Subject: [PATCH 13/17] fix redundant leading / Signed-off-by: Leo Chen --- go_executable_build.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/go_executable_build.sh b/go_executable_build.sh index 927fcaca3..22c9a3ae4 100755 --- a/go_executable_build.sh +++ b/go_executable_build.sh @@ -70,9 +70,9 @@ function upload fi for bin in "${!SRC[@]}"; do - [ -e $BINDIR/$bin ] && $AWSCLI s3 cp $BINDIR/$bin s3://$BUCKET/$FOLDER/$bin --acl public-read + [ -e $BINDIR/$bin ] && $AWSCLI s3 cp $BINDIR/$bin s3://${BUCKET}$FOLDER/$bin --acl public-read done - [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://$BUCKET/$FOLDER/md5sum.txt --acl public-read + [ -e $BINDIR/md5sum.txt ] && $AWSCLI s3 cp $BINDIR/md5sum.txt s3://${BUCKET}$FOLDER/md5sum.txt --acl public-read } ################################ MAIN FUNCTION ############################## @@ -82,7 +82,7 @@ while getopts "hp:a:o:b:f:" option; do p) PROFILE=$OPTARG ;; a) GOARCH=$OPTARG ;; o) GOOS=$OPTARG ;; - b) BUCKET=$OPTARG ;; + b) BUCKET=$OPTARG/ ;; f) FOLDER=$OPTARG ;; esac done From 4f7790c5ecf8d08a990a4bffbea6b174230f5564 Mon Sep 17 00:00:00 2001 From: ak Date: Thu, 6 Sep 2018 23:01:56 -0700 Subject: [PATCH 14/17] IDC (almost there) --- identitychain/identitychain.go | 104 +++++++++++++++---------- identitychain/identitychain_handler.go | 2 +- identitychain/identitychain_test.go | 20 ----- node/node.go | 1 - proto/identity/identity.go | 6 +- runid/run_identity.go | 11 +++ runwait/run_wait.go | 9 ++- 7 files changed, 85 insertions(+), 68 deletions(-) delete mode 100644 identitychain/identitychain_test.go diff --git a/identitychain/identitychain.go b/identitychain/identitychain.go index c84cb412d..5f973ca5f 100644 --- a/identitychain/identitychain.go +++ b/identitychain/identitychain.go @@ -18,7 +18,8 @@ var identityPerBlock = 100000 // IdentityChain (Blockchain) keeps Identities per epoch, currently centralized! type IdentityChain struct { - Identities []*IdentityBlock + //Identities []*IdentityBlock //No need to have the identity block as of now + Identities []*node.Node PendingIdentities []*node.Node log log.Logger Peer p2p.Peer @@ -51,16 +52,21 @@ type GlobalBlockchainConfig struct { //Shard func (IDC *IdentityChain) Shard() { + + IDC.SelectIds() IDC.CreateShardAssignment() IDC.ElectLeaders() IDC.BroadCastNewConfiguration() } -// +//ElectLeaders func (IDC *IdentityChain) ElectLeaders() { + return } +//BroadCastNewConfiguration func (IDC *IdentityChain) BroadCastNewConfiguration() { + fmt.Println("Broadcasting leader and shard info to everyone!") // allPeers := make([]p2p.Peer, len(IDC.SelectedIdentitites)) // msgToSend := proto. // p2p.BroadCastMessage(allPeers, msgToSend) @@ -71,34 +77,38 @@ func (IDC *IdentityChain) BroadCastNewConfiguration() { func (IDC *IdentityChain) CreateShardAssignment() { num := seekRandomNumber(IDC.EpochNum, IDC.SelectedIdentitites) IDC.NumberOfShards = IDC.NumberOfShards + needNewShards() - IDC.SelectedIdentitites = generateRandomPermutations(num, IDC.SelectedIdentitites) + IDC.generateRandomPermutations(num) IDC.PeerToShardMap = make(map[*node.Node]int) numberInOneShard := len(IDC.SelectedIdentitites) / IDC.NumberOfShards - for peerNum := 1; peerNum <= len(IDC.SelectedIdentitites); peerNum++ { + fmt.Println(len(IDC.SelectedIdentitites)) + for peerNum := 0; peerNum < len(IDC.SelectedIdentitites); peerNum++ { IDC.PeerToShardMap[IDC.SelectedIdentitites[peerNum]] = peerNum / numberInOneShard } } -func generateRandomPermutations(num int, SelectedIdentitites []*node.Node) []*node.Node { +func (IDC *IdentityChain) generateRandomPermutations(num int) { src := rand.NewSource(int64(num)) rnd := rand.New(src) - perm := rnd.Perm(len(SelectedIdentitites)) - SelectedIdentititesCopy := make([]*node.Node, len(SelectedIdentitites)) + perm := rnd.Perm(len(IDC.SelectedIdentitites)) + SelectedIdentititesCopy := make([]*node.Node, len(IDC.SelectedIdentitites)) for j, i := range perm { - SelectedIdentititesCopy[j] = SelectedIdentitites[i] + SelectedIdentititesCopy[j] = IDC.SelectedIdentitites[i] } - return SelectedIdentititesCopy + IDC.SelectedIdentitites = SelectedIdentititesCopy } // SelectIds as func (IDC *IdentityChain) SelectIds() { selectNumber := IDC.NumberOfNodesInShard - len(IDC.Identities) - IB := IDC.GetLatestBlock() - currentIDS := IB.GetIdentities() + // Insert the lines below once you have a identity block + // IB := IDC.GetLatestBlock() + // currentIDS := IB.GetIdentities() + currentIDS := IDC.Identities selectNumber = int(math.Min(float64(len(IDC.PendingIdentities)), float64(selectNumber))) pending := IDC.PendingIdentities[:selectNumber] IDC.SelectedIdentitites = append(currentIDS, pending...) IDC.PendingIdentities = []*node.Node{} + } //Checks how many new shards we need. Currently we say 0. @@ -106,37 +116,6 @@ func needNewShards() int { return 0 } -// GetLatestBlock gests the latest block at the end of the chain -func (IDC *IdentityChain) GetLatestBlock() *IdentityBlock { - if len(IDC.Identities) == 0 { - return nil - } - return IDC.Identities[len(IDC.Identities)-1] -} - -//UpdateIdentityChain is to create the Blocks to be added to the chain -func (IDC *IdentityChain) UpdateIdentityChain() { - - //If there are no more Identities registring the blockchain is dead - if len(IDC.PendingIdentities) == 0 { - // This is abd, because previous block might not be alive - return - } - if len(IDC.Identities) == 0 { - block := NewGenesisBlock() - IDC.Identities = append(IDC.Identities, block) - } else { - prevBlock := IDC.GetLatestBlock() - prevBlockHash := prevBlock.CalculateBlockHash() - NewIdentities := IDC.PendingIdentities[:identityPerBlock] - 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) - } - -} - //StartServer a server and process the request by a handler. func (IDC *IdentityChain) StartServer() { fmt.Println("Starting server...") @@ -171,6 +150,47 @@ func New(Peer p2p.Peer) *IdentityChain { IDC := IdentityChain{} IDC.Peer = Peer IDC.log = log.New() + IDC.NumberOfShards = 1 //to be filled via global config + IDC.NumberOfNodesInShard = 500 //to be filled via global config + IDC.Identities = make([]*node.Node, 0) + IDC.PendingIdentities = make([]*node.Node, 0) + IDC.SelectedIdentitites = make([]*node.Node, 0) IDC.PowMap = make(map[p2p.Peer]string) return &IDC } + +// ------------------------------------------------------------- + +// The code below is needed when we have a actual identity block +// GetLatestBlock gests the latest block at the end of the chain +// func (IDC *IdentityChain) GetLatestBlock() *IdentityBlock { +// if len(IDC.Identities) == 0 { +// return nil +// } +// return IDC.Identities[len(IDC.Identities)-1] +// } + +//UpdateIdentityChain is to create the Blocks to be added to the chain +// func (IDC *IdentityChain) UpdateIdentityChain() { + +// //If there are no more Identities registring the blockchain is dead +// if len(IDC.PendingIdentities) == 0 { +// // This is abd, because previous block might not be alive +// return +// } +// if len(IDC.Identities) == 0 { +// block := NewGenesisBlock() +// IDC.Identities = append(IDC.Identities, block) +// } else { +// prevBlock := IDC.GetLatestBlock() +// prevBlockHash := prevBlock.CalculateBlockHash() +// NewIdentities := IDC.PendingIdentities[:identityPerBlock] +// 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) +// } + +// } + +// ------------------------------------------------------------- diff --git a/identitychain/identitychain_handler.go b/identitychain/identitychain_handler.go index 7b004fd2e..48c4e937e 100644 --- a/identitychain/identitychain_handler.go +++ b/identitychain/identitychain_handler.go @@ -74,7 +74,6 @@ func (IDC *IdentityChain) registerIdentity(msgPayload []byte) { fmt.Println("identity payload read") } 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 @@ -108,6 +107,7 @@ func (IDC *IdentityChain) acceptNewConnection(msgPayload []byte) { challengeNonce := int((rnd.Int31())) req := pow.NewRequest(5, []byte(strconv.Itoa(challengeNonce))) IDC.PowMap[Node.Self] = req + fmt.Println(Node.Self) fmt.Println(req) buffer.Write([]byte(req)) // 32 byte block hash diff --git a/identitychain/identitychain_test.go b/identitychain/identitychain_test.go deleted file mode 100644 index 10599f8ac..000000000 --- a/identitychain/identitychain_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package identitychain - -import ( - "fmt" - "os" - "testing" - - "github.com/simple-rules/harmony-benchmark/p2p" -) - -func TestIDCFormed(test *testing.T) { - peer := p2p.Peer{Ip: "127.0.0.1", Port: "8080"} - IDC := New(peer) - if IDC == nil { - fmt.Println("IDC not formed.") - os.Exit(1) - } -} - -//TODO Mock netconnection to test whether identitychain is listening. diff --git a/node/node.go b/node/node.go index 35fc1f7a6..16b209a77 100644 --- a/node/node.go +++ b/node/node.go @@ -173,7 +173,6 @@ func (node *Node) processPOWMessage(message []byte) { 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 diff --git a/proto/identity/identity.go b/proto/identity/identity.go index a3ab381f9..c8e8a711a 100644 --- a/proto/identity/identity.go +++ b/proto/identity/identity.go @@ -22,6 +22,7 @@ type MessageType int const ( REGISTER MessageType = iota ANNOUNCE + CONFIG ) // Returns string name for the MessageType enum @@ -29,15 +30,16 @@ func (msgType MessageType) String() string { names := [...]string{ "REGISTER", "ANNOUNCE", + "CONFIG", } - if msgType < REGISTER || msgType > ANNOUNCE { + if msgType < REGISTER || msgType > CONFIG { return "Unknown" } return names[msgType] } -// GetIdentityMessageType Get the consensus message type from the identity message +// GetIdentityMessageType Get the identity message type from the identity message func GetIdentityMessageType(message []byte) (MessageType, error) { if len(message) < 1 { return 0, errors.New("Failed to get identity message type: no data available.") diff --git a/runid/run_identity.go b/runid/run_identity.go index 37de5082e..f8f0265dc 100644 --- a/runid/run_identity.go +++ b/runid/run_identity.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "time" "github.com/simple-rules/harmony-benchmark/identitychain" "github.com/simple-rules/harmony-benchmark/p2p" @@ -15,5 +16,15 @@ func main() { peer := p2p.Peer{Ip: *ip, Port: *port} IDC := identitychain.New(peer) fmt.Println(IDC) + epochTimer := time.NewTicker(10 * time.Second) + go func() { + for t := range epochTimer.C { + + fmt.Println("Changing epoch at ", t) + IDC.Shard() + + } + }() IDC.StartServer() + } diff --git a/runwait/run_wait.go b/runwait/run_wait.go index 62431c679..254efe598 100644 --- a/runwait/run_wait.go +++ b/runwait/run_wait.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "time" "github.com/simple-rules/harmony-benchmark/node" "github.com/simple-rules/harmony-benchmark/p2p" @@ -12,14 +13,18 @@ func main() { ip := flag.String("ip", "localhost", "IP of the node") port := flag.String("port", "8080", "port of the node") flag.Parse() + + i := 0 peer := p2p.Peer{Ip: *ip, Port: *port} + fmt.Println("Now onto node i", i) 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") + + time.Sleep(5 * time.Second) + //} } From 0c5e80cf6eecb59bbf9672643081e91cf2a26ecf Mon Sep 17 00:00:00 2001 From: Richard Liu Date: Thu, 6 Sep 2018 23:29:50 -0700 Subject: [PATCH 15/17] add arguments --- client/txgen/main.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/txgen/main.go b/client/txgen/main.go index 0951df84f..1fe71d770 100644 --- a/client/txgen/main.go +++ b/client/txgen/main.go @@ -33,6 +33,7 @@ type txGenSettings struct { numOfAddress int crossShard bool maxNumTxsPerBatch int + crossShardRatio int } var ( @@ -115,7 +116,7 @@ UTXOLOOP: randNum := rand.Intn(100) - if setting.crossShard && randNum < 30 { // 1/3 cross shard transactions: add another txinput from another shard + if setting.crossShard && randNum < setting.crossShardRatio { // 30% cross shard transactions: add another txinput from another shard generateCrossShardTx(&txInfo) } else { generateSingleShardTx(&txInfo) @@ -234,8 +235,9 @@ func main() { maxNumTxsPerBatch := flag.Int("max_num_txs_per_batch", 100000, "number of transactions to send per message") logFolder := flag.String("log_folder", "latest", "the folder collecting the logs of this execution") numSubset := flag.Int("numSubset", 3, "the number of subsets of utxos to process separately") - duration := flag.Int("duration", 60, "duration of the tx generation in second") + duration := flag.Int("duration", 60, "duration of the tx generation in second. If it's negative, the experiment runs forever.") versionFlag := flag.Bool("version", false, "Output version info") + crossShardRatio := flag.Int("cross_shard_ratio", 30, "The percentage of cross shard transactions.") flag.Parse() if *versionFlag { @@ -251,6 +253,7 @@ func main() { // Do cross shard tx if there are more than one shard setting.crossShard = len(shardIds) > 1 setting.maxNumTxsPerBatch = *maxNumTxsPerBatch + setting.crossShardRatio = *crossShardRatio // TODO(Richard): refactor this chuck to a single method // Setup a logger to stdout and log file. @@ -312,7 +315,7 @@ func main() { batchCounter := 0 for true { t := time.Now() - if t.Sub(start).Seconds() >= totalTime { + if totalTime > 0 && t.Sub(start).Seconds() >= totalTime { log.Debug("Generator timer ended.", "duration", (int(t.Sub(start))), "startTime", start, "totalTime", totalTime) break } From e4c6c303c8722bfd56437d25cb3b7d8e32636e59 Mon Sep 17 00:00:00 2001 From: Rongjian Lan Date: Fri, 7 Sep 2018 00:40:44 -0700 Subject: [PATCH 16/17] Fix cross shard tx unlocking issue, fix txgen random shardId duplication issue, add some more utility funcs in utxoPool --- blockchain/utxopool.go | 78 ++++++++++++++++++++++++++++++++++-------- client/client.go | 1 + client/txgen/main.go | 44 +++++++++++++++--------- node/node_handler.go | 12 ++++++- 4 files changed, 103 insertions(+), 32 deletions(-) diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 831b602cf..b978b0946 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -115,8 +115,9 @@ func (utxoPool *UTXOPool) VerifyStateBlock(stateBlock *Block) bool { } // VerifyOneTransaction verifies if a list of transactions valid. +// Add another sanity check function (e.g. spending the same utxo) called before this one. func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[[20]byte]map[string]map[uint32]bool) (err error, crossShard bool) { - if len(tx.Proofs) != 0 { + if len(tx.Proofs) > 1 { return utxoPool.VerifyUnlockTransaction(tx) } @@ -223,7 +224,7 @@ func (utxoPool *UTXOPool) Update(transactions []*Transaction) { // UpdateOneTransaction updates utxoPool in respect to the new Transaction. func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { - isUnlockTx := len(tx.Proofs) != 0 + isUnlockTx := len(tx.Proofs) > 1 unlockToCommit := true if isUnlockTx { for _, proof := range tx.Proofs { @@ -286,7 +287,6 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:]) if _, ok := utxoPool.LockedUtxoMap[in.Address]; !ok { utxoPool.LockedUtxoMap[in.Address] = make(TXHash2Vout2AmountMap) - utxoPool.LockedUtxoMap[in.Address][inTxID] = make(Vout2AmountMap) } if _, ok := utxoPool.LockedUtxoMap[in.Address][inTxID]; !ok { utxoPool.LockedUtxoMap[in.Address][inTxID] = make(Vout2AmountMap) @@ -300,16 +300,17 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { // Update if !isCrossShard || isUnlockTx { if !unlockToCommit { - if isValidCrossShard { - // unlock-to-abort, bring back (unlock) the utxo input - for _, in := range tx.TxInput { - // Only unlock the input for my own shard. - if in.ShardID != utxoPool.ShardID { - continue - } + // unlock-to-abort, bring back (unlock) the utxo input + for _, in := range tx.TxInput { + // Only unlock the input for my own shard. + if in.ShardID != utxoPool.ShardID { + continue + } - // Simply bring back the locked (removed) utxo - inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:]) + inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:]) + + if utxoPool.LockedUtxoExists(in.Address, inTxID, in.PreviousOutPoint.Index) { + // bring back the locked (removed) utxo if _, ok := utxoPool.UtxoMap[in.Address]; !ok { utxoPool.UtxoMap[in.Address] = make(TXHash2Vout2AmountMap) utxoPool.UtxoMap[in.Address][inTxID] = make(Vout2AmountMap) @@ -339,6 +340,17 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { } utxoPool.UtxoMap[out.Address][txID][uint32(index)] = out.Amount } + if isUnlockTx { // for unlock-to-commit transaction, also need to delete the locked utxo + for _, in := range tx.TxInput { + // Only unlock the input for my own shard. + if in.ShardID != utxoPool.ShardID { + continue + } + + inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:]) + utxoPool.DeleteOneLockedUtxo(in.Address, inTxID, in.PreviousOutPoint.Index) + } + } } } // If it's a cross shard locking Tx, then don't update so the input UTXOs are locked (removed), and the money is not spendable until unlock-to-commit or unlock-to-abort } @@ -397,12 +409,13 @@ func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transact if len(selected) < maxNumTxs { if err == nil || crossShard { - selected = append(selected, tx) if crossShard { proof := CrossShardTxProof{Accept: err == nil, TxID: tx.ID, TxInput: getShardTxInput(tx, utxoPool.ShardID)} txAndProof := CrossShardTxAndProof{tx, &proof} crossShardTxs = append(crossShardTxs, &txAndProof) + tx.Proofs = append(tx.Proofs, proof) } + selected = append(selected, tx) } else { invalid = append(invalid, tx) } @@ -434,6 +447,23 @@ func (utxoPool *UTXOPool) DeleteOneUtxo(address [20]byte, txID string, index uin } } +// DeleteOneBalanceItem deletes one balance item of UTXOPool and clean up if possible. +func (utxoPool *UTXOPool) LockedUtxoExists(address [20]byte, txID string, index uint32) bool { + _, ok := utxoPool.LockedUtxoMap[address] + if !ok { + return false + } + _, ok = utxoPool.LockedUtxoMap[address][txID] + if !ok { + return false + } + _, ok = utxoPool.LockedUtxoMap[address][txID][index] + if !ok { + return false + } + return true +} + // DeleteOneBalanceItem deletes one balance item of UTXOPool and clean up if possible. func (utxoPool *UTXOPool) DeleteOneLockedUtxo(address [20]byte, txID string, index uint32) { delete(utxoPool.LockedUtxoMap[address][txID], index) @@ -466,8 +496,17 @@ func (utxoPool *UTXOPool) CleanUp() { // Used for debugging. func (utxoPool *UTXOPool) String() string { + return printUtxos(&utxoPool.UtxoMap) +} + +// Used for debugging. +func (utxoPool *UTXOPool) StringOfLockedUtxos() string { + return printUtxos(&utxoPool.LockedUtxoMap) +} + +func printUtxos(utxos *UtxoMap) string { res := "" - for address, v1 := range utxoPool.UtxoMap { + for address, v1 := range *utxos { for txid, v2 := range v1 { for index, value := range v2 { res += fmt.Sprintf("address: %v, tx id: %v, index: %v, value: %v\n", address, txid, index, value) @@ -490,8 +529,17 @@ func (utxoPool *UTXOPool) GetSizeInByteOfUtxoMap() int { // A utility func that counts the total number of utxos in a pool. func (utxoPool *UTXOPool) CountNumOfUtxos() int { + return countNumOfUtxos(&utxoPool.UtxoMap) +} + +// A utility func that counts the total number of locked utxos in a pool. +func (utxoPool *UTXOPool) CountNumOfLockedUtxos() int { + return countNumOfUtxos(&utxoPool.LockedUtxoMap) +} + +func countNumOfUtxos(utxos *UtxoMap) int { countAll := 0 - for _, utxoMap := range utxoPool.UtxoMap { + for _, utxoMap := range *utxos { for txIdStr, val := range utxoMap { _, err := hex.DecodeString(txIdStr) if err != nil { diff --git a/client/client.go b/client/client.go index 32823eb2c..0a0d22b79 100644 --- a/client/client.go +++ b/client/client.go @@ -57,6 +57,7 @@ func (client *Client) TransactionMessageHandler(msgPayload []byte) { func (client *Client) handleProofOfLockMessage(proofs *[]blockchain.CrossShardTxProof) { txsToSend := []blockchain.Transaction{} + //fmt.Printf("PENDING CLIENT TX - %d\n", len(client.PendingCrossTxs)) // Loop through the newly received list of proofs client.PendingCrossTxsMutex.Lock() for _, proof := range *proofs { diff --git a/client/txgen/main.go b/client/txgen/main.go index 0951df84f..d7141678e 100644 --- a/client/txgen/main.go +++ b/client/txgen/main.go @@ -73,7 +73,7 @@ type TxInfo struct { // Returns: // all single-shard txs // all cross-shard txs -func generateSimulatedTransactions(subsetId, numSubset int, shardID int, dataNodes []*node.Node) ([]*blockchain.Transaction, []*blockchain.Transaction) { +func generateSimulatedTransactions(subsetId, numSubset int, shardId int, dataNodes []*node.Node) ([]*blockchain.Transaction, []*blockchain.Transaction) { /* UTXO map structure: address - [ @@ -90,13 +90,13 @@ func generateSimulatedTransactions(subsetId, numSubset int, shardID int, dataNod utxoPoolMutex.Lock() txInfo := TxInfo{} - txInfo.shardID = shardID + txInfo.shardID = shardId txInfo.dataNodes = dataNodes txInfo.txCount = 0 UTXOLOOP: // Loop over all addresses - for address, txMap := range dataNodes[shardID].UtxoPool.UtxoMap { + for address, txMap := range dataNodes[shardId].UtxoPool.UtxoMap { if int(binary.BigEndian.Uint32(address[:]))%numSubset == subsetId%numSubset { // Work on one subset of utxo at a time txInfo.address = address // Loop over all txIds for the address @@ -115,18 +115,22 @@ UTXOLOOP: randNum := rand.Intn(100) - if setting.crossShard && randNum < 30 { // 1/3 cross shard transactions: add another txinput from another shard - generateCrossShardTx(&txInfo) - } else { - generateSingleShardTx(&txInfo) - } - if txInfo.txCount >= setting.maxNumTxsPerBatch { - break UTXOLOOP + if randNum < 30 { + if setting.crossShard && randNum < 10 { // 1/3 cross shard transactions: add another txinput from another shard + generateCrossShardTx(&txInfo) + } else { + generateSingleShardTx(&txInfo) + } + if txInfo.txCount >= setting.maxNumTxsPerBatch { + break UTXOLOOP + } } } } } } + //fmt.Printf("UTXO CLIENT - %d\n", shardId) + //fmt.Println(dataNodes[shardId].UtxoPool.CountNumOfUtxos()) utxoPoolMutex.Unlock() log.Debug("[Generator] generated transations", "single-shard", len(txInfo.txs), "cross-shard", len(txInfo.crossTxs)) return txInfo.txs, txInfo.crossTxs @@ -134,8 +138,14 @@ UTXOLOOP: func generateCrossShardTx(txInfo *TxInfo) { nodeShardID := txInfo.dataNodes[txInfo.shardID].Consensus.ShardID + crossShardId := nodeShardID // a random shard to spend money to - crossShardId := rand.Intn(len(txInfo.dataNodes)) + for true { + crossShardId = uint32(rand.Intn(len(txInfo.dataNodes))) + if crossShardId != nodeShardID { + break + } + } crossShardNode := txInfo.dataNodes[crossShardId] crossShardUtxosMap := crossShardNode.UtxoPool.UtxoMap[txInfo.address] @@ -155,7 +165,7 @@ func generateCrossShardTx(txInfo *TxInfo) { for crossShardIndex, crossShardValue := range crossShardUtxos { crossUtxoValue = crossShardValue - crossTxin = blockchain.NewTXInput(blockchain.NewOutPoint(&crossTxId, crossShardIndex), txInfo.address, uint32(crossShardId)) + crossTxin = blockchain.NewTXInput(blockchain.NewOutPoint(&crossTxId, crossShardIndex), txInfo.address, crossShardId) break } if crossTxin != nil { @@ -179,7 +189,7 @@ func generateCrossShardTx(txInfo *TxInfo) { // Spend the utxo from the other shard, if any, to a random address in [0 - N) if crossTxin != nil { - crossTxout := blockchain.TXOutput{Amount: crossUtxoValue, Address: pki.GetAddressFromInt(rand.Intn(setting.numOfAddress) + 1), ShardID: uint32(crossShardId)} + crossTxout := blockchain.TXOutput{Amount: crossUtxoValue, Address: pki.GetAddressFromInt(rand.Intn(setting.numOfAddress) + 1), ShardID: crossShardId} txOutputs = append(txOutputs, crossTxout) } @@ -231,7 +241,7 @@ func printVersion(me string) { func main() { configFile := flag.String("config_file", "local_config.txt", "file containing all ip addresses and config") - maxNumTxsPerBatch := flag.Int("max_num_txs_per_batch", 100000, "number of transactions to send per message") + maxNumTxsPerBatch := flag.Int("max_num_txs_per_batch", 10000, "number of transactions to send per message") logFolder := flag.String("log_folder", "latest", "the folder collecting the logs of this execution") numSubset := flag.Int("numSubset", 3, "the number of subsets of utxos to process separately") duration := flag.Int("duration", 60, "duration of the tx generation in second") @@ -320,7 +330,7 @@ func main() { constructAndSendTransaction(batchCounter, *numSubset, shardId, leaders, nodes, clientNode, clientPort) } batchCounter++ - time.Sleep(2000 * time.Millisecond) + time.Sleep(5000 * time.Millisecond) } // Send a stop message to stop the nodes at the end @@ -337,13 +347,15 @@ func constructAndSendTransaction(subsetId, numSubset, shardId int, leaders []p2p txs, crossTxs := generateSimulatedTransactions(subsetId, numSubset, shardId, nodes) allCrossTxs = append(allCrossTxs, crossTxs...) - log.Debug("[Generator] Sending single-shard txs ...", "leader", leader, "numTxs", len(txs), "numCrossTxs", len(crossTxs)) + log.Debug("[Generator] Sending single-shard txs ...", "leader", leader, "numTxs", len(txs)) msg := proto_node.ConstructTransactionListMessage(txs) p2p.SendMessage(leader, msg) // Note cross shard txs are later sent in batch if len(allCrossTxs) > 0 { log.Debug("[Generator] Broadcasting cross-shard txs ...", "allCrossTxs", len(allCrossTxs)) + //fmt.Printf("SENDING CLIENT TXS: %d\n", shardId) + //fmt.Println(allCrossTxs) msg := proto_node.ConstructTransactionListMessage(allCrossTxs) p2p.BroadcastMessage(leaders, msg) diff --git a/node/node_handler.go b/node/node_handler.go index faf2312d6..f7916272b 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -22,7 +22,7 @@ const ( // The max number of transaction per a block. MaxNumberOfTransactionsPerBlock = 10000 // The number of blocks allowed before generating state block - NumBlocksBeforeStateBlock = 100 + NumBlocksBeforeStateBlock = 1000 ) // NodeHandler handles a new incoming connection. @@ -360,4 +360,14 @@ func (node *Node) UpdateUtxoAndState(newBlock *blockchain.Block) { } // Clear transaction-in-Consensus list node.transactionInConsensus = []*blockchain.Transaction{} + //if node.Consensus.IsLeader { + // fmt.Printf("TX in New BLOCK - %d %s\n", node.UtxoPool.ShardID, newBlock.IsStateBlock()) + // //fmt.Println(newBlock.Transactions) + // fmt.Printf("LEADER CURRENT UTXO - %d\n", node.UtxoPool.ShardID) + // fmt.Println(node.UtxoPool.CountNumOfUtxos()) + // //fmt.Println(node.UtxoPool) + // fmt.Printf("LEADER LOCKED UTXO - %d\n", node.UtxoPool.ShardID) + // fmt.Println(node.UtxoPool.CountNumOfLockedUtxos()) + // //fmt.Println(node.UtxoPool.StringOfLockedUtxos()) + //} } From dbbb29bf53f0fe6216b207ebc9fe11cc054c8477 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Fri, 7 Sep 2018 08:06:47 -0700 Subject: [PATCH 17/17] add test for merkle tree --- blockchain/merkle_tree.go | 20 ++++++++++++-------- blockchain/merkle_tree_test.go | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/blockchain/merkle_tree.go b/blockchain/merkle_tree.go index 0061520c3..b83ef8b3a 100644 --- a/blockchain/merkle_tree.go +++ b/blockchain/merkle_tree.go @@ -18,6 +18,9 @@ type MerkleNode struct { // NewMerkleTree creates a new Merkle tree from a sequence of data func NewMerkleTree(data [][]byte) *MerkleTree { + if len(data) == 0 { + return nil + } var nodes []*MerkleNode for _, datum := range data { @@ -49,15 +52,16 @@ func NewMerkleTree(data [][]byte) *MerkleTree { func NewMerkleNode(left, right *MerkleNode, data []byte) *MerkleNode { mNode := MerkleNode{} - if left == nil && right == nil { - hash := sha256.Sum256(data) - mNode.Data = hash[:] - } else { - prevHashes := append(left.Data, right.Data...) - hash := sha256.Sum256(prevHashes) - mNode.Data = hash[:] + prevHashes := []byte{} + if left != nil { + prevHashes = append(prevHashes, left.Data...) } - + if right != nil { + prevHashes = append(prevHashes, right.Data...) + } + prevHashes = append(prevHashes, data...) + hash := sha256.Sum256(prevHashes) + mNode.Data = hash[:] mNode.Left = left mNode.Right = right diff --git a/blockchain/merkle_tree_test.go b/blockchain/merkle_tree_test.go index ca5de9824..04a7adbee 100644 --- a/blockchain/merkle_tree_test.go +++ b/blockchain/merkle_tree_test.go @@ -13,6 +13,7 @@ func TestNewMerkleNode(t *testing.T) { []byte("node3"), } + fmt.Println("TEting") // Level 1 n1 := NewMerkleNode(nil, nil, data[0]) @@ -59,3 +60,23 @@ func TestNewMerkleTree(t *testing.T) { t.Errorf("Merkle tree root hash is incorrect") } } + +func TestNewMerkleTree2(t *testing.T) { + data := [][]byte{ + []byte("node1"), + []byte("node2"), + } + // Level 1 + n1 := NewMerkleNode(nil, nil, data[0]) + n2 := NewMerkleNode(nil, nil, data[1]) + + // Level 2 + n3 := NewMerkleNode(n1, n2, nil) + + rootHash := fmt.Sprintf("%x", n3.Data) + mTree := NewMerkleTree(data) + + if rootHash != fmt.Sprintf("%x", mTree.RootNode.Data) { + t.Errorf("Merkle tree root hash is incorrect") + } +}