github.com/annchain/OG@v0.0.9/tests/txsync/tx_sync.go (about)

     1  // Copyright © 2019 Annchain Authors <EMAIL ADDRESS>
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package main
    15  
    16  import (
    17  	"encoding/json"
    18  	"fmt"
    19  	"github.com/annchain/OG/wserver"
    20  	"github.com/gorilla/websocket"
    21  	"github.com/sirupsen/logrus"
    22  	"net/http"
    23  	"net/url"
    24  	"time"
    25  )
    26  
    27  type pm struct {
    28  	message string
    29  	port    int
    30  }
    31  
    32  const PORT_OFFSET_WS = 2
    33  const PORT_OFFSET_RPC = 0
    34  const PORT_START = 8000
    35  const PORT_GAP = 100
    36  const NODES = 30
    37  const REPORT_INTERVAL_SECONDS = 5
    38  
    39  func main() {
    40  	logrus.SetFormatter(&logrus.TextFormatter{
    41  		ForceColors:   true,
    42  		FullTimestamp: true,
    43  	})
    44  	logrus.SetLevel(logrus.InfoLevel)
    45  	agg := make(chan pm, 1000)
    46  	count := 0
    47  
    48  	maxPort := PORT_START
    49  
    50  	for port := PORT_START; port <= PORT_START+NODES*PORT_GAP; port += PORT_GAP {
    51  		err := startListen(agg, port)
    52  		if err != nil {
    53  			continue
    54  		}
    55  		if port > maxPort {
    56  			maxPort = port
    57  		}
    58  		count += 1
    59  	}
    60  	mapcount := make(map[string]map[int]struct{})
    61  
    62  	deleted := 0
    63  
    64  	ticker := time.NewTicker(time.Second * REPORT_INTERVAL_SECONDS)
    65  	defer ticker.Stop()
    66  
    67  	http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 5
    68  
    69  	lastCheck := time.Now()
    70  
    71  	for {
    72  		select {
    73  		case <-ticker.C:
    74  			logrus.Warn("Ticker")
    75  			toDelete := []string{}
    76  			for k := range mapcount {
    77  				changed := false
    78  				// manual query to double confirm
    79  				for missingPort := PORT_START; missingPort <= maxPort; missingPort += PORT_GAP {
    80  					if _, ok := mapcount[k][missingPort]; !ok {
    81  						if manualQuery(missingPort, k) {
    82  							mapcount[k][missingPort] = struct{}{}
    83  							changed = true
    84  							logrus.WithField("hash", k).WithField("port", missingPort).
    85  								Debug("manually fetched by rpc. ws missing?")
    86  						}
    87  					}
    88  				}
    89  				if !changed {
    90  					if len(mapcount[k]) == count {
    91  						logrus.WithField("hash", k).Debug("Should be fulfilled but not.")
    92  						toDelete = append(toDelete, k)
    93  					} else {
    94  						logrus.WithField("key", k).WithField("value", mapcount[k]).Warn("Still not fulfilled")
    95  					}
    96  				}
    97  			}
    98  			for _, k := range toDelete {
    99  				delete(mapcount, k)
   100  				deleted += 1
   101  			}
   102  			logrus.WithField("count", deleted).
   103  				WithField("v", float64(deleted)/(time.Since(lastCheck).Seconds())).
   104  				Info("tps")
   105  			lastCheck = time.Now()
   106  			deleted = 0
   107  		case m := <-agg:
   108  			uidata := &wserver.UIData{}
   109  			err := json.Unmarshal([]byte(m.message), uidata)
   110  			if err != nil {
   111  				logrus.WithField("port", m.port).WithError(err).Error("unmarshal")
   112  				return
   113  			}
   114  			for _, node := range uidata.Nodes {
   115  				key := node.Data.Unit
   116  				//logrus.WithFields(logrus.Fields{
   117  				//	"port": m.port,
   118  				//	"len":  len(uidata.Nodes),
   119  				//	"tx":   key,
   120  				//}).Debug("new tx")
   121  
   122  				if _, ok := mapcount[key]; !ok {
   123  					mapcount[key] = make(map[int]struct{})
   124  				}
   125  				mapcount[key][m.port] = struct{}{}
   126  				if len(mapcount[key]) == count {
   127  					logrus.WithField("key", key).Debug("fully announced")
   128  					delete(mapcount, key)
   129  					deleted += 1
   130  				}
   131  			}
   132  		}
   133  	}
   134  }
   135  func manualQuery(port int, hash string) bool {
   136  	resp, err := http.Get(fmt.Sprintf("http://localhost:%d/transaction?hash=%s", port+PORT_OFFSET_RPC, hash))
   137  
   138  	if err != nil {
   139  		logrus.WithField("port", port).WithError(err).Warn("Request query error")
   140  		return false
   141  	}
   142  	defer resp.Body.Close()
   143  	return true
   144  
   145  }
   146  func startListen(agg chan pm, port int) error {
   147  	wsPort := port + PORT_OFFSET_WS
   148  	u := url.URL{Scheme: "ws", Host: fmt.Sprintf("127.0.0.1:%d", wsPort), Path: "/ws"}
   149  	logrus.Infof("connecting to %s", u.String())
   150  
   151  	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
   152  	if err != nil {
   153  		logrus.WithError(err).Errorf("dial")
   154  		return err
   155  	}
   156  
   157  	go func() {
   158  		err := c.WriteMessage(websocket.TextMessage, []byte("{\"event\": \"new_unit\"}"))
   159  		if err != nil {
   160  			logrus.WithField("port", wsPort).Error("write")
   161  			return
   162  		}
   163  
   164  		for {
   165  			_, message, err := c.ReadMessage()
   166  			if err != nil {
   167  				logrus.WithError(err).WithField("port", wsPort).Error("read error")
   168  				return
   169  			}
   170  			agg <- pm{message: string(message), port: port}
   171  		}
   172  	}()
   173  	return nil
   174  }