<commit_before>package server

import (
	"encoding/json"
	"net/http"
	"strings"
	"time"

	nickHelix "github.com/nicklaw5/helix"

	"github.com/dgrijalva/jwt-go"
	log "github.com/sirupsen/logrus"
)

type userAcessTokenData struct {
	AccessToken  string
	RefreshToken string
	Scope        string
}

type tokenClaims struct {
	UserID         string
	StandardClaims jwt.StandardClaims
}

func (t *tokenClaims) Valid() error {
	return nil
}

func (s *Server) handleCallback(w http.ResponseWriter, r *http.Request) {
	code := r.URL.Query().Get("code")

	resp, err := s.helixUserClient.Client.RequestUserAccessToken(code)
	if err != nil || resp.StatusCode >= 400 {
		log.Errorf("failed to request userAccessToken: %s %v", err, resp)
		s.dashboardRedirect(w, r, http.StatusBadRequest, "")
		return
	}

	// validate
	success, validateResp, err := s.helixClient.Client.ValidateToken(resp.Data.AccessToken)
	if !success || err != nil {
		log.Errorf("failed to veryify new Token %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	token, err := s.createApiToken(validateResp.Data.UserID)
	if err != nil {
		log.Errorf("failed to create jwt token in callback %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	marshalled, err := json.Marshal(userAcessTokenData{resp.Data.AccessToken, resp.Data.RefreshToken, strings.Join(resp.Data.Scopes, " ")})
	if err != nil {
		log.Errorf("failed to marshal userAcessToken in callback %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	err = s.store.Client.HSet("userAccessTokensData", validateResp.Data.UserID, marshalled).Err()
	if err != nil {
		log.Errorf("failed to set userAccessToken in callback: %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	s.dashboardRedirect(w, r, http.StatusOK, token)
}

func (s *Server) createApiToken(userID string) (string, error) {
	expirationTime := time.Now().Add(365 * 24 * time.Hour)
	claims := &tokenClaims{
		UserID: userID,
		StandardClaims: jwt.StandardClaims{
			// In JWT, the expiry time is expressed as unix milliseconds
			ExpiresAt: expirationTime.Unix(),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString([]byte(s.cfg.Secret))

	return tokenString, err
}

func (s *Server) dashboardRedirect(w http.ResponseWriter, r *http.Request, status int, scToken string) {
	cookie := http.Cookie{
		Name:    "scToken",
		Value:   scToken,
		Domain:  s.cfg.CookieDomain,
		Expires: time.Now().Add(365 * 24 * time.Hour),
		Path:    "/",
	}

	http.SetCookie(w, &cookie)

	http.Redirect(w, r, s.cfg.WebBaseUrl+"/dashboard", http.StatusFound)
}

func (s *Server) getUserAccessToken(userID string) (userAcessTokenData, error) {
	val, err := s.store.Client.HGet("userAccessTokensData", userID).Result()
	if err != nil {
		return userAcessTokenData{}, err
	}

	var token userAcessTokenData
	if err := json.Unmarshal([]byte(val), &token); err != nil {
		return userAcessTokenData{}, err
	}

	return token, nil
}

func (s *Server) authenticate(r *http.Request) (bool, *nickHelix.ValidateTokenResponse, *userAcessTokenData) {
	scToken := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")

	// Initialize a new instance of `Claims`
	claims := &tokenClaims{}

	// Parse the JWT string and store the result in `claims`.
	// Note that we are passing the key in this method as well. This method will return an error
	// if the token is invalid (if it has expired according to the expiry time we set on sign in),
	// or if the signature does not match
	tkn, err := jwt.ParseWithClaims(scToken, claims, func(token *jwt.Token) (interface{}, error) {
		return []byte(s.cfg.Secret), nil
	})
	if err != nil || !tkn.Valid {
		log.Errorf("found to validate jwt: %s", err)
		return false, nil, nil
	}

	token, err := s.getUserAccessToken(claims.UserID)
	if err != nil {
		log.Errorf("Failed to get userAccessTokenData: %s", err.Error())
		return false, nil, nil
	}

	success, resp, err := s.helixClient.Client.ValidateToken(token.AccessToken)
	if !success || err != nil {
		if err != nil {
			log.Errorf("token did not validate: %s", err)
		}

		// Token might be expired, let's try refreshing
		if resp.Error == "Unauthorized" {
			success, refreshResp := s.refreshToken(scToken, token)
			if !success {
				return false, nil, nil
			}

			success, resp, err = s.helixClient.Client.ValidateToken(refreshResp.AccessToken)
			if !success || err != nil {
				if err != nil {
					log.Errorf("refreshed Token did not validate: %s", err)
				}

				return success, resp, refreshResp
			}
		}

		return false, nil, nil
	}

	return success, resp, &token
}

func (s *Server) refreshToken(userID string, token userAcessTokenData) (bool, *userAcessTokenData) {
	resp, err := s.helixClient.Client.RefreshUserAccessToken(token.RefreshToken)
	if err != nil {
		log.Errorf("failed refresh userAcessToken: %s", err)
		return false, nil
	}

	newToken := userAcessTokenData{resp.Data.AccessToken, resp.Data.RefreshToken, strings.Join(resp.Data.Scopes, " ")}
	marshalled, err := json.Marshal(newToken)
	if err != nil {
		log.Errorf("failed marshal refreshed userAcessToken: %s", err)
		return false, nil
	}

	err = s.store.Client.HSet("userAccessTokensData", userID, marshalled).Err()
	if err != nil {
		log.Errorf("failed to set userAccessTokenData to redis: %s", err)
		return false, nil
	}

	return true, &newToken
}

func (s *Server) tokenRefreshRoutine() {
	for {
		time.Sleep(time.Hour)

		tokens, err := s.store.Client.HGetAll("userAccessTokensData").Result()
		if err != nil {
			log.Errorf("tried refreshing tokens: %s", err)
			continue
		}

		log.Infof("starting refresh of %d tokens", len(tokens))

		for userID, tokenDataString := range tokens {
			var userToken userAcessTokenData
			if err := json.Unmarshal([]byte(tokenDataString), &userToken); err != nil {
				log.Errorf("failed unmarshal userAccessTokenData in tokenRefreshRoutine %s", err)
				continue
			}

			s.refreshToken(userID, userToken)
			time.Sleep(time.Millisecond * 500)
		}

		log.Infof("finished refresh of %d tokens", len(tokens))
	}
}
<commit_msg>subscribe webhooks once again<commit_after>package server

import (
	"encoding/json"
	"net/http"
	"strings"
	"time"

	nickHelix "github.com/nicklaw5/helix"

	"github.com/dgrijalva/jwt-go"
	log "github.com/sirupsen/logrus"
)

type userAcessTokenData struct {
	AccessToken  string
	RefreshToken string
	Scope        string
}

type tokenClaims struct {
	UserID         string
	StandardClaims jwt.StandardClaims
}

func (t *tokenClaims) Valid() error {
	return nil
}

func (s *Server) handleCallback(w http.ResponseWriter, r *http.Request) {
	code := r.URL.Query().Get("code")

	resp, err := s.helixUserClient.Client.RequestUserAccessToken(code)
	if err != nil || resp.StatusCode >= 400 {
		log.Errorf("failed to request userAccessToken: %s %v", err, resp)
		s.dashboardRedirect(w, r, http.StatusBadRequest, "")
		return
	}

	// validate
	success, validateResp, err := s.helixClient.Client.ValidateToken(resp.Data.AccessToken)
	if !success || err != nil {
		log.Errorf("failed to veryify new Token %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	token, err := s.createApiToken(validateResp.Data.UserID)
	if err != nil {
		log.Errorf("failed to create jwt token in callback %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	marshalled, err := json.Marshal(userAcessTokenData{resp.Data.AccessToken, resp.Data.RefreshToken, strings.Join(resp.Data.Scopes, " ")})
	if err != nil {
		log.Errorf("failed to marshal userAcessToken in callback %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	err = s.store.Client.HSet("userAccessTokensData", validateResp.Data.UserID, marshalled).Err()
	if err != nil {
		log.Errorf("failed to set userAccessToken in callback: %s", err)
		s.dashboardRedirect(w, r, http.StatusInternalServerError, "")
	}

	s.dashboardRedirect(w, r, http.StatusOK, token)
}

func (s *Server) createApiToken(userID string) (string, error) {
	expirationTime := time.Now().Add(365 * 24 * time.Hour)
	claims := &tokenClaims{
		UserID: userID,
		StandardClaims: jwt.StandardClaims{
			// In JWT, the expiry time is expressed as unix milliseconds
			ExpiresAt: expirationTime.Unix(),
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString([]byte(s.cfg.Secret))

	return tokenString, err
}

func (s *Server) dashboardRedirect(w http.ResponseWriter, r *http.Request, status int, scToken string) {
	cookie := http.Cookie{
		Name:    "scToken",
		Value:   scToken,
		Domain:  s.cfg.CookieDomain,
		Expires: time.Now().Add(365 * 24 * time.Hour),
		Path:    "/",
	}

	http.SetCookie(w, &cookie)

	http.Redirect(w, r, s.cfg.WebBaseUrl+"/dashboard", http.StatusFound)
}

func (s *Server) getUserAccessToken(userID string) (userAcessTokenData, error) {
	val, err := s.store.Client.HGet("userAccessTokensData", userID).Result()
	if err != nil {
		return userAcessTokenData{}, err
	}

	var token userAcessTokenData
	if err := json.Unmarshal([]byte(val), &token); err != nil {
		return userAcessTokenData{}, err
	}

	return token, nil
}

func (s *Server) authenticate(r *http.Request) (bool, *nickHelix.ValidateTokenResponse, *userAcessTokenData) {
	scToken := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")

	// Initialize a new instance of `Claims`
	claims := &tokenClaims{}

	// Parse the JWT string and store the result in `claims`.
	// Note that we are passing the key in this method as well. This method will return an error
	// if the token is invalid (if it has expired according to the expiry time we set on sign in),
	// or if the signature does not match
	tkn, err := jwt.ParseWithClaims(scToken, claims, func(token *jwt.Token) (interface{}, error) {
		return []byte(s.cfg.Secret), nil
	})
	if err != nil || !tkn.Valid {
		log.Errorf("found to validate jwt: %s", err)
		return false, nil, nil
	}

	token, err := s.getUserAccessToken(claims.UserID)
	if err != nil {
		log.Errorf("Failed to get userAccessTokenData: %s", err.Error())
		return false, nil, nil
	}

	success, resp, err := s.helixClient.Client.ValidateToken(token.AccessToken)
	if !success || err != nil {
		if err != nil {
			log.Errorf("token did not validate: %s", err)
		}

		// Token might be expired, let's try refreshing
		if resp.Error == "Unauthorized" {
			success, refreshResp := s.refreshToken(scToken, token)
			if !success {
				return false, nil, nil
			}

			success, resp, err = s.helixClient.Client.ValidateToken(refreshResp.AccessToken)
			if !success || err != nil {
				if err != nil {
					log.Errorf("refreshed Token did not validate: %s", err)
				}

				return success, resp, refreshResp
			}
		}

		return false, nil, nil
	}

	return success, resp, &token
}

func (s *Server) refreshToken(userID string, token userAcessTokenData) (bool, *userAcessTokenData) {
	resp, err := s.helixClient.Client.RefreshUserAccessToken(token.RefreshToken)
	if err != nil {
		log.Errorf("failed refresh userAcessToken: %s", err)
		return false, nil
	}

	newToken := userAcessTokenData{resp.Data.AccessToken, resp.Data.RefreshToken, strings.Join(resp.Data.Scopes, " ")}
	marshalled, err := json.Marshal(newToken)
	if err != nil {
		log.Errorf("failed marshal refreshed userAcessToken: %s", err)
		return false, nil
	}

	err = s.store.Client.HSet("userAccessTokensData", userID, marshalled).Err()
	if err != nil {
		log.Errorf("failed to set userAccessTokenData to redis: %s", err)
		return false, nil
	}

	return true, &newToken
}

func (s *Server) tokenRefreshRoutine() {
	for {
		time.Sleep(time.Hour)

		tokens, err := s.store.Client.HGetAll("userAccessTokensData").Result()
		if err != nil {
			log.Errorf("tried refreshing tokens: %s", err)
			continue
		}

		log.Infof("starting refresh of %d tokens", len(tokens))

		for userID, tokenDataString := range tokens {
			var userToken userAcessTokenData
			if err := json.Unmarshal([]byte(tokenDataString), &userToken); err != nil {
				log.Errorf("failed unmarshal userAccessTokenData in tokenRefreshRoutine %s", err)
				continue
			}

			s.subscribeChannelPoints(userID)

			s.refreshToken(userID, userToken)
			time.Sleep(time.Millisecond * 500)
		}

		log.Infof("finished refresh of %d tokens", len(tokens))
	}
}
<|endoftext|>


<commit_before>package chat

import (
	"fmt"
	"io"
	"net"
	"sync"
)

type (
	// FakeConnection is an interface for a network connection
	FakeConnection struct {
		Outgoing  []byte
		Incoming  []byte
		Lock      *sync.Mutex
		EnableLog bool
	}
	FakeNetwork struct{}
)

func NewMockedChatConnection() *FakeConnection {
	fmt.Printf("Creating new mocked connection\n")
	return &FakeConnection{
		Lock:      new(sync.Mutex),
		Incoming:  make([]byte, 0),
		Outgoing:  make([]byte, 0),
		EnableLog: false,
	}
}

func (m *FakeConnection) Write(p []byte) (int, error) {
	fmt.Printf("Writing data to connection\n")
	m.Lock.Lock()
	defer m.Lock.Unlock()
	m.Outgoing = p
	return len(m.Outgoing), nil
}

func (m *FakeConnection) ReadOutgoing() []byte {
	fmt.Printf("Reading outgoing data from connection\n")
	m.Lock.Lock()
	defer m.Lock.Unlock()
	outgoing := m.Outgoing
	return outgoing
}

func (m *FakeConnection) Read(p []byte) (int, error) {
	fmt.Printf("Reading data from connection\n")
	m.Lock.Lock()
	defer m.Lock.Unlock()
	if len(m.Incoming) == 0 {
		return 0, io.EOF
	}
	i := 0
	for _, bit := range m.Incoming {
		p[i] = bit
		i++
	}
	return i, nil
}

func (f *FakeNetwork) Network() string {
	fmt.Printf("Reading network\n")
	return ``
}

func (f *FakeNetwork) String() string {
	fmt.Printf("Returning string\n")
	return ``
}

func (m *FakeConnection) Close() error {
	fmt.Printf("Closing connection\n")
	return nil
}

func (m *FakeConnection) RemoteAddr() net.Addr {
	fmt.Printf("Reading remote address\n")
	return new(FakeNetwork)
}
<commit_msg>Add end messages to fake connection<commit_after>package chat

import (
	"fmt"
	"io"
	"net"
	"sync"
)

type (
	// FakeConnection is an interface for a network connection
	FakeConnection struct {
		Outgoing  []byte
		Incoming  []byte
		Lock      *sync.Mutex
		EnableLog bool
	}
	FakeNetwork struct{}
)

func NewMockedChatConnection() *FakeConnection {
	fmt.Printf("Creating new mocked connection\n")
	return &FakeConnection{
		Lock:      new(sync.Mutex),
		Incoming:  make([]byte, 0),
		Outgoing:  make([]byte, 0),
		EnableLog: false,
	}
}

func (m *FakeConnection) Write(p []byte) (int, error) {
	fmt.Printf("Start - Writing data to connection\n")
	m.Lock.Lock()
	defer m.Lock.Unlock()
	m.Outgoing = p
	fmt.Printf("End - Writing data to connection\n")
	return len(m.Outgoing), nil
}

func (m *FakeConnection) ReadOutgoing() []byte {
	fmt.Printf("Start - Reading outgoing data from connection\n")
	m.Lock.Lock()
	defer m.Lock.Unlock()
	outgoing := m.Outgoing
	fmt.Printf("End - Reading outgoing data from connection\n")
	return outgoing
}

func (m *FakeConnection) Read(p []byte) (int, error) {
	fmt.Printf("Start - Reading data from connection\n")
	m.Lock.Lock()
	defer m.Lock.Unlock()
	if len(m.Incoming) == 0 {
		fmt.Printf("End - EOF Reading data from connection\n")
		return 0, io.EOF
	}
	i := 0
	for _, bit := range m.Incoming {
		p[i] = bit
		i++
	}
	fmt.Printf("End - Reading data from connection\n")
	return i, nil
}

func (f *FakeNetwork) Network() string {
	fmt.Printf("Reading network\n")
	return ``
}

func (f *FakeNetwork) String() string {
	fmt.Printf("Returning string\n")
	return ``
}

func (m *FakeConnection) Close() error {
	fmt.Printf("Closing connection\n")
	return nil
}

func (m *FakeConnection) RemoteAddr() net.Addr {
	fmt.Printf("Reading remote address\n")
	return new(FakeNetwork)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"github.com/codegangsta/cli"
	"io"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"text/template"
	"unicode"
)

const (
	TK_SYMBOL = iota
	TK_STRUCT_BEGIN
	TK_STRUCT_END
	TK_DATA_TYPE
	TK_ARRAY
	TK_EOF
)

var (
	datatypes map[string]lang_type
)

var (
	TOKEN_EOF = &token{typ: TK_EOF}
)

type (
	func_info struct {
		T string `json:"t"` // type
		R string `json:"r"` // read
		W string `json:"w"` // write
	}
	lang_type struct {
		Go func_info `json:"go"` // golang
		Cs func_info `json:"cs"` // c#
	}
)

type (
	field_info struct {
		Name  string
		Typ   string
		Array bool
	}
	struct_info struct {
		Name   string
		Fields []field_info
	}
)

type token struct {
	typ     int
	literal string
	r       rune
}

func syntax_error(p *Parser) {
	log.Println("syntax error @line:", p.lexer.lineno)
	log.Println(">> \033[1;31m", p.lexer.lines[p.lexer.lineno-1], "\033[0m <<")
	os.Exit(-1)
}

type Lexer struct {
	reader *bytes.Buffer
	lines  []string
	lineno int
}

func (lex *Lexer) init(r io.Reader) {
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}

	// 按行读入源码
	scanner := bufio.NewScanner(bytes.NewBuffer(bts))
	for scanner.Scan() {
		lex.lines = append(lex.lines, scanner.Text())
	}

	// 清除注释
	re := regexp.MustCompile("(?m:^#(.*)$)")
	bts = re.ReplaceAllLiteral(bts, nil)
	lex.reader = bytes.NewBuffer(bts)
	lex.lineno = 1
}

func (lex *Lexer) next() (t *token) {
	defer func() {
		//log.Println(t)
	}()
	var r rune
	var err error
	for {
		r, _, err = lex.reader.ReadRune()
		if err == io.EOF {
			return TOKEN_EOF
		} else if unicode.IsSpace(r) {
			if r == '\n' {
				lex.lineno++
			}
			continue
		}
		break
	}

	if r == '=' {
		for k := 0; k < 2; k++ { // check "==="
			r, _, err = lex.reader.ReadRune()
			if err == io.EOF {
				return TOKEN_EOF
			}
			if r != '=' {
				lex.reader.UnreadRune()
				return &token{typ: TK_STRUCT_BEGIN}
			}
		}
		return &token{typ: TK_STRUCT_END}
	} else if unicode.IsLetter(r) {
		var runes []rune
		for {
			runes = append(runes, r)
			r, _, err = lex.reader.ReadRune()
			if err == io.EOF {
				break
			} else if unicode.IsLetter(r) || unicode.IsNumber(r) || r == '_' {
				continue
			} else {
				lex.reader.UnreadRune()
				break
			}
		}

		t := &token{}
		t.literal = string(runes)
		if _, ok := datatypes[t.literal]; ok {
			t.typ = TK_DATA_TYPE
		} else if t.literal == "array" {
			t.typ = TK_ARRAY
		} else {
			t.typ = TK_SYMBOL
		}

		return t
	} else {
		log.Fatal("lex error @line:", lex.lineno)
	}
	return nil
}

func (lex *Lexer) eof() bool {
	for {
		r, _, err := lex.reader.ReadRune()
		if err == io.EOF {
			return true
		} else if unicode.IsSpace(r) {
			if r == '\n' {
				lex.lineno++
			}
			continue
		} else {
			lex.reader.UnreadRune()
			return false
		}
	}
}

//////////////////////////////////////////////////////////////
type Parser struct {
	lexer *Lexer
	infos []struct_info
}

func (p *Parser) init(lex *Lexer) {
	p.lexer = lex
}

func (p *Parser) match(typ int) *token {
	t := p.lexer.next()
	if t.typ != typ {
		syntax_error(p)
	}
	return t
}

func (p *Parser) expr() bool {
	if p.lexer.eof() {
		return false
	}
	info := struct_info{}

	t := p.match(TK_SYMBOL)
	info.Name = t.literal

	p.match(TK_STRUCT_BEGIN)
	p.fields(&info)
	p.infos = append(p.infos, info)
	return true
}

func (p *Parser) fields(info *struct_info) {
	for {
		t := p.lexer.next()
		if t.typ == TK_STRUCT_END {
			return
		}
		if t.typ != TK_SYMBOL {
			syntax_error(p)
		}

		field := field_info{Name: t.literal}
		t = p.lexer.next()
		if t.typ == TK_ARRAY {
			field.Array = true
			t = p.lexer.next()
		}

		if t.typ == TK_DATA_TYPE || t.typ == TK_SYMBOL {
			field.Typ = t.literal
		} else {
			syntax_error(p)
		}

		info.Fields = append(info.Fields, field)
	}
}

func semantic_check(infos []struct_info) {
	for _, info := range infos {
		for _, field := range info.Fields {
			if _, ok := datatypes[field.Typ]; !ok {
				for _, info := range infos {
					if info.Name == field.Typ {
						goto NEXT
					}
				}
				log.Fatal("symbol not defined:", field.Typ)
			}
		NEXT:
		}
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "Protocol Data Structure Generator"
	app.Usage = "handle proto.txt"
	app.Authors = []cli.Author{{Name: "xtaci"}, {Name: "ycs"}}
	app.Version = "1.0"
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "file,f", Value: "./proto.txt", Usage: "input proto.txt file"},
		cli.StringFlag{Name: "template,t", Value: "./templates/server/proto.tmpl", Usage: "template file"},
	}
	app.Action = func(c *cli.Context) {
		// load function mapping
		f, err := os.Open("func_map.json")
		if err != nil {
			log.Fatal(err)
		}
		if err := json.NewDecoder(f).Decode(&datatypes); err != nil {
			log.Fatal(err)
		}

		// parse
		file, err := os.Open(c.String("file"))
		if err != nil {
			log.Fatal(err)
		}
		lexer := Lexer{}
		lexer.init(file)
		p := Parser{}
		p.init(&lexer)
		for p.expr() {
		}

		// semantic
		semantic_check(p.infos)

		// use template to generate final output
		funcMap := template.FuncMap{
			"goType": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Go.T
				} else {
					return ""
				}
			},
			"goRead": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Go.R
				} else {
					return ""
				}
			},
			"goWrite": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Go.W
				} else {
					return ""
				}
			},
			"csType": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Cs.T
				} else {
					return ""
				}
			},
			"csRead": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Cs.R
				} else {
					return ""
				}
			},
			"csWrite": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Cs.W
				} else {
					return ""
				}
			},
		}
		tmpl, err := template.New("proto.tmpl").Funcs(funcMap).ParseFiles(c.String("template"))
		if err != nil {
			log.Fatal(err)
		}
		err = tmpl.Execute(os.Stdout, p.infos)
		if err != nil {
			log.Fatal(err)
		}
	}
	app.Run(os.Args)
}
<commit_msg>简单的语义测试<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"github.com/codegangsta/cli"
	"io"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"text/template"
	"unicode"
)

const (
	TK_SYMBOL = iota
	TK_STRUCT_BEGIN
	TK_STRUCT_END
	TK_DATA_TYPE
	TK_ARRAY
	TK_EOF
)

var (
	datatypes map[string]lang_type
)

var (
	TOKEN_EOF = &token{typ: TK_EOF}
)

type (
	func_info struct {
		T string `json:"t"` // type
		R string `json:"r"` // read
		W string `json:"w"` // write
	}
	lang_type struct {
		Go func_info `json:"go"` // golang
		Cs func_info `json:"cs"` // c#
	}
)

type (
	field_info struct {
		Name  string
		Typ   string
		Array bool
	}
	struct_info struct {
		Name   string
		Fields []field_info
	}
)

type token struct {
	typ     int
	literal string
	r       rune
}

func syntax_error(p *Parser) {
	log.Println("syntax error @line:", p.lexer.lineno)
	log.Println(">> \033[1;31m", p.lexer.lines[p.lexer.lineno-1], "\033[0m <<")
	os.Exit(-1)
}

type Lexer struct {
	reader *bytes.Buffer
	lines  []string
	lineno int
}

func (lex *Lexer) init(r io.Reader) {
	bts, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}

	// 按行读入源码
	scanner := bufio.NewScanner(bytes.NewBuffer(bts))
	for scanner.Scan() {
		lex.lines = append(lex.lines, scanner.Text())
	}

	// 清除注释
	re := regexp.MustCompile("(?m:^#(.*)$)")
	bts = re.ReplaceAllLiteral(bts, nil)
	lex.reader = bytes.NewBuffer(bts)
	lex.lineno = 1
}

func (lex *Lexer) next() (t *token) {
	defer func() {
		//log.Println(t)
	}()
	var r rune
	var err error
	for {
		r, _, err = lex.reader.ReadRune()
		if err == io.EOF {
			return TOKEN_EOF
		} else if unicode.IsSpace(r) {
			if r == '\n' {
				lex.lineno++
			}
			continue
		}
		break
	}

	if r == '=' {
		for k := 0; k < 2; k++ { // check "==="
			r, _, err = lex.reader.ReadRune()
			if err == io.EOF {
				return TOKEN_EOF
			}
			if r != '=' {
				lex.reader.UnreadRune()
				return &token{typ: TK_STRUCT_BEGIN}
			}
		}
		return &token{typ: TK_STRUCT_END}
	} else if unicode.IsLetter(r) {
		var runes []rune
		for {
			runes = append(runes, r)
			r, _, err = lex.reader.ReadRune()
			if err == io.EOF {
				break
			} else if unicode.IsLetter(r) || unicode.IsNumber(r) || r == '_' {
				continue
			} else {
				lex.reader.UnreadRune()
				break
			}
		}

		t := &token{}
		t.literal = string(runes)
		if _, ok := datatypes[t.literal]; ok {
			t.typ = TK_DATA_TYPE
		} else if t.literal == "array" {
			t.typ = TK_ARRAY
		} else {
			t.typ = TK_SYMBOL
		}

		return t
	} else {
		log.Fatal("lex error @line:", lex.lineno)
	}
	return nil
}

func (lex *Lexer) eof() bool {
	for {
		r, _, err := lex.reader.ReadRune()
		if err == io.EOF {
			return true
		} else if unicode.IsSpace(r) {
			if r == '\n' {
				lex.lineno++
			}
			continue
		} else {
			lex.reader.UnreadRune()
			return false
		}
	}
}

//////////////////////////////////////////////////////////////
type Parser struct {
	lexer   *Lexer
	infos   []struct_info
	symbols map[string]bool
}

func (p *Parser) init(lex *Lexer) {
	p.lexer = lex
	p.symbols = make(map[string]bool)
}

func (p *Parser) match(typ int) *token {
	t := p.lexer.next()
	if t.typ != typ {
		syntax_error(p)
	}
	return t
}

func (p *Parser) expr() bool {
	if p.lexer.eof() {
		return false
	}
	info := struct_info{}

	t := p.match(TK_SYMBOL)
	info.Name = t.literal

	p.match(TK_STRUCT_BEGIN)
	p.fields(&info)
	p.infos = append(p.infos, info)
	return true
}

func (p *Parser) fields(info *struct_info) {
	for {
		t := p.lexer.next()
		if t.typ == TK_STRUCT_END {
			return
		}
		if t.typ != TK_SYMBOL {
			syntax_error(p)
		}

		p.symbols[t.literal] = true
		field := field_info{Name: t.literal}
		t = p.lexer.next()
		if t.typ == TK_ARRAY {
			field.Array = true
			t = p.lexer.next()
		}

		if t.typ == TK_DATA_TYPE || t.typ == TK_SYMBOL {
			field.Typ = t.literal
		} else {
			syntax_error(p)
		}

		info.Fields = append(info.Fields, field)
	}
}

func (p *Parser) semantic_check() {
	for _, info := range p.infos {
	FIELDLOOP:
		for _, field := range info.Fields {
			if _, ok := datatypes[field.Typ]; !ok {
				if p.symbols[field.Typ] {
					continue FIELDLOOP
				}
				log.Fatal("symbol not found:", field)
			}
		}
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "Protocol Data Structure Generator"
	app.Usage = "handle proto.txt"
	app.Authors = []cli.Author{{Name: "xtaci"}, {Name: "ycs"}}
	app.Version = "1.0"
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "file,f", Value: "./proto.txt", Usage: "input proto.txt file"},
		cli.StringFlag{Name: "template,t", Value: "./templates/server/proto.tmpl", Usage: "template file"},
	}
	app.Action = func(c *cli.Context) {
		// load function mapping
		f, err := os.Open("func_map.json")
		if err != nil {
			log.Fatal(err)
		}
		if err := json.NewDecoder(f).Decode(&datatypes); err != nil {
			log.Fatal(err)
		}

		// parse
		file, err := os.Open(c.String("file"))
		if err != nil {
			log.Fatal(err)
		}
		lexer := Lexer{}
		lexer.init(file)
		p := Parser{}
		p.init(&lexer)
		for p.expr() {
		}

		// semantic
		p.semantic_check()

		// use template to generate final output
		funcMap := template.FuncMap{
			"goType": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Go.T
				} else {
					return ""
				}
			},
			"goRead": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Go.R
				} else {
					return ""
				}
			},
			"goWrite": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Go.W
				} else {
					return ""
				}
			},
			"csType": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Cs.T
				} else {
					return ""
				}
			},
			"csRead": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Cs.R
				} else {
					return ""
				}
			},
			"csWrite": func(t string) string {
				if v, ok := datatypes[t]; ok {
					return v.Cs.W
				} else {
					return ""
				}
			},
		}
		tmpl, err := template.New("proto.tmpl").Funcs(funcMap).ParseFiles(c.String("template"))
		if err != nil {
			log.Fatal(err)
		}
		err = tmpl.Execute(os.Stdout, p.infos)
		if err != nil {
			log.Fatal(err)
		}
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package protocol

import (
	"context"
	"encoding/hex"
	"reflect"
	"testing"
	"time"

	"chain/crypto/ed25519"
	"chain/errors"
	"chain/protocol/bc"
	"chain/protocol/mempool"
	"chain/protocol/memstore"
	"chain/protocol/state"
	"chain/testutil"
)

func TestGetBlock(t *testing.T) {
	ctx := context.Background()

	emptyPool := mempool.New()
	noBlocks := memstore.New()
	oneBlock := memstore.New()
	oneBlock.SaveBlock(ctx, &bc.Block{})
	oneBlock.SaveSnapshot(ctx, 1, state.Empty())

	cases := []struct {
		store   Store
		want    *bc.Block
		wantErr error
	}{
		{noBlocks, nil, nil},
		{oneBlock, &bc.Block{}, nil},
	}

	for _, test := range cases {
		c, err := NewChain(ctx, test.store, emptyPool, nil)
		if err != nil {
			testutil.FatalErr(t, err)
		}
		got, gotErr := c.GetBlock(ctx, c.Height())

		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("got latest = %+v want %+v", got, test.want)
		}

		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("got latest err = %q want %q", gotErr, test.wantErr)
		}
	}
}

func TestNoTimeTravel(t *testing.T) {
	ctx := context.Background()
	c, err := NewChain(ctx, memstore.New(), mempool.New(), nil)
	if err != nil {
		t.Fatal(err)
	}

	c.setHeight(1)
	c.setHeight(2)

	c.setHeight(1) // don't go backward
	if c.state.height != 2 {
		t.Fatalf("c.state.height = %d want 2", c.state.height)
	}
}

func TestWaitForBlockSoonAlreadyExists(t *testing.T) {
	c, _ := newTestChain(t, time.Now())
	makeEmptyBlock(t, c) // height=2
	makeEmptyBlock(t, c) // height=3

	err := c.WaitForBlockSoon(2)
	if err != nil {
		t.Fatal(err)
	}
}

func TestWaitForBlockSoonDistantFuture(t *testing.T) {
	c, _ := newTestChain(t, time.Now())

	got := c.WaitForBlockSoon(100) // distant future
	want := ErrTheDistantFuture
	if got != want {
		t.Errorf("WaitForBlockSoon(100) = %+v want %+v", got, want)
	}
}

func TestWaitForBlockSoonWaits(t *testing.T) {
	// This test is inherently racy. It's possible
	// that the block creation might run before
	// the wait's internal test loop finds no block.
	// In that case, the test will pass, but it will
	// not have tested anything.
	//
	// It's the best we can do.

	c, _ := newTestChain(t, time.Now())
	makeEmptyBlock(t, c) // height=2

	go func() {
		time.Sleep(10 * time.Millisecond) // sorry for the slow test 😔
		makeEmptyBlock(t, c)              // height=3
	}()

	err := c.WaitForBlockSoon(3)
	if err != nil {
		t.Fatal(err)
	}
	if g := c.Height(); g != 3 {
		t.Errorf("height after waiting = %d want 3", g)
	}
}

func TestGenerateBlock(t *testing.T) {
	ctx := context.Background()
	now := time.Unix(233400000, 0)
	c, b1 := newTestChain(t, now)

	initialBlockHash := b1.Hash()
	assetID := bc.ComputeAssetID(nil, initialBlockHash, 1)

	txs := []*bc.Tx{
		bc.NewTx(bc.TxData{
			Version: 1,
			Inputs: []*bc.TxInput{
				bc.NewIssuanceInput(now, now.Add(time.Hour), initialBlockHash, 50, nil, nil, [][]byte{
					nil,
					mustDecodeHex("30450221009037e1d39b7d59d24eba8012baddd5f4ab886a51b46f52b7c479ddfa55eeb5c5022076008409243475b25dfba6db85e15cf3d74561a147375941e4830baa69769b5101"),
					mustDecodeHex("51210210b002870438af79b829bc22c4505e14779ef0080c411ad497d7a0846ee0af6f51ae")}),
			},
			Outputs: []*bc.TxOutput{
				bc.NewTxOutput(assetID, 50, mustDecodeHex("a9145881cd104f8d64635751ac0f3c0decf9150c110687"), nil),
			},
		}),
		bc.NewTx(bc.TxData{
			Version: 1,
			Inputs: []*bc.TxInput{
				bc.NewIssuanceInput(now, now.Add(time.Hour), initialBlockHash, 50, nil, nil, [][]byte{
					nil,
					mustDecodeHex("3045022100f3bcffcfd6a1ce9542b653500386cd0ee7b9c86c59390ca0fc0238c0ebe3f1d6022065ac468a51a016842660c3a616c99a9aa5109a3bad1877ba3e0f010f3972472e01"),
					mustDecodeHex("51210210b002870438af79b829bc22c4505e14779ef0080c411ad497d7a0846ee0af6f51ae"),
				}),
			},
			Outputs: []*bc.TxOutput{
				bc.NewTxOutput(assetID, 50, mustDecodeHex("a914c171e443e05b953baa7b7d834028ed91e47b4d0b87"), nil),
			},
		}),
	}
	for _, tx := range txs {
		err := c.pool.Insert(ctx, tx)
		if err != nil {
			t.Log(errors.Stack(err))
			t.Fatal(err)
		}
	}

	got, _, err := c.GenerateBlock(ctx, b1, state.Empty(), now)
	if err != nil {
		t.Fatalf("err got = %v want nil", err)
	}

	// TODO(bobg): verify these hashes are correct
	var wantTxRoot, wantAssetsRoot bc.Hash
	copy(wantTxRoot[:], mustDecodeHex("29a11bc539b34ffc05725e0ddc99edce3d054fd02741a21c5ea53d38d7014a09"))
	copy(wantAssetsRoot[:], mustDecodeHex("dddc627ae1e1f0872ca2b80d4d13866cae2ccbdb177fce8c6dd75d371d946cda"))

	want := &bc.Block{
		BlockHeader: bc.BlockHeader{
			Version:                bc.NewBlockVersion,
			Height:                 2,
			PreviousBlockHash:      b1.Hash(),
			TransactionsMerkleRoot: wantTxRoot,
			AssetsMerkleRoot:       wantAssetsRoot,
			TimestampMS:            bc.Millis(now),
			ConsensusProgram:       b1.ConsensusProgram,
		},
		Transactions: txs,
	}

	if !reflect.DeepEqual(got, want) {
		t.Errorf("generated block:\ngot:  %+v\nwant: %+v", got, want)
	}
}

func TestValidateBlockForSig(t *testing.T) {
	initialBlock, err := NewInitialBlock(testutil.TestPubs, 1, time.Now())
	if err != nil {
		t.Fatal("unexpected error ", err)
	}

	ctx := context.Background()
	c, err := NewChain(ctx, memstore.New(), mempool.New(), nil)
	if err != nil {
		t.Fatal("unexpected error ", err)
	}

	err = c.ValidateBlockForSig(ctx, initialBlock)
	if err != nil {
		t.Error("unexpected error ", err)
	}
}

// newTestChain returns a new Chain using memstore and mempool for storage,
// along with an initial block b1 (with a 0/0 multisig program).
// It commits b1 before returning.
func newTestChain(tb testing.TB, ts time.Time) (c *Chain, b1 *bc.Block) {
	ctx := context.Background()
	c, err := NewChain(ctx, memstore.New(), mempool.New(), nil)
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	b1, err = NewInitialBlock(nil, 0, ts)
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	err = c.CommitBlock(ctx, b1, state.Empty())
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	return c, b1
}

func makeEmptyBlock(tb testing.TB, c *Chain) {
	ctx := context.Background()

	curBlock, err := c.GetBlock(ctx, c.Height())
	if err != nil {
		testutil.FatalErr(tb, err)
	}

	if len(curBlock.Transactions) > 0 {
		tb.Fatal("cannot make nonempty block")
	}

	curState := state.Empty()

	nextBlock, nextState, err := c.GenerateBlock(ctx, curBlock, curState, time.Now())
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	err = c.CommitBlock(ctx, nextBlock, nextState)
	if err != nil {
		testutil.FatalErr(tb, err)
	}
}

func signBlock(t testing.TB, b *bc.Block, keys []ed25519.PrivateKey) {
	var sigs [][]byte
	for _, key := range keys {
		hash := b.HashForSig()
		sig := ed25519.Sign(key, hash[:])
		sigs = append(sigs, sig)
	}
	b.Witness = sigs
}

func privToPub(privs []ed25519.PrivateKey) []ed25519.PublicKey {
	var public []ed25519.PublicKey
	for _, priv := range privs {
		public = append(public, priv.Public().(ed25519.PublicKey))
	}
	return public
}

func newPrivKey(t *testing.T) ed25519.PrivateKey {
	_, priv, err := ed25519.GenerateKey(nil)
	if err != nil {
		t.Fatal(err)
	}
	return priv
}

func mustDecodeHex(s string) []byte {
	data, err := hex.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return data
}
<commit_msg>protocol: remove unused test functions<commit_after>package protocol

import (
	"context"
	"encoding/hex"
	"reflect"
	"testing"
	"time"

	"chain/errors"
	"chain/protocol/bc"
	"chain/protocol/mempool"
	"chain/protocol/memstore"
	"chain/protocol/state"
	"chain/testutil"
)

func TestGetBlock(t *testing.T) {
	ctx := context.Background()

	emptyPool := mempool.New()
	noBlocks := memstore.New()
	oneBlock := memstore.New()
	oneBlock.SaveBlock(ctx, &bc.Block{})
	oneBlock.SaveSnapshot(ctx, 1, state.Empty())

	cases := []struct {
		store   Store
		want    *bc.Block
		wantErr error
	}{
		{noBlocks, nil, nil},
		{oneBlock, &bc.Block{}, nil},
	}

	for _, test := range cases {
		c, err := NewChain(ctx, test.store, emptyPool, nil)
		if err != nil {
			testutil.FatalErr(t, err)
		}
		got, gotErr := c.GetBlock(ctx, c.Height())

		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("got latest = %+v want %+v", got, test.want)
		}

		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("got latest err = %q want %q", gotErr, test.wantErr)
		}
	}
}

func TestNoTimeTravel(t *testing.T) {
	ctx := context.Background()
	c, err := NewChain(ctx, memstore.New(), mempool.New(), nil)
	if err != nil {
		t.Fatal(err)
	}

	c.setHeight(1)
	c.setHeight(2)

	c.setHeight(1) // don't go backward
	if c.state.height != 2 {
		t.Fatalf("c.state.height = %d want 2", c.state.height)
	}
}

func TestWaitForBlockSoonAlreadyExists(t *testing.T) {
	c, _ := newTestChain(t, time.Now())
	makeEmptyBlock(t, c) // height=2
	makeEmptyBlock(t, c) // height=3

	err := c.WaitForBlockSoon(2)
	if err != nil {
		t.Fatal(err)
	}
}

func TestWaitForBlockSoonDistantFuture(t *testing.T) {
	c, _ := newTestChain(t, time.Now())

	got := c.WaitForBlockSoon(100) // distant future
	want := ErrTheDistantFuture
	if got != want {
		t.Errorf("WaitForBlockSoon(100) = %+v want %+v", got, want)
	}
}

func TestWaitForBlockSoonWaits(t *testing.T) {
	// This test is inherently racy. It's possible
	// that the block creation might run before
	// the wait's internal test loop finds no block.
	// In that case, the test will pass, but it will
	// not have tested anything.
	//
	// It's the best we can do.

	c, _ := newTestChain(t, time.Now())
	makeEmptyBlock(t, c) // height=2

	go func() {
		time.Sleep(10 * time.Millisecond) // sorry for the slow test 😔
		makeEmptyBlock(t, c)              // height=3
	}()

	err := c.WaitForBlockSoon(3)
	if err != nil {
		t.Fatal(err)
	}
	if g := c.Height(); g != 3 {
		t.Errorf("height after waiting = %d want 3", g)
	}
}

func TestGenerateBlock(t *testing.T) {
	ctx := context.Background()
	now := time.Unix(233400000, 0)
	c, b1 := newTestChain(t, now)

	initialBlockHash := b1.Hash()
	assetID := bc.ComputeAssetID(nil, initialBlockHash, 1)

	txs := []*bc.Tx{
		bc.NewTx(bc.TxData{
			Version: 1,
			Inputs: []*bc.TxInput{
				bc.NewIssuanceInput(now, now.Add(time.Hour), initialBlockHash, 50, nil, nil, [][]byte{
					nil,
					mustDecodeHex("30450221009037e1d39b7d59d24eba8012baddd5f4ab886a51b46f52b7c479ddfa55eeb5c5022076008409243475b25dfba6db85e15cf3d74561a147375941e4830baa69769b5101"),
					mustDecodeHex("51210210b002870438af79b829bc22c4505e14779ef0080c411ad497d7a0846ee0af6f51ae")}),
			},
			Outputs: []*bc.TxOutput{
				bc.NewTxOutput(assetID, 50, mustDecodeHex("a9145881cd104f8d64635751ac0f3c0decf9150c110687"), nil),
			},
		}),
		bc.NewTx(bc.TxData{
			Version: 1,
			Inputs: []*bc.TxInput{
				bc.NewIssuanceInput(now, now.Add(time.Hour), initialBlockHash, 50, nil, nil, [][]byte{
					nil,
					mustDecodeHex("3045022100f3bcffcfd6a1ce9542b653500386cd0ee7b9c86c59390ca0fc0238c0ebe3f1d6022065ac468a51a016842660c3a616c99a9aa5109a3bad1877ba3e0f010f3972472e01"),
					mustDecodeHex("51210210b002870438af79b829bc22c4505e14779ef0080c411ad497d7a0846ee0af6f51ae"),
				}),
			},
			Outputs: []*bc.TxOutput{
				bc.NewTxOutput(assetID, 50, mustDecodeHex("a914c171e443e05b953baa7b7d834028ed91e47b4d0b87"), nil),
			},
		}),
	}
	for _, tx := range txs {
		err := c.pool.Insert(ctx, tx)
		if err != nil {
			t.Log(errors.Stack(err))
			t.Fatal(err)
		}
	}

	got, _, err := c.GenerateBlock(ctx, b1, state.Empty(), now)
	if err != nil {
		t.Fatalf("err got = %v want nil", err)
	}

	// TODO(bobg): verify these hashes are correct
	var wantTxRoot, wantAssetsRoot bc.Hash
	copy(wantTxRoot[:], mustDecodeHex("29a11bc539b34ffc05725e0ddc99edce3d054fd02741a21c5ea53d38d7014a09"))
	copy(wantAssetsRoot[:], mustDecodeHex("dddc627ae1e1f0872ca2b80d4d13866cae2ccbdb177fce8c6dd75d371d946cda"))

	want := &bc.Block{
		BlockHeader: bc.BlockHeader{
			Version:                bc.NewBlockVersion,
			Height:                 2,
			PreviousBlockHash:      b1.Hash(),
			TransactionsMerkleRoot: wantTxRoot,
			AssetsMerkleRoot:       wantAssetsRoot,
			TimestampMS:            bc.Millis(now),
			ConsensusProgram:       b1.ConsensusProgram,
		},
		Transactions: txs,
	}

	if !reflect.DeepEqual(got, want) {
		t.Errorf("generated block:\ngot:  %+v\nwant: %+v", got, want)
	}
}

func TestValidateBlockForSig(t *testing.T) {
	initialBlock, err := NewInitialBlock(testutil.TestPubs, 1, time.Now())
	if err != nil {
		t.Fatal("unexpected error ", err)
	}

	ctx := context.Background()
	c, err := NewChain(ctx, memstore.New(), mempool.New(), nil)
	if err != nil {
		t.Fatal("unexpected error ", err)
	}

	err = c.ValidateBlockForSig(ctx, initialBlock)
	if err != nil {
		t.Error("unexpected error ", err)
	}
}

// newTestChain returns a new Chain using memstore and mempool for storage,
// along with an initial block b1 (with a 0/0 multisig program).
// It commits b1 before returning.
func newTestChain(tb testing.TB, ts time.Time) (c *Chain, b1 *bc.Block) {
	ctx := context.Background()
	c, err := NewChain(ctx, memstore.New(), mempool.New(), nil)
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	b1, err = NewInitialBlock(nil, 0, ts)
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	err = c.CommitBlock(ctx, b1, state.Empty())
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	return c, b1
}

func makeEmptyBlock(tb testing.TB, c *Chain) {
	ctx := context.Background()

	curBlock, err := c.GetBlock(ctx, c.Height())
	if err != nil {
		testutil.FatalErr(tb, err)
	}

	if len(curBlock.Transactions) > 0 {
		tb.Fatal("cannot make nonempty block")
	}

	curState := state.Empty()

	nextBlock, nextState, err := c.GenerateBlock(ctx, curBlock, curState, time.Now())
	if err != nil {
		testutil.FatalErr(tb, err)
	}
	err = c.CommitBlock(ctx, nextBlock, nextState)
	if err != nil {
		testutil.FatalErr(tb, err)
	}
}

func mustDecodeHex(s string) []byte {
	data, err := hex.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return data
}
<|endoftext|>


<commit_before>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package gce

import (
	"os"

	"github.com/juju/errors"
	"github.com/juju/schema"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/provider/gce/google"
)

// TODO(ericsnow) While not strictly config-related, we could use some
// mechanism by which we can validate the values we've hard-coded in
// this provider match up with the external authoritative sources. One
// example of this is the data stored in instancetypes.go. Similarly
// we should also ensure the cloud-images metadata is correct and
// up-to-date, though that is more the responsibility of that team.
// Regardless, it may be useful to include a tool somewhere in juju
// that we can use to validate this provider's potentially out-of-date
// data.

// The GCE-specific config keys.
const (
	cfgAuthFile      = "auth-file"
	cfgPrivateKey    = "private-key"
	cfgClientID      = "client-id"
	cfgClientEmail   = "client-email"
	cfgRegion        = "region"
	cfgProjectID     = "project-id"
	cfgImageEndpoint = "image-endpoint"
)

// boilerplateConfig will be shown in help output, so please keep it up to
// date when you change environment configuration below.
var boilerplateConfig = `
gce:
  type: gce

  # Google Auth Info
  # The GCE provider uses OAuth to authenticate. This requires that
  # you set it up and get the relevant credentials. For more information
  # see https://cloud.google.com/compute/docs/api/how-tos/authorization.
  # The key information can be downloaded as a JSON file, or copied, from:
  #   https://console.developers.google.com/project/<projet>/apiui/credential
  # Either set the path to the downloaded JSON file here:
  auth-file:

  # ...or set the individual fields for the credentials. Either way, all
  # three of these are required and have specific meaning to GCE.
  # private-key:
  # client-email:
  # client-id:

  # Google instance info
  # To provision instances and perform related operations, the provider
  # will need to know which GCE project to use and into which region to
  # provision. While the region has a default, the project ID is
  # required. For information on the project ID, see
  # https://cloud.google.com/compute/docs/projects and regarding regions
  # see https://cloud.google.com/compute/docs/zones.
  project-id:
  # region: us-central1

  # The GCE provider uses pre-built images when provisioning instances.
  # You can customize the location in which to find them with the
  # image-endpoint setting. The default value is the a location within
  # GCE, so it will give you the best speed when bootstrapping or adding
  # machines. For more information on the image cache see
  # https://cloud-images.ubuntu.com/.
  # image-endpoint: https://www.googleapis.com
`[1:]

// configFields is the spec for each GCE config value's type.
var configFields = schema.Fields{
	cfgAuthFile:      schema.String(),
	cfgPrivateKey:    schema.String(),
	cfgClientID:      schema.String(),
	cfgClientEmail:   schema.String(),
	cfgRegion:        schema.String(),
	cfgProjectID:     schema.String(),
	cfgImageEndpoint: schema.String(),
}

// TODO(ericsnow) Do we need custom defaults for "image-metadata-url" or
// "agent-metadata-url"? The defaults are the official ones (e.g.
// cloud-images).

var configDefaults = schema.Defaults{
	cfgAuthFile: schema.Omit,
	// See http://cloud-images.ubuntu.com/releases/streams/v1/com.ubuntu.cloud:released:gce.json
	cfgImageEndpoint: "https://www.googleapis.com",
	cfgRegion:        "us-central1",
}

var configSecretFields = []string{
	cfgPrivateKey,
}

var configImmutableFields = []string{
	cfgAuthFile,
	cfgPrivateKey,
	cfgClientID,
	cfgClientEmail,
	cfgRegion,
	cfgProjectID,
	cfgImageEndpoint,
}

var configAuthFields = []string{
	cfgPrivateKey,
	cfgClientID,
	cfgClientEmail,
}

// osEnvFields is the mapping from GCE env vars to config keys.
var osEnvFields = map[string]string{
	google.OSEnvPrivateKey:    cfgPrivateKey,
	google.OSEnvClientID:      cfgClientID,
	google.OSEnvClientEmail:   cfgClientEmail,
	google.OSEnvRegion:        cfgRegion,
	google.OSEnvProjectID:     cfgProjectID,
	google.OSEnvImageEndpoint: cfgImageEndpoint,
}

func parseOSEnv() (map[string]interface{}, error) {
	// TODO(ericsnow) Support pulling ID/PK from shell environment variables.
	return nil, nil
}

// handleInvalidField converts a google.InvalidConfigValue into a new
// error, translating a {provider/gce/google}.OSEnvVar* value into a
// GCE config key in the new error.
func handleInvalidField(err error) error {
	vErr := err.(*google.InvalidConfigValue)
	if strValue, ok := vErr.Value.(string); ok && strValue == "" {
		key := osEnvFields[vErr.Key]
		return errors.Errorf("%s: must not be empty", key)
	}
	return err
}

type environConfig struct {
	*config.Config
	attrs       map[string]interface{}
	credentials *google.Credentials
}

// newConfig builds a new environConfig from the provided Config and
// returns it.
func newConfig(cfg *config.Config) *environConfig {
	return &environConfig{
		Config: cfg,
		attrs:  cfg.UnknownAttrs(),
	}
}

// newValidConfig builds a new environConfig from the provided Config
// and returns it. This includes applying the provided defaults
// values, if any. The resulting config values are validated.
func newValidConfig(cfg *config.Config, defaults map[string]interface{}) (*environConfig, error) {
	credentials, err := parseCredentials(cfg)
	if err != nil {
		return nil, errors.Trace(err)
	}
	handled, err := applyCredentials(cfg, credentials)
	if err != nil {
		return nil, errors.Trace(err)
	}
	cfg = handled

	// Ensure that the provided config is valid.
	if err := config.Validate(cfg, nil); err != nil {
		return nil, errors.Trace(err)
	}

	// Apply the defaults and coerce/validate the custom config attrs.
	validated, err := cfg.ValidateUnknownAttrs(configFields, defaults)
	if err != nil {
		return nil, errors.Trace(err)
	}
	validCfg, err := cfg.Apply(validated)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// Build the config.
	ecfg := newConfig(validCfg)
	ecfg.credentials = credentials

	// Do final validation.
	if err := ecfg.validate(); err != nil {
		return nil, errors.Trace(err)
	}

	return ecfg, nil
}

func (c *environConfig) authFile() string {
	if c.attrs[cfgAuthFile] == nil {
		return ""
	}
	return c.attrs[cfgAuthFile].(string)
}

func (c *environConfig) privateKey() string {
	return c.attrs[cfgPrivateKey].(string)
}

func (c *environConfig) clientID() string {
	return c.attrs[cfgClientID].(string)
}

func (c *environConfig) clientEmail() string {
	return c.attrs[cfgClientEmail].(string)
}

func (c *environConfig) region() string {
	return c.attrs[cfgRegion].(string)
}

func (c *environConfig) projectID() string {
	return c.attrs[cfgProjectID].(string)
}

// imageEndpoint identifies where the provider should look for
// cloud images (i.e. for simplestreams).
func (c *environConfig) imageEndpoint() string {
	return c.attrs[cfgImageEndpoint].(string)
}

// auth build a new Credentials based on the config and returns it.
func (c *environConfig) auth() *google.Credentials {
	if c.credentials == nil {
		c.credentials = &google.Credentials{
			ClientID:    c.clientID(),
			ClientEmail: c.clientEmail(),
			PrivateKey:  []byte(c.privateKey()),
		}
	}
	return c.credentials
}

// newConnection build a ConnectionConfig based on the config and returns it.
func (c *environConfig) newConnection() google.ConnectionConfig {
	return google.ConnectionConfig{
		Region:    c.region(),
		ProjectID: c.projectID(),
	}
}

// secret gathers the "secret" config values and returns them.
func (c *environConfig) secret() map[string]string {
	secretAttrs := make(map[string]string, len(configSecretFields))
	for _, key := range configSecretFields {
		secretAttrs[key] = c.attrs[key].(string)
	}
	return secretAttrs
}

// validate checks GCE-specific config values.
func (c environConfig) validate() error {
	// All fields must be populated, even with just the default.
	for field := range configFields {
		if dflt, ok := configDefaults[field]; ok && dflt == schema.Omit {
			continue
		}
		if c.attrs[field].(string) == "" {
			return errors.Errorf("%s: must not be empty", field)
		}
	}

	// Check sanity of GCE fields.
	if err := c.auth().Validate(); err != nil {
		return errors.Trace(handleInvalidField(err))
	}
	if err := c.newConnection().Validate(); err != nil {
		return errors.Trace(handleInvalidField(err))
	}

	return nil
}

// update applies changes from the provided config to the env config.
// Changes to any immutable attributes result in an error.
func (c *environConfig) update(cfg *config.Config) error {
	// Validate the updates. newValidConfig does not modify the "known"
	// config attributes so it is safe to call Validate here first.
	if err := config.Validate(cfg, c.Config); err != nil {
		return errors.Trace(err)
	}

	updates, err := newValidConfig(cfg, configDefaults)
	if err != nil {
		return errors.Trace(err)
	}

	// Check that no immutable fields have changed.
	attrs := updates.UnknownAttrs()
	for _, field := range configImmutableFields {
		if attrs[field] != c.attrs[field] {
			return errors.Errorf("%s: cannot change from %v to %v", field, c.attrs[field], attrs[field])
		}
	}

	// Apply the updates.
	c.Config = cfg
	c.attrs = cfg.UnknownAttrs()
	return nil
}

// parseCredentials extracts the OAuth2 info from the config from the
// individual fields (falling back on the JSON file).
func parseCredentials(cfg *config.Config) (*google.Credentials, error) {
	attrs := cfg.UnknownAttrs()

	// Try the auth fields first.
	values := make(map[string]string)
	for _, field := range configAuthFields {
		if existing, ok := attrs[field].(string); ok && existing != "" {
			for key, candidate := range osEnvFields {
				if field == candidate {
					values[key] = existing
					break
				}
			}
		}
	}
	if len(values) > 0 {
		creds, err := google.NewCredentials(values)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return creds, nil
	}

	// Fall back to the auth file.
	filename, ok := attrs[cfgAuthFile].(string)
	if !ok || filename == "" {
		// The missing credentials will be caught later.
		return nil, nil
	}
	authFile, err := os.Open(filename)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer authFile.Close()
	creds, err := google.ParseJSONKey(authFile)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return creds, nil
}

func applyCredentials(cfg *config.Config, creds *google.Credentials) (*config.Config, error) {
	updates := make(map[string]interface{})
	for k, v := range creds.Values() {
		if v == "" {
			continue
		}
		if field, ok := osEnvFields[k]; ok {
			for _, authField := range configAuthFields {
				if field == authField {
					updates[field] = v
					break
				}
			}
		}
	}
	updated, err := cfg.Apply(updates)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return updated, nil
}
<commit_msg>Use "" for the auth-file default instead of schema.Omit.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package gce

import (
	"os"

	"github.com/juju/errors"
	"github.com/juju/schema"

	"github.com/juju/juju/environs/config"
	"github.com/juju/juju/provider/gce/google"
)

// TODO(ericsnow) While not strictly config-related, we could use some
// mechanism by which we can validate the values we've hard-coded in
// this provider match up with the external authoritative sources. One
// example of this is the data stored in instancetypes.go. Similarly
// we should also ensure the cloud-images metadata is correct and
// up-to-date, though that is more the responsibility of that team.
// Regardless, it may be useful to include a tool somewhere in juju
// that we can use to validate this provider's potentially out-of-date
// data.

// The GCE-specific config keys.
const (
	cfgAuthFile      = "auth-file"
	cfgPrivateKey    = "private-key"
	cfgClientID      = "client-id"
	cfgClientEmail   = "client-email"
	cfgRegion        = "region"
	cfgProjectID     = "project-id"
	cfgImageEndpoint = "image-endpoint"
)

// boilerplateConfig will be shown in help output, so please keep it up to
// date when you change environment configuration below.
var boilerplateConfig = `
gce:
  type: gce

  # Google Auth Info
  # The GCE provider uses OAuth to authenticate. This requires that
  # you set it up and get the relevant credentials. For more information
  # see https://cloud.google.com/compute/docs/api/how-tos/authorization.
  # The key information can be downloaded as a JSON file, or copied, from:
  #   https://console.developers.google.com/project/<projet>/apiui/credential
  # Either set the path to the downloaded JSON file here:
  auth-file:

  # ...or set the individual fields for the credentials. Either way, all
  # three of these are required and have specific meaning to GCE.
  # private-key:
  # client-email:
  # client-id:

  # Google instance info
  # To provision instances and perform related operations, the provider
  # will need to know which GCE project to use and into which region to
  # provision. While the region has a default, the project ID is
  # required. For information on the project ID, see
  # https://cloud.google.com/compute/docs/projects and regarding regions
  # see https://cloud.google.com/compute/docs/zones.
  project-id:
  # region: us-central1

  # The GCE provider uses pre-built images when provisioning instances.
  # You can customize the location in which to find them with the
  # image-endpoint setting. The default value is the a location within
  # GCE, so it will give you the best speed when bootstrapping or adding
  # machines. For more information on the image cache see
  # https://cloud-images.ubuntu.com/.
  # image-endpoint: https://www.googleapis.com
`[1:]

// configFields is the spec for each GCE config value's type.
var configFields = schema.Fields{
	cfgAuthFile:      schema.String(),
	cfgPrivateKey:    schema.String(),
	cfgClientID:      schema.String(),
	cfgClientEmail:   schema.String(),
	cfgRegion:        schema.String(),
	cfgProjectID:     schema.String(),
	cfgImageEndpoint: schema.String(),
}

// TODO(ericsnow) Do we need custom defaults for "image-metadata-url" or
// "agent-metadata-url"? The defaults are the official ones (e.g.
// cloud-images).

var configDefaults = schema.Defaults{
	cfgAuthFile: "",
	// See http://cloud-images.ubuntu.com/releases/streams/v1/com.ubuntu.cloud:released:gce.json
	cfgImageEndpoint: "https://www.googleapis.com",
	cfgRegion:        "us-central1",
}

var configSecretFields = []string{
	cfgPrivateKey,
}

var configImmutableFields = []string{
	cfgAuthFile,
	cfgPrivateKey,
	cfgClientID,
	cfgClientEmail,
	cfgRegion,
	cfgProjectID,
	cfgImageEndpoint,
}

var configAuthFields = []string{
	cfgPrivateKey,
	cfgClientID,
	cfgClientEmail,
}

// osEnvFields is the mapping from GCE env vars to config keys.
var osEnvFields = map[string]string{
	google.OSEnvPrivateKey:    cfgPrivateKey,
	google.OSEnvClientID:      cfgClientID,
	google.OSEnvClientEmail:   cfgClientEmail,
	google.OSEnvRegion:        cfgRegion,
	google.OSEnvProjectID:     cfgProjectID,
	google.OSEnvImageEndpoint: cfgImageEndpoint,
}

func parseOSEnv() (map[string]interface{}, error) {
	// TODO(ericsnow) Support pulling ID/PK from shell environment variables.
	return nil, nil
}

// handleInvalidField converts a google.InvalidConfigValue into a new
// error, translating a {provider/gce/google}.OSEnvVar* value into a
// GCE config key in the new error.
func handleInvalidField(err error) error {
	vErr := err.(*google.InvalidConfigValue)
	if strValue, ok := vErr.Value.(string); ok && strValue == "" {
		key := osEnvFields[vErr.Key]
		return errors.Errorf("%s: must not be empty", key)
	}
	return err
}

type environConfig struct {
	*config.Config
	attrs       map[string]interface{}
	credentials *google.Credentials
}

// newConfig builds a new environConfig from the provided Config and
// returns it.
func newConfig(cfg *config.Config) *environConfig {
	return &environConfig{
		Config: cfg,
		attrs:  cfg.UnknownAttrs(),
	}
}

// newValidConfig builds a new environConfig from the provided Config
// and returns it. This includes applying the provided defaults
// values, if any. The resulting config values are validated.
func newValidConfig(cfg *config.Config, defaults map[string]interface{}) (*environConfig, error) {
	credentials, err := parseCredentials(cfg)
	if err != nil {
		return nil, errors.Trace(err)
	}
	handled, err := applyCredentials(cfg, credentials)
	if err != nil {
		return nil, errors.Trace(err)
	}
	cfg = handled

	// Ensure that the provided config is valid.
	if err := config.Validate(cfg, nil); err != nil {
		return nil, errors.Trace(err)
	}

	// Apply the defaults and coerce/validate the custom config attrs.
	validated, err := cfg.ValidateUnknownAttrs(configFields, defaults)
	if err != nil {
		return nil, errors.Trace(err)
	}
	validCfg, err := cfg.Apply(validated)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// Build the config.
	ecfg := newConfig(validCfg)
	ecfg.credentials = credentials

	// Do final validation.
	if err := ecfg.validate(); err != nil {
		return nil, errors.Trace(err)
	}

	return ecfg, nil
}

func (c *environConfig) authFile() string {
	if c.attrs[cfgAuthFile] == nil {
		return ""
	}
	return c.attrs[cfgAuthFile].(string)
}

func (c *environConfig) privateKey() string {
	return c.attrs[cfgPrivateKey].(string)
}

func (c *environConfig) clientID() string {
	return c.attrs[cfgClientID].(string)
}

func (c *environConfig) clientEmail() string {
	return c.attrs[cfgClientEmail].(string)
}

func (c *environConfig) region() string {
	return c.attrs[cfgRegion].(string)
}

func (c *environConfig) projectID() string {
	return c.attrs[cfgProjectID].(string)
}

// imageEndpoint identifies where the provider should look for
// cloud images (i.e. for simplestreams).
func (c *environConfig) imageEndpoint() string {
	return c.attrs[cfgImageEndpoint].(string)
}

// auth build a new Credentials based on the config and returns it.
func (c *environConfig) auth() *google.Credentials {
	if c.credentials == nil {
		c.credentials = &google.Credentials{
			ClientID:    c.clientID(),
			ClientEmail: c.clientEmail(),
			PrivateKey:  []byte(c.privateKey()),
		}
	}
	return c.credentials
}

// newConnection build a ConnectionConfig based on the config and returns it.
func (c *environConfig) newConnection() google.ConnectionConfig {
	return google.ConnectionConfig{
		Region:    c.region(),
		ProjectID: c.projectID(),
	}
}

// secret gathers the "secret" config values and returns them.
func (c *environConfig) secret() map[string]string {
	secretAttrs := make(map[string]string, len(configSecretFields))
	for _, key := range configSecretFields {
		secretAttrs[key] = c.attrs[key].(string)
	}
	return secretAttrs
}

// validate checks GCE-specific config values.
func (c environConfig) validate() error {
	// All fields must be populated, even with just the default.
	for field := range configFields {
		if dflt, ok := configDefaults[field]; ok && dflt == "" {
			continue
		}
		if c.attrs[field].(string) == "" {
			return errors.Errorf("%s: must not be empty", field)
		}
	}

	// Check sanity of GCE fields.
	if err := c.auth().Validate(); err != nil {
		return errors.Trace(handleInvalidField(err))
	}
	if err := c.newConnection().Validate(); err != nil {
		return errors.Trace(handleInvalidField(err))
	}

	return nil
}

// update applies changes from the provided config to the env config.
// Changes to any immutable attributes result in an error.
func (c *environConfig) update(cfg *config.Config) error {
	// Validate the updates. newValidConfig does not modify the "known"
	// config attributes so it is safe to call Validate here first.
	if err := config.Validate(cfg, c.Config); err != nil {
		return errors.Trace(err)
	}

	updates, err := newValidConfig(cfg, configDefaults)
	if err != nil {
		return errors.Trace(err)
	}

	// Check that no immutable fields have changed.
	attrs := updates.UnknownAttrs()
	for _, field := range configImmutableFields {
		if attrs[field] != c.attrs[field] {
			return errors.Errorf("%s: cannot change from %v to %v", field, c.attrs[field], attrs[field])
		}
	}

	// Apply the updates.
	c.Config = cfg
	c.attrs = cfg.UnknownAttrs()
	return nil
}

// parseCredentials extracts the OAuth2 info from the config from the
// individual fields (falling back on the JSON file).
func parseCredentials(cfg *config.Config) (*google.Credentials, error) {
	attrs := cfg.UnknownAttrs()

	// Try the auth fields first.
	values := make(map[string]string)
	for _, field := range configAuthFields {
		if existing, ok := attrs[field].(string); ok && existing != "" {
			for key, candidate := range osEnvFields {
				if field == candidate {
					values[key] = existing
					break
				}
			}
		}
	}
	if len(values) > 0 {
		creds, err := google.NewCredentials(values)
		if err != nil {
			return nil, errors.Trace(err)
		}
		return creds, nil
	}

	// Fall back to the auth file.
	filename, ok := attrs[cfgAuthFile].(string)
	if !ok || filename == "" {
		// The missing credentials will be caught later.
		return nil, nil
	}
	authFile, err := os.Open(filename)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer authFile.Close()
	creds, err := google.ParseJSONKey(authFile)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return creds, nil
}

func applyCredentials(cfg *config.Config, creds *google.Credentials) (*config.Config, error) {
	updates := make(map[string]interface{})
	for k, v := range creds.Values() {
		if v == "" {
			continue
		}
		if field, ok := osEnvFields[k]; ok {
			for _, authField := range configAuthFields {
				if field == authField {
					updates[field] = v
					break
				}
			}
		}
	}
	updated, err := cfg.Apply(updates)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return updated, nil
}
<|endoftext|>


<commit_before>package swarm_test

import (
	"fmt"
	"testing"
	"time"

	inet "github.com/libp2p/go-libp2p/p2p/net"
	testutil "github.com/libp2p/go-libp2p/p2p/test/util"
	context "golang.org/x/net/context"
)

// TestConnectednessCorrect starts a few networks, connects a few
// and tests Connectedness value is correct.
func TestConnectednessCorrect(t *testing.T) {

	ctx := context.Background()

	nets := make([]inet.Network, 4)
	for i := 0; i < 4; i++ {
		nets[i] = testutil.GenSwarmNetwork(t, ctx)
	}

	// connect 0-1, 0-2, 0-3, 1-2, 2-3

	dial := func(a, b inet.Network) {
		testutil.DivulgeAddresses(b, a)
		if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
			t.Fatalf("Failed to dial: %s", err)
		}
	}

	dial(nets[0], nets[1])
	dial(nets[0], nets[3])
	dial(nets[1], nets[2])
	dial(nets[3], nets[2])

	// The notifications for new connections get sent out asynchronously.
	// There is the potential for a race condition here, so we sleep to ensure
	// that they have been received.
	time.Sleep(time.Millisecond * 100)

	// test those connected show up correctly

	// test connected
	expectConnectedness(t, nets[0], nets[1], inet.Connected)
	expectConnectedness(t, nets[0], nets[3], inet.Connected)
	expectConnectedness(t, nets[1], nets[2], inet.Connected)
	expectConnectedness(t, nets[3], nets[2], inet.Connected)

	// test not connected
	expectConnectedness(t, nets[0], nets[2], inet.NotConnected)
	expectConnectedness(t, nets[1], nets[3], inet.NotConnected)

	if len(nets[0].Peers()) != 2 {
		t.Fatal("expected net 0 to have two peers")
	}

	if len(nets[2].Conns()) != 2 {
		t.Fatal("expected net 2 to have two conns")
	}

	if len(nets[1].ConnsToPeer(nets[3].LocalPeer())) != 0 {
		t.Fatal("net 1 should have no connections to net 3")
	}

	if err := nets[2].ClosePeer(nets[1].LocalPeer()); err != nil {
		t.Fatal(err)
	}

	expectConnectedness(t, nets[2], nets[1], inet.NotConnected)

	for _, n := range nets {
		n.Close()
	}

	for _, n := range nets {
		<-n.Process().Closed()
	}
}

func expectConnectedness(t *testing.T, a, b inet.Network, expected inet.Connectedness) {
	es := "%s is connected to %s, but Connectedness incorrect. %s %s %s"
	atob := a.Connectedness(b.LocalPeer())
	btoa := b.Connectedness(a.LocalPeer())
	if atob != expected {
		t.Errorf(es, a, b, printConns(a), printConns(b), atob)
	}

	// test symmetric case
	if btoa != expected {
		t.Errorf(es, b, a, printConns(b), printConns(a), btoa)
	}
}

func printConns(n inet.Network) string {
	s := fmt.Sprintf("Connections in %s:\n", n)
	for _, c := range n.Conns() {
		s = s + fmt.Sprintf("- %s\n", c)
	}
	return s
}

func TestNetworkOpenStream(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	nets := make([]inet.Network, 4)
	for i := 0; i < 4; i++ {
		nets[i] = testutil.GenSwarmNetwork(t, ctx)
	}

	dial := func(a, b inet.Network) {
		testutil.DivulgeAddresses(b, a)
		if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
			t.Fatalf("Failed to dial: %s", err)
		}
	}

	dial(nets[0], nets[1])
	dial(nets[0], nets[3])
	dial(nets[1], nets[2])

	done := make(chan bool)
	nets[1].SetStreamHandler(func(s inet.Stream) {
		defer close(done)
		defer s.Close()

		buf := make([]byte, 10)
		_, err := s.Read(buf)
		if err != nil {
			t.Error(err)
			return
		}
		if string(buf) != "hello ipfs" {
			t.Error("got wrong message")
		}
	})

	s, err := nets[0].NewStream(ctx, nets[1].LocalPeer())
	if err != nil {
		t.Fatal(err)
	}

	_, err = s.Write([]byte("hello ipfs"))
	if err != nil {
		t.Fatal(err)
	}

	err = s.Close()
	if err != nil {
		t.Fatal(err)
	}

	select {
	case <-done:
	case <-time.After(time.Millisecond * 100):
		t.Fatal("timed out waiting on stream")
	}

	_, err = nets[1].NewStream(ctx, nets[3].LocalPeer())
	if err == nil {
		t.Fatal("expected stream open 1->3 to fail")
	}
}
<commit_msg>sleep before final connectedness check<commit_after>package swarm_test

import (
	"fmt"
	"testing"
	"time"

	inet "github.com/libp2p/go-libp2p/p2p/net"
	testutil "github.com/libp2p/go-libp2p/p2p/test/util"
	context "golang.org/x/net/context"
)

// TestConnectednessCorrect starts a few networks, connects a few
// and tests Connectedness value is correct.
func TestConnectednessCorrect(t *testing.T) {

	ctx := context.Background()

	nets := make([]inet.Network, 4)
	for i := 0; i < 4; i++ {
		nets[i] = testutil.GenSwarmNetwork(t, ctx)
	}

	// connect 0-1, 0-2, 0-3, 1-2, 2-3

	dial := func(a, b inet.Network) {
		testutil.DivulgeAddresses(b, a)
		if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
			t.Fatalf("Failed to dial: %s", err)
		}
	}

	dial(nets[0], nets[1])
	dial(nets[0], nets[3])
	dial(nets[1], nets[2])
	dial(nets[3], nets[2])

	// The notifications for new connections get sent out asynchronously.
	// There is the potential for a race condition here, so we sleep to ensure
	// that they have been received.
	time.Sleep(time.Millisecond * 100)

	// test those connected show up correctly

	// test connected
	expectConnectedness(t, nets[0], nets[1], inet.Connected)
	expectConnectedness(t, nets[0], nets[3], inet.Connected)
	expectConnectedness(t, nets[1], nets[2], inet.Connected)
	expectConnectedness(t, nets[3], nets[2], inet.Connected)

	// test not connected
	expectConnectedness(t, nets[0], nets[2], inet.NotConnected)
	expectConnectedness(t, nets[1], nets[3], inet.NotConnected)

	if len(nets[0].Peers()) != 2 {
		t.Fatal("expected net 0 to have two peers")
	}

	if len(nets[2].Conns()) != 2 {
		t.Fatal("expected net 2 to have two conns")
	}

	if len(nets[1].ConnsToPeer(nets[3].LocalPeer())) != 0 {
		t.Fatal("net 1 should have no connections to net 3")
	}

	if err := nets[2].ClosePeer(nets[1].LocalPeer()); err != nil {
		t.Fatal(err)
	}

	time.Sleep(time.Millisecond * 50)

	expectConnectedness(t, nets[2], nets[1], inet.NotConnected)

	for _, n := range nets {
		n.Close()
	}

	for _, n := range nets {
		<-n.Process().Closed()
	}
}

func expectConnectedness(t *testing.T, a, b inet.Network, expected inet.Connectedness) {
	es := "%s is connected to %s, but Connectedness incorrect. %s %s %s"
	atob := a.Connectedness(b.LocalPeer())
	btoa := b.Connectedness(a.LocalPeer())
	if atob != expected {
		t.Errorf(es, a, b, printConns(a), printConns(b), atob)
	}

	// test symmetric case
	if btoa != expected {
		t.Errorf(es, b, a, printConns(b), printConns(a), btoa)
	}
}

func printConns(n inet.Network) string {
	s := fmt.Sprintf("Connections in %s:\n", n)
	for _, c := range n.Conns() {
		s = s + fmt.Sprintf("- %s\n", c)
	}
	return s
}

func TestNetworkOpenStream(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	nets := make([]inet.Network, 4)
	for i := 0; i < 4; i++ {
		nets[i] = testutil.GenSwarmNetwork(t, ctx)
	}

	dial := func(a, b inet.Network) {
		testutil.DivulgeAddresses(b, a)
		if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
			t.Fatalf("Failed to dial: %s", err)
		}
	}

	dial(nets[0], nets[1])
	dial(nets[0], nets[3])
	dial(nets[1], nets[2])

	done := make(chan bool)
	nets[1].SetStreamHandler(func(s inet.Stream) {
		defer close(done)
		defer s.Close()

		buf := make([]byte, 10)
		_, err := s.Read(buf)
		if err != nil {
			t.Error(err)
			return
		}
		if string(buf) != "hello ipfs" {
			t.Error("got wrong message")
		}
	})

	s, err := nets[0].NewStream(ctx, nets[1].LocalPeer())
	if err != nil {
		t.Fatal(err)
	}

	_, err = s.Write([]byte("hello ipfs"))
	if err != nil {
		t.Fatal(err)
	}

	err = s.Close()
	if err != nil {
		t.Fatal(err)
	}

	select {
	case <-done:
	case <-time.After(time.Millisecond * 100):
		t.Fatal("timed out waiting on stream")
	}

	_, err = nets[1].NewStream(ctx, nets[3].LocalPeer())
	if err == nil {
		t.Fatal("expected stream open 1->3 to fail")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package gfx

//------------------------------------------------------------------------------

import (
	"fmt"
	"reflect"

	"strconv"

	"github.com/drakmaniso/glam/color"
	"github.com/drakmaniso/glam/geom"
)

/*
#include "glad.h"

void VertexAttribute(
	GLuint vao,
	GLuint index,
	GLuint binding,
	GLint size,
	GLenum type,
	GLboolean normalized,
	GLuint relativeOffset
) {
	glVertexArrayAttribFormat(vao, index, size, type, normalized, relativeOffset);
	glVertexArrayAttribBinding(vao, index, binding);
	glEnableVertexArrayAttrib(vao, index);
}

static inline void VertexBuffer(GLuint vao, GLuint binding, GLuint buffer, GLintptr offset, GLsizei stride) {
	glVertexArrayVertexBuffer(vao, binding, buffer, offset, stride);
}
*/
import "C"

//------------------------------------------------------------------------------

// VertexFormat prepares everything the pipeline needs to use a
// vertex buffer of a specific format, and assign a binding index to it.
//
// The format must be a struct with layout tags.
func (p *Pipeline) VertexFormat(binding uint32, format interface{}) error {
	f := reflect.TypeOf(format)
	if f.Kind() != reflect.Struct {
		return fmt.Errorf("attributes binding format must be a struct, not a %s", f.Kind())
	}

	p.attribStride[binding] = f.Size()

	for i := 0; i < f.NumField(); i++ {
		a := f.Field(i)
		al := a.Tag.Get("layout")
		if al == "" {
			continue
		}
		ali, err := strconv.Atoi(al)
		if err != nil {
			return fmt.Errorf("invalid layout for attributes binding: %q", al)
		}
		//TODO: check that ali is in range
		at := a.Type
		var as int32
		ao := a.Offset
		var ate C.GLenum
		switch {
		// Float32
		case at.ConvertibleTo(float32Type):
			as = 1
			ate = C.GL_FLOAT
		case at.ConvertibleTo(vec4Type), at.ConvertibleTo(rgbaType):
			as = 4
			ate = C.GL_FLOAT
		case at.ConvertibleTo(vec3Type), at.ConvertibleTo(rgbType):
			as = 3
			ate = C.GL_FLOAT
		case at.ConvertibleTo(vec2Type):
			as = 2
			ate = C.GL_FLOAT
		// Int32
		case at.ConvertibleTo(int32Type):
			as = 1
			ate = C.GL_INT
		case at.ConvertibleTo(ivec4Type):
			as = 4
			ate = C.GL_INT
		case at.ConvertibleTo(ivec3Type):
			as = 3
			ate = C.GL_INT
		case at.ConvertibleTo(ivec2Type):
			as = 2
			ate = C.GL_INT
		}

		C.VertexAttribute(
			p.vao,
			C.GLuint(ali),
			C.GLuint(0), //TODO
			C.GLint(as),
			ate,
			C.GLboolean(0), //TODO
			C.GLuint(ao),
		)
	}
	return nil
}

var (
	float32Type = reflect.TypeOf(float32(0))
	vec4Type    = reflect.TypeOf(geom.Vec4{})
	vec3Type    = reflect.TypeOf(geom.Vec3{})
	vec2Type    = reflect.TypeOf(geom.Vec2{})
	int32Type   = reflect.TypeOf(int32(0))
	ivec4Type   = reflect.TypeOf(geom.IVec4{})
	ivec3Type   = reflect.TypeOf(geom.IVec3{})
	ivec2Type   = reflect.TypeOf(geom.IVec2{})
	rgbType     = reflect.TypeOf(color.RGB{})
	rgbaType    = reflect.TypeOf(color.RGBA{})
)

//------------------------------------------------------------------------------

// VertexBuffer binds a buffer to a vertex buffer binding index.
//
// The buffer should use the same struct type than the one used in the
// corresponding call to VertexBufferFormat.
func (p *Pipeline) VertexBuffer(binding uint32, b Buffer, offset uintptr) {
	C.VertexBuffer(p.vao, C.GLuint(binding), b.buffer, C.GLintptr(offset), C.GLsizei(p.attribStride[binding]))
}

//------------------------------------------------------------------------------
<commit_msg>Fix vertex format binding<commit_after>// Copyright (c) 2013-2016 Laurent Moussault. All rights reserved.
// Licensed under a simplified BSD license (see LICENSE file).

package gfx

//------------------------------------------------------------------------------

import (
	"fmt"
	"reflect"

	"strconv"

	"github.com/drakmaniso/glam/color"
	"github.com/drakmaniso/glam/geom"
)

/*
#include "glad.h"

void VertexAttribute(
	GLuint vao,
	GLuint index,
	GLuint binding,
	GLint size,
	GLenum type,
	GLboolean normalized,
	GLuint relativeOffset
) {
	glVertexArrayAttribFormat(vao, index, size, type, normalized, relativeOffset);
	glVertexArrayAttribBinding(vao, index, binding);
	glEnableVertexArrayAttrib(vao, index);
}

static inline void VertexBuffer(GLuint vao, GLuint binding, GLuint buffer, GLintptr offset, GLsizei stride) {
	glVertexArrayVertexBuffer(vao, binding, buffer, offset, stride);
}
*/
import "C"

//------------------------------------------------------------------------------

// VertexFormat prepares everything the pipeline needs to use a
// vertex buffer of a specific format, and assign a binding index to it.
//
// The format must be a struct with layout tags.
func (p *Pipeline) VertexFormat(binding uint32, format interface{}) error {
	f := reflect.TypeOf(format)
	if f.Kind() != reflect.Struct {
		return fmt.Errorf("attributes binding format must be a struct, not a %s", f.Kind())
	}

	p.attribStride[binding] = f.Size()

	for i := 0; i < f.NumField(); i++ {
		a := f.Field(i)
		al := a.Tag.Get("layout")
		if al == "" {
			continue
		}
		ali, err := strconv.Atoi(al)
		if err != nil {
			return fmt.Errorf("invalid layout for attributes binding: %q", al)
		}
		//TODO: check that ali is in range
		at := a.Type
		var as int32
		ao := a.Offset
		var ate C.GLenum
		switch {
		// Float32
		case at.ConvertibleTo(float32Type):
			as = 1
			ate = C.GL_FLOAT
		case at.ConvertibleTo(vec4Type), at.ConvertibleTo(rgbaType):
			as = 4
			ate = C.GL_FLOAT
		case at.ConvertibleTo(vec3Type), at.ConvertibleTo(rgbType):
			as = 3
			ate = C.GL_FLOAT
		case at.ConvertibleTo(vec2Type):
			as = 2
			ate = C.GL_FLOAT
		// Int32
		case at.ConvertibleTo(int32Type):
			as = 1
			ate = C.GL_INT
		case at.ConvertibleTo(ivec4Type):
			as = 4
			ate = C.GL_INT
		case at.ConvertibleTo(ivec3Type):
			as = 3
			ate = C.GL_INT
		case at.ConvertibleTo(ivec2Type):
			as = 2
			ate = C.GL_INT
		}

		C.VertexAttribute(
			p.vao,
			C.GLuint(ali),
			C.GLuint(binding),
			C.GLint(as),
			ate,
			C.GLboolean(0), //TODO
			C.GLuint(ao),
		)
	}
	return nil
}

var (
	float32Type = reflect.TypeOf(float32(0))
	vec4Type    = reflect.TypeOf(geom.Vec4{})
	vec3Type    = reflect.TypeOf(geom.Vec3{})
	vec2Type    = reflect.TypeOf(geom.Vec2{})
	int32Type   = reflect.TypeOf(int32(0))
	ivec4Type   = reflect.TypeOf(geom.IVec4{})
	ivec3Type   = reflect.TypeOf(geom.IVec3{})
	ivec2Type   = reflect.TypeOf(geom.IVec2{})
	rgbType     = reflect.TypeOf(color.RGB{})
	rgbaType    = reflect.TypeOf(color.RGBA{})
)

//------------------------------------------------------------------------------

// VertexBuffer binds a buffer to a vertex buffer binding index.
//
// The buffer should use the same struct type than the one used in the
// corresponding call to VertexBufferFormat.
func (p *Pipeline) VertexBuffer(binding uint32, b Buffer, offset uintptr) {
	C.VertexBuffer(p.vao, C.GLuint(binding), b.buffer, C.GLintptr(offset), C.GLsizei(p.attribStride[binding]))
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package libp2pquic

import (
	"context"
	"errors"
	"io"
	"net"

	"github.com/minio/sha256-simd"
	"golang.org/x/crypto/hkdf"

	logging "github.com/ipfs/go-log"
	ic "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/pnet"
	tpt "github.com/libp2p/go-libp2p-core/transport"
	p2ptls "github.com/libp2p/go-libp2p-tls"
	filter "github.com/libp2p/go-maddr-filter"
	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
	mafmt "github.com/multiformats/go-multiaddr-fmt"
	manet "github.com/multiformats/go-multiaddr-net"
)

var log = logging.Logger("quic-transport")

var quicConfig = &quic.Config{
	MaxIncomingStreams:                    1000,
	MaxIncomingUniStreams:                 -1,             // disable unidirectional streams
	MaxReceiveStreamFlowControlWindow:     10 * (1 << 20), // 10 MB
	MaxReceiveConnectionFlowControlWindow: 15 * (1 << 20), // 15 MB
	AcceptToken: func(clientAddr net.Addr, _ *quic.Token) bool {
		// TODO(#6): require source address validation when under load
		return true
	},
	KeepAlive: true,
}

const statelessResetKeyInfo = "libp2p quic stateless reset key"

type connManager struct {
	reuseUDP4 *reuse
	reuseUDP6 *reuse
}

func newConnManager(filters *filter.Filters) (*connManager, error) {
	reuseUDP4, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	reuseUDP6, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	return &connManager{
		reuseUDP4: reuseUDP4,
		reuseUDP6: reuseUDP6,
	}, nil
}

func (c *connManager) getReuse(network string) (*reuse, error) {
	switch network {
	case "udp4":
		return c.reuseUDP4, nil
	case "udp6":
		return c.reuseUDP6, nil
	default:
		return nil, errors.New("invalid network: must be either udp4 or udp6")
	}
}

func (c *connManager) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Listen(network, laddr)
}

func (c *connManager) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Dial(network, raddr)
}

// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
	privKey     ic.PrivKey
	localPeer   peer.ID
	identity    *p2ptls.Identity
	connManager *connManager
	config      *quic.Config
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Transport, error) {
	if len(psk) > 0 {
		log.Error("QUIC doesn't support private networks yet.")
		return nil, errors.New("QUIC doesn't support private networks yet")
	}
	localPeer, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	identity, err := p2ptls.NewIdentity(key)
	if err != nil {
		return nil, err
	}
	connManager, err := newConnManager(filters)
	if err != nil {
		return nil, err
	}
	config := quicConfig.Clone()
	keyBytes, err := key.Raw()
	if err != nil {
		return nil, err
	}
	keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(statelessResetKeyInfo))
	config.StatelessResetKey = make([]byte, 32)
	if _, err := io.ReadFull(keyReader, config.StatelessResetKey); err != nil {
		return nil, err
	}

	return &transport{
		privKey:     key,
		localPeer:   localPeer,
		identity:    identity,
		connManager: connManager,
		config:      config,
	}, nil
}

// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error) {
	network, host, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, err
	}
	addr, err := net.ResolveUDPAddr(network, host)
	if err != nil {
		return nil, err
	}
	remoteMultiaddr, err := toQuicMultiaddr(addr)
	if err != nil {
		return nil, err
	}
	tlsConf, keyCh := t.identity.ConfigForPeer(p)
	pconn, err := t.connManager.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, t.config)
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	// Should be ready by this point, don't block.
	var remotePubKey ic.PubKey
	select {
	case remotePubKey = <-keyCh:
	default:
	}
	if remotePubKey == nil {
		pconn.DecreaseCount()
		return nil, errors.New("go-libp2p-quic-transport BUG: expected remote pub key to be set")
	}
	go func() {
		<-sess.Context().Done()
		pconn.DecreaseCount()
	}()

	localMultiaddr, err := toQuicMultiaddr(pconn.LocalAddr())
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	return &conn{
		sess:            sess,
		transport:       t,
		privKey:         t.privKey,
		localPeer:       t.localPeer,
		localMultiaddr:  localMultiaddr,
		remotePubKey:    remotePubKey,
		remotePeerID:    p,
		remoteMultiaddr: remoteMultiaddr,
	}, nil
}

// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
	return mafmt.QUIC.Matches(addr)
}

// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
	lnet, host, err := manet.DialArgs(addr)
	if err != nil {
		return nil, err
	}
	laddr, err := net.ResolveUDPAddr(lnet, host)
	if err != nil {
		return nil, err
	}
	conn, err := t.connManager.Listen(lnet, laddr)
	if err != nil {
		return nil, err
	}
	return newListener(conn, t, t.localPeer, t.privKey, t.identity)
}

// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
	return false
}

// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
	return []int{ma.P_QUIC}
}

func (t *transport) String() string {
	return "QUIC"
}
<commit_msg>fix: avoid dialing/listening on dns addresses<commit_after>package libp2pquic

import (
	"context"
	"errors"
	"io"
	"net"

	"github.com/minio/sha256-simd"
	"golang.org/x/crypto/hkdf"

	logging "github.com/ipfs/go-log"
	ic "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/pnet"
	tpt "github.com/libp2p/go-libp2p-core/transport"
	p2ptls "github.com/libp2p/go-libp2p-tls"
	filter "github.com/libp2p/go-maddr-filter"
	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
	mafmt "github.com/multiformats/go-multiaddr-fmt"
	manet "github.com/multiformats/go-multiaddr-net"
)

var log = logging.Logger("quic-transport")

var quicConfig = &quic.Config{
	MaxIncomingStreams:                    1000,
	MaxIncomingUniStreams:                 -1,             // disable unidirectional streams
	MaxReceiveStreamFlowControlWindow:     10 * (1 << 20), // 10 MB
	MaxReceiveConnectionFlowControlWindow: 15 * (1 << 20), // 15 MB
	AcceptToken: func(clientAddr net.Addr, _ *quic.Token) bool {
		// TODO(#6): require source address validation when under load
		return true
	},
	KeepAlive: true,
}

const statelessResetKeyInfo = "libp2p quic stateless reset key"

type connManager struct {
	reuseUDP4 *reuse
	reuseUDP6 *reuse
}

func newConnManager(filters *filter.Filters) (*connManager, error) {
	reuseUDP4, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	reuseUDP6, err := newReuse(filters)
	if err != nil {
		return nil, err
	}
	return &connManager{
		reuseUDP4: reuseUDP4,
		reuseUDP6: reuseUDP6,
	}, nil
}

func (c *connManager) getReuse(network string) (*reuse, error) {
	switch network {
	case "udp4":
		return c.reuseUDP4, nil
	case "udp6":
		return c.reuseUDP6, nil
	default:
		return nil, errors.New("invalid network: must be either udp4 or udp6")
	}
}

func (c *connManager) Listen(network string, laddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Listen(network, laddr)
}

func (c *connManager) Dial(network string, raddr *net.UDPAddr) (*reuseConn, error) {
	reuse, err := c.getReuse(network)
	if err != nil {
		return nil, err
	}
	return reuse.Dial(network, raddr)
}

// The Transport implements the tpt.Transport interface for QUIC connections.
type transport struct {
	privKey     ic.PrivKey
	localPeer   peer.ID
	identity    *p2ptls.Identity
	connManager *connManager
	config      *quic.Config
}

var _ tpt.Transport = &transport{}

// NewTransport creates a new QUIC transport
func NewTransport(key ic.PrivKey, psk pnet.PSK, filters *filter.Filters) (tpt.Transport, error) {
	if len(psk) > 0 {
		log.Error("QUIC doesn't support private networks yet.")
		return nil, errors.New("QUIC doesn't support private networks yet")
	}
	localPeer, err := peer.IDFromPrivateKey(key)
	if err != nil {
		return nil, err
	}
	identity, err := p2ptls.NewIdentity(key)
	if err != nil {
		return nil, err
	}
	connManager, err := newConnManager(filters)
	if err != nil {
		return nil, err
	}
	config := quicConfig.Clone()
	keyBytes, err := key.Raw()
	if err != nil {
		return nil, err
	}
	keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(statelessResetKeyInfo))
	config.StatelessResetKey = make([]byte, 32)
	if _, err := io.ReadFull(keyReader, config.StatelessResetKey); err != nil {
		return nil, err
	}

	return &transport{
		privKey:     key,
		localPeer:   localPeer,
		identity:    identity,
		connManager: connManager,
		config:      config,
	}, nil
}

// Dial dials a new QUIC connection
func (t *transport) Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (tpt.CapableConn, error) {
	network, host, err := manet.DialArgs(raddr)
	if err != nil {
		return nil, err
	}
	addr, err := net.ResolveUDPAddr(network, host)
	if err != nil {
		return nil, err
	}
	remoteMultiaddr, err := toQuicMultiaddr(addr)
	if err != nil {
		return nil, err
	}
	tlsConf, keyCh := t.identity.ConfigForPeer(p)
	pconn, err := t.connManager.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	sess, err := quic.DialContext(ctx, pconn, addr, host, tlsConf, t.config)
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	// Should be ready by this point, don't block.
	var remotePubKey ic.PubKey
	select {
	case remotePubKey = <-keyCh:
	default:
	}
	if remotePubKey == nil {
		pconn.DecreaseCount()
		return nil, errors.New("go-libp2p-quic-transport BUG: expected remote pub key to be set")
	}
	go func() {
		<-sess.Context().Done()
		pconn.DecreaseCount()
	}()

	localMultiaddr, err := toQuicMultiaddr(pconn.LocalAddr())
	if err != nil {
		pconn.DecreaseCount()
		return nil, err
	}
	return &conn{
		sess:            sess,
		transport:       t,
		privKey:         t.privKey,
		localPeer:       t.localPeer,
		localMultiaddr:  localMultiaddr,
		remotePubKey:    remotePubKey,
		remotePeerID:    p,
		remoteMultiaddr: remoteMultiaddr,
	}, nil
}

// Don't use mafmt.QUIC as we don't want to dial DNS addresses. Just /ip{4,6}/udp/quic
var dialMatcher = mafmt.And(mafmt.IP, mafmt.Base(ma.P_UDP), mafmt.Base(ma.P_QUIC))

// CanDial determines if we can dial to an address
func (t *transport) CanDial(addr ma.Multiaddr) bool {
	return dialMatcher.Matches(addr)
}

// Listen listens for new QUIC connections on the passed multiaddr.
func (t *transport) Listen(addr ma.Multiaddr) (tpt.Listener, error) {
	lnet, host, err := manet.DialArgs(addr)
	if err != nil {
		return nil, err
	}
	laddr, err := net.ResolveUDPAddr(lnet, host)
	if err != nil {
		return nil, err
	}
	conn, err := t.connManager.Listen(lnet, laddr)
	if err != nil {
		return nil, err
	}
	return newListener(conn, t, t.localPeer, t.privKey, t.identity)
}

// Proxy returns true if this transport proxies.
func (t *transport) Proxy() bool {
	return false
}

// Protocols returns the set of protocols handled by this transport.
func (t *transport) Protocols() []int {
	return []int{ma.P_QUIC}
}

func (t *transport) String() string {
	return "QUIC"
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/json"
)

// TODO: maybe properties should return a more useful datastructure?
func GetProperties() (string, string, string, string, string, string, string, string) {
	type propertiesResponse struct {
		FactomdVersion       string `json:"factomdversion"`
		FactomdVersionErr    string `json:"factomdversionerr"`
		FactomdAPIVersion    string `json:"factomdapiversion"`
		FactomdAPIVersionErr string `json:"factomdapiversionerr"`
		WalletVersion        string `json:"walletversion"`
		WalletVersionErr     string `json:"walletversionerr"`
		WalletAPIVersion     string `json:"walletapiversion"`
		WalletAPIVersionErr  string `json:"walletapiversionerr"`
	}

	// get properties from the factom API and the wallet API
	props := new(propertiesResponse)
	wprops := new(propertiesResponse)
	req := NewJSON2Request("properties", APICounter(), nil)
	wreq := NewJSON2Request("properties", APICounter(), nil)

	resp, err := factomdRequest(req)
	if err != nil {
		props.FactomdVersionErr = err.Error()
	} else if resp.Error != nil {
		props.FactomdVersionErr = resp.Error.Error()
	} else if jerr := json.Unmarshal(resp.JSONResult(), props); jerr != nil {
		props.FactomdVersionErr = jerr.Error()
	}

	wresp, werr := walletRequest(wreq)

	if werr != nil {
		wprops.WalletVersionErr = werr.Error()
	} else if wresp.Error != nil {
		wprops.WalletVersionErr = wresp.Error.Error()
	} else if jwerr := json.Unmarshal(wresp.JSONResult(), wprops); jwerr != nil {
		wprops.WalletVersionErr = jwerr.Error()
	}

	return props.FactomdVersion, props.FactomdVersionErr, props.FactomdAPIVersion, props.FactomdAPIVersionErr, wprops.WalletVersion, wprops.WalletVersionErr, wprops.WalletAPIVersion, wprops.WalletAPIVersionErr
}
<commit_msg>changed signature for GetProperties function<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/json"
)

// PropertiesResponse represents properties of the running factomd and factom
// wallet.
type PropertiesResponse struct {
	FactomdVersion       string `json:"factomdversion"`
	FactomdVersionErr    string `json:"factomdversionerr"`
	FactomdAPIVersion    string `json:"factomdapiversion"`
	FactomdAPIVersionErr string `json:"factomdapiversionerr"`
	WalletVersion        string `json:"walletversion"`
	WalletVersionErr     string `json:"walletversionerr"`
	WalletAPIVersion     string `json:"walletapiversion"`
	WalletAPIVersionErr  string `json:"walletapiversionerr"`
}

// GetProperties requests various properties of the factomd and factom wallet
// software and API versions.
func GetProperties() (*PropertiesResponse, error) {
	// get properties from the factom API and the wallet API
	props := new(PropertiesResponse)
	// wprops := new(PropertiesResponse)
	req := NewJSON2Request("properties", APICounter(), nil)
	wreq := NewJSON2Request("properties", APICounter(), nil)

	resp, err := factomdRequest(req)
	if err != nil {
		props.FactomdVersionErr = err.Error()
		return props, err
	} else if resp.Error != nil {
		props.FactomdVersionErr = resp.Error.Error()
	} else if jerr := json.Unmarshal(resp.JSONResult(), props); jerr != nil {
		props.FactomdVersionErr = jerr.Error()
		return props, jerr
	}

	wresp, werr := walletRequest(wreq)
	wprops := new(PropertiesResponse)
	if werr != nil {
		props.WalletVersionErr = werr.Error()
		return props, werr
	} else if wresp.Error != nil {
		props.WalletVersionErr = wresp.Error.Error()
	} else if jwerr := json.Unmarshal(wresp.JSONResult(), wprops); jwerr != nil {
		props.WalletVersionErr = jwerr.Error()
		return props, jwerr
	}
	props.WalletVersion = wprops.WalletVersion
	props.WalletVersionErr = wprops.WalletVersionErr
	props.WalletAPIVersion = wprops.WalletAPIVersion
	props.WalletVersionErr = wprops.WalletAPIVersionErr

	return props, nil
}
<|endoftext|>