Merge branch 'master' of github.com:harmony-one/harmony into rj_branch

pull/136/head
Rongjian Lan 6 years ago
commit 1aa5cc8ea9
  1. 32
      beaconchain/libs/beaconchain.go
  2. 7
      beaconchain/libs/beaconchain_handler.go
  3. 0
      beaconchain/libs/beaconchain_test.go
  4. 6
      beaconchain/main/main.go
  5. 13
      benchmark.go
  6. 10
      client/client.go
  7. 42
      client/txgen/main.go
  8. 12
      client/wallet/main.go
  9. 12
      client/wallet_v2/main.go
  10. 13
      consensus/consensus.go
  11. 7
      consensus/consensus_leader.go
  12. 9
      consensus/consensus_leader_msg_test.go
  13. 4
      consensus/consensus_test.go
  14. 7
      consensus/consensus_validator.go
  15. 8
      consensus/consensus_validator_msg_test.go
  16. 9
      deploy.sh
  17. 2
      go_executable_build.sh
  18. 78
      newnode/newnode.go
  19. 12
      newnode/newnode_handler.go
  20. 64
      node/node.go
  21. 24
      node/node_handler.go
  22. 183
      node/node_handler_p2p.go
  23. 37
      node/node_test.go
  24. 21
      node/p2p.go
  25. 31
      p2p/helper.go
  26. 55
      p2p/helper_test.go
  27. 13
      p2p/host/host.go
  28. 99
      p2p/host/hostv1/hostv1.go
  29. 94
      p2p/host/hostv2/hostv2.go
  30. 2
      p2p/host/hostv2/util.go
  31. 130
      p2p/host/message.go
  32. 28
      p2p/p2p.go
  33. 25
      p2p/p2pimpl/p2pimpl.go
  34. 146
      p2pv2/host.go
  35. 95
      services/explorer/rest.go
  36. 158
      services/explorer/rest_test.go
  37. 2
      services/syncing/downloader/client.go
  38. 0
      services/syncing/downloader/errors.go
  39. 0
      services/syncing/downloader/gen.sh
  40. 2
      services/syncing/downloader/interface.go
  41. 0
      services/syncing/downloader/proto/downloader.pb.go
  42. 0
      services/syncing/downloader/proto/downloader.proto
  43. 2
      services/syncing/downloader/server.go
  44. 4
      services/syncing/downloader/server_test.go
  45. 0
      services/syncing/errors.go
  46. 0
      services/syncing/interface.go
  47. 2
      services/syncing/syncing.go
  48. 6
      services/syncing/syncing_test.go
  49. 6
      utils/singleton_test.go
  50. 20
      utils/utils.go

@ -2,14 +2,14 @@ package beaconchain
import ( import (
"math/rand" "math/rand"
"net"
"os"
"sync" "sync"
"github.com/dedis/kyber" "github.com/dedis/kyber"
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/proto/bcconn" "github.com/harmony-one/harmony/proto/bcconn"
proto_identity "github.com/harmony-one/harmony/proto/identity" proto_identity "github.com/harmony-one/harmony/proto/identity"
"github.com/harmony-one/harmony/utils" "github.com/harmony-one/harmony/utils"
@ -28,6 +28,7 @@ type BeaconChain struct {
NumberOfNodesAdded int NumberOfNodesAdded int
IP string IP string
Port string Port string
host host.Host
} }
//New beaconchain initialization //New beaconchain initialization
@ -35,14 +36,15 @@ func New(numShards int, ip, port string) *BeaconChain {
bc := BeaconChain{} bc := BeaconChain{}
bc.log = log.New() bc.log = log.New()
bc.NumberOfShards = numShards bc.NumberOfShards = numShards
bc.PubKey = generateIDCKeys() bc.PubKey = generateBCKey()
bc.NumberOfNodesAdded = 0 bc.NumberOfNodesAdded = 0
bc.Port = port bc.Port = port
bc.IP = ip bc.IP = ip
bc.host = p2pimpl.NewHost(p2p.Peer{IP: ip, Port: port})
return &bc return &bc
} }
func generateIDCKeys() kyber.Point { func generateBCKey() kyber.Point {
r := rand.Intn(1000) r := rand.Intn(1000)
priKey := pki.GetPrivateKeyFromInt(r) priKey := pki.GetPrivateKeyFromInt(r)
pubkey := pki.GetPublicKeyFromPrivateKey(priKey) pubkey := pki.GetPublicKeyFromPrivateKey(priKey)
@ -61,28 +63,10 @@ func (bc *BeaconChain) AcceptConnections(b []byte) {
response := bcconn.ResponseRandomNumber{NumberOfShards: bc.NumberOfShards, NumberOfNodesAdded: bc.NumberOfNodesAdded, Leaders: bc.Leaders} response := bcconn.ResponseRandomNumber{NumberOfShards: bc.NumberOfShards, NumberOfNodesAdded: bc.NumberOfNodesAdded, Leaders: bc.Leaders}
msg := bcconn.SerializeRandomInfo(response) msg := bcconn.SerializeRandomInfo(response)
msgToSend := proto_identity.ConstructIdentityMessage(proto_identity.Acknowledge, msg) msgToSend := proto_identity.ConstructIdentityMessage(proto_identity.Acknowledge, msg)
p2p.SendMessage(Node.Self, msgToSend) host.SendMessage(bc.host, Node.Self, msgToSend)
} }
//StartServer a server and process the request by a handler. //StartServer a server and process the request by a handler.
func (bc *BeaconChain) StartServer() { func (bc *BeaconChain) StartServer() {
bc.log.Info("Starting Beaconchain server ...") bc.host.BindHandlerAndServe(bc.BeaconChainHandler)
ip := bc.IP
port := bc.Port
addr := net.JoinHostPort(ip, port)
listen, err := net.Listen("tcp", addr)
if err != nil {
bc.log.Crit("Socket listen port failed")
os.Exit(1)
}
defer listen.Close()
for {
bc.log.Info("beacon chain is now listening ..")
conn, err := listen.Accept()
if err != nil {
bc.log.Crit("Error listening on port. Exiting", "8081")
continue
}
go bc.BeaconChainHandler(conn)
}
} }

@ -1,21 +1,18 @@
package beaconchain package beaconchain
import ( import (
"net"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/proto" "github.com/harmony-one/harmony/proto"
proto_identity "github.com/harmony-one/harmony/proto/identity" proto_identity "github.com/harmony-one/harmony/proto/identity"
) )
// BeaconChainHandler handles registration of new Identities // BeaconChainHandler handles registration of new Identities
func (bc *BeaconChain) BeaconChainHandler(conn net.Conn) { func (bc *BeaconChain) BeaconChainHandler(s p2p.Stream) {
content, err := p2p.ReadMessageContent(conn) content, err := p2p.ReadMessageContent(s)
if err != nil { if err != nil {
bc.log.Error("Read p2p data failed") bc.log.Error("Read p2p data failed")
return return
} }
bc.log.Info("received connection", "connectionIp", conn.RemoteAddr())
msgCategory, err := proto.GetMessageCategory(content) msgCategory, err := proto.GetMessageCategory(content)
if err != nil { if err != nil {
bc.log.Error("Read message category failed", "err", err) bc.log.Error("Read message category failed", "err", err)

@ -6,7 +6,8 @@ import (
"os" "os"
"path" "path"
"github.com/harmony-one/harmony/beaconchain" beaconchain "github.com/harmony-one/harmony/beaconchain/libs"
"github.com/harmony-one/harmony/log"
) )
var ( var (
@ -33,6 +34,9 @@ func main() {
printVersion(os.Args[0]) printVersion(os.Args[0])
} }
h := log.StdoutHandler
log.Root().SetHandler(h)
bc := beaconchain.New(*numShards, *ip, *port) bc := beaconchain.New(*numShards, *ip, *port)
bc.StartServer() bc.StartServer()
} }

@ -9,6 +9,8 @@ import (
"runtime" "runtime"
"time" "time"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/attack" "github.com/harmony-one/harmony/attack"
"github.com/harmony-one/harmony/consensus" "github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/db" "github.com/harmony-one/harmony/db"
@ -117,13 +119,11 @@ func main() {
if *peerDiscovery { if *peerDiscovery {
candidateNode := pkg_newnode.New(*ip, *port) candidateNode := pkg_newnode.New(*ip, *port)
BCPeer := p2p.Peer{IP: *idcIP, Port: *idcPort} BCPeer := p2p.Peer{IP: *idcIP, Port: *idcPort}
service := candidateNode.NewService(*ip, *port) candidateNode.ContactBeaconChain(BCPeer)
candidateNode.ConnectBeaconChain(BCPeer)
shardID = candidateNode.GetShardID() shardID = candidateNode.GetShardID()
leader = candidateNode.GetLeader() leader = candidateNode.GetLeader()
selfPeer = candidateNode.GetSelfPeer() selfPeer = candidateNode.GetSelfPeer()
clientPeer = candidateNode.GetClientPeer() clientPeer = candidateNode.GetClientPeer()
service.Stop()
selfPeer.PubKey = candidateNode.PubK selfPeer.PubKey = candidateNode.PubK
} else { } else {
@ -162,8 +162,9 @@ func main() {
ldb, _ = InitLDBDatabase(*ip, *port) ldb, _ = InitLDBDatabase(*ip, *port)
} }
host := p2pimpl.NewHost(selfPeer)
// Consensus object. // Consensus object.
consensus := consensus.New(selfPeer, shardID, peers, leader) consensus := consensus.New(host, shardID, peers, leader)
consensus.MinPeers = *minPeers consensus.MinPeers = *minPeers
// Start Profiler for leader if profile argument is on // Start Profiler for leader if profile argument is on
@ -178,9 +179,7 @@ func main() {
// Set logger to attack model. // Set logger to attack model.
attack.GetInstance().SetLogger(consensus.Log) attack.GetInstance().SetLogger(consensus.Log)
// Current node. // Current node.
currentNode := node.New(consensus, ldb, selfPeer) currentNode := node.New(host, consensus, ldb)
// Add self peer.
currentNode.SelfPeer = selfPeer
// If there is a client configured in the node list. // If there is a client configured in the node list.
if clientPeer != nil { if clientPeer != nil {
currentNode.ClientPeer = clientPeer currentNode.ClientPeer = clientPeer

@ -5,6 +5,7 @@ import (
"encoding/gob" "encoding/gob"
"sync" "sync"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/proto/node" "github.com/harmony-one/harmony/proto/node"
"github.com/harmony-one/harmony/blockchain" "github.com/harmony-one/harmony/blockchain"
@ -23,6 +24,9 @@ type Client struct {
ShardUtxoMap map[uint32]blockchain.UtxoMap ShardUtxoMap map[uint32]blockchain.UtxoMap
ShardUtxoMapMutex sync.Mutex // Mutex for the UTXO maps ShardUtxoMapMutex sync.Mutex // Mutex for the UTXO maps
log log.Logger // Log utility log log.Logger // Log utility
// The p2p host used to send/receive p2p messages
host host.Host
} }
// TransactionMessageHandler is the message handler for Client/Transaction messages. // TransactionMessageHandler is the message handler for Client/Transaction messages.
@ -120,16 +124,16 @@ func (client *Client) handleFetchUtxoResponseMessage(utxoResponse client_proto.F
func (client *Client) sendCrossShardTxUnlockMessage(txsToSend []*blockchain.Transaction) { func (client *Client) sendCrossShardTxUnlockMessage(txsToSend []*blockchain.Transaction) {
for shardID, txs := range BuildOutputShardTransactionMap(txsToSend) { for shardID, txs := range BuildOutputShardTransactionMap(txsToSend) {
p2p.SendMessage((*client.Leaders)[shardID], node.ConstructUnlockToCommitOrAbortMessage(txs)) host.SendMessage(client.host, (*client.Leaders)[shardID], node.ConstructUnlockToCommitOrAbortMessage(txs))
} }
} }
// NewClient creates a new Client // NewClient creates a new Client
func NewClient(leaders *map[uint32]p2p.Peer) *Client { func NewClient(host host.Host, leaders *map[uint32]p2p.Peer) *Client {
client := Client{} client := Client{}
client.PendingCrossTxs = make(map[[32]byte]*blockchain.Transaction) client.PendingCrossTxs = make(map[[32]byte]*blockchain.Transaction)
client.Leaders = leaders client.Leaders = leaders
client.host = host
// Logger // Logger
client.log = log.New() client.log = log.New()
return &client return &client

@ -21,6 +21,7 @@ import (
"github.com/harmony-one/harmony/newnode" "github.com/harmony-one/harmony/newnode"
"github.com/harmony-one/harmony/node" "github.com/harmony-one/harmony/node"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
proto_node "github.com/harmony-one/harmony/proto/node" proto_node "github.com/harmony-one/harmony/proto/node"
"github.com/harmony-one/harmony/utils" "github.com/harmony-one/harmony/utils"
) )
@ -70,21 +71,15 @@ func main() {
var config *client_config.Config var config *client_config.Config
if *peerDiscovery { if *peerDiscovery {
candidateNode := newnode.New(*ip, *port) candidateNode := newnode.New(*ip, *port)
BCPeer := p2p.Peer{IP: *idcIP, Port: *idcPort} BCPeer := p2p.Peer{IP: *idcIP, Port: *idcPort}
service := candidateNode.NewService(*ip, *port) candidateNode.ContactBeaconChain(BCPeer)
candidateNode.ConnectBeaconChain(BCPeer)
peers = nil peers = nil
service.Stop()
clientPeer = &p2p.Peer{IP: *ip, Port: *port} clientPeer = &p2p.Peer{IP: *ip, Port: *port}
_, pubKey := utils.GenKey(clientPeer.IP, clientPeer.Port) _, pubKey := utils.GenKey(clientPeer.IP, clientPeer.Port)
clientPeer.PubKey = pubKey clientPeer.PubKey = pubKey
shardIDLeaderMap = candidateNode.Leaders shardIDLeaderMap = candidateNode.Leaders
} else { } else {
// Read the configs // Read the configs
config = client_config.NewConfig() config = client_config.NewConfig()
@ -94,6 +89,9 @@ func main() {
_, pubKey := utils.GenKey(clientPeer.IP, clientPeer.Port) _, pubKey := utils.GenKey(clientPeer.IP, clientPeer.Port)
clientPeer.PubKey = pubKey clientPeer.PubKey = pubKey
} }
if clientPeer == nil {
panic("Client Peer is nil!")
}
debugPrintShardIDLeaderMap(shardIDLeaderMap) debugPrintShardIDLeaderMap(shardIDLeaderMap)
// Do cross shard tx if there are more than one shard // Do cross shard tx if there are more than one shard
@ -116,20 +114,20 @@ func main() {
// Nodes containing utxopools to mirror the shards' data in the network // Nodes containing utxopools to mirror the shards' data in the network
nodes := []*node.Node{} nodes := []*node.Node{}
for shardID := range shardIDLeaderMap { for shardID := range shardIDLeaderMap {
node := node.New(&consensus.Consensus{ShardID: shardID}, nil, *clientPeer) _, pubKey := utils.GenKey(clientPeer.IP, clientPeer.Port)
clientPeer.PubKey = pubKey
host := p2pimpl.NewHost(*clientPeer)
node := node.New(host, &consensus.Consensus{ShardID: shardID}, nil)
// Assign many fake addresses so we have enough address to play with at first // Assign many fake addresses so we have enough address to play with at first
node.AddTestingAddresses(setting.NumOfAddress) node.AddTestingAddresses(setting.NumOfAddress)
nodes = append(nodes, node) nodes = append(nodes, node)
} }
// Client/txgenerator server node setup // Client/txgenerator server node setup
if clientPeer == nil { host := p2pimpl.NewHost(*clientPeer)
panic("Client Peer is nil!") consensusObj := consensus.New(host, "0", nil, p2p.Peer{})
} clientNode := node.New(host, consensusObj, nil)
consensusObj := consensus.New(*clientPeer, "0", nil, p2p.Peer{}) clientNode.Client = client.NewClient(clientNode.GetHost(), &shardIDLeaderMap)
clientNode := node.New(consensusObj, nil, *clientPeer)
clientNode.Client = client.NewClient(&shardIDLeaderMap)
// This func is used to update the client's utxopool when new blocks are received from the leaders // This func is used to update the client's utxopool when new blocks are received from the leaders
updateBlocksFunc := func(blocks []*blockchain.Block) { updateBlocksFunc := func(blocks []*blockchain.Block) {
@ -222,7 +220,7 @@ func main() {
lock.Lock() lock.Lock()
for shardID, txs := range shardIDTxsMap { // Send the txs to corresponding shards for shardID, txs := range shardIDTxsMap { // Send the txs to corresponding shards
go func(shardID uint32, txs types.Transactions) { go func(shardID uint32, txs types.Transactions) {
SendTxsToLeaderAccount(shardIDLeaderMap[shardID], txs) SendTxsToLeaderAccount(clientNode, shardIDLeaderMap[shardID], txs)
}(shardID, txs) }(shardID, txs)
} }
lock.Unlock() lock.Unlock()
@ -275,7 +273,7 @@ func main() {
lock.Lock() lock.Lock()
for shardID, txs := range shardIDTxsMap { // Send the txs to corresponding shards for shardID, txs := range shardIDTxsMap { // Send the txs to corresponding shards
go func(shardID uint32, txs []*blockchain.Transaction) { go func(shardID uint32, txs []*blockchain.Transaction) {
SendTxsToLeader(shardIDLeaderMap[shardID], txs) SendTxsToLeader(clientNode, shardIDLeaderMap[shardID], txs)
}(shardID, txs) }(shardID, txs)
} }
lock.Unlock() lock.Unlock()
@ -292,22 +290,22 @@ func main() {
} else { } else {
peers = append(config.GetValidators(), clientNode.Client.GetLeaders()...) peers = append(config.GetValidators(), clientNode.Client.GetLeaders()...)
} }
p2p.BroadcastMessage(peers, msg) clientNode.BroadcastMessage(peers, msg)
time.Sleep(3000 * time.Millisecond) time.Sleep(3000 * time.Millisecond)
} }
// SendTxsToLeader sends txs to leader. // SendTxsToLeader sends txs to leader.
func SendTxsToLeader(leader p2p.Peer, txs []*blockchain.Transaction) { func SendTxsToLeader(clientNode *node.Node, leader p2p.Peer, txs []*blockchain.Transaction) {
log.Debug("[Generator] Sending txs to...", "leader", leader, "numTxs", len(txs)) log.Debug("[Generator] Sending txs to...", "leader", leader, "numTxs", len(txs))
msg := proto_node.ConstructTransactionListMessage(txs) msg := proto_node.ConstructTransactionListMessage(txs)
p2p.SendMessage(leader, msg) clientNode.SendMessage(leader, msg)
} }
// SendTxsToLeaderAccount sends txs to leader account. // SendTxsToLeaderAccount sends txs to leader account.
func SendTxsToLeaderAccount(leader p2p.Peer, txs types.Transactions) { func SendTxsToLeaderAccount(clientNode *node.Node, leader p2p.Peer, txs types.Transactions) {
log.Debug("[Generator] Sending account-based txs to...", "leader", leader, "numTxs", len(txs)) log.Debug("[Generator] Sending account-based txs to...", "leader", leader, "numTxs", len(txs))
msg := proto_node.ConstructTransactionListMessageAccount(txs) msg := proto_node.ConstructTransactionListMessageAccount(txs)
p2p.SendMessage(leader, msg) clientNode.SendMessage(leader, msg)
} }
func debugPrintShardIDLeaderMap(leaderMap map[uint32]p2p.Peer) { func debugPrintShardIDLeaderMap(leaderMap map[uint32]p2p.Peer) {

@ -9,6 +9,8 @@ import (
"log" "log"
"strings" "strings"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"io" "io"
"io/ioutil" "io/ioutil"
math_rand "math/rand" math_rand "math/rand"
@ -257,9 +259,9 @@ func CreateWalletServerNode() *node.Node {
shardIDLeaderMap = getShardIDToLeaderMap() shardIDLeaderMap = getShardIDToLeaderMap()
clientPeer = &p2p.Peer{Port: "127.0.0.1", IP: "1234"} clientPeer = &p2p.Peer{Port: "127.0.0.1", IP: "1234"}
} }
walletNode := node.New(nil, nil, *clientPeer) // TODO(ricl): shouldn't the selfPeer for client being clientPeer?? host := p2pimpl.NewHost(*clientPeer)
walletNode.Client = client.NewClient(&shardIDLeaderMap) walletNode := node.New(host, nil, nil)
walletNode.ClientPeer = clientPeer walletNode.Client = client.NewClient(walletNode.GetHost(), &shardIDLeaderMap)
return walletNode return walletNode
} }
@ -272,7 +274,7 @@ func ExecuteTransaction(tx blockchain.Transaction, walletNode *node.Node) error
} }
msg := proto_node.ConstructTransactionListMessage([]*blockchain.Transaction{&tx}) msg := proto_node.ConstructTransactionListMessage([]*blockchain.Transaction{&tx})
p2p.BroadcastMessage(walletNode.Client.GetLeaders(), msg) walletNode.BroadcastMessage(walletNode.Client.GetLeaders(), msg)
doneSignal := make(chan int) doneSignal := make(chan int)
go func() { go func() {
@ -297,7 +299,7 @@ func ExecuteTransaction(tx blockchain.Transaction, walletNode *node.Node) error
func FetchUtxos(addresses [][20]byte, walletNode *node.Node) (map[uint32]blockchain.UtxoMap, error) { func FetchUtxos(addresses [][20]byte, walletNode *node.Node) (map[uint32]blockchain.UtxoMap, error) {
fmt.Println("Fetching account balance...") fmt.Println("Fetching account balance...")
walletNode.Client.ShardUtxoMap = make(map[uint32]blockchain.UtxoMap) walletNode.Client.ShardUtxoMap = make(map[uint32]blockchain.UtxoMap)
p2p.BroadcastMessage(walletNode.Client.GetLeaders(), proto_node.ConstructFetchUtxoMessage(*walletNode.ClientPeer, addresses)) walletNode.BroadcastMessage(walletNode.Client.GetLeaders(), proto_node.ConstructFetchUtxoMessage(*walletNode.ClientPeer, addresses))
doneSignal := make(chan int) doneSignal := make(chan int)
go func() { go func() {

@ -9,6 +9,8 @@ import (
"log" "log"
"strings" "strings"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"io" "io"
"io/ioutil" "io/ioutil"
math_rand "math/rand" math_rand "math/rand"
@ -257,9 +259,9 @@ func CreateWalletServerNode() *node.Node {
shardIDLeaderMap = getShardIDToLeaderMap() shardIDLeaderMap = getShardIDToLeaderMap()
clientPeer = &p2p.Peer{Port: "127.0.0.1", IP: "1234"} clientPeer = &p2p.Peer{Port: "127.0.0.1", IP: "1234"}
} }
walletNode := node.New(nil, nil, *clientPeer) host := p2pimpl.NewHost(*clientPeer)
walletNode.Client = client.NewClient(&shardIDLeaderMap) walletNode := node.New(host, nil, nil)
walletNode.ClientPeer = clientPeer walletNode.Client = client.NewClient(walletNode.GetHost(), &shardIDLeaderMap)
return walletNode return walletNode
} }
@ -272,7 +274,7 @@ func ExecuteTransaction(tx blockchain.Transaction, walletNode *node.Node) error
} }
msg := proto_node.ConstructTransactionListMessage([]*blockchain.Transaction{&tx}) msg := proto_node.ConstructTransactionListMessage([]*blockchain.Transaction{&tx})
p2p.BroadcastMessage(walletNode.Client.GetLeaders(), msg) walletNode.BroadcastMessage(walletNode.Client.GetLeaders(), msg)
doneSignal := make(chan int) doneSignal := make(chan int)
go func() { go func() {
@ -297,7 +299,7 @@ func ExecuteTransaction(tx blockchain.Transaction, walletNode *node.Node) error
func FetchUtxos(addresses [][20]byte, walletNode *node.Node) (map[uint32]blockchain.UtxoMap, error) { func FetchUtxos(addresses [][20]byte, walletNode *node.Node) (map[uint32]blockchain.UtxoMap, error) {
fmt.Println("Fetching account balance...") fmt.Println("Fetching account balance...")
walletNode.Client.ShardUtxoMap = make(map[uint32]blockchain.UtxoMap) walletNode.Client.ShardUtxoMap = make(map[uint32]blockchain.UtxoMap)
p2p.BroadcastMessage(walletNode.Client.GetLeaders(), proto_node.ConstructFetchUtxoMessage(*walletNode.ClientPeer, addresses)) walletNode.BroadcastMessage(walletNode.Client.GetLeaders(), proto_node.ConstructFetchUtxoMessage(*walletNode.ClientPeer, addresses))
doneSignal := make(chan int) doneSignal := make(chan int)
go func() { go func() {

@ -19,6 +19,7 @@ import (
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/utils" "github.com/harmony-one/harmony/utils"
) )
@ -95,6 +96,9 @@ type Consensus struct {
Log log.Logger Log log.Logger
uniqueIDInstance *utils.UniqueValidatorID uniqueIDInstance *utils.UniqueValidatorID
// The p2p host used to send/receive p2p messages
host host.Host
} }
// BlockConsensusStatus used to keep track of the consensus status of multiple blocks received so far // BlockConsensusStatus used to keep track of the consensus status of multiple blocks received so far
@ -109,9 +113,11 @@ type BlockConsensusStatus struct {
} }
// New creates a new Consensus object // New creates a new Consensus object
func New(selfPeer p2p.Peer, ShardID string, peers []p2p.Peer, leader p2p.Peer) *Consensus { func New(host host.Host, ShardID string, peers []p2p.Peer, leader p2p.Peer) *Consensus {
consensus := Consensus{} consensus := Consensus{}
consensus.host = host
selfPeer := host.GetSelfPeer()
if leader.Port == selfPeer.Port && leader.IP == selfPeer.IP { if leader.Port == selfPeer.Port && leader.IP == selfPeer.IP {
consensus.IsLeader = true consensus.IsLeader = true
} else { } else {
@ -411,3 +417,8 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
func (consensus *Consensus) GetNodeID() uint16 { func (consensus *Consensus) GetNodeID() uint16 {
return consensus.nodeID return consensus.nodeID
} }
// SendMessage sends message thru p2p host to peer.
func (consensus *Consensus) SendMessage(peer p2p.Peer, message []byte) {
host.SendMessage(consensus.host, peer, message)
}

@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/profiler" "github.com/harmony-one/harmony/profiler"
@ -133,7 +134,7 @@ func (consensus *Consensus) startConsensus(newBlock *blockchain.Block) {
consensus.Log.Debug("Stop encoding block") consensus.Log.Debug("Stop encoding block")
msgToSend := consensus.constructAnnounceMessage() msgToSend := consensus.constructAnnounceMessage()
p2p.BroadcastMessageFromLeader(consensus.GetValidatorPeers(), msgToSend) host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend)
// Set state to AnnounceDone // Set state to AnnounceDone
consensus.state = AnnounceDone consensus.state = AnnounceDone
consensus.commitByLeader(true) consensus.commitByLeader(true)
@ -260,7 +261,7 @@ func (consensus *Consensus) processCommitMessage(payload []byte, targetState Sta
consensus.responseByLeader(challengeScalar, targetState == ChallengeDone) consensus.responseByLeader(challengeScalar, targetState == ChallengeDone)
// Broadcast challenge message // Broadcast challenge message
p2p.BroadcastMessageFromLeader(consensus.GetValidatorPeers(), msgToSend) host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend)
// Set state to targetState (ChallengeDone or FinalChallengeDone) // Set state to targetState (ChallengeDone or FinalChallengeDone)
consensus.state = targetState consensus.state = targetState
@ -417,7 +418,7 @@ func (consensus *Consensus) processResponseMessage(payload []byte, targetState S
// Start the second round of Cosi // Start the second round of Cosi
msgToSend := consensus.constructCollectiveSigMessage(collectiveSig, bitmap) msgToSend := consensus.constructCollectiveSigMessage(collectiveSig, bitmap)
p2p.BroadcastMessageFromLeader(consensus.GetValidatorPeers(), msgToSend) host.BroadcastMessageFromLeader(consensus.host, consensus.GetValidatorPeers(), msgToSend)
consensus.commitByLeader(false) consensus.commitByLeader(false)
} else { } else {
consensus.Log.Debug("Consensus reached with signatures.", "numOfSignatures", len(*responses)) consensus.Log.Debug("Consensus reached with signatures.", "numOfSignatures", len(*responses))

@ -3,6 +3,8 @@ package consensus
import ( import (
"testing" "testing"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/crypto"
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
@ -12,7 +14,8 @@ import (
func TestConstructAnnounceMessage(test *testing.T) { func TestConstructAnnounceMessage(test *testing.T) {
leader := p2p.Peer{IP: "1", Port: "2"} leader := p2p.Peer{IP: "1", Port: "2"}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := New(host, "0", []p2p.Peer{leader, validator}, leader)
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
header := consensus.blockHeader header := consensus.blockHeader
msg := consensus.constructAnnounceMessage() msg := consensus.constructAnnounceMessage()
@ -34,8 +37,8 @@ func TestConstructChallengeMessage(test *testing.T) {
validatorPriKey.UnmarshalBinary(priKeyInBytes[:]) validatorPriKey.UnmarshalBinary(priKeyInBytes[:])
validatorPubKey := pki.GetPublicKeyFromScalar(leaderPriKey) validatorPubKey := pki.GetPublicKeyFromScalar(leaderPriKey)
validator := p2p.Peer{IP: "3", Port: "5", PubKey: validatorPubKey} validator := p2p.Peer{IP: "3", Port: "5", PubKey: validatorPubKey}
host := p2pimpl.NewHost(leader)
consensus := New(leader, "0", []p2p.Peer{leader, validator}, leader) consensus := New(host, "0", []p2p.Peer{leader, validator}, leader)
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
(*consensus.commitments)[0] = leaderPubKey (*consensus.commitments)[0] = leaderPubKey
(*consensus.commitments)[1] = validatorPubKey (*consensus.commitments)[1] = validatorPubKey

@ -4,12 +4,14 @@ import (
"testing" "testing"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
) )
func TestNew(test *testing.T) { func TestNew(test *testing.T) {
leader := p2p.Peer{IP: "1", Port: "2"} leader := p2p.Peer{IP: "1", Port: "2"}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := New(host, "0", []p2p.Peer{leader, validator}, leader)
if consensus.consensusID != 0 { if consensus.consensusID != 0 {
test.Errorf("Consensus Id is initialized to the wrong value: %d", consensus.consensusID) test.Errorf("Consensus Id is initialized to the wrong value: %d", consensus.consensusID)
} }

@ -10,7 +10,6 @@ import (
"github.com/harmony-one/harmony/blockchain" "github.com/harmony-one/harmony/blockchain"
"github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/crypto"
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p"
proto_consensus "github.com/harmony-one/harmony/proto/consensus" proto_consensus "github.com/harmony-one/harmony/proto/consensus"
"github.com/harmony-one/harmony/utils" "github.com/harmony-one/harmony/utils"
) )
@ -130,7 +129,7 @@ func (consensus *Consensus) processAnnounceMessage(payload []byte) {
// Store the commitment secret // Store the commitment secret
consensus.secret[consensusID] = secret consensus.secret[consensusID] = secret
p2p.SendMessage(consensus.leader, msgToSend) consensus.SendMessage(consensus.leader, msgToSend)
// consensus.Log.Warn("Sending Commit to leader", "state", targetState) // consensus.Log.Warn("Sending Commit to leader", "state", targetState)
// Set state to CommitDone // Set state to CommitDone
@ -249,7 +248,7 @@ func (consensus *Consensus) processChallengeMessage(payload []byte, targetState
} }
msgToSend := consensus.constructResponseMessage(msgTypeToSend, response) msgToSend := consensus.constructResponseMessage(msgTypeToSend, response)
p2p.SendMessage(consensus.leader, msgToSend) consensus.SendMessage(consensus.leader, msgToSend)
// consensus.Log.Warn("Sending Response to leader", "state", targetState) // consensus.Log.Warn("Sending Response to leader", "state", targetState)
// Set state to target state (ResponseDone, FinalResponseDone) // Set state to target state (ResponseDone, FinalResponseDone)
consensus.state = targetState consensus.state = targetState
@ -367,7 +366,7 @@ func (consensus *Consensus) processCollectiveSigMessage(payload []byte) {
// Store the commitment secret // Store the commitment secret
consensus.secret[consensusID] = secret consensus.secret[consensusID] = secret
p2p.SendMessage(consensus.leader, msgToSend) consensus.SendMessage(consensus.leader, msgToSend)
// Set state to CommitDone // Set state to CommitDone
consensus.state = FinalCommitDone consensus.state = FinalCommitDone

@ -3,6 +3,8 @@ package consensus
import ( import (
"testing" "testing"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/crypto"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
consensus_proto "github.com/harmony-one/harmony/proto/consensus" consensus_proto "github.com/harmony-one/harmony/proto/consensus"
@ -11,7 +13,8 @@ import (
func TestConstructCommitMessage(test *testing.T) { func TestConstructCommitMessage(test *testing.T) {
leader := p2p.Peer{IP: "1", Port: "2"} leader := p2p.Peer{IP: "1", Port: "2"}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := New(host, "0", []p2p.Peer{leader, validator}, leader)
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
_, msg := consensus.constructCommitMessage(consensus_proto.Commit) _, msg := consensus.constructCommitMessage(consensus_proto.Commit)
@ -23,7 +26,8 @@ func TestConstructCommitMessage(test *testing.T) {
func TestConstructResponseMessage(test *testing.T) { func TestConstructResponseMessage(test *testing.T) {
leader := p2p.Peer{IP: "1", Port: "2"} leader := p2p.Peer{IP: "1", Port: "2"}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := New(host, "0", []p2p.Peer{leader, validator}, leader)
consensus.blockHash = [32]byte{} consensus.blockHash = [32]byte{}
msg := consensus.constructResponseMessage(consensus_proto.Response, crypto.Ed25519Curve.Scalar()) msg := consensus.constructResponseMessage(consensus_proto.Response, crypto.Ed25519Curve.Scalar())

@ -24,6 +24,7 @@ USAGE: $ME [OPTIONS] config_file_name
-t toggle txgen (default: $TXGEN) -t toggle txgen (default: $TXGEN)
-D duration txgen run duration (default: $DURATION) -D duration txgen run duration (default: $DURATION)
-m min_peers minimal number of peers to start consensus (default: $MIN) -m min_peers minimal number of peers to start consensus (default: $MIN)
-s shards number of shards (default: $SHARDS)
This script will build all the binaries and start benchmark and txgen based on the configuration file. This script will build all the binaries and start benchmark and txgen based on the configuration file.
@ -41,8 +42,9 @@ DB=
TXGEN=true TXGEN=true
DURATION=90 DURATION=90
MIN=5 MIN=5
SHARDS=2
while getopts "hpdtD:m:" option; do while getopts "hpdtD:m:s:" option; do
case $option in case $option in
h) usage ;; h) usage ;;
p) PEER='-peer_discovery' ;; p) PEER='-peer_discovery' ;;
@ -50,6 +52,7 @@ while getopts "hpdtD:m:" option; do
t) TXGEN=false ;; t) TXGEN=false ;;
D) DURATION=$OPTARG ;; D) DURATION=$OPTARG ;;
m) MIN=$OPTARG ;; m) MIN=$OPTARG ;;
s) SHARDS=$OPTARG ;;
esac esac
done done
@ -72,7 +75,7 @@ cleanup
echo "compiling ..." echo "compiling ..."
go build -o bin/benchmark go build -o bin/benchmark
go build -o bin/txgen client/txgen/main.go go build -o bin/txgen client/txgen/main.go
go build -o bin/beacon runbeacon/run-beacon.go go build -o bin/beacon beaconchain/main/main.go
# Create a tmp folder for logs # Create a tmp folder for logs
t=`date +"%Y%m%d-%H%M%S"` t=`date +"%Y%m%d-%H%M%S"`
@ -82,7 +85,7 @@ mkdir -p $log_folder
if [ -n "$PEER" ]; then if [ -n "$PEER" ]; then
echo "launching beacon chain ..." echo "launching beacon chain ..."
./bin/beacon > $log_folder/beacon.log 2>&1 & ./bin/beacon -numShards $SHARDS > $log_folder/beacon.log 2>&1 &
sleep 1 #wait or beachchain up sleep 1 #wait or beachchain up
fi fi

@ -2,7 +2,7 @@
declare -A SRC declare -A SRC
SRC[benchmark]=benchmark.go SRC[benchmark]=benchmark.go
SRC[txgen]=client/txgen/main.go SRC[txgen]=client/txgen/main.go
SRC[beacon]=runbeacon/run-beacon.go SRC[beacon]=beaconchain/main/main.go
BINDIR=bin BINDIR=bin
BUCKET=unique-bucket-bin BUCKET=unique-bucket-bin

@ -2,27 +2,22 @@ package newnode
import ( import (
"fmt" "fmt"
"net"
"os" "os"
"strconv" "strconv"
"sync"
"time" "time"
"github.com/harmony-one/harmony/p2p/p2pimpl"
"github.com/dedis/kyber" "github.com/dedis/kyber"
"github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/crypto"
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/proto/bcconn" "github.com/harmony-one/harmony/proto/bcconn"
proto_identity "github.com/harmony-one/harmony/proto/identity" proto_identity "github.com/harmony-one/harmony/proto/identity"
"github.com/harmony-one/harmony/utils" "github.com/harmony-one/harmony/utils"
) )
// Service is the server for listening.
type Service struct {
ch chan bool
waitGroup *sync.WaitGroup
}
//NewNode is ther struct for a candidate node //NewNode is ther struct for a candidate node
type NewNode struct { type NewNode struct {
Role string Role string
@ -36,7 +31,7 @@ type NewNode struct {
priK kyber.Scalar priK kyber.Scalar
log log.Logger log log.Logger
SetInfo bool SetInfo bool
Service *Service host host.Host
} }
// New candidatenode initialization // New candidatenode initialization
@ -48,6 +43,7 @@ func New(ip string, port string) *NewNode {
node.Self = p2p.Peer{IP: ip, Port: port, PubKey: pubKey, ValidatorID: -1} node.Self = p2p.Peer{IP: ip, Port: port, PubKey: pubKey, ValidatorID: -1}
node.log = log.New() node.log = log.New()
node.SetInfo = false node.SetInfo = false
node.host = p2pimpl.NewHost(node.Self)
node.Leaders = map[uint32]p2p.Peer{} node.Leaders = map[uint32]p2p.Peer{}
return &node return &node
} }
@ -58,66 +54,18 @@ type registerResponseRandomNumber struct {
Leaders []*bcconn.NodeInfo Leaders []*bcconn.NodeInfo
} }
// NewService starts a newservice in the candidate node // ContactBeaconChain starts a newservice in the candidate node
func (node *NewNode) NewService(ip, port string) *Service { func (node *NewNode) ContactBeaconChain(BCPeer p2p.Peer) {
laddr, err := net.ResolveTCPAddr("tcp", ip+":"+port) go node.host.BindHandlerAndServe(node.NodeHandler)
if nil != err { node.requestBeaconChain(BCPeer)
node.log.Crit("cannot resolve the tcp address of the new node", err)
}
listener, err := net.ListenTCP("tcp", laddr)
if nil != err {
node.log.Crit("cannot start a listener for new node", err)
}
node.log.Debug("listening on", "address", laddr.String())
node.Service = &Service{
ch: make(chan bool),
waitGroup: &sync.WaitGroup{},
}
node.Service.waitGroup.Add(1)
go node.Serve(listener)
return node.Service
}
// Serve Accept connections and spawn a goroutine to serve each one. Stop listening
// if anything is received on the service's channel.
func (node *NewNode) Serve(listener *net.TCPListener) {
defer node.Service.waitGroup.Done()
for {
select {
case <-node.Service.ch:
node.log.Debug("stopping listening on", "address", listener.Addr())
listener.Close()
node.log.Debug("stopped listening")
return
default:
}
listener.SetDeadline(time.Now().Add(1e9)) // This deadline is for 1 second to accept new connections.
conn, err := listener.AcceptTCP()
if nil != err {
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
continue
}
node.log.Error(err.Error())
}
node.Service.waitGroup.Add(1)
go node.NodeHandler(conn)
}
}
// Stop the service by closing the service's channel. Block until the service
// is really stopped.
func (s *Service) Stop() {
close(s.ch)
s.waitGroup.Wait()
} }
func (node NewNode) String() string { func (node NewNode) String() string {
return fmt.Sprintf("idc: %v:%v and node infi %v", node.Self.IP, node.Self.Port, node.SetInfo) return fmt.Sprintf("idc: %v:%v and node info %v", node.Self.IP, node.Self.Port, node.SetInfo)
} }
// ConnectBeaconChain connects to beacon chain // RequestBeaconChain requests beacon chain for identity data
func (node *NewNode) ConnectBeaconChain(BCPeer p2p.Peer) { func (node *NewNode) requestBeaconChain(BCPeer p2p.Peer) {
node.log.Info("connecting to beacon chain now ...") node.log.Info("connecting to beacon chain now ...")
pubk, err := node.PubK.MarshalBinary() pubk, err := node.PubK.MarshalBinary()
if err != nil { if err != nil {
@ -141,7 +89,7 @@ checkLoop:
gotShardInfo = true gotShardInfo = true
break checkLoop break checkLoop
} else { } else {
p2p.SendMessage(BCPeer, msgToSend) host.SendMessage(node.host, BCPeer, msgToSend)
} }
} }
} }

@ -1,7 +1,7 @@
package newnode package newnode
import ( import (
"net" "time"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/proto" "github.com/harmony-one/harmony/proto"
@ -9,11 +9,11 @@ import (
) )
// NodeHandler handles a new incoming connection. // NodeHandler handles a new incoming connection.
func (node *NewNode) NodeHandler(conn net.Conn) { func (node *NewNode) NodeHandler(s p2p.Stream) {
defer conn.Close() defer s.Close()
defer node.Service.waitGroup.Done() defer node.host.Close()
content, err := p2p.ReadMessageContent(conn) s.SetReadDeadline(time.Now().Add(1 * time.Second)) // This deadline is for 1 second to accept new connections.
content, err := p2p.ReadMessageContent(s)
if err != nil { if err != nil {
node.log.Error("Read p2p data failed", "err", err, "node", node) node.log.Error("Read p2p data failed", "err", err, "node", node)
return return

@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"math/rand" "math/rand"
"net"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -28,11 +27,11 @@ import (
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/node/worker" "github.com/harmony-one/harmony/node/worker"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2pv2" "github.com/harmony-one/harmony/p2p/host"
proto_node "github.com/harmony-one/harmony/proto/node" proto_node "github.com/harmony-one/harmony/proto/node"
"github.com/harmony-one/harmony/syncing" "github.com/harmony-one/harmony/services/syncing"
"github.com/harmony-one/harmony/syncing/downloader" "github.com/harmony-one/harmony/services/syncing/downloader"
downloader_pb "github.com/harmony-one/harmony/syncing/downloader/proto" downloader_pb "github.com/harmony-one/harmony/services/syncing/downloader/proto"
) )
// State is a state of a node. // State is a state of a node.
@ -56,7 +55,7 @@ const (
) )
const ( const (
syncingPortDifference = 1000 syncingPortDifference = 3000
waitBeforeJoinShard = time.Second * 3 waitBeforeJoinShard = time.Second * 3
timeOutToJoinShard = time.Minute * 10 timeOutToJoinShard = time.Minute * 10
) )
@ -106,6 +105,8 @@ type Node struct {
// Test only // Test only
TestBankKeys []*ecdsa.PrivateKey TestBankKeys []*ecdsa.PrivateKey
// The p2p host used to send/receive p2p messages
host host.Host
// Channel to stop sending ping message // Channel to stop sending ping message
StopPing chan int StopPing chan int
@ -164,15 +165,7 @@ func (node *Node) getTransactionsForNewBlockAccount(maxNumTxs int) (types.Transa
// StartServer starts a server and process the request by a handler. // StartServer starts a server and process the request by a handler.
func (node *Node) StartServer() { func (node *Node) StartServer() {
if p2p.Version == 1 { node.host.BindHandlerAndServe(node.StreamHandler)
node.log.Debug("Starting server", "node", node, "ip", node.SelfPeer.IP, "port", node.SelfPeer.Port)
node.listenOnPort(node.SelfPeer.Port)
} else {
p2pv2.InitHost(node.SelfPeer.IP, node.SelfPeer.Port)
p2pv2.BindHandler(node.NodeHandlerV1)
// Hang forever
<-make(chan struct{})
}
} }
// SetLog sets log for Node. // SetLog sets log for Node.
@ -181,32 +174,6 @@ func (node *Node) SetLog() *Node {
return node return node
} }
// Version 0 p2p. Going to be deprecated.
func (node *Node) listenOnPort(port string) {
addr := net.JoinHostPort("", port)
listen, err := net.Listen("tcp4", addr)
if err != nil {
node.log.Error("Socket listen port failed", "addr", addr, "err", err)
return
}
if listen == nil {
node.log.Error("Listen returned nil", "addr", addr)
return
}
defer listen.Close()
backoff := p2p.NewExpBackoff(250*time.Millisecond, 15*time.Second, 2.0)
for {
conn, err := listen.Accept()
if err != nil {
node.log.Error("Error listening on port.", "port", port,
"err", err)
backoff.Sleep()
continue
}
go node.NodeHandler(conn)
}
}
func (node *Node) String() string { func (node *Node) String() string {
return node.Consensus.String() return node.Consensus.String()
} }
@ -261,10 +228,15 @@ func DeserializeNode(d []byte) *NetworkNode {
} }
// New creates a new node. // New creates a new node.
func New(consensus *bft.Consensus, db *hdb.LDBDatabase, selfPeer p2p.Peer) *Node { func New(host host.Host, consensus *bft.Consensus, db *hdb.LDBDatabase) *Node {
node := Node{} node := Node{}
if consensus != nil { if host != nil {
node.host = host
node.SelfPeer = host.GetSelfPeer()
}
if host != nil && consensus != nil {
// Consensus and associated channel to communicate blocks // Consensus and associated channel to communicate blocks
node.Consensus = consensus node.Consensus = consensus
node.BlockChannel = make(chan blockchain.Block) node.BlockChannel = make(chan blockchain.Block)
@ -316,11 +288,9 @@ func New(consensus *bft.Consensus, db *hdb.LDBDatabase, selfPeer p2p.Peer) *Node
node.Chain = chain node.Chain = chain
node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, params.TestChainConfig, chain) node.TxPool = core.NewTxPool(core.DefaultTxPoolConfig, params.TestChainConfig, chain)
node.BlockChannelAccount = make(chan *types.Block) node.BlockChannelAccount = make(chan *types.Block)
node.Worker = worker.New(params.TestChainConfig, chain, node.Consensus, pki.GetAddressFromPublicKey(selfPeer.PubKey)) node.Worker = worker.New(params.TestChainConfig, chain, node.Consensus, pki.GetAddressFromPublicKey(node.SelfPeer.PubKey))
} }
node.SelfPeer = selfPeer
// Logger // Logger
node.log = log.New() node.log = log.New()
if consensus.IsLeader { if consensus.IsLeader {
@ -425,7 +395,7 @@ func (node *Node) JoinShard(leader p2p.Peer) {
buffer := ping.ConstructPingMessage() buffer := ping.ConstructPingMessage()
// Talk to leader. // Talk to leader.
p2p.SendMessage(leader, buffer) node.SendMessage(leader, buffer)
case <-timeout.C: case <-timeout.C:
node.log.Info("JoinShard timeout") node.log.Info("JoinShard timeout")
return return

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"net"
"os" "os"
"strconv" "strconv"
"time" "time"
@ -16,6 +15,7 @@ import (
hmy_crypto "github.com/harmony-one/harmony/crypto" hmy_crypto "github.com/harmony-one/harmony/crypto"
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/proto" "github.com/harmony-one/harmony/proto"
"github.com/harmony-one/harmony/proto/client" "github.com/harmony-one/harmony/proto/client"
"github.com/harmony-one/harmony/proto/consensus" "github.com/harmony-one/harmony/proto/consensus"
@ -34,17 +34,17 @@ const (
// MaybeBroadcastAsValidator returns if the node is a validator node. // MaybeBroadcastAsValidator returns if the node is a validator node.
func (node *Node) MaybeBroadcastAsValidator(content []byte) { func (node *Node) MaybeBroadcastAsValidator(content []byte) {
if node.SelfPeer.ValidatorID > 0 && node.SelfPeer.ValidatorID <= p2p.MaxBroadCast { if node.SelfPeer.ValidatorID > 0 && node.SelfPeer.ValidatorID <= host.MaxBroadCast {
go p2p.BroadcastMessageFromValidator(node.SelfPeer, node.Consensus.GetValidatorPeers(), content) go host.BroadcastMessageFromValidator(node.host, node.SelfPeer, node.Consensus.GetValidatorPeers(), content)
} }
} }
// NodeHandler handles a new incoming connection. // StreamHandler handles a new incoming connection.
func (node *Node) NodeHandler(conn net.Conn) { func (node *Node) StreamHandler(s p2p.Stream) {
defer conn.Close() defer s.Close()
// Read p2p message payload // Read p2p message payload
content, err := p2p.ReadMessageContent(conn) content, err := p2p.ReadMessageContent(s)
if err != nil { if err != nil {
node.log.Error("Read p2p data failed", "err", err, "node", node) node.log.Error("Read p2p data failed", "err", err, "node", node)
@ -137,7 +137,7 @@ func (node *Node) NodeHandler(conn net.Conn) {
utxoMap := node.UtxoPool.GetUtxoMapByAddresses(fetchUtxoMessage.Addresses) utxoMap := node.UtxoPool.GetUtxoMapByAddresses(fetchUtxoMessage.Addresses)
p2p.SendMessage(fetchUtxoMessage.Sender, client.ConstructFetchUtxoResponseMessage(&utxoMap, node.UtxoPool.ShardID)) node.SendMessage(fetchUtxoMessage.Sender, client.ConstructFetchUtxoResponseMessage(&utxoMap, node.UtxoPool.ShardID))
} }
case proto_node.Control: case proto_node.Control:
node.log.Info("NET: received message: Node/Control") node.log.Info("NET: received message: Node/Control")
@ -204,7 +204,7 @@ func (node *Node) NodeHandler(conn net.Conn) {
} }
} }
default: default:
node.log.Error("Unknown", "MsgCateory:", msgCategory) node.log.Error("Unknown", "MsgCategory", msgCategory)
} }
// Post processing after receiving messsages. // Post processing after receiving messsages.
@ -385,7 +385,7 @@ func (node *Node) SendBackProofOfAcceptOrReject() {
node.crossTxToReturnMutex.Unlock() node.crossTxToReturnMutex.Unlock()
node.log.Debug("SENDING PROOF TO CLIENT", "proofs", len(proofs)) node.log.Debug("SENDING PROOF TO CLIENT", "proofs", len(proofs))
p2p.SendMessage(*node.ClientPeer, client.ConstructProofOfAcceptOrRejectMessage(proofs)) node.SendMessage(*node.ClientPeer, client.ConstructProofOfAcceptOrRejectMessage(proofs))
} }
} }
@ -394,7 +394,7 @@ func (node *Node) SendBackProofOfAcceptOrReject() {
func (node *Node) BroadcastNewBlock(newBlock *blockchain.Block) { func (node *Node) BroadcastNewBlock(newBlock *blockchain.Block) {
if node.ClientPeer != nil { if node.ClientPeer != nil {
node.log.Debug("NET: SENDING NEW BLOCK TO CLIENT") node.log.Debug("NET: SENDING NEW BLOCK TO CLIENT")
p2p.SendMessage(*node.ClientPeer, proto_node.ConstructBlocksSyncMessage([]blockchain.Block{*newBlock})) node.SendMessage(*node.ClientPeer, proto_node.ConstructBlocksSyncMessage([]blockchain.Block{*newBlock}))
} }
} }
@ -566,7 +566,7 @@ func (node *Node) pingMessageHandler(msgPayload []byte) int {
// Broadcast the message to all validators, as publicKeys is updated // Broadcast the message to all validators, as publicKeys is updated
// FIXME: HAR-89 use a separate nodefind/neighbor message // FIXME: HAR-89 use a separate nodefind/neighbor message
p2p.BroadcastMessageFromLeader(peers, buffer) host.BroadcastMessageFromLeader(node.GetHost(), peers, buffer)
return len(peers) return len(peers)
} }

@ -1,183 +0,0 @@
package node
import (
"bytes"
"encoding/gob"
"fmt"
"os"
"github.com/harmony-one/harmony/blockchain"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2pv2"
"github.com/harmony-one/harmony/proto"
"github.com/harmony-one/harmony/proto/client"
"github.com/harmony-one/harmony/proto/consensus"
proto_identity "github.com/harmony-one/harmony/proto/identity"
proto_node "github.com/harmony-one/harmony/proto/node"
netp2p "github.com/libp2p/go-libp2p-net"
)
// NodeHandlerV1 handles a new incoming connection.
func (node *Node) NodeHandlerV1(s netp2p.Stream) {
defer s.Close()
// Read p2p message payload
content, err := p2pv2.ReadData(s)
if err != nil {
node.log.Error("Read p2p data failed", "err", err, "node", node)
return
}
// TODO: this is tree broadcasting. this needs to be removed later. Actually the whole logic needs to be replaced by p2p.
node.MaybeBroadcastAsValidator(content)
consensusObj := node.Consensus
msgCategory, err := proto.GetMessageCategory(content)
if err != nil {
node.log.Error("Read node type failed", "err", err, "node", node)
return
}
msgType, err := proto.GetMessageType(content)
if err != nil {
node.log.Error("Read action type failed", "err", err, "node", node)
return
}
msgPayload, err := proto.GetMessagePayload(content)
if err != nil {
node.log.Error("Read message payload failed", "err", err, "node", node)
return
}
switch msgCategory {
case proto.Identity:
actionType := proto_identity.IDMessageType(msgType)
switch actionType {
case proto_identity.Identity:
messageType := proto_identity.MessageType(msgPayload[0])
switch messageType {
case proto_identity.Register:
fmt.Println("received a identity message")
// TODO(ak): fix it.
// node.processPOWMessage(msgPayload)
node.log.Info("NET: received message: IDENTITY/REGISTER")
default:
node.log.Error("Announce message should be sent to IdentityChain")
}
}
case proto.Consensus:
actionType := consensus.ConMessageType(msgType)
switch actionType {
case consensus.Consensus:
if consensusObj.IsLeader {
node.log.Info("NET: received message: Consensus/Leader")
consensusObj.ProcessMessageLeader(msgPayload)
} else {
node.log.Info("NET: received message: Consensus/Validator")
consensusObj.ProcessMessageValidator(msgPayload)
}
}
case proto.Node:
actionType := proto_node.MessageType(msgType)
switch actionType {
case proto_node.Transaction:
node.log.Info("NET: received message: Node/Transaction")
node.transactionMessageHandler(msgPayload)
case proto_node.Block:
node.log.Info("NET: received message: Node/Block")
blockMsgType := proto_node.BlockMessageType(msgPayload[0])
switch blockMsgType {
case proto_node.Sync:
decoder := gob.NewDecoder(bytes.NewReader(msgPayload[1:])) // skip the Sync messge type
blocks := new([]*blockchain.Block)
decoder.Decode(blocks)
if node.Client != nil && node.Client.UpdateBlocks != nil && blocks != nil {
node.Client.UpdateBlocks(*blocks)
}
}
case proto_node.Client:
node.log.Info("NET: received message: Node/Client")
clientMsgType := proto_node.ClientMessageType(msgPayload[0])
switch clientMsgType {
case proto_node.LookupUtxo:
decoder := gob.NewDecoder(bytes.NewReader(msgPayload[1:])) // skip the LookupUtxo messge type
fetchUtxoMessage := new(proto_node.FetchUtxoMessage)
decoder.Decode(fetchUtxoMessage)
utxoMap := node.UtxoPool.GetUtxoMapByAddresses(fetchUtxoMessage.Addresses)
p2p.SendMessage(fetchUtxoMessage.Sender, client.ConstructFetchUtxoResponseMessage(&utxoMap, node.UtxoPool.ShardID))
}
case proto_node.Control:
node.log.Info("NET: received message: Node/Control")
controlType := msgPayload[0]
if proto_node.ControlMessageType(controlType) == proto_node.STOP {
if node.Chain == nil {
node.log.Debug("Stopping Node", "node", node, "numBlocks", len(node.blockchain.Blocks), "numTxsProcessed", node.countNumTransactionsInBlockchain())
sizeInBytes := node.UtxoPool.GetSizeInByteOfUtxoMap()
node.log.Debug("UtxoPool Report", "numEntries", len(node.UtxoPool.UtxoMap), "sizeInBytes", sizeInBytes)
avgBlockSizeInBytes := 0
txCount := 0
blockCount := 0
totalTxCount := 0
totalBlockCount := 0
avgTxSize := 0
for _, block := range node.blockchain.Blocks {
if block.IsStateBlock() {
totalTxCount += int(block.State.NumTransactions)
totalBlockCount += int(block.State.NumBlocks)
} else {
byteBuffer := bytes.NewBuffer([]byte{})
encoder := gob.NewEncoder(byteBuffer)
encoder.Encode(block)
avgBlockSizeInBytes += len(byteBuffer.Bytes())
txCount += len(block.Transactions)
blockCount++
totalTxCount += len(block.TransactionIds)
totalBlockCount++
byteBuffer = bytes.NewBuffer([]byte{})
encoder = gob.NewEncoder(byteBuffer)
encoder.Encode(block.Transactions)
avgTxSize += len(byteBuffer.Bytes())
}
}
if blockCount != 0 {
avgBlockSizeInBytes = avgBlockSizeInBytes / blockCount
avgTxSize = avgTxSize / txCount
}
node.log.Debug("Blockchain Report", "totalNumBlocks", totalBlockCount, "avgBlockSizeInCurrentEpoch", avgBlockSizeInBytes, "totalNumTxs", totalTxCount, "avgTxSzieInCurrentEpoch", avgTxSize)
} else {
node.log.Debug("Stopping Node (Account Model)", "node", node, "CurBlockNum", node.Chain.CurrentHeader().Number, "numTxsProcessed", node.countNumTransactionsInBlockchainAccount())
}
os.Exit(0)
}
case proto_node.PING:
// Leader receives PING from new node.
node.pingMessageHandler(msgPayload)
case proto_node.PONG:
// The new node receives back from leader.
node.pongMessageHandler(msgPayload)
}
case proto.Client:
actionType := client.MessageType(msgType)
node.log.Info("NET: received message: Client/Transaction")
switch actionType {
case client.Transaction:
if node.Client != nil {
node.Client.TransactionMessageHandler(msgPayload)
}
}
default:
node.log.Error("Unknown", "MsgCateory:", msgCategory)
}
}

@ -10,6 +10,7 @@ import (
"github.com/harmony-one/harmony/crypto" "github.com/harmony-one/harmony/crypto"
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/p2pimpl"
proto_node "github.com/harmony-one/harmony/proto/node" proto_node "github.com/harmony-one/harmony/proto/node"
"github.com/harmony-one/harmony/utils" "github.com/harmony-one/harmony/utils"
) )
@ -18,9 +19,9 @@ func TestNewNewNode(t *testing.T) {
_, pubKey := utils.GenKey("1", "2") _, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey} leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := consensus.New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(consensus, nil, leader) node := New(host, consensus, nil)
if node.Consensus == nil { if node.Consensus == nil {
t.Error("Consensus is not initialized for the node") t.Error("Consensus is not initialized for the node")
} }
@ -46,9 +47,10 @@ func TestCountNumTransactionsInBlockchain(t *testing.T) {
_, pubKey := utils.GenKey("1", "2") _, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey} leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := consensus.New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(consensus, nil, leader) node := New(host, consensus, nil)
node.AddTestingAddresses(1000) node.AddTestingAddresses(1000)
if node.countNumTransactionsInBlockchain() != 1001 { if node.countNumTransactionsInBlockchain() != 1001 {
t.Error("Count of transactions in the blockchain is incorrect") t.Error("Count of transactions in the blockchain is incorrect")
@ -59,9 +61,10 @@ func TestGetSyncingPeers(t *testing.T) {
_, pubKey := utils.GenKey("1", "2") _, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey} leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := consensus.New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(consensus, nil, leader) node := New(host, consensus, nil)
peer := p2p.Peer{IP: "1.1.1.1", Port: "2000"} peer := p2p.Peer{IP: "1.1.1.1", Port: "2000"}
peer2 := p2p.Peer{IP: "2.1.1.1", Port: "2000"} peer2 := p2p.Peer{IP: "2.1.1.1", Port: "2000"}
node.Neighbors.Store("minh", peer) node.Neighbors.Store("minh", peer)
@ -101,9 +104,10 @@ func TestAddPeers(t *testing.T) {
_, pubKey := utils.GenKey("1", "2") _, pubKey := utils.GenKey("1", "2")
leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey} leader := p2p.Peer{IP: "1", Port: "2", PubKey: pubKey}
validator := p2p.Peer{IP: "3", Port: "5"} validator := p2p.Peer{IP: "3", Port: "5"}
consensus := consensus.New(leader, "0", []p2p.Peer{leader, validator}, leader) host := p2pimpl.NewHost(leader)
consensus := consensus.New(host, "0", []p2p.Peer{leader, validator}, leader)
node := New(consensus, nil, leader) node := New(host, consensus, nil)
r1 := node.AddPeers(peers1) r1 := node.AddPeers(peers1)
e1 := 2 e1 := 2
if r1 != e1 { if r1 != e1 {
@ -116,7 +120,7 @@ func TestAddPeers(t *testing.T) {
} }
} }
func sendPingMessage(leader p2p.Peer) { func sendPingMessage(node *Node, leader p2p.Peer) {
priKey1 := crypto.Ed25519Curve.Scalar().SetInt64(int64(333)) priKey1 := crypto.Ed25519Curve.Scalar().SetInt64(int64(333))
pubKey1 := pki.GetPublicKeyFromScalar(priKey1) pubKey1 := pki.GetPublicKeyFromScalar(priKey1)
@ -132,11 +136,11 @@ func sendPingMessage(leader p2p.Peer) {
fmt.Println("waiting for 5 seconds ...") fmt.Println("waiting for 5 seconds ...")
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
p2p.SendMessage(leader, buf1) node.SendMessage(leader, buf1)
fmt.Println("sent ping message ...") fmt.Println("sent ping message ...")
} }
func sendPongMessage(leader p2p.Peer) { func sendPongMessage(node *Node, leader p2p.Peer) {
priKey1 := crypto.Ed25519Curve.Scalar().SetInt64(int64(333)) priKey1 := crypto.Ed25519Curve.Scalar().SetInt64(int64(333))
pubKey1 := pki.GetPublicKeyFromScalar(priKey1) pubKey1 := pki.GetPublicKeyFromScalar(priKey1)
p1 := p2p.Peer{ p1 := p2p.Peer{
@ -158,7 +162,7 @@ func sendPongMessage(leader p2p.Peer) {
fmt.Println("waiting for 10 seconds ...") fmt.Println("waiting for 10 seconds ...")
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
p2p.SendMessage(leader, buf1) node.SendMessage(leader, buf1)
fmt.Println("sent pong message ...") fmt.Println("sent pong message ...")
} }
@ -173,10 +177,11 @@ func TestPingPongHandler(test *testing.T) {
_, pubKey := utils.GenKey("127.0.0.1", "8881") _, pubKey := utils.GenKey("127.0.0.1", "8881")
leader := p2p.Peer{IP: "127.0.0.1", Port: "8881", PubKey: pubKey} leader := p2p.Peer{IP: "127.0.0.1", Port: "8881", PubKey: pubKey}
// validator := p2p.Peer{IP: "127.0.0.1", Port: "9991"} // validator := p2p.Peer{IP: "127.0.0.1", Port: "9991"}
consensus := consensus.New(leader, "0", []p2p.Peer{leader}, leader) host := p2pimpl.NewHost(leader)
node := New(consensus, nil, leader) consensus := consensus.New(host, "0", []p2p.Peer{leader}, leader)
node := New(host, consensus, nil)
//go sendPingMessage(leader) //go sendPingMessage(leader)
go sendPongMessage(leader) go sendPongMessage(node, leader)
go exitServer() go exitServer()
node.StartServer() node.StartServer()
} }

@ -0,0 +1,21 @@
package node
import (
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
)
// SendMessage sends data to ip, port
func (node *Node) SendMessage(p p2p.Peer, data []byte) {
host.SendMessage(node.host, p, data)
}
// BroadcastMessage broadcasts message to peers
func (node *Node) BroadcastMessage(peers []p2p.Peer, data []byte) {
host.BroadcastMessage(node.host, peers, data)
}
// GetHost returns the p2p host
func (node *Node) GetHost() host.Host {
return node.host
}

@ -6,7 +6,6 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"log" "log"
"net"
"time" "time"
) )
@ -28,13 +27,13 @@ content (n bytes) - actual message content
const BatchSizeInByte = 1 << 16 const BatchSizeInByte = 1 << 16
// ReadMessageContent reads the message type and content size, and return the actual content. // ReadMessageContent reads the message type and content size, and return the actual content.
func ReadMessageContent(conn net.Conn) ([]byte, error) { func ReadMessageContent(s Stream) ([]byte, error) {
var ( var (
contentBuf = bytes.NewBuffer([]byte{}) contentBuf = bytes.NewBuffer([]byte{})
r = bufio.NewReader(conn) r = bufio.NewReader(s)
) )
timeoutDuration := 1 * time.Second timeoutDuration := 1 * time.Second
conn.SetReadDeadline(time.Now().Add(timeoutDuration)) s.SetReadDeadline(time.Now().Add(timeoutDuration))
//// Read 1 byte for message type //// Read 1 byte for message type
_, err := r.ReadByte() _, err := r.ReadByte()
switch err { switch err {
@ -67,7 +66,7 @@ func ReadMessageContent(conn net.Conn) ([]byte, error) {
ILOOP: ILOOP:
for { for {
timeoutDuration := 10 * time.Second timeoutDuration := 10 * time.Second
conn.SetReadDeadline(time.Now().Add(timeoutDuration)) s.SetReadDeadline(time.Now().Add(timeoutDuration))
if bytesToRead < BatchSizeInByte { if bytesToRead < BatchSizeInByte {
// Read the last number of bytes less than 1024 // Read the last number of bytes less than 1024
tmpBuf = make([]byte, bytesToRead) tmpBuf = make([]byte, bytesToRead)
@ -91,25 +90,3 @@ ILOOP:
} }
return contentBuf.Bytes(), nil return contentBuf.Bytes(), nil
} }
// CreateMessage create a general message. FIXME: this is not used
func CreateMessage(msgType byte, data []byte) []byte {
buffer := bytes.NewBuffer([]byte{})
buffer.WriteByte(msgType)
fourBytes := make([]byte, 4)
binary.BigEndian.PutUint32(fourBytes, uint32(len(data)))
buffer.Write(fourBytes)
buffer.Write(data)
return buffer.Bytes()
}
// SendMessageContent send message over net connection. FIXME: this is not used
func SendMessageContent(conn net.Conn, data []byte) {
msgToSend := CreateMessage(byte(1), data)
w := bufio.NewWriter(conn)
w.Write(msgToSend)
w.Flush()
}

@ -1,55 +0,0 @@
package p2p_test
import (
"bufio"
"net"
"testing"
"github.com/harmony-one/harmony/p2p"
)
func setUpTestServer(times int, t *testing.T, conCreated chan struct{}) {
t.Parallel()
ln, _ := net.Listen("tcp", ":8081")
conCreated <- struct{}{}
conn, _ := ln.Accept()
defer conn.Close()
var (
w = bufio.NewWriter(conn)
)
for times > 0 {
times--
data, err := p2p.ReadMessageContent(conn)
if err != nil {
t.Fatalf("error when ReadMessageContent %v", err)
}
data = p2p.CreateMessage(byte(1), data)
w.Write(data)
w.Flush()
}
}
func TestNewNewNode(t *testing.T) {
times := 100
conCreated := make(chan struct{})
go setUpTestServer(times, t, conCreated)
<-conCreated
conn, _ := net.Dial("tcp", "127.0.0.1:8081")
defer conn.Close()
for times > 0 {
times--
myMsg := "minhdoan"
p2p.SendMessageContent(conn, []byte(myMsg))
data, err := p2p.ReadMessageContent(conn)
if err != nil {
t.Error("got an error when trying to receive an expected message from server.")
}
if string(data) != myMsg {
t.Error("did not receive expected message")
}
}
}

@ -0,0 +1,13 @@
package host
import (
"github.com/harmony-one/harmony/p2p"
)
// Host is the client + server in p2p network.
type Host interface {
GetSelfPeer() p2p.Peer
SendMessage(p2p.Peer, []byte) error
BindHandlerAndServe(handler p2p.StreamHandler)
Close() error
}

@ -0,0 +1,99 @@
package hostv1
import (
"io"
"net"
"time"
"github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p"
)
// HostV1 is the version 1 p2p host, using direct socket call.
type HostV1 struct {
self p2p.Peer
listener net.Listener
quit chan bool
}
// New creates a HostV1
func New(self p2p.Peer) *HostV1 {
h := &HostV1{
self: self,
quit: make(chan bool, 1),
}
return h
}
// GetSelfPeer gets self peer
func (host *HostV1) GetSelfPeer() p2p.Peer {
return host.self
}
// BindHandlerAndServe Version 0 p2p. Going to be deprecated.
func (host *HostV1) BindHandlerAndServe(handler p2p.StreamHandler) {
port := host.self.Port
addr := net.JoinHostPort(host.self.IP, port)
var err error
host.listener, err = net.Listen("tcp4", addr)
if err != nil {
log.Error("Socket listen port failed", "addr", addr, "err", err)
return
}
if host.listener == nil {
log.Error("Listen returned nil", "addr", addr)
return
}
backoff := p2p.NewExpBackoff(250*time.Millisecond, 15*time.Second, 2.0)
for { // Keep listening
select {
case <-host.quit:
return
default:
{
conn, err := host.listener.Accept()
if err != nil {
log.Error("Error listening on port.", "port", port,
"err", err)
backoff.Sleep()
continue
}
// log.Debug("Received New connection", "local", conn.LocalAddr(), "remote", conn.RemoteAddr())
go handler(conn)
}
}
}
}
// SendMessage sends message to peer
func (host *HostV1) SendMessage(peer p2p.Peer, message []byte) (err error) {
addr := net.JoinHostPort(peer.IP, peer.Port)
conn, err := net.Dial("tcp", addr)
// log.Debug("Dial from local to remote", "localID", net.JoinHostPort(host.self.IP, host.self.Port), "local", conn.LocalAddr(), "remote", addr)
if err != nil {
log.Warn("Dial() failed", "from", net.JoinHostPort(host.self.IP, host.self.Port), "to", addr, "error", err)
return
}
defer conn.Close()
nw, err := conn.Write(message)
if err != nil {
log.Warn("Write() failed", "addr", conn.RemoteAddr(), "error", err)
return
}
if nw < len(message) {
log.Warn("Write() returned short count",
"addr", conn.RemoteAddr(), "actual", nw, "expected", len(message))
return io.ErrShortWrite
}
// No ack (reply) message from the receiver for now.
return
}
// Close closes the host
func (host *HostV1) Close() error {
host.quit <- true
return host.listener.Close()
}

@ -0,0 +1,94 @@
package hostv2
import (
"bufio"
"context"
"fmt"
"github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p"
libp2p "github.com/libp2p/go-libp2p"
libp2phost "github.com/libp2p/go-libp2p-host"
net "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
peerstore "github.com/libp2p/go-libp2p-peerstore"
multiaddr "github.com/multiformats/go-multiaddr"
)
const (
// BatchSizeInByte The batch size in byte (64MB) in which we return data
BatchSizeInByte = 1 << 16
// ProtocolID The ID of protocol used in stream handling.
ProtocolID = "/harmony/0.0.1"
)
// HostV2 is the version 2 p2p host
type HostV2 struct {
h libp2phost.Host
self p2p.Peer
}
// Peerstore returns the peer store
func (host *HostV2) Peerstore() peerstore.Peerstore {
return host.h.Peerstore()
}
// New creates a host for p2p communication
func New(self p2p.Peer) *HostV2 {
addr := fmt.Sprintf("/ip4/%s/tcp/%s", self.IP, self.Port)
sourceAddr, err := multiaddr.NewMultiaddr(addr)
catchError(err)
priv := addrToPrivKey(addr)
p2pHost, err := libp2p.New(context.Background(),
libp2p.ListenAddrs(sourceAddr),
libp2p.Identity(priv),
libp2p.NoSecurity, // The security (signature generation and verification) is, for now, taken care by ourselves.
// TODO(ricl): Other features to probe
// libp2p.EnableRelay; libp2p.Routing;
)
catchError(err)
log.Debug("Host is up!", "port", self.Port, "id", p2pHost.ID().Pretty(), "addrs", sourceAddr)
h := &HostV2{
h: p2pHost,
self: self,
}
return h
}
// GetSelfPeer gets self peer
func (host *HostV2) GetSelfPeer() p2p.Peer {
return host.self
}
// BindHandlerAndServe bind a streamHandler to the harmony protocol.
func (host *HostV2) BindHandlerAndServe(handler p2p.StreamHandler) {
host.h.SetStreamHandler(ProtocolID, func(s net.Stream) {
handler(s)
})
// Hang forever
<-make(chan struct{})
}
// SendMessage a p2p message sending function with signature compatible to p2pv1.
func (host *HostV2) SendMessage(p p2p.Peer, message []byte) error {
addr := fmt.Sprintf("/ip4/%s/tcp/%s", p.IP, p.Port)
targetAddr, err := multiaddr.NewMultiaddr(addr)
priv := addrToPrivKey(addr)
peerID, _ := peer.IDFromPrivateKey(priv)
host.Peerstore().AddAddrs(peerID, []multiaddr.Multiaddr{targetAddr}, peerstore.PermanentAddrTTL)
s, err := host.h.NewStream(context.Background(), peerID, ProtocolID)
catchError(err)
// Create a buffered stream so that read and writes are non blocking.
w := bufio.NewWriter(bufio.NewWriter(s))
// Create a thread to read and write data.
go writeData(w, message)
return nil
}
// Close closes the host
func (host *HostV2) Close() error {
return host.h.Close()
}

@ -1,4 +1,4 @@
package p2pv2 package hostv2
import ( import (
"bufio" "bufio"

@ -1,46 +1,26 @@
package p2p package host
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"io"
"net" "net"
"runtime" "runtime"
"time" "time"
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2pv2" "github.com/harmony-one/harmony/p2p"
"github.com/dedis/kyber"
) )
// Peer is the object for a p2p peer (node) // SendMessage is to connect a socket given a port and send the given message.
type Peer struct { // TODO(minhdoan, rj): need to check if a peer is reachable or not.
IP string // IP address of the peer func SendMessage(host Host, p p2p.Peer, message []byte) {
Port string // Port number of the peer
PubKey kyber.Point // Public key of the peer
Ready bool // Ready is true if the peer is ready to join consensus.
ValidatorID int // -1 is the default value, means not assigned any validator ID in the shard
// TODO(minhdoan, rj): use this Ready to not send/broadcast to this peer if it wasn't available.
}
// MaxBroadCast is the maximum number of neighbors to broadcast
const MaxBroadCast = 20
// Version The version number of p2p library
// 1 - Direct socket connection
// 2 - libp2p
const Version = 1
// SendMessage sends the message to the peer
func SendMessage(peer Peer, msg []byte) {
// Construct normal p2p message // Construct normal p2p message
content := ConstructP2pMessage(byte(0), msg) content := ConstructP2pMessage(byte(0), message)
go send(peer.IP, peer.Port, content) go send(host, p, content)
} }
// BroadcastMessage sends the message to a list of peers // BroadcastMessage sends the message to a list of peers
func BroadcastMessage(peers []Peer, msg []byte) { func BroadcastMessage(h Host, peers []p2p.Peer, msg []byte) {
if len(peers) == 0 { if len(peers) == 0 {
return return
} }
@ -52,7 +32,7 @@ func BroadcastMessage(peers []Peer, msg []byte) {
start := time.Now() start := time.Now()
for _, peer := range peers { for _, peer := range peers {
peerCopy := peer peerCopy := peer
go send(peerCopy.IP, peerCopy.Port, content) go send(h, peerCopy, content)
} }
log.Info("Broadcasting Done", "time spent(s)", time.Since(start).Seconds()) log.Info("Broadcasting Done", "time spent(s)", time.Since(start).Seconds())
@ -63,31 +43,6 @@ func BroadcastMessage(peers []Peer, msg []byte) {
} }
} }
// SelectMyPeers chooses a list of peers based on the range of ValidatorID
// This is a quick hack of the current p2p networking model
func SelectMyPeers(peers []Peer, min int, max int) []Peer {
res := []Peer{}
for _, peer := range peers {
if peer.ValidatorID >= min && peer.ValidatorID <= max {
res = append(res, peer)
}
}
return res
}
// BroadcastMessageFromLeader sends the message to a list of peers from a leader.
func BroadcastMessageFromLeader(peers []Peer, msg []byte) {
// TODO(minhdoan): Enable back for multicast.
peers = SelectMyPeers(peers, 1, MaxBroadCast)
BroadcastMessage(peers, msg)
}
// BroadcastMessageFromValidator sends the message to a list of peers from a validator.
func BroadcastMessageFromValidator(selfPeer Peer, peers []Peer, msg []byte) {
peers = SelectMyPeers(peers, selfPeer.ValidatorID*MaxBroadCast+1, (selfPeer.ValidatorID+1)*MaxBroadCast)
BroadcastMessage(peers, msg)
}
// ConstructP2pMessage constructs the p2p message as [messageType, contentSize, content] // ConstructP2pMessage constructs the p2p message as [messageType, contentSize, content]
func ConstructP2pMessage(msgType byte, content []byte) []byte { func ConstructP2pMessage(msgType byte, content []byte) []byte {
@ -103,61 +58,56 @@ func ConstructP2pMessage(msgType byte, content []byte) []byte {
return byteBuffer.Bytes() return byteBuffer.Bytes()
} }
// SocketClient is to connect a socket given a port and send the given message. // BroadcastMessageFromLeader sends the message to a list of peers from a leader.
// TODO(minhdoan, rj): need to check if a peer is reachable or not. func BroadcastMessageFromLeader(h Host, peers []p2p.Peer, msg []byte) {
func sendWithSocketClient(ip, port string, message []byte) (err error) { // TODO(minhdoan): Enable back for multicast.
//log.Printf("Sending message to ip %s and port %s\n", ip, port) peers = SelectMyPeers(peers, 1, MaxBroadCast)
addr := net.JoinHostPort(ip, port) BroadcastMessage(h, peers, msg)
conn, err := net.Dial("tcp", addr) log.Info("Done sending from leader")
}
if err != nil {
log.Warn("Dial() failed", "addr", addr, "error", err)
return
}
defer conn.Close()
nw, err := conn.Write(message) // BroadcastMessageFromValidator sends the message to a list of peers from a validator.
if err != nil { func BroadcastMessageFromValidator(h Host, selfPeer p2p.Peer, peers []p2p.Peer, msg []byte) {
log.Warn("Write() failed", "addr", conn.RemoteAddr(), "error", err) peers = SelectMyPeers(peers, selfPeer.ValidatorID*MaxBroadCast+1, (selfPeer.ValidatorID+1)*MaxBroadCast)
return BroadcastMessage(h, peers, msg)
} log.Info("Done sending from validator")
if nw < len(message) { }
log.Warn("Write() returned short count",
"addr", conn.RemoteAddr(), "actual", nw, "expected", len(message))
return io.ErrShortWrite
}
//log.Printf("Sent to ip %s and port %s: %s\n", ip, port, message) // MaxBroadCast is the maximum number of neighbors to broadcast
const MaxBroadCast = 20
// No ack (reply) message from the receiver for now. // SelectMyPeers chooses a list of peers based on the range of ValidatorID
return // This is a quick hack of the current p2p networking model
func SelectMyPeers(peers []p2p.Peer, min int, max int) []p2p.Peer {
res := []p2p.Peer{}
for _, peer := range peers {
if peer.ValidatorID >= min && peer.ValidatorID <= max {
res = append(res, peer)
}
}
return res
} }
// Send a message to another node with given port. // Send a message to another node with given port.
func send(ip, port string, message []byte) { func send(h Host, peer p2p.Peer, message []byte) {
// Add attack code here. // Add attack code here.
//attack.GetInstance().Run() //attack.GetInstance().Run()
backoff := NewExpBackoff(250*time.Millisecond, 10*time.Second, 2) backoff := p2p.NewExpBackoff(250*time.Millisecond, 10*time.Second, 2)
for trial := 0; trial < 10; trial++ { for trial := 0; trial < 10; trial++ {
var err error var err error
if Version == 1 { h.SendMessage(peer, message)
// TODO(ricl): remove sendWithSocketClient related code.
err = sendWithSocketClient(ip, port, message)
} else {
err = p2pv2.Send(ip, port, message)
}
if err == nil { if err == nil {
if trial > 0 { if trial > 0 {
log.Warn("retry sendWithSocketClient", "rety", trial) log.Warn("retry send", "rety", trial)
} }
return return
} }
log.Info("sleeping before trying to send again", log.Info("sleeping before trying to send again",
"duration", backoff.Cur, "addr", net.JoinHostPort(ip, port)) "duration", backoff.Cur, "addr", net.JoinHostPort(peer.IP, peer.Port))
backoff.Sleep() backoff.Sleep()
} }
log.Error("gave up sending a message", "addr", net.JoinHostPort(ip, port)) log.Error("gave up sending a message", "addr", net.JoinHostPort(peer.IP, peer.Port))
} }
// DialWithSocketClient joins host port and establishes connection // DialWithSocketClient joins host port and establishes connection

@ -0,0 +1,28 @@
package p2p
import (
"time"
"github.com/dedis/kyber"
)
// Stream is abstract p2p stream from where we read message
type Stream interface {
Read([]byte) (int, error)
Write([]byte) (int, error)
Close() error
SetReadDeadline(time.Time) error
}
// StreamHandler handles incoming p2p message.
type StreamHandler func(Stream)
// Peer is the object for a p2p peer (node)
type Peer struct {
IP string // IP address of the peer
Port string // Port number of the peer
PubKey kyber.Point // Public key of the peer
Ready bool // Ready is true if the peer is ready to join consensus.
ValidatorID int // -1 is the default value, means not assigned any validator ID in the shard
// TODO(minhdoan, rj): use this Ready to not send/broadcast to this peer if it wasn't available.
}

@ -0,0 +1,25 @@
package p2pimpl
import (
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
"github.com/harmony-one/harmony/p2p/host/hostv1"
"github.com/harmony-one/harmony/p2p/host/hostv2"
)
// Version The version number of p2p library
// 1 - Direct socket connection
// 2 - libp2p
const Version = 1
// NewHost starts the host
func NewHost(peer p2p.Peer) host.Host {
// log.Debug("New Host", "ip/port", net.JoinHostPort(peer.IP, peer.Port))
if Version == 1 {
h := hostv1.New(peer)
return h
}
h := hostv2.New(peer)
return h
}

@ -1,146 +0,0 @@
package p2pv2
import (
"bufio"
"bytes"
"context"
"encoding/binary"
"fmt"
"io"
"time"
"github.com/harmony-one/harmony/log"
libp2p "github.com/libp2p/go-libp2p"
host "github.com/libp2p/go-libp2p-host"
net "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
peerstore "github.com/libp2p/go-libp2p-peerstore"
multiaddr "github.com/multiformats/go-multiaddr"
)
var (
myHost host.Host // TODO(ricl): this should be a field in node.
)
const (
// BatchSizeInByte The batch size in byte (64MB) in which we return data
BatchSizeInByte = 1 << 16
// ProtocolID The ID of protocol used in stream handling.
ProtocolID = "/harmony/0.0.1"
)
// InitHost Initialize a host for p2p communication
func InitHost(ip, port string) {
addr := fmt.Sprintf("/ip4/%s/tcp/%s", ip, port)
sourceAddr, err := multiaddr.NewMultiaddr(addr)
catchError(err)
priv := addrToPrivKey(addr)
myHost, err = libp2p.New(context.Background(),
libp2p.ListenAddrs(sourceAddr),
libp2p.Identity(priv),
libp2p.NoSecurity, // The security (signature generation and verification) is, for now, taken care by ourselves.
// TODO(ricl): Other features to probe
// libp2p.EnableRelay; libp2p.Routing;
)
catchError(err)
log.Debug("Host is up!", "port", port, "id", myHost.ID().Pretty(), "addrs", sourceAddr)
}
// BindHandler bind a streamHandler to the harmony protocol.
func BindHandler(handler net.StreamHandler) {
myHost.SetStreamHandler(ProtocolID, handler)
}
// Send a p2p message sending function with signature compatible to p2pv1.
func Send(ip, port string, message []byte) error {
addr := fmt.Sprintf("/ip4/%s/tcp/%s", ip, port)
targetAddr, err := multiaddr.NewMultiaddr(addr)
priv := addrToPrivKey(addr)
peerID, _ := peer.IDFromPrivateKey(priv)
myHost.Peerstore().AddAddrs(peerID, []multiaddr.Multiaddr{targetAddr}, peerstore.PermanentAddrTTL)
s, err := myHost.NewStream(context.Background(), peerID, ProtocolID)
catchError(err)
// Create a buffered stream so that read and writes are non blocking.
w := bufio.NewWriter(bufio.NewWriter(s))
// Create a thread to read and write data.
go writeData(w, message)
return nil
}
// ReadData Call this function in streamHandler to get the binary data.
func ReadData(s net.Stream) ([]byte, error) {
timeoutDuration := 1 * time.Second
s.SetReadDeadline(time.Now().Add(timeoutDuration))
// Create a buffered stream so that read and writes are non blocking.
rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))
contentBuf := bytes.NewBuffer([]byte{})
// Read 1 byte for message type
_, err := rw.ReadByte()
switch err {
case nil:
//log.Printf("Received p2p message type: %x\n", msgType)
case io.EOF:
fallthrough
default:
log.Error("Error reading the p2p message type field", "err", err)
return contentBuf.Bytes(), err
}
// TODO: check on msgType and take actions accordingly
// Read 4 bytes for message size
fourBytes := make([]byte, 4)
n, err := rw.Read(fourBytes)
if err != nil {
log.Error("Error reading the p2p message size field", "err", err)
return contentBuf.Bytes(), err
} else if n < len(fourBytes) {
log.Error("Invalid byte size", "bytes", n)
return contentBuf.Bytes(), err
}
//log.Print(fourBytes)
// Number of bytes for the message content
bytesToRead := binary.BigEndian.Uint32(fourBytes)
//log.Printf("The content size is %d bytes.", bytesToRead)
// Read the content in chunk of size `BatchSizeInByte`
tmpBuf := make([]byte, BatchSizeInByte)
ILOOP:
for {
// TODO(ricl): is this necessary? If yes, figure out how to make it work
// timeoutDuration := 10 * time.Second
// s.SetReadDeadline(time.Now().Add(timeoutDuration))
if bytesToRead < BatchSizeInByte {
// Read the last number of bytes less than `BatchSizeInByte`
tmpBuf = make([]byte, bytesToRead)
}
n, err := rw.Read(tmpBuf)
contentBuf.Write(tmpBuf[:n])
switch err {
case io.EOF:
// TODO: should we return error here, or just ignore it?
log.Error("EOF reached while reading p2p message")
break ILOOP
case nil:
bytesToRead -= uint32(n) // TODO: think about avoid the casting in every loop
if bytesToRead <= 0 {
break ILOOP
}
default:
log.Error("Error reading p2p message")
return []byte{}, err
}
}
return contentBuf.Bytes(), nil
}
// GetHost Get the p2p host
func GetHost() host.Host {
return myHost
}

@ -0,0 +1,95 @@
package explorer
import (
"encoding/json"
"log"
"net"
"net/http"
"github.com/gorilla/mux"
)
// Constants for explorer service.
const (
ExplorerServicePort = "5000"
)
// Service is the struct for explorer service.
type Service struct {
people []Person
router *mux.Router
}
// Init is to do init for ExplorerService.
func (s *Service) Init() {
s.people = append(s.people, Person{ID: "1", Firstname: "John", Lastname: "Doe", Address: &Address{City: "City X", State: "State X"}})
s.people = append(s.people, Person{ID: "2", Firstname: "Koko", Lastname: "Doe", Address: &Address{City: "City Z", State: "State Y"}})
}
// Run is to run serving explorer.
func (s *Service) Run() {
// Init address.
addr := net.JoinHostPort("", ExplorerServicePort)
// Set up router
s.router = mux.NewRouter()
s.router.HandleFunc("/people", s.GetPeopleEndpoint).Methods("GET")
s.router.HandleFunc("/people/{id}", s.GetPersonEndpoint).Methods("GET")
s.router.HandleFunc("/people/{id}", s.CreatePersonEndpoint).Methods("POST")
s.router.HandleFunc("/people/{id}", s.DeletePersonEndpoint).Methods("DELETE")
// Do serving now.
go log.Fatal(http.ListenAndServe(addr, s.router))
}
// Person is fake struct for testing.
type Person struct {
ID string `json:"id,omitempty"`
Firstname string `json:"firstname,omitempty"`
Lastname string `json:"lastname,omitempty"`
Address *Address `json:"address,omitempty"`
}
// Address is fake struct for testing.
type Address struct {
City string `json:"city,omitempty"`
State string `json:"state,omitempty"`
}
// GetPersonEndpoint is the specific person end point.
func (s *Service) GetPersonEndpoint(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
for _, item := range s.people {
if item.ID == params["id"] {
json.NewEncoder(w).Encode(item)
return
}
}
json.NewEncoder(w).Encode(&Person{})
}
// GetPeopleEndpoint is the people end point.
func (s *Service) GetPeopleEndpoint(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(s.people)
}
// CreatePersonEndpoint is post people/{id} end point.
func (s *Service) CreatePersonEndpoint(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
var person Person
_ = json.NewDecoder(r.Body).Decode(&person)
person.ID = params["id"]
s.people = append(s.people, person)
json.NewEncoder(w).Encode(s.people)
}
// DeletePersonEndpoint is delete people/{id} end point.
func (s *Service) DeletePersonEndpoint(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
for index, item := range s.people {
if item.ID == params["id"] {
s.people = append(s.people[:index], s.people[index+1:]...)
break
}
json.NewEncoder(w).Encode(s.people)
}
}

@ -0,0 +1,158 @@
package explorer_test
// http://www.golangprograms.com/golang-restful-api-using-grom-and-gorilla-mux.html
// https://dev.to/codehakase/building-a-restful-api-with-go
// https://thenewstack.io/make-a-restful-json-api-go/
// https://medium.com/@kelvin_sp/building-and-testing-a-rest-api-in-golang-using-gorilla-mux-and-mysql-1f0518818ff6
// var a App
// func TestMain(m *testing.M) {
// a = App{}
// a.Initialize("root", "", "rest_api_example")
// ensureTableExists()
// code := m.Run()
// clearTable()
// os.Exit(code)
// }
// func ensureTableExists() {
// if _, err := a.DB.Exec(tableCreationQuery); err != nil {
// log.Fatal(err)
// }
// }
// func clearTable() {
// a.DB.Exec("DELETE FROM users")
// a.DB.Exec("ALTER TABLE users AUTO_INCREMENT = 1")
// }
// func executeRequest(req *http.Request) *httptest.ResponseRecorder {
// rr := httptest.NewRecorder()
// a.Router.ServeHTTP(rr, req)
// return rr
// }
// func checkResponseCode(t *testing.T, expected, actual int) {
// if expected != actual {
// t.Errorf("Expected response code %d. Got %d\n", expected, actual)
// }
// }
// func TestGetNonExistentUser(t *testing.T) {
// clearTable()
// req, _ := http.NewRequest("GET", "/user/45", nil)
// response := executeRequest(req)
// checkResponseCode(t, http.StatusNotFound, response.Code)
// var m map[string]string
// json.Unmarshal(response.Body.Bytes(), &m)
// if m["error"] != "User not found" {
// t.Errorf("Expected the 'error' key of the response to be set to 'User not found'. Got '%s'", m["error"])
// }
// }
// func TestCreateUser(t *testing.T) {
// clearTable()
// payload := []byte(`{"name":"test user","age":30}`)
// req, _ := http.NewRequest("POST", "/user", bytes.NewBuffer(payload))
// response := executeRequest(req)
// checkResponseCode(t, http.StatusCreated, response.Code)
// var m map[string]interface{}
// json.Unmarshal(response.Body.Bytes(), &m)
// if m["name"] != "test user" {
// t.Errorf("Expected user name to be 'test user'. Got '%v'", m["name"])
// }
// if m["age"] != 30.0 {
// t.Errorf("Expected user age to be '30'. Got '%v'", m["age"])
// }
// // the id is compared to 1.0 because JSON unmarshaling converts numbers to
// // floats, when the target is a map[string]interface{}
// if m["id"] != 1.0 {
// t.Errorf("Expected product ID to be '1'. Got '%v'", m["id"])
// }
// }
// func addUsers(count int) {
// if count < 1 {
// count = 1
// }
// for i := 0; i < count; i++ {
// statement := fmt.Sprintf("INSERT INTO users(name, age) VALUES('%s', %d)", ("User " + strconv.Itoa(i+1)), ((i + 1) * 10))
// a.DB.Exec(statement)
// }
// }
// func TestGetUser(t *testing.T) {
// clearTable()
// addUsers(1)
// req, _ := http.NewRequest("GET", "/user/1", nil)
// response := executeRequest(req)
// checkResponseCode(t, http.StatusOK, response.Code)
// }
// func TestUpdateUser(t *testing.T) {
// clearTable()
// addUsers(1)
// req, _ := http.NewRequest("GET", "/user/1", nil)
// response := executeRequest(req)
// var originalUser map[string]interface{}
// json.Unmarshal(response.Body.Bytes(), &originalUser)
// payload := []byte(`{"name":"test user - updated name","age":21}`)
// req, _ = http.NewRequest("PUT", "/user/1", bytes.NewBuffer(payload))
// response = executeRequest(req)
// checkResponseCode(t, http.StatusOK, response.Code)
// var m map[string]interface{}
// json.Unmarshal(response.Body.Bytes(), &m)
// if m["id"] != originalUser["id"] {
// t.Errorf("Expected the id to remain the same (%v). Got %v", originalUser["id"], m["id"])
// }
// if m["name"] == originalUser["name"] {
// t.Errorf("Expected the name to change from '%v' to '%v'. Got '%v'", originalUser["name"], m["name"], m["name"])
// }
// if m["age"] == originalUser["age"] {
// t.Errorf("Expected the age to change from '%v' to '%v'. Got '%v'", originalUser["age"], m["age"], m["age"])
// }
// }
// func TestDeleteUser(t *testing.T) {
// clearTable()
// addUsers(1)
// req, _ := http.NewRequest("GET", "/user/1", nil)
// response := executeRequest(req)
// checkResponseCode(t, http.StatusOK, response.Code)
// req, _ = http.NewRequest("DELETE", "/user/1", nil)
// response = executeRequest(req)
// checkResponseCode(t, http.StatusOK, response.Code)
// req, _ = http.NewRequest("GET", "/user/1", nil)
// response = executeRequest(req)
// checkResponseCode(t, http.StatusNotFound, response.Code)
// }

@ -6,7 +6,7 @@ import (
"log" "log"
"time" "time"
pb "github.com/harmony-one/harmony/syncing/downloader/proto" pb "github.com/harmony-one/harmony/services/syncing/downloader/proto"
"google.golang.org/grpc" "google.golang.org/grpc"
) )

@ -1,7 +1,7 @@
package downloader package downloader
import ( import (
pb "github.com/harmony-one/harmony/syncing/downloader/proto" pb "github.com/harmony-one/harmony/services/syncing/downloader/proto"
) )
// DownloadInterface is the interface for downloader package. // DownloadInterface is the interface for downloader package.

@ -7,7 +7,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
pb "github.com/harmony-one/harmony/syncing/downloader/proto" pb "github.com/harmony-one/harmony/services/syncing/downloader/proto"
) )
// Constants for downloader server. // Constants for downloader server.

@ -6,8 +6,8 @@ import (
bc "github.com/harmony-one/harmony/blockchain" bc "github.com/harmony-one/harmony/blockchain"
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/syncing/downloader" "github.com/harmony-one/harmony/services/syncing/downloader"
pb "github.com/harmony-one/harmony/syncing/downloader/proto" pb "github.com/harmony-one/harmony/services/syncing/downloader/proto"
) )
const ( const (

@ -11,7 +11,7 @@ import (
"github.com/harmony-one/harmony/blockchain" "github.com/harmony-one/harmony/blockchain"
"github.com/harmony-one/harmony/log" "github.com/harmony-one/harmony/log"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/syncing/downloader" "github.com/harmony-one/harmony/services/syncing/downloader"
) )
// Constants for syncing. // Constants for syncing.

@ -7,9 +7,9 @@ import (
bc "github.com/harmony-one/harmony/blockchain" bc "github.com/harmony-one/harmony/blockchain"
"github.com/harmony-one/harmony/crypto/pki" "github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/p2p" "github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/syncing" "github.com/harmony-one/harmony/services/syncing"
"github.com/harmony-one/harmony/syncing/downloader" "github.com/harmony-one/harmony/services/syncing/downloader"
pb "github.com/harmony-one/harmony/syncing/downloader/proto" pb "github.com/harmony-one/harmony/services/syncing/downloader/proto"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"google.golang.org/grpc" "google.golang.org/grpc"
) )

@ -9,29 +9,23 @@ import (
var NumThreads = 20 var NumThreads = 20
func TestSingleton(t *testing.T) { func TestSingleton(t *testing.T) {
si := GetUniqueValidatorIDInstance()
var wg sync.WaitGroup var wg sync.WaitGroup
t.Log("unique ID provided by singleton instance")
for i := 0; i < NumThreads; i++ { for i := 0; i < NumThreads; i++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
t.Logf("id:%v\n", si.GetUniqueID())
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
}() }()
} }
wg.Wait() wg.Wait()
t.Log("non-unique ID")
n := 100 n := 100
for i := 0; i < NumThreads; i++ { for i := 0; i < NumThreads; i++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
defer wg.Done() defer wg.Done()
t.Log("num:", n)
n++ n++
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
}() }()

@ -69,20 +69,20 @@ func GenKey(ip, port string) (kyber.Scalar, kyber.Point) {
} }
// AllocateShard uses the number of current nodes and number of shards // AllocateShard uses the number of current nodes and number of shards
// to return the shardnum a new node belongs to, it also tells whether the node is a leader // to return the shardNum a new node belongs to, it also tells whether the node is a leader
func AllocateShard(numnode, numshards int) (int, bool) { func AllocateShard(numOfAddedNodes, numOfShards int) (int, bool) {
if numshards == 1 { if numOfShards == 1 {
if numnode == 1 { if numOfAddedNodes == 1 {
return 1, true return 1, true
} }
return 1, false return 1, false
} }
if numnode > numshards { if numOfAddedNodes > numOfShards {
shardnum := numnode % numshards shardNum := numOfAddedNodes % numOfShards
if shardnum == 0 { if shardNum == 0 {
return numshards, false return numOfShards, false
} }
return shardnum, false return shardNum, false
} }
return numnode, true return numOfAddedNodes, true
} }

Loading…
Cancel
Save