diff options
Diffstat (limited to 'simulation')
-rw-r--r-- | simulation/app.go | 23 | ||||
-rw-r--r-- | simulation/block-list.go | 64 | ||||
-rw-r--r-- | simulation/marshaller.go | 8 | ||||
-rw-r--r-- | simulation/peer-server.go | 53 | ||||
-rw-r--r-- | simulation/verification.go | 260 |
5 files changed, 0 insertions, 408 deletions
diff --git a/simulation/app.go b/simulation/app.go index 9f399ce..1a67a01 100644 --- a/simulation/app.go +++ b/simulation/app.go @@ -150,29 +150,6 @@ func (a *simApp) PrepareWitness(height uint64) (types.Witness, error) { return a.latestWitness, nil } -// TotalOrderingDelivered is called when blocks are delivered by the total -// ordering algorithm. -func (a *simApp) TotalOrderingDelivered( - blockHashes common.Hashes, mode uint32) { - fmt.Println("OUTPUT", a.NodeID, mode, blockHashes) - latencies := []time.Duration{} - func() { - a.lock.RLock() - defer a.lock.RUnlock() - for _, h := range blockHashes { - latencies = append(latencies, time.Since(a.blockTimestamps[h][blockEventReceived])) - } - }() - blockList := &BlockList{ - ID: a.DeliverID, - BlockHash: blockHashes, - ConfirmLatency: latencies, - } - // #nosec G104 - a.netModule.Report(blockList) - a.DeliverID++ -} - // BlockDelivered is called when a block in compaction chain is delivered. func (a *simApp) BlockDelivered( blockHash common.Hash, pos types.Position, result types.FinalizationResult) { diff --git a/simulation/block-list.go b/simulation/block-list.go deleted file mode 100644 index 9e329a7..0000000 --- a/simulation/block-list.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// <http://www.gnu.org/licenses/>. - -package simulation - -import ( - "time" - - "github.com/dexon-foundation/dexon-consensus/common" -) - -// BlockList is the list of blocks from the result of Total Ordering Algorithm. -type BlockList struct { - ID int `json:"id"` - BlockHash common.Hashes `json:"blockhash"` - ConfirmLatency []time.Duration `json:"confirmlatency"` - // The index is required by heap.Interface. - index int -} - -// PendingBlockList is a PrioirtyQueue maintaining the BlockList received -// before the previous one (based on ID). -type PendingBlockList []*BlockList - -// Len, Less and Swap are implementing heap.Interface -func (p PendingBlockList) Len() int { return len(p) } -func (p PendingBlockList) Less(i, j int) bool { return p[i].ID < p[j].ID } -func (p PendingBlockList) Swap(i, j int) { - p[i], p[j] = p[j], p[i] - p[i].index = i - p[j].index = j -} - -// Push item in the Heap. -func (p *PendingBlockList) Push(x interface{}) { - n := len(*p) - item := x.(*BlockList) - item.index = n - *p = append(*p, item) -} - -// Pop the element from the Heap. -func (p *PendingBlockList) Pop() interface{} { - old := *p - n := len(old) - item := old[n-1] - item.index = -1 // For safety. - *p = old[0 : n-1] - return item -} diff --git a/simulation/marshaller.go b/simulation/marshaller.go index 6f8aee4..4d2b511 100644 --- a/simulation/marshaller.go +++ b/simulation/marshaller.go @@ -36,12 +36,6 @@ func (m *jsonMarshaller) Unmarshal( break } msg = notif - case "blocklist": - var blocks BlockList - if err = json.Unmarshal(payload, &blocks); err != nil { - break - } - msg = &blocks case "message": var m message if err = json.Unmarshal(payload, &m); err != nil { @@ -63,8 +57,6 @@ func (m *jsonMarshaller) Marshal(msg interface{}) ( switch msg.(type) { case serverNotification: msgType = "server-notif" - case *BlockList: - msgType = "blocklist" case *message: msgType = "message" default: diff --git a/simulation/peer-server.go b/simulation/peer-server.go index a98c59a..3a925a4 100644 --- a/simulation/peer-server.go +++ b/simulation/peer-server.go @@ -19,12 +19,10 @@ package simulation import ( "context" - "encoding/json" "fmt" "log" "reflect" "sort" - "sync" "time" "github.com/dexon-foundation/dexon-consensus/common" @@ -38,8 +36,6 @@ type PeerServer struct { peers map[types.NodeID]struct{} msgChannel chan *test.TransportEnvelope trans test.TransportServer - peerTotalOrder PeerTotalOrder - peerTotalOrderMu sync.Mutex verifiedLen uint64 cfg *config.Config ctx context.Context @@ -53,7 +49,6 @@ func NewPeerServer() *PeerServer { ctx, cancel := context.WithCancel(context.Background()) return &PeerServer{ peers: make(map[types.NodeID]struct{}), - peerTotalOrder: make(PeerTotalOrder), ctx: ctx, ctxCancel: cancel, blockEvents: make(map[types.NodeID]map[common.Hash][]time.Time), @@ -68,36 +63,6 @@ func (p *PeerServer) isNode(nID types.NodeID) bool { return exist } -// handleBlockList is the handler for messages with BlockList as payload. -func (p *PeerServer) handleBlockList(id types.NodeID, blocks *BlockList) { - p.peerTotalOrderMu.Lock() - defer p.peerTotalOrderMu.Unlock() - - readyForVerify := p.peerTotalOrder[id].PushBlocks(*blocks) - if !readyForVerify { - return - } - // Verify the total order result. - go func(id types.NodeID) { - p.peerTotalOrderMu.Lock() - defer p.peerTotalOrderMu.Unlock() - - var correct bool - var length int - p.peerTotalOrder, correct, length = VerifyTotalOrder(id, p.peerTotalOrder) - if !correct { - log.Printf("The result of Total Ordering Algorithm has error.\n") - } - p.verifiedLen += uint64(length) - if p.verifiedLen >= p.cfg.Node.MaxBlock { - if err := p.trans.Broadcast( - p.peers, &test.FixedLatencyModel{}, ntfShutdown); err != nil { - panic(err) - } - } - }(id) -} - // handleMessage is the handler for messages with Message as payload. func (p *PeerServer) handleMessage(id types.NodeID, m *message) { switch m.Type { @@ -107,16 +72,6 @@ func (p *PeerServer) handleMessage(id types.NodeID, m *message) { if len(p.peers) == 0 { p.ctxCancel() } - case blockTimestamp: - msgs := []timestampMessage{} - if err := json.Unmarshal(m.Payload, &msgs); err != nil { - panic(err) - } - for _, msg := range msgs { - if ok := p.peerTotalOrder[id].PushTimestamp(msg); !ok { - panic(fmt.Errorf("unable to push timestamp: %v", m)) - } - } default: panic(fmt.Errorf("unknown simulation message type: %v", m)) } @@ -157,8 +112,6 @@ func (p *PeerServer) mainLoop() { } // Handle messages based on their type. switch val := e.Msg.(type) { - case *BlockList: - p.handleBlockList(e.From, val) case *message: p.handleMessage(e.From, val) case *test.BlockEventMessage: @@ -235,14 +188,8 @@ func (p *PeerServer) Run() { panic(err) } log.Println("Simulation is ready to go with", len(p.peers), "nodes") - // Initialize total order result cache. - for id := range p.peers { - p.peerTotalOrder[id] = NewTotalOrderResult(id) - } // Block to handle incoming messages. p.mainLoop() - // The simulation is done, clean up. - LogStatus(p.peerTotalOrder) if err := p.trans.Close(); err != nil { log.Printf("Error shutting down peerServer: %v\n", err) } diff --git a/simulation/verification.go b/simulation/verification.go deleted file mode 100644 index a5aad8f..0000000 --- a/simulation/verification.go +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// <http://www.gnu.org/licenses/>. - -package simulation - -import ( - "container/heap" - "log" - "math" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/test" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -type timeStamp struct { - time time.Time - length int -} - -type totalOrderStatus struct { - blockReceive []timeStamp - confirmLatency []time.Duration - blockSeen map[common.Hash]time.Time - internalTimestampLatency []time.Duration - externalTimestampLatency []time.Duration -} - -// TotalOrderResult is the object maintaining peer's result of -// Total Ordering Algorithm. -type TotalOrderResult struct { - nodeID types.NodeID - hashList common.Hashes - curID int - pendingBlockList PendingBlockList - status totalOrderStatus -} - -// PeerTotalOrder stores the TotalOrderResult of each node. -type PeerTotalOrder = map[types.NodeID]*TotalOrderResult - -// NewTotalOrderResult returns pointer to a a new TotalOrderResult instance. -func NewTotalOrderResult(nID types.NodeID) *TotalOrderResult { - totalOrder := &TotalOrderResult{ - nodeID: nID, - status: totalOrderStatus{ - blockSeen: make(map[common.Hash]time.Time), - }, - } - heap.Init(&totalOrder.pendingBlockList) - return totalOrder -} - -func (totalOrder *TotalOrderResult) processStatus(blocks BlockList) { - totalOrder.status.blockReceive = append(totalOrder.status.blockReceive, - timeStamp{ - time: time.Now(), - length: len(blocks.BlockHash), - }) - totalOrder.status.confirmLatency = append(totalOrder.status.confirmLatency, - blocks.ConfirmLatency...) -} - -// PushBlocks push a BlockList into the TotalOrderResult and return true if -// there are new blocks ready for verification. -func (totalOrder *TotalOrderResult) PushBlocks(blocks BlockList) (ready bool) { - totalOrder.processStatus(blocks) - if blocks.ID != totalOrder.curID { - heap.Push(&totalOrder.pendingBlockList, &blocks) - return false - } - - // Append all of the consecutive blockList in the pendingBlockList. - for { - totalOrder.hashList = append(totalOrder.hashList, blocks.BlockHash...) - totalOrder.curID++ - if len(totalOrder.pendingBlockList) == 0 || - totalOrder.pendingBlockList[0].ID != totalOrder.curID { - break - } - blocks = *heap.Pop(&totalOrder.pendingBlockList).(*BlockList) - } - return true -} - -// PushTimestamp logs the information in the msg. -func (totalOrder *TotalOrderResult) PushTimestamp(msg timestampMessage) bool { - pushLatency := func(latency *[]time.Duration, t1, t2 time.Time) { - *latency = append(*latency, t2.Sub(t1)) - } - switch msg.Event { - case blockSeen: - totalOrder.status.blockSeen[msg.BlockHash] = msg.Timestamp - case timestampConfirm: - pushLatency(&totalOrder.status.internalTimestampLatency, - totalOrder.status.blockSeen[msg.BlockHash], msg.Timestamp) - case timestampAck: - if seenTime, exist := totalOrder.status.blockSeen[msg.BlockHash]; exist { - pushLatency(&totalOrder.status.externalTimestampLatency, - seenTime, msg.Timestamp) - } - default: - return false - } - return true -} - -// CalculateBlocksPerSecond calculates the result using status.blockReceive -func (totalOrder *TotalOrderResult) CalculateBlocksPerSecond() float64 { - ts := totalOrder.status.blockReceive - if len(ts) < 2 { - return 0 - } - - diffTime := ts[len(ts)-1].time.Sub(ts[0].time).Seconds() - if diffTime == 0 { - return 0 - } - totalBlocks := 0 - for _, blocks := range ts { - // Blocks received at time zero are confirmed beforehand. - if blocks.time == ts[0].time { - continue - } - totalBlocks += blocks.length - } - return float64(totalBlocks) / diffTime -} - -// CalculateAverageConfirmLatency calculates the result using -// status.confirmLatency -func (totalOrder *TotalOrderResult) CalculateAverageConfirmLatency() float64 { - sum := 0.0 - for _, latency := range totalOrder.status.confirmLatency { - sum += latency.Seconds() - } - return sum / float64(len(totalOrder.status.confirmLatency)) -} - -// CalculateAverageTimestampLatency calculates the result using -// status.timestampLatency -func (totalOrder *TotalOrderResult) CalculateAverageTimestampLatency() ( - internal float64, external float64) { - for _, latency := range totalOrder.status.internalTimestampLatency { - internal += latency.Seconds() - } - if internal > 0 { - internal /= float64(len(totalOrder.status.internalTimestampLatency)) - } - for _, latency := range totalOrder.status.externalTimestampLatency { - external += latency.Seconds() - } - if external > 0 { - external /= float64(len(totalOrder.status.externalTimestampLatency)) - } - return -} - -// VerifyTotalOrder verifies if the result of Total Ordering Algorithm -// returned by all nodes are the same. However, the length of result -// of each nodes may not be the same, so only the common part is verified. -func VerifyTotalOrder(id types.NodeID, - totalOrder PeerTotalOrder) ( - unverifiedMap PeerTotalOrder, correct bool, length int) { - - hasError := false - - // Get the common length from all nodes. - length = math.MaxInt32 - for _, peerTotalOrder := range totalOrder { - if len(peerTotalOrder.hashList) < length { - length = len(peerTotalOrder.hashList) - } - } - - // Verify if the order of the blocks are the same by comparing - // the hash value. - for i := 0; i < length; i++ { - hash := totalOrder[id].hashList[i] - for vid, peerTotalOrder := range totalOrder { - if peerTotalOrder.hashList[i] != hash { - log.Printf("[%d] Unexpected hash %v from %v\n", i, - peerTotalOrder.hashList[i], vid) - hasError = true - } - } - if hasError { - log.Printf("[%d] Hash is %v from %v\n", i, hash, id) - } else { - log.Printf("Block %v confirmed\n", hash) - } - } - - // Remove verified block from list. - if length > 0 { - for vid := range totalOrder { - totalOrder[vid].hashList = - totalOrder[vid].hashList[length:] - } - } - return totalOrder, !hasError, length -} - -// LogStatus prints all the status to log. -func LogStatus(peerTotalOrder PeerTotalOrder) { - for nID, totalOrder := range peerTotalOrder { - log.Printf("[Node %s]\n", nID) - log.Printf(" BPS: %.6f\n", totalOrder.CalculateBlocksPerSecond()) - log.Printf(" Confirm Latency: %.2fms\n", - totalOrder.CalculateAverageConfirmLatency()*1000) - log.Printf(" Confirm Blocks: %v\n", len(totalOrder.status.confirmLatency)) - intLatency, extLatency := totalOrder.CalculateAverageTimestampLatency() - log.Printf(" Internal Timestamp Latency: %.2fms\n", intLatency*1000) - log.Printf(" External Timestamp Latency: %.2fms\n", extLatency*1000) - } - logOverallLatency(peerTotalOrder) -} - -// logOverallLatency prints overall status related to latency. -func logOverallLatency(peerTotalOrder PeerTotalOrder) { - // Let's use brute-force way since the simulation should be done - // at this moment. - var ( - overallConfirmLatency []time.Duration - overallInternalTimestampLatency []time.Duration - overallExternalTimestampLatency []time.Duration - ) - for _, totalOrder := range peerTotalOrder { - overallConfirmLatency = append( - overallConfirmLatency, totalOrder.status.confirmLatency...) - overallInternalTimestampLatency = append( - overallInternalTimestampLatency, - totalOrder.status.internalTimestampLatency...) - overallExternalTimestampLatency = append( - overallExternalTimestampLatency, - totalOrder.status.externalTimestampLatency...) - } - log.Print("[Overall]\n") - avg, dev := test.CalcLatencyStatistics(overallConfirmLatency) - log.Printf(" Confirm Latency: %v, dev: %v\n", avg, dev) - avg, dev = test.CalcLatencyStatistics(overallInternalTimestampLatency) - log.Printf(" Interal Timestamp Latency: %v, dev: %v\n", avg, dev) - avg, dev = test.CalcLatencyStatistics(overallExternalTimestampLatency) - log.Printf(" External Timestamp Latency: %v, dev: %v\n", avg, dev) -} |