The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
woop/syncing/syncing.go

151 lines
3.7 KiB

package syncing
6 years ago
import (
"bufio"
"net"
"sync"
"time"
"github.com/Workiva/go-datastructures/queue"
"github.com/harmony-one/harmony/blockchain"
"github.com/harmony-one/harmony/p2p"
proto_node "github.com/harmony-one/harmony/proto/node"
6 years ago
)
type SyncPeerConfig struct {
peer p2p.Peer
conn net.Conn
w *bufio.Writer
err error
trusted bool
blockHashes [][32]byte
}
type SyncBlockTask struct {
index int
blockHash [32]byte
}
type SyncConfig struct {
peers []SyncPeerConfig
}
func StartBlockSyncing(peers []p2p.Peer) *blockchain.Blockchain {
6 years ago
peer_number := len(peers)
syncConfig := SyncConfig{
peers: make([]SyncPeerConfig, peer_number),
}
for id := range syncConfig.peers {
syncConfig.peers[id].peer = peers[id]
syncConfig.peers[id].trusted = false
}
var wg sync.WaitGroup
wg.Add(peer_number)
for id := range syncConfig.peers {
go func(peerConfig *SyncPeerConfig) {
defer wg.Done()
peerConfig.conn, peerConfig.err = p2p.DialWithSocketClient(peerConfig.peer.Ip, peerConfig.peer.Port)
}(&syncConfig.peers[id])
}
wg.Wait()
activePeerNumber := 0
for _, configPeer := range syncConfig.peers {
if configPeer.err == nil {
activePeerNumber++
configPeer.w = bufio.NewWriter(configPeer.conn)
configPeer.trusted = true
}
}
// Looping to get an array of block hashes from honest nodes.
LOOP_HONEST_NODE:
for {
var wg sync.WaitGroup
wg.Add(activePeerNumber)
for _, configPeer := range syncConfig.peers {
if configPeer.err != nil {
continue
}
go func(peerConfig *SyncPeerConfig) {
defer wg.Done()
msg := proto_node.ConstructBlockchainSyncMessage(proto_node.GetLastBlockHashes, [32]byte{})
6 years ago
peerConfig.w.Write(msg)
peerConfig.w.Flush()
var content []byte
content, peerConfig.err = p2p.ReadMessageContent(peerConfig.conn)
if peerConfig.err != nil {
peerConfig.trusted = false
return
}
var blockchainSyncMessage *proto_node.BlockchainSyncMessage
blockchainSyncMessage, peerConfig.err = proto_node.DeserializeBlockchainSyncMessage(content)
if peerConfig.err != nil {
peerConfig.trusted = false
return
}
peerConfig.blockHashes = blockchainSyncMessage.BlockHashes
}(&configPeer)
}
wg.Wait()
if getConsensus(&syncConfig) {
break LOOP_HONEST_NODE
}
}
taskSyncQueue := queue.New(0)
blockSize := 0
TASK_LOOP:
for _, configPeer := range syncConfig.peers {
if configPeer.trusted {
for id, blockHash := range configPeer.blockHashes {
taskSyncQueue.Put(SyncBlockTask{index: id, blockHash: blockHash})
}
blockSize = len(configPeer.blockHashes)
break TASK_LOOP
}
}
// Initialize blockchain
bc := &blockchain.Blockchain{
Blocks: make([]*blockchain.Block, blockSize),
}
wg.Add(activePeerNumber)
for _, configPeer := range syncConfig.peers {
if configPeer.err != nil {
continue
6 years ago
}
go func(peerConfig *SyncPeerConfig, taskSyncQueue *queue.Queue, bc *blockchain.Blockchain) {
defer wg.Done()
for !taskSyncQueue.Empty() {
task, err := taskSyncQueue.Poll(1, time.Millisecond)
if err == queue.ErrTimeout {
break
}
syncTask := task[0].(SyncBlockTask)
msg := proto_node.ConstructBlockchainSyncMessage(proto_node.GetBlock, syncTask.blockHash)
peerConfig.w.Write(msg)
peerConfig.w.Flush()
var content []byte
content, peerConfig.err = p2p.ReadMessageContent(peerConfig.conn)
if peerConfig.err != nil {
peerConfig.trusted = false
return
}
block, err := blockchain.DeserializeBlock(content)
if err == nil {
bc.Blocks[syncTask.index] = block
}
}
}(&configPeer, taskSyncQueue, bc)
6 years ago
}
wg.Wait()
return bc
6 years ago
}
func getConsensus(syncConfig *SyncConfig) bool {
return true
}