<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ca

import (
	"encoding/json"
	"fmt"
	google_protobuf "google/protobuf"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"testing"
	"time"

	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"

	"github.com/hyperledger/fabric/consensus/helper"
	"github.com/hyperledger/fabric/core"
	"github.com/hyperledger/fabric/core/chaincode"
	"github.com/hyperledger/fabric/core/crypto"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/core/ledger/genesis"
	"github.com/hyperledger/fabric/core/peer"
	"github.com/hyperledger/fabric/core/rest"
	pb "github.com/hyperledger/fabric/protos"
)

var (
	tca    *TCA
	eca    *ECA
	server *grpc.Server
)

type ValidityPeriod struct {
	Name  string
	Value string
}

func TestMain(m *testing.M) {
	setupTestConfig()
	os.Exit(m.Run())
}

func setupTestConfig() {
	viper.AutomaticEnv()
	viper.SetConfigName("ca_test") // name of config file (without extension)
	viper.AddConfigPath("./")      // path to look for the config file in
	viper.AddConfigPath("./..")    // path to look for the config file in
	err := viper.ReadInConfig()    // Find and read the config file
	if err != nil {                // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
}

func TestValidityPeriod(t *testing.T) {
	t.Skip()
	var updateInterval int64
	updateInterval = 37

	// 1. Start TCA and Openchain...
	go startServices(t)

	// ... and wait just let the services finish the startup
	time.Sleep(time.Second * 240)

	// 2. Obtain the validity period by querying and directly from the ledger
	validityPeriod_A := queryValidityPeriod(t)
	validityPeriodFromLedger_A := getValidityPeriodFromLedger(t)

	// 3. Wait for the validity period to be updated...
	time.Sleep(time.Second * 40)

	// ... and read the values again
	validityPeriod_B := queryValidityPeriod(t)
	validityPeriodFromLedger_B := getValidityPeriodFromLedger(t)

	// 5. Stop TCA and Openchain
	stopServices(t)

	// 6. Compare the values
	if validityPeriod_A != validityPeriodFromLedger_A {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_A, validityPeriodFromLedger_A)
		t.Fail()
	}

	if validityPeriod_B != validityPeriodFromLedger_B {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_B, validityPeriodFromLedger_B)
		t.Fail()
	}

	if validityPeriod_B-validityPeriod_A != updateInterval {
		t.Logf("Validity period difference must be equal to the update interval. Expected: %s, Actual: %s", updateInterval, validityPeriod_B-validityPeriod_A)
		t.Fail()
	}

	// 7. since the validity period is used as time in the validators convert both validity periods to Unix time and compare them
	vpA := time.Unix(validityPeriodFromLedger_A, 0)
	vpB := time.Unix(validityPeriodFromLedger_B, 0)

	nextVP := vpA.Add(time.Second * 37)
	if !vpB.Equal(nextVP) {
		t.Logf("Validity period difference must be equal to the update interval. Error converting validity period to Unix time.")
		t.Fail()
	}

	// 8. cleanup tca and openchain folders
	if err := os.RemoveAll(viper.GetString("peer.fileSystemPath")); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", viper.GetString("peer.fileSystemPath"), err)
	}
	if err := os.RemoveAll(".ca"); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", ".ca", err)
	}
}

func startServices(t *testing.T) {
	go startTCA()
	err := startOpenchain(t)
	if err != nil {
		t.Logf("Error starting Openchain: %s", err)
		t.Fail()
	}
}

func stopServices(t *testing.T) {
	stopOpenchain(t)
	stopTCA()
}

func startTCA() {
	LogInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr, os.Stdout)

	eca = NewECA()
	defer eca.Close()

	tca = NewTCA(eca)
	defer tca.Close()

	sockp, err := net.Listen("tcp", viper.GetString("server.port"))
	if err != nil {
		panic("Cannot open port: " + err.Error())
	}

	server = grpc.NewServer()

	eca.Start(server)
	tca.Start(server)

	server.Serve(sockp)
}

func stopTCA() {
	eca.Close()
	tca.Close()
	server.Stop()
}

func queryValidityPeriod(t *testing.T) int64 {
	hash := viper.GetString("pki.validity-period.chaincodeHash")
	args := []string{"system.validity.period"}

	validityPeriod, err := queryTransaction(hash, args, t)
	if err != nil {
		t.Logf("Failed querying validity period: %s", err)
		t.Fail()
	}

	var vp ValidityPeriod
	json.Unmarshal(validityPeriod, &vp)

	value, err := strconv.ParseInt(vp.Value, 10, 64)
	if err != nil {
		t.Logf("Failed parsing validity period: %s", err)
		t.Fail()
	}

	return value
}

func getValidityPeriodFromLedger(t *testing.T) int64 {
	cid := viper.GetString("pki.validity-period.chaincodeHash")

	ledger, err := ledger.GetLedger()
	if err != nil {
		t.Logf("Failed getting access to the ledger: %s", err)
		t.Fail()
	}

	vp_bytes, err := ledger.GetState(cid, "system.validity.period", true)
	if err != nil {
		t.Logf("Failed reading validity period from the ledger: %s", err)
		t.Fail()
	}

	i, err := strconv.ParseInt(string(vp_bytes[:]), 10, 64)
	if err != nil {
		t.Logf("Failed to parse validity period: %s", err)
		t.Fail()
	}

	return i
}

func queryTransaction(hash string, args []string, t *testing.T) ([]byte, error) {

	chaincodeInvocationSpec := createChaincodeInvocationForQuery(args, hash, "system_chaincode_invoker")

	fmt.Printf("Going to query\n")

	response, err := queryChaincode(chaincodeInvocationSpec, t)

	if err != nil {
		return nil, fmt.Errorf("Error querying <%s>: %s", "validity period", err)
	}

	t.Logf("Successfully invoked validity period update: %s", string(response.Msg))

	return response.Msg, nil
}

func queryChaincode(chaincodeInvSpec *pb.ChaincodeInvocationSpec, t *testing.T) (*pb.Response, error) {

	devopsClient, err := getDevopsClient(viper.GetString("pki.validity-period.devops-address"))

	if err != nil {
		return nil, fmt.Errorf("Error retrieving devops client: %s", err)
	}

	resp, err := devopsClient.Query(context.Background(), chaincodeInvSpec)

	if err != nil {
		return nil, fmt.Errorf("Error invoking validity period update system chaincode: %s", err)
	}

	t.Logf("Successfully invoked validity period update: %s(%s)", chaincodeInvSpec, string(resp.Msg))

	return resp, nil
}

func createChaincodeInvocationForQuery(arguments []string, chaincodeHash string, token string) *pb.ChaincodeInvocationSpec {
	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG,
		ChaincodeID: &pb.ChaincodeID{Name: chaincodeHash},
		CtorMsg: &pb.ChaincodeInput{Function: "query",
			Args: arguments,
		},
	}

	spec.SecureContext = string(token)

	invocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}

	return invocationSpec
}

func getSecHelper() (crypto.Peer, error) {
	var secHelper crypto.Peer
	var err error
	if viper.GetBool("security.enabled") {
		enrollID := viper.GetString("security.enrollID")
		enrollSecret := viper.GetString("security.enrollSecret")
		if viper.GetBool("peer.validator.enabled") {
			if err = crypto.RegisterValidator(enrollID, nil, enrollID, enrollSecret); nil != err {
				return nil, err
			}
			secHelper, err = crypto.InitValidator(enrollID, nil)
			if nil != err {
				return nil, err
			}
		} else {
			if err = crypto.RegisterPeer(enrollID, nil, enrollID, enrollSecret); nil != err {
				return nil, err
			}
			secHelper, err = crypto.InitPeer(enrollID, nil)
			if nil != err {
				return nil, err
			}
		}
	}
	return secHelper, err
}

func startOpenchain(t *testing.T) error {

	peerEndpoint, err := peer.GetPeerEndpoint()
	if err != nil {
		return fmt.Errorf("Failed to get Peer Endpoint: %s", err)
	}

	listenAddr := viper.GetString("peer.listenaddress")

	if "" == listenAddr {
		t.Log("Listen address not specified, using peer endpoint address")
		listenAddr = peerEndpoint.Address
	}

	lis, err := net.Listen("tcp", listenAddr)
	if err != nil {
		grpclog.Fatalf("failed to listen: %v", err)
	}

	t.Logf("Security enabled status: %t", viper.GetBool("security.enabled"))

	var opts []grpc.ServerOption
	if viper.GetBool("peer.tls.enabled") {
		creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"), viper.GetString("peer.tls.key.file"))
		if err != nil {
			grpclog.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}

	grpcServer := grpc.NewServer(opts...)

	// Register the Peer server
	var peerServer *peer.PeerImpl

	secHelper, err := getSecHelper()
	if err != nil {
		return err
	}

	secHelperFunc := func() crypto.Peer {
		return secHelper
	}

	if viper.GetBool("peer.validator.enabled") {
		t.Logf("Running as validating peer - installing consensus %s", viper.GetString("peer.validator.consensus"))
		peerServer, _ = peer.NewPeerWithHandler(secHelperFunc, helper.NewConsensusHandler)
	} else {
		t.Log("Running as non-validating peer")
		peerServer, _ = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)
	}
	pb.RegisterPeerServer(grpcServer, peerServer)

	// Register the Admin server
	pb.RegisterAdminServer(grpcServer, core.NewAdminServer())

	// Register ChaincodeSupport server...
	// TODO : not the "DefaultChain" ... we have to revisit when we do multichain

	registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)

	// Register Devops server
	serverDevops := core.NewDevopsServer(peerServer)
	pb.RegisterDevopsServer(grpcServer, serverDevops)

	// Register the ServerOpenchain server
	serverOpenchain, err := rest.NewOpenchainServer()
	if err != nil {
		return fmt.Errorf("Error creating OpenchainServer: %s", err)
	}

	pb.RegisterOpenchainServer(grpcServer, serverOpenchain)

	// Create and register the REST service
	go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)

	rootNode, err := core.GetRootNode()
	if err != nil {
		grpclog.Fatalf("Failed to get peer.discovery.rootnode valey: %s", err)
	}

	t.Logf("Starting peer with id=%s, network id=%s, address=%s, discovery.rootnode=%s, validator=%v",
		peerEndpoint.ID, viper.GetString("peer.networkId"),
		peerEndpoint.Address, rootNode, viper.GetBool("peer.validator.enabled"))

	// Start the grpc server. Done in a goroutine so we can deploy the
	// genesis block if needed.
	serve := make(chan bool)
	go func() {
		grpcServer.Serve(lis)
		serve <- true
	}()

	// Deploy the geneis block if needed.
	if viper.GetBool("peer.validator.enabled") {
		makeGeneisError := genesis.MakeGenesis()
		if makeGeneisError != nil {
			return makeGeneisError
		}
	}

	// Block until grpc server exits
	<-serve

	return nil
}

func stopOpenchain(t *testing.T) {
	clientConn, err := peer.NewPeerClientConnection()
	if err != nil {
		t.Log(fmt.Errorf("Error trying to connect to local peer:", err))
		t.Fail()
	}

	t.Log("Stopping peer...")
	serverClient := pb.NewAdminClient(clientConn)

	status, err := serverClient.StopServer(context.Background(), &google_protobuf.Empty{})
	t.Logf("Current status: %s", status)

}

func registerChaincodeSupport(chainname chaincode.ChainName, grpcServer *grpc.Server, secHelper crypto.Peer) {
	//get user mode
	userRunsCC := false
	if viper.GetString("chaincode.mode") == chaincode.DevModeUserRunsChaincode {
		userRunsCC = true
	}

	//get chaincode startup timeout
	tOut, err := strconv.Atoi(viper.GetString("chaincode.startuptimeout"))
	if err != nil { //what went wrong ?
		fmt.Printf("could not retrive timeout var...setting to 5secs\n")
		tOut = 5000
	}
	ccStartupTimeout := time.Duration(tOut) * time.Millisecond

	//(chainname ChainName, getPeerEndpoint func() (*pb.PeerEndpoint, error), userrunsCC bool, ccstartuptimeout time.Duration, secHelper crypto.Peer)
	pb.RegisterChaincodeSupportServer(grpcServer, chaincode.NewChaincodeSupport(chainname, peer.GetPeerEndpoint, userRunsCC, ccStartupTimeout, secHelper))
}
<commit_msg>Fixes #1510: lint issues in membersrvc/ca/validity_period_test.go<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package ca

import (
	"encoding/json"
	"fmt"
	google_protobuf "google/protobuf"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"testing"
	"time"

	"github.com/spf13/viper"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"

	"github.com/hyperledger/fabric/consensus/helper"
	"github.com/hyperledger/fabric/core"
	"github.com/hyperledger/fabric/core/chaincode"
	"github.com/hyperledger/fabric/core/crypto"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/core/ledger/genesis"
	"github.com/hyperledger/fabric/core/peer"
	"github.com/hyperledger/fabric/core/rest"
	pb "github.com/hyperledger/fabric/protos"
)

var (
	tca    *TCA
	eca    *ECA
	server *grpc.Server
)

type ValidityPeriod struct {
	Name  string
	Value string
}

func TestMain(m *testing.M) {
	setupTestConfig()
	os.Exit(m.Run())
}

func setupTestConfig() {
	viper.AutomaticEnv()
	viper.SetConfigName("ca_test") // name of config file (without extension)
	viper.AddConfigPath("./")      // path to look for the config file in
	viper.AddConfigPath("./..")    // path to look for the config file in
	err := viper.ReadInConfig()    // Find and read the config file
	if err != nil {                // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}
}

func TestValidityPeriod(t *testing.T) {
	t.Skip()
	var updateInterval int64
	updateInterval = 37

	// 1. Start TCA and Openchain...
	go startServices(t)

	// ... and wait just let the services finish the startup
	time.Sleep(time.Second * 240)

	// 2. Obtain the validity period by querying and directly from the ledger
	validityPeriodA := queryValidityPeriod(t)
	validityPeriodFromLedgerA := getValidityPeriodFromLedger(t)

	// 3. Wait for the validity period to be updated...
	time.Sleep(time.Second * 40)

	// ... and read the values again
	validityPeriodB := queryValidityPeriod(t)
	validityPeriodFromLedgerB := getValidityPeriodFromLedger(t)

	// 5. Stop TCA and Openchain
	stopServices(t)

	// 6. Compare the values
	if validityPeriodA != validityPeriodFromLedgerA {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_A, validityPeriodFromLedger_A)
		t.Fail()
	}

	if validityPeriodB != validityPeriodFromLedgerB {
		t.Logf("Validity period read from ledger must be equals tothe one obtained by querying the Openchain. Expected: %s, Actual: %s", validityPeriod_B, validityPeriodFromLedger_B)
		t.Fail()
	}

	if validityPeriodB-validityPeriodA != updateInterval {
		t.Logf("Validity period difference must be equal to the update interval. Expected: %s, Actual: %s", updateInterval, validityPeriod_B-validityPeriod_A)
		t.Fail()
	}

	// 7. since the validity period is used as time in the validators convert both validity periods to Unix time and compare them
	vpA := time.Unix(validityPeriodFromLedgerA, 0)
	vpB := time.Unix(validityPeriodFromLedgerB, 0)

	nextVP := vpA.Add(time.Second * 37)
	if !vpB.Equal(nextVP) {
		t.Logf("Validity period difference must be equal to the update interval. Error converting validity period to Unix time.")
		t.Fail()
	}

	// 8. cleanup tca and openchain folders
	if err := os.RemoveAll(viper.GetString("peer.fileSystemPath")); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", viper.GetString("peer.fileSystemPath"), err)
	}
	if err := os.RemoveAll(".ca"); err != nil {
		t.Logf("Failed removing [%s] [%s]\n", ".ca", err)
	}
}

func startServices(t *testing.T) {
	go startTCA()
	err := startOpenchain(t)
	if err != nil {
		t.Logf("Error starting Openchain: %s", err)
		t.Fail()
	}
}

func stopServices(t *testing.T) {
	stopOpenchain(t)
	stopTCA()
}

func startTCA() {
	LogInit(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr, os.Stdout)

	eca = NewECA()
	defer eca.Close()

	tca = NewTCA(eca)
	defer tca.Close()

	sockp, err := net.Listen("tcp", viper.GetString("server.port"))
	if err != nil {
		panic("Cannot open port: " + err.Error())
	}

	server = grpc.NewServer()

	eca.Start(server)
	tca.Start(server)

	server.Serve(sockp)
}

func stopTCA() {
	eca.Close()
	tca.Close()
	server.Stop()
}

func queryValidityPeriod(t *testing.T) int64 {
	hash := viper.GetString("pki.validity-period.chaincodeHash")
	args := []string{"system.validity.period"}

	validityPeriod, err := queryTransaction(hash, args, t)
	if err != nil {
		t.Logf("Failed querying validity period: %s", err)
		t.Fail()
	}

	var vp ValidityPeriod
	json.Unmarshal(validityPeriod, &vp)

	value, err := strconv.ParseInt(vp.Value, 10, 64)
	if err != nil {
		t.Logf("Failed parsing validity period: %s", err)
		t.Fail()
	}

	return value
}

func getValidityPeriodFromLedger(t *testing.T) int64 {
	cid := viper.GetString("pki.validity-period.chaincodeHash")

	ledger, err := ledger.GetLedger()
	if err != nil {
		t.Logf("Failed getting access to the ledger: %s", err)
		t.Fail()
	}

	vpBytes, err := ledger.GetState(cid, "system.validity.period", true)
	if err != nil {
		t.Logf("Failed reading validity period from the ledger: %s", err)
		t.Fail()
	}

	i, err := strconv.ParseInt(string(vpBytes[:]), 10, 64)
	if err != nil {
		t.Logf("Failed to parse validity period: %s", err)
		t.Fail()
	}

	return i
}

func queryTransaction(hash string, args []string, t *testing.T) ([]byte, error) {

	chaincodeInvocationSpec := createChaincodeInvocationForQuery(args, hash, "system_chaincode_invoker")

	fmt.Printf("Going to query\n")

	response, err := queryChaincode(chaincodeInvocationSpec, t)

	if err != nil {
		return nil, fmt.Errorf("Error querying <%s>: %s", "validity period", err)
	}

	t.Logf("Successfully invoked validity period update: %s", string(response.Msg))

	return response.Msg, nil
}

func queryChaincode(chaincodeInvSpec *pb.ChaincodeInvocationSpec, t *testing.T) (*pb.Response, error) {

	devopsClient, err := getDevopsClient(viper.GetString("pki.validity-period.devops-address"))

	if err != nil {
		return nil, fmt.Errorf("Error retrieving devops client: %s", err)
	}

	resp, err := devopsClient.Query(context.Background(), chaincodeInvSpec)

	if err != nil {
		return nil, fmt.Errorf("Error invoking validity period update system chaincode: %s", err)
	}

	t.Logf("Successfully invoked validity period update: %s(%s)", chaincodeInvSpec, string(resp.Msg))

	return resp, nil
}

func createChaincodeInvocationForQuery(arguments []string, chaincodeHash string, token string) *pb.ChaincodeInvocationSpec {
	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG,
		ChaincodeID: &pb.ChaincodeID{Name: chaincodeHash},
		CtorMsg: &pb.ChaincodeInput{Function: "query",
			Args: arguments,
		},
	}

	spec.SecureContext = string(token)

	invocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}

	return invocationSpec
}

func getSecHelper() (crypto.Peer, error) {
	var secHelper crypto.Peer
	var err error
	if viper.GetBool("security.enabled") {
		enrollID := viper.GetString("security.enrollID")
		enrollSecret := viper.GetString("security.enrollSecret")
		if viper.GetBool("peer.validator.enabled") {
			if err = crypto.RegisterValidator(enrollID, nil, enrollID, enrollSecret); nil != err {
				return nil, err
			}
			secHelper, err = crypto.InitValidator(enrollID, nil)
			if nil != err {
				return nil, err
			}
		} else {
			if err = crypto.RegisterPeer(enrollID, nil, enrollID, enrollSecret); nil != err {
				return nil, err
			}
			secHelper, err = crypto.InitPeer(enrollID, nil)
			if nil != err {
				return nil, err
			}
		}
	}
	return secHelper, err
}

func startOpenchain(t *testing.T) error {

	peerEndpoint, err := peer.GetPeerEndpoint()
	if err != nil {
		return fmt.Errorf("Failed to get Peer Endpoint: %s", err)
	}

	listenAddr := viper.GetString("peer.listenaddress")

	if "" == listenAddr {
		t.Log("Listen address not specified, using peer endpoint address")
		listenAddr = peerEndpoint.Address
	}

	lis, err := net.Listen("tcp", listenAddr)
	if err != nil {
		grpclog.Fatalf("failed to listen: %v", err)
	}

	t.Logf("Security enabled status: %t", viper.GetBool("security.enabled"))

	var opts []grpc.ServerOption
	if viper.GetBool("peer.tls.enabled") {
		creds, err := credentials.NewServerTLSFromFile(viper.GetString("peer.tls.cert.file"), viper.GetString("peer.tls.key.file"))
		if err != nil {
			grpclog.Fatalf("Failed to generate credentials %v", err)
		}
		opts = []grpc.ServerOption{grpc.Creds(creds)}
	}

	grpcServer := grpc.NewServer(opts...)

	// Register the Peer server
	var peerServer *peer.PeerImpl

	secHelper, err := getSecHelper()
	if err != nil {
		return err
	}

	secHelperFunc := func() crypto.Peer {
		return secHelper
	}

	if viper.GetBool("peer.validator.enabled") {
		t.Logf("Running as validating peer - installing consensus %s", viper.GetString("peer.validator.consensus"))
		peerServer, _ = peer.NewPeerWithHandler(secHelperFunc, helper.NewConsensusHandler)
	} else {
		t.Log("Running as non-validating peer")
		peerServer, _ = peer.NewPeerWithHandler(secHelperFunc, peer.NewPeerHandler)
	}
	pb.RegisterPeerServer(grpcServer, peerServer)

	// Register the Admin server
	pb.RegisterAdminServer(grpcServer, core.NewAdminServer())

	// Register ChaincodeSupport server...
	// TODO : not the "DefaultChain" ... we have to revisit when we do multichain

	registerChaincodeSupport(chaincode.DefaultChain, grpcServer, secHelper)

	// Register Devops server
	serverDevops := core.NewDevopsServer(peerServer)
	pb.RegisterDevopsServer(grpcServer, serverDevops)

	// Register the ServerOpenchain server
	serverOpenchain, err := rest.NewOpenchainServer()
	if err != nil {
		return fmt.Errorf("Error creating OpenchainServer: %s", err)
	}

	pb.RegisterOpenchainServer(grpcServer, serverOpenchain)

	// Create and register the REST service
	go rest.StartOpenchainRESTServer(serverOpenchain, serverDevops)

	rootNode, err := core.GetRootNode()
	if err != nil {
		grpclog.Fatalf("Failed to get peer.discovery.rootnode valey: %s", err)
	}

	t.Logf("Starting peer with id=%s, network id=%s, address=%s, discovery.rootnode=%s, validator=%v",
		peerEndpoint.ID, viper.GetString("peer.networkId"),
		peerEndpoint.Address, rootNode, viper.GetBool("peer.validator.enabled"))

	// Start the grpc server. Done in a goroutine so we can deploy the
	// genesis block if needed.
	serve := make(chan bool)
	go func() {
		grpcServer.Serve(lis)
		serve <- true
	}()

	// Deploy the geneis block if needed.
	if viper.GetBool("peer.validator.enabled") {
		makeGeneisError := genesis.MakeGenesis()
		if makeGeneisError != nil {
			return makeGeneisError
		}
	}

	// Block until grpc server exits
	<-serve

	return nil
}

func stopOpenchain(t *testing.T) {
	clientConn, err := peer.NewPeerClientConnection()
	if err != nil {
		t.Log(fmt.Errorf("Error trying to connect to local peer:", err))
		t.Fail()
	}

	t.Log("Stopping peer...")
	serverClient := pb.NewAdminClient(clientConn)

	status, err := serverClient.StopServer(context.Background(), &google_protobuf.Empty{})
	t.Logf("Current status: %s", status)

}

func registerChaincodeSupport(chainname chaincode.ChainName, grpcServer *grpc.Server, secHelper crypto.Peer) {
	//get user mode
	userRunsCC := false
	if viper.GetString("chaincode.mode") == chaincode.DevModeUserRunsChaincode {
		userRunsCC = true
	}

	//get chaincode startup timeout
	tOut, err := strconv.Atoi(viper.GetString("chaincode.startuptimeout"))
	if err != nil { //what went wrong ?
		fmt.Printf("could not retrive timeout var...setting to 5secs\n")
		tOut = 5000
	}
	ccStartupTimeout := time.Duration(tOut) * time.Millisecond

	//(chainname ChainName, getPeerEndpoint func() (*pb.PeerEndpoint, error), userrunsCC bool, ccstartuptimeout time.Duration, secHelper crypto.Peer)
	pb.RegisterChaincodeSupportServer(grpcServer, chaincode.NewChaincodeSupport(chainname, peer.GetPeerEndpoint, userRunsCC, ccStartupTimeout, secHelper))
}
<|endoftext|>


<commit_before>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

// Package treetestcases contains test cases to test Merkle tree implementation.
package treetestcases

import (
	"crypto/sha256"
	"encoding/json"
	"io/ioutil"
	"math/rand"
	"reflect"
	"testing"

	"github.com/stratumn/go/testutil"
	"github.com/stratumn/go/types"
	"github.com/stratumn/goprivate/merkle"
)

var (
	pathA0     merkle.Path
	pathAB0    merkle.Path
	pathAB1    merkle.Path
	pathABC0   merkle.Path
	pathABC1   merkle.Path
	pathABC2   merkle.Path
	pathABCD0  merkle.Path
	pathABCD1  merkle.Path
	pathABCD2  merkle.Path
	pathABCD3  merkle.Path
	pathABCDE0 merkle.Path
	pathABCDE1 merkle.Path
	pathABCDE2 merkle.Path
	pathABCDE3 merkle.Path
	pathABCDE4 merkle.Path
)

func loadPath(filename string, path *merkle.Path) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	if err = json.Unmarshal(data, path); err != nil {
		panic(err)
	}
}

// LoadFixtures loads test fixtures and should be called before running the tests.
func LoadFixtures(testdatapath string) {
	// Load fixtures.
	loadPath(testdatapath+"/path-a-0.json", &pathA0)
	loadPath(testdatapath+"/path-ab-0.json", &pathAB0)
	loadPath(testdatapath+"/path-ab-1.json", &pathAB1)
	loadPath(testdatapath+"/path-abc-0.json", &pathABC0)
	loadPath(testdatapath+"/path-abc-1.json", &pathABC1)
	loadPath(testdatapath+"/path-abc-2.json", &pathABC2)
	loadPath(testdatapath+"/path-abcd-0.json", &pathABCD0)
	loadPath(testdatapath+"/path-abcd-1.json", &pathABCD1)
	loadPath(testdatapath+"/path-abcd-2.json", &pathABCD2)
	loadPath(testdatapath+"/path-abcd-3.json", &pathABCD3)
	loadPath(testdatapath+"/path-abcde-0.json", &pathABCDE0)
	loadPath(testdatapath+"/path-abcde-1.json", &pathABCDE1)
	loadPath(testdatapath+"/path-abcde-2.json", &pathABCDE2)
	loadPath(testdatapath+"/path-abcde-3.json", &pathABCDE3)
	loadPath(testdatapath+"/path-abcde-4.json", &pathABCDE4)
}

// Factory wraps functions to allocate and free a Merkle tree,
// and is used to run the tests on a Merkle tree implementation.
type Factory struct {
	// New create a Merkle tree from leaves.
	New func(leaves []types.Bytes32) (merkle.Tree, error)

	// Free is an optional function to free a Merkle tree.
	Free func(tree merkle.Tree)
}

// RunTests runs all the tests.
func (f Factory) RunTests(t *testing.T) {
	t.Run("NumLeaves", f.TestNumLeaves)
	t.Run("Root", f.TestRoot)
	t.Run("Leaf", f.TestLeaf)
	t.Run("Path", f.TestPath)
	t.Run("PathRandom", f.TestPathRandom)
}

// RunBenchmarks runs all the benchmarks.
func (f Factory) RunBenchmarks(b *testing.B) {
	b.Run("Create", f.BenchmarkCreate)
	b.Run("Path", f.BenchmarkPath)
}

func (f Factory) free(tree merkle.Tree) {
	if f.Free != nil {
		f.Free(tree)
	}
}

// TestNumLeaves tests that the implementation returns the correct number of leaves.
func (f Factory) TestNumLeaves(t *testing.T) {
	tree, err := f.New([]types.Bytes32{*testutil.RandomHash(), *testutil.RandomHash(), *testutil.RandomHash()})
	if err != nil {
		t.Fatal(err)
	}
	defer f.free(tree)

	if got, want := tree.LeavesLen(), 3; got != want {
		t.Errorf("tree.LeavesLen() = %d want %d", got, want)
	}
}

// TestRoot tests that the implementation computes the root correctly.
func (f Factory) TestRoot(t *testing.T) {
	tests := [...]struct {
		leaves   []string
		expected string
	}{
		{[]string{"a"}, "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"},
		{[]string{"a", "b"}, "e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a"},
		{[]string{"a", "b", "c"}, "7075152d03a5cd92104887b476862778ec0c87be5c2fa1c0a90f87c49fad6eff"},
		{[]string{"a", "b", "c", "d"}, "14ede5e8e97ad9372327728f5099b95604a39593cac3bd38a343ad76205213e7"},
		{[]string{"a", "b", "c", "d", "e"}, "d71f8983ad4ee170f8129f1ebcdd7440be7798d8e1c80420bf11f1eced610dba"},
		{[]string{"a", "b", "c", "d", "e", "f"}, "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2"},
		{[]string{"a", "b", "c", "d", "e", "f", "g"}, "e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034"},
		{[]string{"a", "b", "c", "d", "e", "f", "g", "h"}, "bd7c8a900be9b67ba7df5c78a652a8474aedd78adb5083e80e49d9479138a23f"},
		{[]string{"a", "b", "c", "d", "e", "f", "g", "h", "i"}, "386ced54bdc7456fecfc9b43018bbda2fe0a105f4cf7cad6bbb429c18fe852cc"},
	}

	for i, test := range tests {
		var leaves = make([]types.Bytes32, len(test.leaves), len(test.leaves))
		for i, s := range test.leaves {
			leaves[i] = sha256.Sum256([]byte(s))
		}

		tree, err := f.New(leaves)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		if got, want := tree.Root().String(), test.expected; got != want {
			t.Errorf("test#%d: tree.Root() = %q want %q", i, got, want)
		}
	}
}

// TestLeaf tests that the implementation correctly returns leaves.
func (f Factory) TestLeaf(t *testing.T) {
	for i := 1; i < 128; i++ {
		var leaves []types.Bytes32
		for j := 0; j < i; j++ {
			leaves = append(leaves, *testutil.RandomHash())
		}

		tree, err := f.New(leaves)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		for j := 0; j < i; j++ {
			if got, want := tree.Leaf(j).String(), leaves[j].String(); got != want {
				t.Errorf("test#%d: tree.Leaf(%d) = %q want %q", i, j, got, want)
			}
		}
	}
}

// TestPath tests that the implementation correctly computes paths.
func (f Factory) TestPath(t *testing.T) {
	tests := [...]struct {
		leaves   []string
		expected []merkle.Path
	}{
		{
			[]string{"a"},
			[]merkle.Path{pathA0},
		},
		{
			[]string{"a", "b"},
			[]merkle.Path{pathAB0, pathAB1},
		},
		{
			[]string{"a", "b", "c"},
			[]merkle.Path{pathABC0, pathABC1, pathABC2},
		},
		{
			[]string{"a", "b", "c", "d"},
			[]merkle.Path{pathABCD0, pathABCD1, pathABCD2, pathABCD3},
		},
		{
			[]string{"a", "b", "c", "d", "e"},
			[]merkle.Path{pathABCDE0, pathABCDE1, pathABCDE2, pathABCDE3, pathABCDE4},
		},
	}

	for i, test := range tests {
		var leaves = make([]types.Bytes32, len(test.leaves), len(test.leaves))
		for i, s := range test.leaves {
			leaves[i] = sha256.Sum256([]byte(s))
		}

		tree, err := f.New(leaves)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		for j := range test.leaves {
			var (
				got  = tree.Path(j)
				want = test.expected[j]
			)
			if !reflect.DeepEqual(got, want) {
				g, _ := json.MarshalIndent(got, "", "  ")
				w, _ := json.MarshalIndent(want, "", "  ")
				t.Errorf("test#%d: tree.Path(%d) = %s\nwant %s", i, j, g, w)
			}
		}
	}
}

// TestPathRandom tests that the implementation correctly computes paths given random trees.
func (f Factory) TestPathRandom(t *testing.T) {
	for i := 0; i < 10; i++ {
		tests := make([]types.Bytes32, 2+rand.Intn(10000))
		for j := range tests {
			tests[j] = *testutil.RandomHash()
		}

		tree, err := f.New(tests)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		for j := range tests {
			path := tree.Path(j)
			if err := path.Validate(); err != nil {
				t.Error(err)
			}

			if got, want := path[len(path)-1].Parent.String(), tree.Root().String(); got != want {
				t.Errorf("test#%d: tree.Path(%d) last parent = %q want %q", i, j, got, want)
			}
		}
	}
}

// BenchmarkCreateWithSize benchmarks creating trees of given size.
func (f Factory) BenchmarkCreateWithSize(b *testing.B, size int) {
	leaves := make([]types.Bytes32, size)
	for i := 0; i < size; i++ {
		leaves[i] = *testutil.RandomHash()
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		tree, err := f.New(leaves)
		if err != nil {
			b.Error(err)
		}
		defer f.free(tree)
	}
}

// BenchmarkCreate benchmarks creating trees of different sizes.
func (f Factory) BenchmarkCreate(b *testing.B) {
	b.Run("10-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 10) })
	b.Run("100-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 100) })
	b.Run("1000-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 1000) })
	b.Run("10000-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 10000) })
	b.Run("100000-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 100000) })
}

// BenchmarkPathWithSize benchmarks computing paths for trees of given size.
func (f Factory) BenchmarkPathWithSize(b *testing.B, size int) {
	leaves := make([]types.Bytes32, size)
	for i := 0; i < size; i++ {
		leaves[i] = *testutil.RandomHash()
	}

	tree, err := f.New(leaves)
	if err != nil {
		b.Fatal(err)
	}
	defer f.free(tree)

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		tree.Path(i % size)
	}
}

// BenchmarkPath benchmarks computing paths for different sizes.
func (f Factory) BenchmarkPath(b *testing.B) {
	b.Run("10-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 10) })
	b.Run("100-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 100) })
	b.Run("1000-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 1000) })
	b.Run("10000-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 10000) })
	b.Run("100000-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 100000) })
}

func atos(a types.Bytes32) []byte {
	return a[:]
}
<commit_msg>merkle: Disable output during benchmarks<commit_after>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

// Package treetestcases contains test cases to test Merkle tree implementation.
package treetestcases

import (
	"crypto/sha256"
	"encoding/json"
	"io/ioutil"
	"log"
	"math/rand"
	"reflect"
	"testing"

	"github.com/stratumn/go/testutil"
	"github.com/stratumn/go/types"
	"github.com/stratumn/goprivate/merkle"
)

var (
	pathA0     merkle.Path
	pathAB0    merkle.Path
	pathAB1    merkle.Path
	pathABC0   merkle.Path
	pathABC1   merkle.Path
	pathABC2   merkle.Path
	pathABCD0  merkle.Path
	pathABCD1  merkle.Path
	pathABCD2  merkle.Path
	pathABCD3  merkle.Path
	pathABCDE0 merkle.Path
	pathABCDE1 merkle.Path
	pathABCDE2 merkle.Path
	pathABCDE3 merkle.Path
	pathABCDE4 merkle.Path
)

func loadPath(filename string, path *merkle.Path) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	if err = json.Unmarshal(data, path); err != nil {
		panic(err)
	}
}

// LoadFixtures loads test fixtures and should be called before running the tests.
func LoadFixtures(testdatapath string) {
	// Load fixtures.
	loadPath(testdatapath+"/path-a-0.json", &pathA0)
	loadPath(testdatapath+"/path-ab-0.json", &pathAB0)
	loadPath(testdatapath+"/path-ab-1.json", &pathAB1)
	loadPath(testdatapath+"/path-abc-0.json", &pathABC0)
	loadPath(testdatapath+"/path-abc-1.json", &pathABC1)
	loadPath(testdatapath+"/path-abc-2.json", &pathABC2)
	loadPath(testdatapath+"/path-abcd-0.json", &pathABCD0)
	loadPath(testdatapath+"/path-abcd-1.json", &pathABCD1)
	loadPath(testdatapath+"/path-abcd-2.json", &pathABCD2)
	loadPath(testdatapath+"/path-abcd-3.json", &pathABCD3)
	loadPath(testdatapath+"/path-abcde-0.json", &pathABCDE0)
	loadPath(testdatapath+"/path-abcde-1.json", &pathABCDE1)
	loadPath(testdatapath+"/path-abcde-2.json", &pathABCDE2)
	loadPath(testdatapath+"/path-abcde-3.json", &pathABCDE3)
	loadPath(testdatapath+"/path-abcde-4.json", &pathABCDE4)
}

// Factory wraps functions to allocate and free a Merkle tree,
// and is used to run the tests on a Merkle tree implementation.
type Factory struct {
	// New create a Merkle tree from leaves.
	New func(leaves []types.Bytes32) (merkle.Tree, error)

	// Free is an optional function to free a Merkle tree.
	Free func(tree merkle.Tree)
}

// RunTests runs all the tests.
func (f Factory) RunTests(t *testing.T) {
	t.Run("NumLeaves", f.TestNumLeaves)
	t.Run("Root", f.TestRoot)
	t.Run("Leaf", f.TestLeaf)
	t.Run("Path", f.TestPath)
	t.Run("PathRandom", f.TestPathRandom)
}

// RunBenchmarks runs all the benchmarks.
func (f Factory) RunBenchmarks(b *testing.B) {
	b.Run("Create", f.BenchmarkCreate)
	b.Run("Path", f.BenchmarkPath)
}

func (f Factory) free(tree merkle.Tree) {
	if f.Free != nil {
		f.Free(tree)
	}
}

// TestNumLeaves tests that the implementation returns the correct number of leaves.
func (f Factory) TestNumLeaves(t *testing.T) {
	tree, err := f.New([]types.Bytes32{*testutil.RandomHash(), *testutil.RandomHash(), *testutil.RandomHash()})
	if err != nil {
		t.Fatal(err)
	}
	defer f.free(tree)

	if got, want := tree.LeavesLen(), 3; got != want {
		t.Errorf("tree.LeavesLen() = %d want %d", got, want)
	}
}

// TestRoot tests that the implementation computes the root correctly.
func (f Factory) TestRoot(t *testing.T) {
	tests := [...]struct {
		leaves   []string
		expected string
	}{
		{[]string{"a"}, "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"},
		{[]string{"a", "b"}, "e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a"},
		{[]string{"a", "b", "c"}, "7075152d03a5cd92104887b476862778ec0c87be5c2fa1c0a90f87c49fad6eff"},
		{[]string{"a", "b", "c", "d"}, "14ede5e8e97ad9372327728f5099b95604a39593cac3bd38a343ad76205213e7"},
		{[]string{"a", "b", "c", "d", "e"}, "d71f8983ad4ee170f8129f1ebcdd7440be7798d8e1c80420bf11f1eced610dba"},
		{[]string{"a", "b", "c", "d", "e", "f"}, "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2"},
		{[]string{"a", "b", "c", "d", "e", "f", "g"}, "e2a80e0e872a6c6eaed37b4c1f220e1935004805585b5f99617e48e9c8fe4034"},
		{[]string{"a", "b", "c", "d", "e", "f", "g", "h"}, "bd7c8a900be9b67ba7df5c78a652a8474aedd78adb5083e80e49d9479138a23f"},
		{[]string{"a", "b", "c", "d", "e", "f", "g", "h", "i"}, "386ced54bdc7456fecfc9b43018bbda2fe0a105f4cf7cad6bbb429c18fe852cc"},
	}

	for i, test := range tests {
		var leaves = make([]types.Bytes32, len(test.leaves), len(test.leaves))
		for i, s := range test.leaves {
			leaves[i] = sha256.Sum256([]byte(s))
		}

		tree, err := f.New(leaves)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		if got, want := tree.Root().String(), test.expected; got != want {
			t.Errorf("test#%d: tree.Root() = %q want %q", i, got, want)
		}
	}
}

// TestLeaf tests that the implementation correctly returns leaves.
func (f Factory) TestLeaf(t *testing.T) {
	for i := 1; i < 128; i++ {
		var leaves []types.Bytes32
		for j := 0; j < i; j++ {
			leaves = append(leaves, *testutil.RandomHash())
		}

		tree, err := f.New(leaves)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		for j := 0; j < i; j++ {
			if got, want := tree.Leaf(j).String(), leaves[j].String(); got != want {
				t.Errorf("test#%d: tree.Leaf(%d) = %q want %q", i, j, got, want)
			}
		}
	}
}

// TestPath tests that the implementation correctly computes paths.
func (f Factory) TestPath(t *testing.T) {
	tests := [...]struct {
		leaves   []string
		expected []merkle.Path
	}{
		{
			[]string{"a"},
			[]merkle.Path{pathA0},
		},
		{
			[]string{"a", "b"},
			[]merkle.Path{pathAB0, pathAB1},
		},
		{
			[]string{"a", "b", "c"},
			[]merkle.Path{pathABC0, pathABC1, pathABC2},
		},
		{
			[]string{"a", "b", "c", "d"},
			[]merkle.Path{pathABCD0, pathABCD1, pathABCD2, pathABCD3},
		},
		{
			[]string{"a", "b", "c", "d", "e"},
			[]merkle.Path{pathABCDE0, pathABCDE1, pathABCDE2, pathABCDE3, pathABCDE4},
		},
	}

	for i, test := range tests {
		var leaves = make([]types.Bytes32, len(test.leaves), len(test.leaves))
		for i, s := range test.leaves {
			leaves[i] = sha256.Sum256([]byte(s))
		}

		tree, err := f.New(leaves)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		for j := range test.leaves {
			var (
				got  = tree.Path(j)
				want = test.expected[j]
			)
			if !reflect.DeepEqual(got, want) {
				g, _ := json.MarshalIndent(got, "", "  ")
				w, _ := json.MarshalIndent(want, "", "  ")
				t.Errorf("test#%d: tree.Path(%d) = %s\nwant %s", i, j, g, w)
			}
		}
	}
}

// TestPathRandom tests that the implementation correctly computes paths given random trees.
func (f Factory) TestPathRandom(t *testing.T) {
	for i := 0; i < 10; i++ {
		tests := make([]types.Bytes32, 2+rand.Intn(10000))
		for j := range tests {
			tests[j] = *testutil.RandomHash()
		}

		tree, err := f.New(tests)
		if err != nil {
			t.Fatal(err)
		}
		defer f.free(tree)

		for j := range tests {
			path := tree.Path(j)
			if err := path.Validate(); err != nil {
				t.Error(err)
			}

			if got, want := path[len(path)-1].Parent.String(), tree.Root().String(); got != want {
				t.Errorf("test#%d: tree.Path(%d) last parent = %q want %q", i, j, got, want)
			}
		}
	}
}

// BenchmarkCreateWithSize benchmarks creating trees of given size.
func (f Factory) BenchmarkCreateWithSize(b *testing.B, size int) {
	leaves := make([]types.Bytes32, size)
	for i := 0; i < size; i++ {
		leaves[i] = *testutil.RandomHash()
	}

	b.ResetTimer()
	log.SetOutput(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		tree, err := f.New(leaves)
		if err != nil {
			b.Error(err)
		}
		defer f.free(tree)
	}
}

// BenchmarkCreate benchmarks creating trees of different sizes.
func (f Factory) BenchmarkCreate(b *testing.B) {
	b.Run("10-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 10) })
	b.Run("100-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 100) })
	b.Run("1000-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 1000) })
	b.Run("10000-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 10000) })
	b.Run("100000-leaves", func(b *testing.B) { f.BenchmarkCreateWithSize(b, 100000) })
}

// BenchmarkPathWithSize benchmarks computing paths for trees of given size.
func (f Factory) BenchmarkPathWithSize(b *testing.B, size int) {
	leaves := make([]types.Bytes32, size)
	for i := 0; i < size; i++ {
		leaves[i] = *testutil.RandomHash()
	}

	tree, err := f.New(leaves)
	if err != nil {
		b.Fatal(err)
	}
	defer f.free(tree)

	b.ResetTimer()
	log.SetOutput(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		tree.Path(i % size)
	}
}

// BenchmarkPath benchmarks computing paths for different sizes.
func (f Factory) BenchmarkPath(b *testing.B) {
	b.Run("10-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 10) })
	b.Run("100-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 100) })
	b.Run("1000-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 1000) })
	b.Run("10000-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 10000) })
	b.Run("100000-leaves", func(b *testing.B) { f.BenchmarkPathWithSize(b, 100000) })
}

func atos(a types.Bytes32) []byte {
	return a[:]
}
<|endoftext|>


<commit_before>// Make balanced rosters according to weighted criteria

package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"sort"
	"text/tabwriter"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"
)

// Genetic algorithm constants
const (
	// Number of teams to break players into
	numTeams = 6
	// Number of times to run our genetic algorithm
	numRuns = 100
	// Percent of the time we will try to mutate. After each
	// mutation, we have a mutationChance percent chance of
	// mutating again.
	mutationChance = 5
	// We will make numSolutionsPerRun every run, and numParents carry
	// over into the next run to create the next batch of solutions.
	numSolutionsPerRun = 1000
	numParents         = 20
)

type Score float64
type Solution struct {
	players []Player
	score   Score
}

// Implement sort.Interface for []Solution, sorting based on score
type ByScore []Solution

func (a ByScore) Len() int {
	return len(a)
}
func (a ByScore) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
func (a ByScore) Less(i, j int) bool {
	return a[i].score < a[j].score
}

type Team struct {
	players []Player
}

func splitIntoTeams(players []Player) []Team {
	teams := make([]Team, numTeams)
	for _, player := range players {
		teams[player.team].players = append(teams[player.team].players, player)
	}
	return teams
}

func randomizeTeams(players []Player) {
	for i, _ := range players {
		players[i].team = uint8(rand.Intn(numTeams))
	}
}

func PrintTeams(solution Solution) {
	teams := splitIntoTeams(solution.players)
	for i, team := range teams {
		fmt.Printf("Team #%d, %d players. Average rating: %.2f\n",
			i, len(teams[i].players), AverageRating(team))
		writer := new(tabwriter.Writer)
		writer.Init(os.Stdout, 0, 0, 1, ' ', 0)
		for _, filterFunc := range []PlayerFilter{IsMale, IsFemale} {
			filteredPlayers := Filter(team.players, filterFunc)
			sort.Sort(sort.Reverse(ByRating(filteredPlayers)))
			for _, player := range filteredPlayers {
				fmt.Fprintln(writer, player)
			}
		}
		writer.Flush()
	}
}

// Mutate the solution by moving random players to random teams, sometimes.
func mutate(players []Player) {
	for {
		// We have mutationChance of mutating. Otherwise, we break out of our loop
		if rand.Intn(100) > mutationChance {
			return
		}
		// Mutation! Move a random player to a random new team
		players[rand.Intn(len(players))].team = uint8(rand.Intn(numTeams))
	}
}

// Breed via combining the two given solutions, then randomly mutating.
func breed(solution1 Solution, solution2 Solution) Solution {
	// Create the new solution by taking crossover from both inputs
	newPlayers := make([]Player, len(solution1.players))
	for i, _ := range newPlayers {
		// Randomly take each player from solution1 or solution2
		if rand.Intn(100) < 50 {
			newPlayers[i] = solution1.players[i]
		} else {
			newPlayers[i] = solution2.players[i]
		}
	}

	// Mutate the new player list
	mutate(newPlayers)

	solutionScore, _ := ScoreSolution(newPlayers)
	return Solution{newPlayers, solutionScore}
}

// performRun creates a new solution list by breeding parents.
func performRun(parents []Solution) []Solution {
	newSolutions := make([]Solution, numSolutionsPerRun)
	for i, _ := range newSolutions {
		if i < numParents {
			// Keep the parents from last time - elitism!
			newSolutions[i] = parents[i]
		} else {
			// Make a new solution based on two random parents
			newSolutions[i] = breed(
				parents[rand.Intn(len(parents))],
				parents[rand.Intn(len(parents))])
		}
	}
	return newSolutions
}

func parseCommandLine() []Player {
	filenamePointer := kingpin.Arg("input-file",
		"filename from which to get list of players").
		Required().String()
	deterministicPointer := kingpin.Flag("deterministic",
		"makes our output deterministic by allowing the default rand.Seed").
		Short('d').Bool()
	kingpin.Parse()

	if !*deterministicPointer {
		rand.Seed(time.Now().UTC().UnixNano())
	}

	return ParsePlayers(*filenamePointer)
}

func main() {
	players := parseCommandLine()
	if len(players) == 0 {
		panic("Could not find players")
	}

	// Create random Parent solutions to start
	topSolutions := make([]Solution, numParents)
	for i, _ := range topSolutions {
		ourPlayers := make([]Player, len(players))
		copy(ourPlayers, players)
		randomizeTeams(ourPlayers)
		solutionScore, _ := ScoreSolution(ourPlayers)
		topSolutions[i] = Solution{ourPlayers, solutionScore}
	}

	PopulateWorstCases(topSolutions)

	topScore := topSolutions[0].score
	for i := 0; i < numRuns; i++ {
		if topScore != topSolutions[0].score {
			topScore = topSolutions[0].score
			log.Println("New top score! Run number ", i, "Score:", topScore)
			PrintSolutionScoring(topSolutions[0])
		}

		// Create new solutions, and save the best ones
		newSolutions := performRun(topSolutions)
		sort.Sort(ByScore(newSolutions))
		for i, _ := range topSolutions {
			topSolutions[i] = newSolutions[i]
		}
	}
	topSolution := topSolutions[0]
	log.Printf("Top score is %f, solution: %v\n", topSolution, topSolution)
	PrintTeams(topSolution)
	PrintSolutionScoring(topSolution)
}
<commit_msg>rename "topSolutions" -> "parentSolutions"<commit_after>// Make balanced rosters according to weighted criteria

package main

import (
	"fmt"
	"log"
	"math/rand"
	"os"
	"sort"
	"text/tabwriter"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"
)

// Genetic algorithm constants
const (
	// Number of teams to break players into
	numTeams = 6
	// Number of times to run our genetic algorithm
	numRuns = 100
	// Percent of the time we will try to mutate. After each
	// mutation, we have a mutationChance percent chance of
	// mutating again.
	mutationChance = 5
	// We will make numSolutionsPerRun every run, and numParents carry
	// over into the next run to create the next batch of solutions.
	numSolutionsPerRun = 1000
	numParents         = 20
)

type Score float64
type Solution struct {
	players []Player
	score   Score
}

// Implement sort.Interface for []Solution, sorting based on score
type ByScore []Solution

func (a ByScore) Len() int {
	return len(a)
}
func (a ByScore) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}
func (a ByScore) Less(i, j int) bool {
	return a[i].score < a[j].score
}

type Team struct {
	players []Player
}

func splitIntoTeams(players []Player) []Team {
	teams := make([]Team, numTeams)
	for _, player := range players {
		teams[player.team].players = append(teams[player.team].players, player)
	}
	return teams
}

func randomizeTeams(players []Player) {
	for i, _ := range players {
		players[i].team = uint8(rand.Intn(numTeams))
	}
}

func PrintTeams(solution Solution) {
	teams := splitIntoTeams(solution.players)
	for i, team := range teams {
		fmt.Printf("Team #%d, %d players. Average rating: %.2f\n",
			i, len(teams[i].players), AverageRating(team))
		writer := new(tabwriter.Writer)
		writer.Init(os.Stdout, 0, 0, 1, ' ', 0)
		for _, filterFunc := range []PlayerFilter{IsMale, IsFemale} {
			filteredPlayers := Filter(team.players, filterFunc)
			sort.Sort(sort.Reverse(ByRating(filteredPlayers)))
			for _, player := range filteredPlayers {
				fmt.Fprintln(writer, player)
			}
		}
		writer.Flush()
	}
}

// Mutate the solution by moving random players to random teams, sometimes.
func mutate(players []Player) {
	for {
		// We have mutationChance of mutating. Otherwise, we break out of our loop
		if rand.Intn(100) > mutationChance {
			return
		}
		// Mutation! Move a random player to a random new team
		players[rand.Intn(len(players))].team = uint8(rand.Intn(numTeams))
	}
}

// Breed via combining the two given solutions, then randomly mutating.
func breed(solution1 Solution, solution2 Solution) Solution {
	// Create the new solution by taking crossover from both inputs
	newPlayers := make([]Player, len(solution1.players))
	for i, _ := range newPlayers {
		// Randomly take each player from solution1 or solution2
		if rand.Intn(100) < 50 {
			newPlayers[i] = solution1.players[i]
		} else {
			newPlayers[i] = solution2.players[i]
		}
	}

	// Mutate the new player list
	mutate(newPlayers)

	solutionScore, _ := ScoreSolution(newPlayers)
	return Solution{newPlayers, solutionScore}
}

// performRun creates a new solution list by breeding parents.
func performRun(parents []Solution) []Solution {
	newSolutions := make([]Solution, numSolutionsPerRun)
	for i, _ := range newSolutions {
		if i < numParents {
			// Keep the parents from last time - elitism!
			newSolutions[i] = parents[i]
		} else {
			// Make a new solution based on two random parents
			newSolutions[i] = breed(
				parents[rand.Intn(len(parents))],
				parents[rand.Intn(len(parents))])
		}
	}
	return newSolutions
}

func parseCommandLine() []Player {
	filenamePointer := kingpin.Arg("input-file",
		"filename from which to get list of players").
		Required().String()
	deterministicPointer := kingpin.Flag("deterministic",
		"makes our output deterministic by allowing the default rand.Seed").
		Short('d').Bool()
	kingpin.Parse()

	if !*deterministicPointer {
		rand.Seed(time.Now().UTC().UnixNano())
	}

	return ParsePlayers(*filenamePointer)
}

func main() {
	players := parseCommandLine()
	if len(players) == 0 {
		panic("Could not find players")
	}

	// Create random Parent solutions to start
	parentSolutions := make([]Solution, numParents)
	for i, _ := range parentSolutions {
		ourPlayers := make([]Player, len(players))
		copy(ourPlayers, players)
		randomizeTeams(ourPlayers)
		solutionScore, _ := ScoreSolution(ourPlayers)
		parentSolutions[i] = Solution{ourPlayers, solutionScore}
	}

	PopulateWorstCases(parentSolutions)

	topScore := parentSolutions[0].score
	for i := 0; i < numRuns; i++ {
		if topScore != parentSolutions[0].score {
			topScore = parentSolutions[0].score
			log.Println("New top score! Run number ", i, "Score:", topScore)
			PrintSolutionScoring(parentSolutions[0])
		}

		// Create new solutions, and save the best ones
		newSolutions := performRun(parentSolutions)
		sort.Sort(ByScore(newSolutions))
		for i, _ := range parentSolutions {
			parentSolutions[i] = newSolutions[i]
		}
	}
	topSolution := parentSolutions[0]
	log.Printf("Top score is %f, solution: %v\n", topSolution, topSolution)
	PrintTeams(topSolution)
	PrintSolutionScoring(topSolution)
}
<|endoftext|>


<commit_before>package router

import (
	"github.com/ewhal/nyaa/service/user/permission"
	"github.com/nicksnyder/go-i18n/i18n"
	"html/template"
	"log"
	"math"
	"net/url"
	"strconv"
)

var FuncMap = template.FuncMap{
	"min": math.Min,
	"genRoute": func(name string, params ...string) string {
		url, err := Router.Get(name).URL(params...)
		if err == nil {
			return url.String()
		}
		return "error"
	},
	"genRouteWithQuery": func(name string, currentUrl *url.URL, params ...string) template.HTML {
		url, err := Router.Get(name).URL(params...)
		if err == nil {
			return template.HTML(template.HTMLEscapeString(url.String() + "?" + currentUrl.RawQuery)) // TODO: Review application of character escaping
		}
		return "error"
	},
	"genNav": func(nav Navigation, currentUrl *url.URL, pagesSelectable int) template.HTML {
		var ret = ""
		if (nav.TotalItem > 0) {
		maxPages := math.Ceil(float64(nav.TotalItem) / float64(nav.MaxItemPerPage))

		if nav.CurrentPage-1 > 0 {
			url, _ := Router.Get(nav.Route).URL("page", "1")
			ret = ret + "
«
"
		}
		startValue := 1
		if nav.CurrentPage > pagesSelectable/2 {
			startValue = (int(math.Min((float64(nav.CurrentPage)+math.Floor(float64(pagesSelectable)/2)), maxPages)) - pagesSelectable + 1)
		}
		endValue := (startValue + pagesSelectable - 1)
		if endValue > int(maxPages) {
			endValue = int(maxPages)
		}
		log.Println(nav.TotalItem)
		for i := startValue; i <= endValue; i++ {
			pageNum := strconv.Itoa(i)
			url, _ := Router.Get(nav.Route).URL("page", pageNum)
			ret = ret + "
" + strconv.Itoa(i) + "
"
		}
		if nav.CurrentPage < int(maxPages) {
			url, _ := Router.Get(nav.Route).URL("page", strconv.Itoa(nav.CurrentPage+1))
			ret = ret + "
»
"
		}
		}
		return template.HTML(ret)
	},
	"T": i18n.IdentityTfunc,
	"Ts": i18n.IdentityTfunc,
	"getAvatar": func(hash string, size int) string {
		return "https://www.gravatar.com/avatar/" + hash + "?s=" + strconv.Itoa(size)
	},
	"CurrentOrAdmin":       userPermission.CurrentOrAdmin,
	"CurrentUserIdentical": userPermission.CurrentUserIdentical,
	"HasAdmin":             userPermission.HasAdmin,
	"NeedsCaptcha":         userPermission.NeedsCaptcha,
	"GetRole":              userPermission.GetRole,
	"IsFollower":           userPermission.IsFollower,
	"NoEncode": func(str string) template.HTML {
		return template.HTML(str)
	},
	"calcWidthSeed": func(seed uint32, leech uint32) float64 {
		return float64(float64(seed)/(float64(seed)+float64(leech)))*100
	},
	"calcWidthLeech": func(seed uint32, leech uint32) float64 {
		return float64(float64(leech)/(float64(seed)+float64(leech)))*100
	},
}
<commit_msg>Fix one URL escape too much in RSS link<commit_after>package router

import (
	"github.com/ewhal/nyaa/service/user/permission"
	"github.com/nicksnyder/go-i18n/i18n"
	"html/template"
	"log"
	"math"
	"net/url"
	"strconv"
)

var FuncMap = template.FuncMap{
	"min": math.Min,
	"genRoute": func(name string, params ...string) string {
		url, err := Router.Get(name).URL(params...)
		if err == nil {
			return url.String()
		}
		return "error"
	},
	"genRouteWithQuery": func(name string, currentUrl *url.URL, params ...string) template.URL {
		url, err := Router.Get(name).URL(params...)
		if err == nil {
			return template.URL(url.String() + "?" + currentUrl.RawQuery)
		}
		return "error"
	},
	"genNav": func(nav Navigation, currentUrl *url.URL, pagesSelectable int) template.HTML {
		var ret = ""
		if (nav.TotalItem > 0) {
		maxPages := math.Ceil(float64(nav.TotalItem) / float64(nav.MaxItemPerPage))

		if nav.CurrentPage-1 > 0 {
			url, _ := Router.Get(nav.Route).URL("page", "1")
			ret = ret + "
«
"
		}
		startValue := 1
		if nav.CurrentPage > pagesSelectable/2 {
			startValue = (int(math.Min((float64(nav.CurrentPage)+math.Floor(float64(pagesSelectable)/2)), maxPages)) - pagesSelectable + 1)
		}
		endValue := (startValue + pagesSelectable - 1)
		if endValue > int(maxPages) {
			endValue = int(maxPages)
		}
		log.Println(nav.TotalItem)
		for i := startValue; i <= endValue; i++ {
			pageNum := strconv.Itoa(i)
			url, _ := Router.Get(nav.Route).URL("page", pageNum)
			ret = ret + "
" + strconv.Itoa(i) + "
"
		}
		if nav.CurrentPage < int(maxPages) {
			url, _ := Router.Get(nav.Route).URL("page", strconv.Itoa(nav.CurrentPage+1))
			ret = ret + "
»
"
		}
		}
		return template.HTML(ret)
	},
	"T": i18n.IdentityTfunc,
	"Ts": i18n.IdentityTfunc,
	"getAvatar": func(hash string, size int) string {
		return "https://www.gravatar.com/avatar/" + hash + "?s=" + strconv.Itoa(size)
	},
	"CurrentOrAdmin":       userPermission.CurrentOrAdmin,
	"CurrentUserIdentical": userPermission.CurrentUserIdentical,
	"HasAdmin":             userPermission.HasAdmin,
	"NeedsCaptcha":         userPermission.NeedsCaptcha,
	"GetRole":              userPermission.GetRole,
	"IsFollower":           userPermission.IsFollower,
	"NoEncode": func(str string) template.HTML {
		return template.HTML(str)
	},
	"calcWidthSeed": func(seed uint32, leech uint32) float64 {
		return float64(float64(seed)/(float64(seed)+float64(leech)))*100
	},
	"calcWidthLeech": func(seed uint32, leech uint32) float64 {
		return float64(float64(leech)/(float64(seed)+float64(leech)))*100
	},
}
<|endoftext|>


<commit_before>package graphql

import (
	"fmt"

	"github.com/sprucehealth/graphql/gqlerrors"
)

type SchemaConfig struct {
	Query        *Object
	Mutation     *Object
	Subscription *Object
	Types        []Type
	Directives   []*Directive
}

type TypeMap map[string]Type

// Schema Definition
// A Schema is created by supplying the root types of each type of operation,
// query, mutation (optional) and subscription (optional). A schema definition is then supplied to the
// validator and executor.
// Example:
//     myAppSchema, err := NewSchema(SchemaConfig({
//       Query: MyAppQueryRootType,
//       Mutation: MyAppMutationRootType,
//       Subscription: MyAppSubscriptionRootType,
//     });
// Note: If an array of `directives` are provided to GraphQLSchema, that will be
// the exact list of directives represented and allowed. If `directives` is not
// provided then a default set of the specified directives (e.g. @include and
// @skip) will be used. If you wish to provide *additional* directives to these
// specified directives, you must explicitly declare them. Example:
//
//     const MyAppSchema = new GraphQLSchema({
//       ...
//       directives: specifiedDirectives.concat([ myCustomDirective ]),
//     })
type Schema struct {
	typeMap    TypeMap
	directives []*Directive

	queryType        *Object
	mutationType     *Object
	subscriptionType *Object
	implementations  map[string][]*Object
	possibleTypeMap  map[string]map[string]bool
}

func NewSchema(config SchemaConfig) (Schema, error) {
	schema := Schema{}

	if config.Query == nil {
		return schema, gqlerrors.NewFormattedError("Schema query must be Object Type but got: nil.")
	}

	// if schema config contains error at creation time, return those errors
	if config.Query != nil && config.Query.Error() != nil {
		return schema, config.Query.Error()
	}
	if config.Mutation != nil && config.Mutation.Error() != nil {
		return schema, config.Mutation.Error()
	}

	schema.queryType = config.Query
	schema.mutationType = config.Mutation
	schema.subscriptionType = config.Subscription

	// Provide specified directives (e.g. @include and @skip) by default.
	schema.directives = config.Directives
	if len(schema.directives) == 0 {
		schema.directives = SpecifiedDirectives
	}
	// Ensure directive definitions are error-free
	for _, dir := range schema.directives {
		if dir.err != nil {
			return schema, dir.err
		}
	}

	// Build type map now to detect any errors within this schema.
	typeMap := TypeMap{}
	initialTypes := make([]Type, 0, 4+len(config.Types))
	if schema.QueryType() != nil {
		initialTypes = append(initialTypes, schema.QueryType())
	}
	if schema.MutationType() != nil {
		initialTypes = append(initialTypes, schema.MutationType())
	}
	if schema.SubscriptionType() != nil {
		initialTypes = append(initialTypes, schema.SubscriptionType())
	}
	if SchemaType != nil {
		initialTypes = append(initialTypes, SchemaType)
	}

	for _, ttype := range config.Types {
		// assume that user will never add a nil object to config
		initialTypes = append(initialTypes, ttype)
	}

	for _, ttype := range initialTypes {
		if ttype.Error() != nil {
			return schema, ttype.Error()
		}
		var err error
		typeMap, err = typeMapReducer(&schema, typeMap, ttype)
		if err != nil {
			return schema, err
		}
	}

	schema.typeMap = typeMap

	// Keep track of all implementations by interface name.
	if schema.implementations == nil {
		schema.implementations = map[string][]*Object{}
	}
	for _, ttype := range schema.typeMap {
		if ttype, ok := ttype.(*Object); ok {
			for _, iface := range ttype.Interfaces() {
				schema.implementations[iface.Name()] = append(schema.implementations[iface.Name()], ttype)
			}
		}
	}

	// Enforce correct interface implementations
	for _, ttype := range schema.typeMap {
		if ttype, ok := ttype.(*Object); ok {
			for _, iface := range ttype.Interfaces() {
				err := assertObjectImplementsInterface(&schema, ttype, iface)
				if err != nil {
					return schema, err
				}
			}
		}
	}

	return schema, nil
}

func (gq *Schema) QueryType() *Object {
	return gq.queryType
}

func (gq *Schema) MutationType() *Object {
	return gq.mutationType
}

func (gq *Schema) SubscriptionType() *Object {
	return gq.subscriptionType
}

func (gq *Schema) Directives() []*Directive {
	return gq.directives
}

func (gq *Schema) Directive(name string) *Directive {
	for _, directive := range gq.Directives() {
		if directive.Name == name {
			return directive
		}
	}
	return nil
}

func (gq *Schema) TypeMap() TypeMap {
	return gq.typeMap
}

func (gq *Schema) Type(name string) Type {
	return gq.TypeMap()[name]
}

func (gq *Schema) PossibleTypes(abstractType Abstract) []*Object {
	if abstractType, ok := abstractType.(*Union); ok {
		return abstractType.Types()
	}
	if abstractType, ok := abstractType.(*Interface); ok {
		if impls, ok := gq.implementations[abstractType.Name()]; ok {
			return impls
		}
	}
	return []*Object{}
}
func (gq *Schema) IsPossibleType(abstractType Abstract, possibleType *Object) bool {
	possibleTypeMap := gq.possibleTypeMap
	if possibleTypeMap == nil {
		possibleTypeMap = map[string]map[string]bool{}
	}

	if typeMap, ok := possibleTypeMap[abstractType.Name()]; !ok {
		typeMap = map[string]bool{}
		for _, possibleType := range gq.PossibleTypes(abstractType) {
			typeMap[possibleType.Name()] = true
		}
		possibleTypeMap[abstractType.Name()] = typeMap
	}

	gq.possibleTypeMap = possibleTypeMap
	if typeMap, ok := possibleTypeMap[abstractType.Name()]; ok {
		isPossible, _ := typeMap[possibleType.Name()]
		return isPossible
	}
	return false
}
func typeMapReducer(schema *Schema, typeMap TypeMap, objectType Type) (TypeMap, error) {
	var err error
	if objectType == nil || objectType.Name() == "" {
		return typeMap, nil
	}

	switch objectType := objectType.(type) {
	case *List:
		if objectType.OfType != nil {
			return typeMapReducer(schema, typeMap, objectType.OfType)
		}
	case *NonNull:
		if objectType.OfType != nil {
			return typeMapReducer(schema, typeMap, objectType.OfType)
		}
	case *Object:
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
	}

	if mappedObjectType, ok := typeMap[objectType.Name()]; ok {
		if mappedObjectType != objectType {
			return typeMap, gqlerrors.NewFormattedError(fmt.Sprintf(`Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name()))
		}
		return typeMap, nil
	}
	if objectType.Name() == "" {
		return typeMap, nil
	}

	typeMap[objectType.Name()] = objectType

	switch objectType := objectType.(type) {
	case *Union:
		types := schema.PossibleTypes(objectType)
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, innerObjectType := range types {
			if innerObjectType.Error() != nil {
				return typeMap, innerObjectType.Error()
			}
			typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
			if err != nil {
				return typeMap, err
			}
		}
	case *Interface:
		types := schema.PossibleTypes(objectType)
		if objectType.err != nil {
			return typeMap, objectType.err
		}
		for _, innerObjectType := range types {
			if innerObjectType.Error() != nil {
				return typeMap, innerObjectType.Error()
			}
			typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
			if err != nil {
				return typeMap, err
			}
		}
	case *Object:
		interfaces := objectType.Interfaces()
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, innerObjectType := range interfaces {
			if innerObjectType.Error() != nil {
				return typeMap, innerObjectType.Error()
			}
			typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
			if err != nil {
				return typeMap, err
			}
		}
	}

	switch objectType := objectType.(type) {
	case *Object:
		fieldMap := objectType.Fields()
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, field := range fieldMap {
			for _, arg := range field.Args {
				typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
				if err != nil {
					return typeMap, err
				}
			}
			typeMap, err = typeMapReducer(schema, typeMap, field.Type)
			if err != nil {
				return typeMap, err
			}
		}
	case *Interface:
		fieldMap := objectType.Fields()
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, field := range fieldMap {
			for _, arg := range field.Args {
				typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
				if err != nil {
					return typeMap, err
				}
			}
			typeMap, err = typeMapReducer(schema, typeMap, field.Type)
			if err != nil {
				return typeMap, err
			}
		}
	case *InputObject:
		fieldMap := objectType.Fields()
		if objectType.err != nil {
			return typeMap, objectType.err
		}
		for _, field := range fieldMap {
			typeMap, err = typeMapReducer(schema, typeMap, field.Type)
			if err != nil {
				return typeMap, err
			}
		}
	}
	return typeMap, nil
}

func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Interface) error {
	objectFieldMap := object.Fields()
	ifaceFieldMap := iface.Fields()

	// Assert each interface field is implemented.
	for fieldName := range ifaceFieldMap {
		objectField := objectFieldMap[fieldName]
		ifaceField := ifaceFieldMap[fieldName]

		// Assert interface field exists on object.
		if objectField == nil {
			return gqlerrors.NewFormattedError(fmt.Sprintf(`"%v" expects field "%v" but "%v" does not provide it.`, iface, fieldName, object))
		}

		// Assert interface field type matches object field type.
		if !isTypeSubTypeOf(schema, objectField.Type, ifaceField.Type) {
			return gqlerrors.NewFormattedError(fmt.Sprintf(`%v.%v expects type "%v" but %v.%v provides type "%v".`,
				iface, fieldName, ifaceField.Type,
				object, fieldName, objectField.Type))
		}

		// Assert each interface field arg is implemented.
		for _, ifaceArg := range ifaceField.Args {
			argName := ifaceArg.PrivateName
			var objectArg *Argument
			for _, arg := range objectField.Args {
				if arg.PrivateName == argName {
					objectArg = arg
					break
				}
			}
			// Assert interface field arg exists on object field.
			if objectArg == nil {
				return gqlerrors.NewFormattedError(fmt.Sprintf(`%v.%v expects argument "%v" but %v.%v does not provide it.`,
					iface, fieldName, argName,
					object, fieldName))
			}

			// Assert interface field arg type matches object field arg type.
			if !isEqualType(ifaceArg.Type, objectArg.Type) {
				return gqlerrors.NewFormattedError(fmt.Sprintf(
					`%v.%v(%v:) expects type "%v" `+
						`but %v.%v(%v:) provides `+
						`type "%v".`,
					iface, fieldName, argName, ifaceArg.Type,
					object, fieldName, argName, objectArg.Type))
			}
		}
		// Assert additional arguments must not be required.
		for _, objectArg := range objectField.Args {
			argName := objectArg.PrivateName
			var ifaceArg *Argument
			for _, arg := range ifaceField.Args {
				if arg.PrivateName == argName {
					ifaceArg = arg
					break
				}
			}
			if ifaceArg == nil {
				_, ok := objectArg.Type.(*NonNull)
				if ok {
					return gqlerrors.NewFormattedError(
						fmt.Sprintf(`%v.%v(%v:) is of required type "%v" but is not also provided by the interface %v.%v.`,
							object, fieldName, argName, objectArg.Type, iface, fieldName))
				}
			}
		}
	}
	return nil
}

func isEqualType(typeA, typeB Type) bool {
	// Equivalent type is a valid subtype
	if typeA == typeB {
		return true
	}
	// If either type is non-null, the other must also be non-null.
	if typeA, ok := typeA.(*NonNull); ok {
		if typeB, ok := typeB.(*NonNull); ok {
			return isEqualType(typeA.OfType, typeB.OfType)
		}
	}
	// If either type is a list, the other must also be a list.
	if typeA, ok := typeA.(*List); ok {
		if typeB, ok := typeB.(*List); ok {
			return isEqualType(typeA.OfType, typeB.OfType)
		}
	}
	return typeA == typeB
}

// isTypeSubTypeOf Provided a type and a super type, return true if the first type is either
// equal or a subset of the second super type (covariant).
func isTypeSubTypeOf(schema *Schema, maybeSubType Type, superType Type) bool {
	// Equivalent type is a valid subtype
	if maybeSubType == superType {
		return true
	}

	// If superType is non-null, maybeSubType must also be nullable.
	if superType, ok := superType.(*NonNull); ok {
		if maybeSubType, ok := maybeSubType.(*NonNull); ok {
			return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
		}
		return false
	}
	if maybeSubType, ok := maybeSubType.(*NonNull); ok {
		// If superType is nullable, maybeSubType may be non-null.
		return isTypeSubTypeOf(schema, maybeSubType.OfType, superType)
	}

	// If superType type is a list, maybeSubType type must also be a list.
	if superType, ok := superType.(*List); ok {
		if maybeSubType, ok := maybeSubType.(*List); ok {
			return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
		}
		return false
	} else if _, ok := maybeSubType.(*List); ok {
		// If superType is not a list, maybeSubType must also be not a list.
		return false
	}

	// If superType type is an abstract type, maybeSubType type may be a currently
	// possible object type.
	if superType, ok := superType.(*Interface); ok {
		if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
			return true
		}
	}
	if superType, ok := superType.(*Union); ok {
		if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
			return true
		}
	}

	// Otherwise, the child type is not a valid subtype of the parent type.
	return false
}
<commit_msg>Make Schema.IsPossibleType safe for concurrent access<commit_after>package graphql

import (
	"fmt"

	"github.com/golang/sync/syncmap"
	"github.com/sprucehealth/graphql/gqlerrors"
)

type SchemaConfig struct {
	Query        *Object
	Mutation     *Object
	Subscription *Object
	Types        []Type
	Directives   []*Directive
}

type TypeMap map[string]Type

// Schema Definition
// A Schema is created by supplying the root types of each type of operation,
// query, mutation (optional) and subscription (optional). A schema definition is then supplied to the
// validator and executor.
// Example:
//     myAppSchema, err := NewSchema(SchemaConfig({
//       Query: MyAppQueryRootType,
//       Mutation: MyAppMutationRootType,
//       Subscription: MyAppSubscriptionRootType,
//     });
// Note: If an array of `directives` are provided to GraphQLSchema, that will be
// the exact list of directives represented and allowed. If `directives` is not
// provided then a default set of the specified directives (e.g. @include and
// @skip) will be used. If you wish to provide *additional* directives to these
// specified directives, you must explicitly declare them. Example:
//
//     const MyAppSchema = new GraphQLSchema({
//       ...
//       directives: specifiedDirectives.concat([ myCustomDirective ]),
//     })
type Schema struct {
	typeMap    TypeMap
	directives []*Directive

	queryType        *Object
	mutationType     *Object
	subscriptionType *Object
	implementations  map[string][]*Object
	possibleTypeMap  *syncmap.Map // abstract type name -> map[string]struct{}
}

func NewSchema(config SchemaConfig) (Schema, error) {
	schema := Schema{
		possibleTypeMap: &syncmap.Map{},
	}

	if config.Query == nil {
		return schema, gqlerrors.NewFormattedError("Schema query must be Object Type but got: nil.")
	}

	// if schema config contains error at creation time, return those errors
	if config.Query != nil && config.Query.Error() != nil {
		return schema, config.Query.Error()
	}
	if config.Mutation != nil && config.Mutation.Error() != nil {
		return schema, config.Mutation.Error()
	}

	schema.queryType = config.Query
	schema.mutationType = config.Mutation
	schema.subscriptionType = config.Subscription

	// Provide specified directives (e.g. @include and @skip) by default.
	schema.directives = config.Directives
	if len(schema.directives) == 0 {
		schema.directives = SpecifiedDirectives
	}
	// Ensure directive definitions are error-free
	for _, dir := range schema.directives {
		if dir.err != nil {
			return schema, dir.err
		}
	}

	// Build type map now to detect any errors within this schema.
	typeMap := TypeMap{}
	initialTypes := make([]Type, 0, 4+len(config.Types))
	if schema.QueryType() != nil {
		initialTypes = append(initialTypes, schema.QueryType())
	}
	if schema.MutationType() != nil {
		initialTypes = append(initialTypes, schema.MutationType())
	}
	if schema.SubscriptionType() != nil {
		initialTypes = append(initialTypes, schema.SubscriptionType())
	}
	if SchemaType != nil {
		initialTypes = append(initialTypes, SchemaType)
	}

	for _, ttype := range config.Types {
		// assume that user will never add a nil object to config
		initialTypes = append(initialTypes, ttype)
	}

	for _, ttype := range initialTypes {
		if ttype.Error() != nil {
			return schema, ttype.Error()
		}
		var err error
		typeMap, err = typeMapReducer(&schema, typeMap, ttype)
		if err != nil {
			return schema, err
		}
	}

	schema.typeMap = typeMap

	// Keep track of all implementations by interface name.
	if schema.implementations == nil {
		schema.implementations = map[string][]*Object{}
	}
	for _, ttype := range schema.typeMap {
		if ttype, ok := ttype.(*Object); ok {
			for _, iface := range ttype.Interfaces() {
				schema.implementations[iface.Name()] = append(schema.implementations[iface.Name()], ttype)
			}
		}
	}

	// Enforce correct interface implementations
	for _, ttype := range schema.typeMap {
		if ttype, ok := ttype.(*Object); ok {
			for _, iface := range ttype.Interfaces() {
				err := assertObjectImplementsInterface(&schema, ttype, iface)
				if err != nil {
					return schema, err
				}
			}
		}
	}

	return schema, nil
}

func (gq *Schema) QueryType() *Object {
	return gq.queryType
}

func (gq *Schema) MutationType() *Object {
	return gq.mutationType
}

func (gq *Schema) SubscriptionType() *Object {
	return gq.subscriptionType
}

func (gq *Schema) Directives() []*Directive {
	return gq.directives
}

func (gq *Schema) Directive(name string) *Directive {
	for _, directive := range gq.Directives() {
		if directive.Name == name {
			return directive
		}
	}
	return nil
}

func (gq *Schema) TypeMap() TypeMap {
	return gq.typeMap
}

func (gq *Schema) Type(name string) Type {
	return gq.TypeMap()[name]
}

func (gq *Schema) PossibleTypes(abstractType Abstract) []*Object {
	switch abstractType := abstractType.(type) {
	case *Union:
		return abstractType.Types()
	case *Interface:
		if impls, ok := gq.implementations[abstractType.Name()]; ok {
			return impls
		}
	}
	return []*Object{}
}
func (gq *Schema) IsPossibleType(abstractType Abstract, possibleType *Object) bool {
	name := abstractType.Name()
	typeMapVal, _ := gq.possibleTypeMap.Load(name)
	typeMap, ok := typeMapVal.(map[string]struct{})

	if !ok {
		possibleTypes := gq.PossibleTypes(abstractType)
		typeMap = make(map[string]struct{}, len(possibleTypes))
		for _, possibleType := range possibleTypes {
			typeMap[possibleType.Name()] = struct{}{}
		}
		gq.possibleTypeMap.Store(name, typeMap)
	}

	_, isPossible := typeMap[possibleType.Name()]
	return isPossible
}
func typeMapReducer(schema *Schema, typeMap TypeMap, objectType Type) (TypeMap, error) {
	var err error
	if objectType == nil || objectType.Name() == "" {
		return typeMap, nil
	}

	switch objectType := objectType.(type) {
	case *List:
		if objectType.OfType != nil {
			return typeMapReducer(schema, typeMap, objectType.OfType)
		}
	case *NonNull:
		if objectType.OfType != nil {
			return typeMapReducer(schema, typeMap, objectType.OfType)
		}
	case *Object:
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
	}

	if mappedObjectType, ok := typeMap[objectType.Name()]; ok {
		if mappedObjectType != objectType {
			return typeMap, gqlerrors.NewFormattedError(fmt.Sprintf(`Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name()))
		}
		return typeMap, nil
	}
	if objectType.Name() == "" {
		return typeMap, nil
	}

	typeMap[objectType.Name()] = objectType

	switch objectType := objectType.(type) {
	case *Union:
		types := schema.PossibleTypes(objectType)
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, innerObjectType := range types {
			if innerObjectType.Error() != nil {
				return typeMap, innerObjectType.Error()
			}
			typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
			if err != nil {
				return typeMap, err
			}
		}
	case *Interface:
		types := schema.PossibleTypes(objectType)
		if objectType.err != nil {
			return typeMap, objectType.err
		}
		for _, innerObjectType := range types {
			if innerObjectType.Error() != nil {
				return typeMap, innerObjectType.Error()
			}
			typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
			if err != nil {
				return typeMap, err
			}
		}
	case *Object:
		interfaces := objectType.Interfaces()
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, innerObjectType := range interfaces {
			if innerObjectType.Error() != nil {
				return typeMap, innerObjectType.Error()
			}
			typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
			if err != nil {
				return typeMap, err
			}
		}
	}

	switch objectType := objectType.(type) {
	case *Object:
		fieldMap := objectType.Fields()
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, field := range fieldMap {
			for _, arg := range field.Args {
				typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
				if err != nil {
					return typeMap, err
				}
			}
			typeMap, err = typeMapReducer(schema, typeMap, field.Type)
			if err != nil {
				return typeMap, err
			}
		}
	case *Interface:
		fieldMap := objectType.Fields()
		if objectType.Error() != nil {
			return typeMap, objectType.Error()
		}
		for _, field := range fieldMap {
			for _, arg := range field.Args {
				typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
				if err != nil {
					return typeMap, err
				}
			}
			typeMap, err = typeMapReducer(schema, typeMap, field.Type)
			if err != nil {
				return typeMap, err
			}
		}
	case *InputObject:
		fieldMap := objectType.Fields()
		if objectType.err != nil {
			return typeMap, objectType.err
		}
		for _, field := range fieldMap {
			typeMap, err = typeMapReducer(schema, typeMap, field.Type)
			if err != nil {
				return typeMap, err
			}
		}
	}
	return typeMap, nil
}

func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Interface) error {
	objectFieldMap := object.Fields()
	ifaceFieldMap := iface.Fields()

	// Assert each interface field is implemented.
	for fieldName := range ifaceFieldMap {
		objectField := objectFieldMap[fieldName]
		ifaceField := ifaceFieldMap[fieldName]

		// Assert interface field exists on object.
		if objectField == nil {
			return gqlerrors.NewFormattedError(fmt.Sprintf(`"%v" expects field "%v" but "%v" does not provide it.`, iface, fieldName, object))
		}

		// Assert interface field type matches object field type.
		if !isTypeSubTypeOf(schema, objectField.Type, ifaceField.Type) {
			return gqlerrors.NewFormattedError(fmt.Sprintf(`%v.%v expects type "%v" but %v.%v provides type "%v".`,
				iface, fieldName, ifaceField.Type,
				object, fieldName, objectField.Type))
		}

		// Assert each interface field arg is implemented.
		for _, ifaceArg := range ifaceField.Args {
			argName := ifaceArg.PrivateName
			var objectArg *Argument
			for _, arg := range objectField.Args {
				if arg.PrivateName == argName {
					objectArg = arg
					break
				}
			}
			// Assert interface field arg exists on object field.
			if objectArg == nil {
				return gqlerrors.NewFormattedError(fmt.Sprintf(`%v.%v expects argument "%v" but %v.%v does not provide it.`,
					iface, fieldName, argName,
					object, fieldName))
			}

			// Assert interface field arg type matches object field arg type.
			if !isEqualType(ifaceArg.Type, objectArg.Type) {
				return gqlerrors.NewFormattedError(fmt.Sprintf(
					`%v.%v(%v:) expects type "%v" `+
						`but %v.%v(%v:) provides `+
						`type "%v".`,
					iface, fieldName, argName, ifaceArg.Type,
					object, fieldName, argName, objectArg.Type))
			}
		}
		// Assert additional arguments must not be required.
		for _, objectArg := range objectField.Args {
			argName := objectArg.PrivateName
			var ifaceArg *Argument
			for _, arg := range ifaceField.Args {
				if arg.PrivateName == argName {
					ifaceArg = arg
					break
				}
			}
			if ifaceArg == nil {
				_, ok := objectArg.Type.(*NonNull)
				if ok {
					return gqlerrors.NewFormattedError(
						fmt.Sprintf(`%v.%v(%v:) is of required type "%v" but is not also provided by the interface %v.%v.`,
							object, fieldName, argName, objectArg.Type, iface, fieldName))
				}
			}
		}
	}
	return nil
}

func isEqualType(typeA, typeB Type) bool {
	// Equivalent type is a valid subtype
	if typeA == typeB {
		return true
	}
	// If either type is non-null, the other must also be non-null.
	if typeA, ok := typeA.(*NonNull); ok {
		if typeB, ok := typeB.(*NonNull); ok {
			return isEqualType(typeA.OfType, typeB.OfType)
		}
	}
	// If either type is a list, the other must also be a list.
	if typeA, ok := typeA.(*List); ok {
		if typeB, ok := typeB.(*List); ok {
			return isEqualType(typeA.OfType, typeB.OfType)
		}
	}
	return typeA == typeB
}

// isTypeSubTypeOf Provided a type and a super type, return true if the first type is either
// equal or a subset of the second super type (covariant).
func isTypeSubTypeOf(schema *Schema, maybeSubType Type, superType Type) bool {
	// Equivalent type is a valid subtype
	if maybeSubType == superType {
		return true
	}

	// If superType is non-null, maybeSubType must also be nullable.
	if superType, ok := superType.(*NonNull); ok {
		if maybeSubType, ok := maybeSubType.(*NonNull); ok {
			return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
		}
		return false
	}
	if maybeSubType, ok := maybeSubType.(*NonNull); ok {
		// If superType is nullable, maybeSubType may be non-null.
		return isTypeSubTypeOf(schema, maybeSubType.OfType, superType)
	}

	// If superType type is a list, maybeSubType type must also be a list.
	if superType, ok := superType.(*List); ok {
		if maybeSubType, ok := maybeSubType.(*List); ok {
			return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
		}
		return false
	} else if _, ok := maybeSubType.(*List); ok {
		// If superType is not a list, maybeSubType must also be not a list.
		return false
	}

	// If superType type is an abstract type, maybeSubType type may be a currently
	// possible object type.
	if superType, ok := superType.(*Interface); ok {
		if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
			return true
		}
	}
	if superType, ok := superType.(*Union); ok {
		if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
			return true
		}
	}

	// Otherwise, the child type is not a valid subtype of the parent type.
	return false
}
<|endoftext|>


<commit_before><commit_msg>support for event type started<commit_after><|endoftext|>


<commit_before>package common

import (
	"errors"
)

type RouterInfo []byte

//
// Read a RouterIdentity from the RouterInfo, returning the
// RouterIdentity and any parsing errors.
//
func (router_info RouterInfo) RouterIdentity() (router_identity RouterIdentity, err error) {
	router_identity, _, err = ReadRouterIdentity(router_info)
	return
}

//
// Return the Date the RouterInfo was published and any errors
// encountered parsing the RouterInfo.
//
func (router_info RouterInfo) Published() (date Date, err error) {
	_, remainder, _ := ReadRouterIdentity(router_info)
	if len(remainder) < 8 {
		err = errors.New("error parsing date: not enough data")
		return
	}
	copy(remainder[:8], date[:])
	return
}

//
// Return the Integer representing the number of RouterAddresses
// are contained in this RouterInfo.
//
func (router_info RouterInfo) RouterAddressCount() (count int, err error) {
	_, remainder, _ := ReadRouterIdentity(router_info)
	if len(remainder) < 9 {
		err = errors.New("error parsing router addresses: not enough data")
		return
	}
	count = Integer([]byte{remainder[8]})
	return
}

//
// Read the RouterAddresses inside this RouterInfo and return
// them in a slice.
//
func (router_info RouterInfo) RouterAddresses() (router_addresses []RouterAddress, err error) {
	_, remainder, _ := ReadRouterIdentity(router_info)
	if len(remainder) < 9 {
		err = errors.New("error parsing router addresses: not enough data")
		return
	}
	remaining := router_info[9:]
	var router_address RouterAddress
	addr_count, cerr := router_info.RouterAddressCount()
	if cerr != nil {
		err = cerr
		return
	}
	for i := 0; i < addr_count; i++ {
		router_address, remaining, err = ReadRouterAddress(remaining)
		if err == nil {
			router_addresses = append(router_addresses, router_address)
		}
	}
	return
}

//
// Return the PeerSize value, currently unused and always zero.
//
func (router_info RouterInfo) PeerSize() int {
	// Peer size is unused:
	// https://geti2p.net/en/docs/spec/common-structures#struct_RouterAddress
	return 0
}

//
// Return the Options Mapping inside this RouterInfo.
//
func (router_info RouterInfo) Options() Mapping {
	head := router_info.optionsLocation()
	size := head + router_info.optionsSize()
	return Mapping(router_info[head:size])
}

//
// Return the 40 bytes that follow the Mapping in the RouterInfo.
//
func (router_info RouterInfo) Signature() Signature {
	head := router_info.optionsLocation()
	size := head + router_info.optionsSize()
	return Signature(router_info[head+size : head+size+40])
}

//
// Used to determine where in the RouterInfo the Mapping
// data begins for parsing.
//
func (router_info RouterInfo) optionsLocation() int {
	offset := 9
	var router_address RouterAddress
	remaining := router_info[9:]
	addr_count, _ := router_info.RouterAddressCount()
	for i := 0; i < addr_count; i++ {
		router_address, remaining, _ = ReadRouterAddress(remaining)
		offset += len(router_address)
	}
	return offset
}

//
// Used to determine the size of the options in the RouterInfo
// for parsing.
//
func (router_info RouterInfo) optionsSize() int {
	head := router_info.optionsLocation()
	return Integer(router_info[head:head+1]) + 1
}
<commit_msg>working on router info<commit_after>package common

/*
I2P RouterInfo
https://geti2p.net/en/docs/spec/common-structures#struct_RouterInfo
Accurate for version 0.9.24

+----+----+----+----+----+----+----+----+
| router_ident                          |
+                                       +
|                                       |
~                                       ~
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+
| published                             |
+----+----+----+----+----+----+----+----+
|size| RouterAddress 0                  |
+----+                                  +
|                                       |
~                                       ~
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+
| RouterAddress 1                       |
+                                       +
|                                       |
~                                       ~
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+
| RouterAddress ($size-1)               |
+                                       +
|                                       |
~                                       ~
~                                       ~
|                                       |
+----+----+----+----+-//-+----+----+----+
|psiz| options                          |
+----+----+----+----+-//-+----+----+----+
| signature                             |
+                                       +
|                                       |
+                                       +
|                                       |
+                                       +
|                                       |
+                                       +
|                                       |
+----+----+----+----+----+----+----+----+

router_ident :: RouterIdentity
                length -> >= 387 bytes

published :: Date
             length -> 8 bytes

size :: Integer
        length -> 1 byte
        The number of RouterAddresses to follow, 0-255

addresses :: [RouterAddress]
             length -> varies

peer_size :: Integer
             length -> 1 byte
             The number of peer Hashes to follow, 0-255, unused, always zero
             value -> 0

options :: Mapping

signature :: Signature
             length -> 40 bytes
*/

import (
	"errors"
	log "github.com/Sirupsen/logrus"
)

type RouterInfo []byte

//
// Read a RouterIdentity from the RouterInfo, returning the RouterIdentity and any errors
// encountered parsing the RouterIdentity.
//
func (router_info RouterInfo) RouterIdentity() (router_identity RouterIdentity, err error) {
	router_identity, _, err = ReadRouterIdentity(router_info)
	return
}

//
// Return the Date the RouterInfo was published and any errors encountered parsing the RouterInfo.
//
func (router_info RouterInfo) Published() (date Date, err error) {
	_, remainder, _ := ReadRouterIdentity(router_info)
	remainder_len := len(remainder)
	if remainder_len < 8 {
		log.WithFields(log.Fields{
			"data_len":     remainder_len,
			"required_len": 8,
			"reason":       "not enough data",
		}).Error("error parsing router info")
		err = errors.New("error parsing date: not enough data")
		return
	}
	copy(remainder[:8], date[:])
	return
}

//
// Return the Integer representing the number of RouterAddresses that are contained in this RouterInfo.
//
func (router_info RouterInfo) RouterAddressCount() (count int, err error) {
	_, remainder, _ := ReadRouterIdentity(router_info)
	remainder_len := len(remainder)
	if remainder_len < 9 {
		log.WithFields(log.Fields{
			"data_len":     remainder_len,
			"required_len": 9,
			"reason":       "not enough data",
		}).Error("error parsing router info")
		err = errors.New("error parsing router addresses: not enough data")
		return
	}
	count = Integer([]byte{remainder[8]})
	return
}

//
// Read the RouterAddresses inside this RouterInfo and return them in a slice, returning
// a partial list if data is missing.
//
func (router_info RouterInfo) RouterAddresses() (router_addresses []RouterAddress, err error) {
	_, remainder, _ := ReadRouterIdentity(router_info)
	remainder_len := len(remainder)
	if remainder_len < 9 {
		log.WithFields(log.Fields{
			"data_len":     remainder_len,
			"required_len": 9,
			"reason":       "not enough data",
		}).Error("error parsing router info")
		err = errors.New("error parsing router addresses: not enough data")
		return
	}
	remaining := router_info[9:]
	var router_address RouterAddress
	addr_count, cerr := router_info.RouterAddressCount()
	if cerr != nil {
		err = cerr
		return
	}
	for i := 0; i < addr_count; i++ {
		router_address, remaining, err = ReadRouterAddress(remaining)
		if err == nil {
			router_addresses = append(router_addresses, router_address)
		}
	}
	return
}

//
// Return the PeerSize value, currently unused and always zero.
//
func (router_info RouterInfo) PeerSize() int {
	// Peer size is unused:
	// https://geti2p.net/en/docs/spec/common-structures#struct_RouterAddress
	return 0
}

//
// Return the Options Mapping inside this RouterInfo.
//
func (router_info RouterInfo) Options() (mapping Mapping) {
	head := router_info.optionsLocation()
	size := head + router_info.optionsSize()
	mapping = Mapping(router_info[head:size])
	return
}

//
// Return the 40 bytes that follow the Mapping in the RouterInfo.
//
func (router_info RouterInfo) Signature() (signature Signature) {
	head := router_info.optionsLocation()
	size := head + router_info.optionsSize()
	signature = Signature(router_info[head+size : head+size+40])
	return
}

//
// Used during parsing to determine where in the RouterInfo the Mapping data begins.
//
func (router_info RouterInfo) optionsLocation() (location int) {
	location = 9
	var router_address RouterAddress
	remaining := router_info[9:]
	addr_count, _ := router_info.RouterAddressCount()
	for i := 0; i < addr_count; i++ {
		router_address, remaining, _ = ReadRouterAddress(remaining)
		location += len(router_address)
	}
	return
}

//
// Used during parsing to determine the size of the options in the RouterInfo.
//
func (router_info RouterInfo) optionsSize() (size int) {
	head := router_info.optionsLocation()
	size = Integer(router_info[head:head+1]) + 1
	return
}
<|endoftext|>