<|start_filename|>gateway/websocket.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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.

*/

// deprecate
package gateway

import (
	"fmt"
	"github.com/Loopring/relay-cluster/accountmanager"
	"github.com/Loopring/relay-cluster/market"
	"github.com/Loopring/relay-lib/log"
	"github.com/Loopring/relay-lib/marketcap"
	"github.com/gorilla/websocket"
	"net/http"
)

type WebsocketService interface {
	Start(port string)
	Stop()
}

type WebsocketOptions struct {
	Port string
}

type WebsocketServiceImpl struct {
	port     string
	upgrader websocket.Upgrader
}

type WebsocketRequest map[string]string

// this code is not stable
func NewWebsocketService(port string, trendManager market.TrendManager, accountManager accountmanager.AccountManager, capProvider marketcap.MarketCapProvider) *WebsocketServiceImpl {
	l := &WebsocketServiceImpl{}
	l.port = port
	l.upgrader = websocket.Upgrader{
		CheckOrigin:     func(r *http.Request) bool { return true },
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}
	return l
}

func (ws *WebsocketServiceImpl) Start() {

	node := newSocketNode()
	go node.run()
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		ws.serve(node, w, r)
	})

	err := http.ListenAndServe(":"+ws.port, nil)
	if err != nil {
		log.Fatal("ListenAndServe Websocket Error : " + err.Error())
	}

	return
}

func (ws *WebsocketServiceImpl) serve(node *SocketNode, w http.ResponseWriter, r *http.Request) {
	conn, err := ws.upgrader.Upgrade(w, r, nil)
	fmt.Print(conn.LocalAddr())
	if err != nil {
		log.Error("get ws connection error , " + err.Error())
		return
	}
	client := &SocketClient{node: node, conn: conn}
	client.node.register <- client
	go client.write()
	go client.read()
}


<|start_filename|>accountmanager/manager_test.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 accountmanager_test

import (
	"encoding/json"
	"github.com/Loopring/relay-cluster/accountmanager"
	"github.com/Loopring/relay-lib/cache"
	"github.com/Loopring/relay-lib/cache/redis"
	"github.com/Loopring/relay-lib/eth/accessor"
	"github.com/Loopring/relay-lib/eth/loopringaccessor"
	"github.com/Loopring/relay-lib/log"
	"github.com/Loopring/relay-lib/marketutil"
	"github.com/Loopring/relay-lib/zklock"
	"github.com/ethereum/go-ethereum/common"
	"go.uber.org/zap"
	"testing"
)

func init() {
	logConfig := `{
	  "level": "debug",
	  "development": false,
	  "encoding": "json",
	  "outputPaths": ["stdout"],
	  "errorOutputPaths": ["stderr"],
	  "encoderConfig": {
	    "messageKey": "message",
	    "levelKey": "level",
	    "levelEncoder": "lowercase"
	  }
	}`
	rawJSON := []byte(logConfig)

	var (
		cfg zap.Config
		err error
	)
	if err = json.Unmarshal(rawJSON, &cfg); err != nil {
		panic(err)
	}
	log.Initialize(cfg)
	cache.NewCache(redis.RedisOptions{Host: "127.0.0.1", Port: "6379"})

	accessor.Initialize(accessor.AccessorOptions{RawUrls: []string{"http://13.230.23.98:8545"}})

	options := loopringaccessor.LoopringProtocolOptions{}
	options.Address = make(map[string]string)
	options.Address["1.5"] = "0x8d8812b72d1e4ffCeC158D25f56748b7d67c1e78"
	loopringaccessor.InitLoopringAccessor(options)

	utiloptions := marketutil.MarketOptions{}
	utiloptions.TokenFile = "/Users/yuhongyu/Desktop/service/go/src/github.com/Loopring/relay-cluster/config/tokens.json"
	marketutil.Initialize(&utiloptions)

	zklock.Initialize(zklock.ZkLockConfig{ZkServers: "127.0.0.1:2181", ConnectTimeOut: 10000})
	acctOptions := &accountmanager.AccountManagerOptions{}
	//options.CacheDuration =
	accountmanager.Initialize(acctOptions, "127.0.0.1:9092")

}

func TestAccountManager_GetBalance(t *testing.T) {

	balances, err := accountmanager.GetBalanceWithSymbolResult(common.HexToAddress("0x634211e61Ac19baF71153d193b3482d12d669c5C"))
	if nil != err {
		t.Fatalf("err:%s", err.Error())
	}
	for k, v := range balances {
		t.Logf("token:%s, balance:%s", k, v.String())
	}
}

func TestAccountManager_UnlockedWallet(t *testing.T) {
	//owner := common.HexToAddress("0x750ad4351bb728cec7d639a9511f9d6488f1e259")
	//data := append(append(owner.Bytes(), owner.Bytes()...), owner.Bytes()...)
	//t.Log(common.BytesToAddress(data[0:20]).Hex(), common.BytesToAddress(data[20:40]).Hex(), common.BytesToAddress(data[40:]).Hex())
	//accManager := test.GenerateAccountManager()
	//
	//if err := accManager.UnlockedWallet("0x750ad4351bb728cec7d639a9511f9d6488f1e259"); nil != err {
	//	t.Errorf("err:%s", err.Error())
	//} else {
	//	t.Log("##ooooo")
	//}
	//balances,err := accManager.GetBalanceWithSymbolResult(common.HexToAddress("0x750ad4351bb728cec7d639a9511f9d6488f1e259"))
	//if nil != err {
	//	t.Fatalf("err:%s", err.Error())
	//}
	//for k,v := range balances {
	//	t.Logf("token:%s, balance:%s", k, v.Balance.String())
	//}
}
func TestAccountManager_GetBAndAllowance(t *testing.T) {
	balance, allowance, err := accountmanager.GetBalanceAndAllowance(common.HexToAddress("0x750ad4351bb728cec7d639a9511f9d6488f1e259"), common.HexToAddress("0x"), common.HexToAddress("0x"))
	if nil != err {
		t.Fatalf("err:%s", err.Error())
	}
	t.Logf("balance:%s, allowance:%s", balance.String(), allowance.String())
}

func TestAccountManager_GetAllowances(t *testing.T) {
	spender := common.HexToAddress("0x17233e07c67d086464fD408148c3ABB56245FA64")
	allowances, err := accountmanager.GetAllowanceWithSymbolResult(common.HexToAddress("0x634211e61Ac19baF71153d193b3482d12d669c5C"), spender)
	if nil != err {
		t.Fatalf("err:%s", err.Error())
	}
	for k, v := range allowances {
		t.Logf("token:%s, spener:%s, allowance:%s", k, spender.Hex(), v.String())
	}

}


<|start_filename|>vendor/github.com/Loopring/relay-lib/cache/redis/cluster.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 redis

import (
	"fmt"
	"github.com/Loopring/relay-lib/log"
	"github.com/chasex/redis-go-cluster"
)

type ClusterOptions struct {
	StartNodes   []string
	ConnTimeout  int
	ReadTimeout  int
	WriteTimeout int
	KeepAlive    int
	AliveTime    int
}

type ClusterCacheImpl struct {
	options redis.Options
	cluster *redis.Cluster
}

func (impl *ClusterCacheImpl) Initialize(cfg interface{}) {
	options := cfg.(redis.Options)
	impl.options = options

	cluster, err := redis.NewCluster(&impl.options)

	if err != nil {
		log.Fatal(err.Error())
	}

	impl.cluster = cluster
}

func (impl *ClusterCacheImpl) Get(key string) ([]byte, error) {

	//log.Info("[REDIS-Get] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	reply, err := cluster.Do("get", key)

	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return []byte{}, err
	} else if nil == reply {
		if nil == err {
			err = fmt.Errorf("no this key:%s", key)
		}
		return []byte{}, err
	} else {
		return reply.([]byte), err
	}
}

func (impl *ClusterCacheImpl) Exists(key string) (bool, error) {

	//log.Info("[REDIS-Exists] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	reply, err := cluster.Do("exists", key)

	if err != nil {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return false, err
	} else {
		exists := reply.(int64)
		if exists == 1 {
			return true, nil
		} else {
			return false, nil
		}
	}
}

func (impl *ClusterCacheImpl) Set(key string, value []byte, ttl int64) error {

	//log.Info("[REDIS-Set] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	if _, err := cluster.Do("set", key, value); err != nil {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return err
	}

	if ttl > 0 {
		if _, err := cluster.Do("expire", key, ttl); err != nil {
			log.Errorf(" key:%s, err:%s", key, err.Error())
			return err
		}
	}
	return nil
}

func (impl *ClusterCacheImpl) Del(key string) error {

	//log.Info("[REDIS-Del] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	_, err := cluster.Do("del", key)
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	}
	return err
}

func (impl *ClusterCacheImpl) Dels(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("redis dels args empty")
	}

	//log.Info("[REDIS-Dels]")

	cluster := impl.cluster
	defer cluster.Close()

	var list []interface{}

	for _, v := range args {
		list = append(list, v)
	}

	num, err := cluster.Do("del", list...)
	if err != nil {
		log.Debugf("delete multi keys error:%s", err.Error())
	} else {
		log.Debugf("delete %d keys", num.(int64))
	}

	return nil
}

func (impl *ClusterCacheImpl) Keys(keyFormat string) ([][]byte, error) {

	//log.Info("[REDIS-Keys]")

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, keyFormat)
	reply, err := cluster.Do("keys", vs...)
	res := [][]byte{}
	if nil != err {
		log.Errorf(" key:%s, err:%s", keyFormat, err.Error())
	} else if nil == err && nil != reply {
		rs := reply.([]interface{})
		for _, r := range rs {
			if nil == r {
				res = append(res, []byte{})
			} else {
				res = append(res, r.([]byte))
			}
		}
	}
	return res, err
}

func (impl *ClusterCacheImpl) HMSet(key string, ttl int64, args ...[]byte) error {
	if len(args) == 0 {
		return fmt.Errorf("redis hmset args empty")
	}
	//log.Info("[REDIS-ZAdd] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	if len(args)%2 != 0 {
		return fmt.Errorf("the length of `args` must be even")
	}

	vs := []interface{}{}
	vs = append(vs, key)
	for _, v := range args {
		vs = append(vs, v)
	}
	_, err := cluster.Do("hmset", vs...)
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	}
	if ttl > 0 {
		if _, err := cluster.Do("expire", key, ttl); err != nil {
			log.Errorf(" key:%s, err:%s", key, err.Error())
			return err
		}
	}
	return err
}

func (impl *ClusterCacheImpl) ZAdd(key string, ttl int64, args ...[]byte) error {
	if len(args) == 0 {
		return fmt.Errorf("redis zadd args empty")
	}
	//log.Info("[REDIS-ZAdd] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	if len(args)%2 != 0 {
		return fmt.Errorf("the length of `args` must be even")
	}
	vs := []interface{}{}
	vs = append(vs, key)
	for _, v := range args {
		vs = append(vs, v)
	}
	_, err := cluster.Do("zadd", vs...)
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	}
	if ttl > 0 {
		if _, err := cluster.Do("expire", key, ttl); err != nil {
			log.Errorf(" key:%s, err:%s", key, err.Error())
			return err
		}
	}
	return err
}

func (impl *ClusterCacheImpl) HMGet(key string, fields ...[]byte) ([][]byte, error) {
	if len(fields) == 0 {
		return [][]byte{}, fmt.Errorf("redis hmget fields empty")
	}
	//log.Info("[REDIS-HMGet] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key)
	for _, v := range fields {
		vs = append(vs, v)
	}
	reply, err := cluster.Do("hmget", vs...)

	res := [][]byte{}
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	} else if nil == err && nil != reply {
		rs := reply.([]interface{})
		for _, r := range rs {
			if nil == r {
				res = append(res, []byte{})
			} else {
				res = append(res, r.([]byte))
			}
		}
	}
	return res, err
}

func (impl *ClusterCacheImpl) ZRange(key string, start, stop int64, withScores bool) ([][]byte, error) {

	//log.Info("[REDIS-ZRange] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key, start, stop)
	if withScores {
		vs = append(vs, []byte("WITHSCORES"))
	}
	reply, err := cluster.Do("ZRANGE", vs...)

	res := [][]byte{}
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	} else if nil == err && nil != reply {
		rs := reply.([]interface{})
		for _, r := range rs {
			if nil == r {
				res = append(res, []byte{})
			} else {
				res = append(res, r.([]byte))
			}
		}
	}
	return res, err
}

func (impl *ClusterCacheImpl) HDel(key string, fields ...[]byte) (int64, error) {
	if len(fields) == 0 {
		return 0, fmt.Errorf("redis hdel fields empty")
	}
	//log.Info("[REDIS-HDel] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key)
	for _, v := range fields {
		vs = append(vs, v)
	}
	reply, err := cluster.Do("hdel", vs...)

	if err != nil {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return 0, err
	} else {
		res := reply.(int64)
		return res, err
	}
}
func (impl *ClusterCacheImpl) SCard(key string) (int64, error) {

	//log.Info("[REDIS-SCARD] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key)
	reply, err := cluster.Do("scard", vs...)

	if err != nil {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return 0, err
	} else {
		res := reply.(int64)
		return res, err
	}
}

func (impl *ClusterCacheImpl) ZRemRangeByScore(key string, start, stop int64) (int64, error) {

	//log.Info("[REDIS-ZRemRangeByScore] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key, start, stop)

	reply, err := cluster.Do("ZREMRANGEBYSCORE", vs...)

	if err != nil {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return 0, err
	} else {
		res := reply.(int64)
		return res, err
	}
}

func (impl *ClusterCacheImpl) SRem(key string, members ...[]byte) (int64, error) {
	if len(members) == 0 {
		return 0, fmt.Errorf("redis srem members empty")
	}
	//log.Info("[REDIS-SRem] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key)
	for _, v := range members {
		vs = append(vs, v)
	}
	reply, err := cluster.Do("srem", vs...)

	if err != nil {
		log.Errorf(" key:%s, err:%s", key, err.Error())
		return 0, err
	} else {
		res := reply.(int64)
		return res, err
	}
}

func (impl *ClusterCacheImpl) SIsMember(key string, member []byte) (bool, error) {

	//log.Info("[REDIS-SIsMember] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	reply, err := cluster.Do("sismember", key, member)
	if err != nil {
		log.Errorf("key:%s, err:%s", key, err.Error())
		return false, err
	} else {
		return reply.(int64) > 0, nil
	}
}

func (impl *ClusterCacheImpl) HGetAll(key string) ([][]byte, error) {

	//log.Info("[REDIS-HGetAll] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	reply, err := cluster.Do("hgetall", key)

	res := [][]byte{}
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	} else if nil == err && nil != reply {
		rs := reply.([]interface{})
		for _, r := range rs {
			res = append(res, r.([]byte))
		}
	}
	return res, err
}
func (impl *ClusterCacheImpl) HVals(key string) ([][]byte, error) {

	//log.Info("[REDIS-HVals] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	//todo:test nil result
	reply, err := cluster.Do("hvals", key)

	res := [][]byte{}
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	} else if nil == err && nil != reply {
		rs := reply.([]interface{})
		for _, r := range rs {
			res = append(res, r.([]byte))
		}
	}
	return res, err
}

func (impl *ClusterCacheImpl) HExists(key string, field []byte) (bool, error) {

	//log.Info("[REDIS-HExists] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	reply, err := cluster.Do("hexists", key, field)
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	} else if nil == err && nil != reply {
		exists := reply.(int64)
		return exists > 0, nil
	}

	return false, err
}

func (impl *ClusterCacheImpl) SAdd(key string, ttl int64, members ...[]byte) error {
	if len(members) == 0 {
		return fmt.Errorf("redis sadd members empty")
	}
	//log.Info("[REDIS-SAdd] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	vs := []interface{}{}
	vs = append(vs, key)
	for _, v := range members {
		vs = append(vs, v)
	}
	_, err := cluster.Do("sadd", vs...)
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	}
	if ttl > 0 {
		if _, err := cluster.Do("expire", key, ttl); err != nil {
			log.Errorf(" key:%s, err:%s", key, err.Error())
			return err
		}
	}
	return err
}

func (impl *ClusterCacheImpl) SMembers(key string) ([][]byte, error) {

	//log.Info("[REDIS-SMembers] key : " + key)

	cluster := impl.cluster
	defer cluster.Close()

	reply, err := cluster.Do("smembers", key)

	res := [][]byte{}
	if nil != err {
		log.Errorf(" key:%s, err:%s", key, err.Error())
	} else if nil == err && nil != reply {
		rs := reply.([]interface{})
		for _, r := range rs {
			res = append(res, r.([]byte))
		}
	}
	return res, err
}


<|start_filename|>vendor/github.com/Loopring/motan-go/provider/cgi.go<|end_filename|>
package provider

// CGI RFC: https://datatracker.ietf.org/doc/rfc3875/?include_text=1

import (
	"errors"
	"fmt"
	cgi "github.com/beberlei/fastcgi-serve/fcgiclient"
	motan "github.com/Loopring/motan-go/core"
	"github.com/Loopring/motan-go/log"
	"strconv"
	"strings"
	"time"
	// "github.com/yangchenxing/go-nginx-conf-parser"
)

const (
	CGIKeyPrefix   = "CGI_"
	DefaultCGIHost = "127.0.0.1"
	DefaultCGIPort = 9000
	HTTPMethodPOST = "POST"
	HTTPMethodGET  = "GET"
)

var serverEnvironment = map[string]string{"SERVER_SOFTWARE": "Motan / CGI"}
var NeededCGIEnv = []string{"REQUEST_METHOD", "SCRIPT_FILENAME", "DOCUMENT_ROOT"}

type CgiProvider struct {
	url *motan.URL
}

func (c *CgiProvider) Initialize() {
}

func (c *CgiProvider) Destroy() {
}

func (c *CgiProvider) SetSerialization(s motan.Serialization) {}

func (c *CgiProvider) SetProxy(proxy bool) {}

func (c *CgiProvider) Call(request motan.Request) motan.Response {
	defer func() {
		// @TODO if cgi server die, should let server node unavailable
		if err := recover(); err != nil {
			vlog.Errorln("cgi provider call error! ", err)
		}
	}()
	t := time.Now().UnixNano()
	resp := &motan.MotanResponse{Attachment: make(map[string]string)}
	toType := make([]interface{}, 1)
	if err := request.ProcessDeserializable(toType); err != nil {
		fillException(resp, t, err)
		return resp
	}
	env := make(map[string]string)
	reqParams := ""

	for name, value := range serverEnvironment {
		env[name] = value
	}
	cgiKey := ""
	for _, key := range NeededCGIEnv {
		cgiKey = CGIKeyPrefix + key
		if info, ok := c.url.Parameters[cgiKey]; ok {
			env[key] = info
		} else {
			vlog.Infof("NeededCGIEnv %s is not exist\n", cgiKey)
		}
	}

	for k, v := range request.GetAttachments() {
		env["MOTAN_"+k] = v
	}

	if env["REQUEST_METHOD"] == HTTPMethodGET {
		if queryStr, err := buildQueryStr(request, c.url, nil); err == nil {
			env["QUERY_STRING"] = queryStr
		}
	} else if env["REQUEST_METHOD"] == HTTPMethodPOST {
		if getReqParams, err := buildQueryStr(request, c.url, nil); err == nil {
			reqParams = getReqParams
		}
		env["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
		env["CONTENT_LENGTH"] = strconv.Itoa(len(reqParams))
	}

	cgiHost := DefaultCGIHost
	cgiPort := DefaultCGIPort
	if host, ok := c.url.Parameters["CGI_HOST"]; ok {
		cgiHost = host
	}
	if portStr, ok := c.url.Parameters["CGI_PORT"]; ok {
		cgiPort, _ = strconv.Atoi(portStr)
	}
	ccgi, err := cgi.New(cgiHost, cgiPort)
	if err != nil {
		vlog.Errorf("new CGI err: %v", err)
		fillException(resp, t, err)
		return resp
	}
	content, _, err := ccgi.Request(env, reqParams)
	if err != nil {
		vlog.Errorf("CGI Call error: %+v\n", err)
		fillException(resp, t, err)
		return resp
	}

	statusCode, headers, body, err := ParseFastCgiResponse(string(content))
	resp.RequestID = request.GetRequestID()
	resp.ProcessTime = int64((time.Now().UnixNano() - t) / 1000000)
	if err != nil {
		//@TODO ErrTYpe
		resp.Exception = &motan.Exception{ErrCode: statusCode, ErrMsg: fmt.Sprintf("%s", err), ErrType: statusCode}
		return resp
	}
	for k, v := range headers {
		resp.SetAttachment(k, v)
	}
	// resp.Value, _ = MarshalX(body)
	resp.Value = body
	return resp
}

func ParseFastCgiResponse(content string) (int, map[string]string, string, error) {
	var headers map[string]string

	parts := strings.SplitN(content, "\r\n\r\n", 2)

	if len(parts) < 2 {
		return 502, headers, "", errors.New("Cannot parse FastCGI Response")
	}

	headerParts := strings.Split(parts[0], "\r\n")
	headers = make(map[string]string, len(headerParts))
	body := parts[1]
	status := 200

	if strings.HasPrefix(headerParts[0], "Status:") {
		lineParts := strings.SplitN(headerParts[0], " ", 3)
		status, _ = strconv.Atoi(lineParts[1])
	}

	for _, line := range headerParts {
		lineParts := strings.SplitN(line, ":", 2)

		if len(lineParts) < 2 {
			continue
		}

		lineParts[1] = strings.TrimSpace(lineParts[1])

		if lineParts[0] == "Status" {
			continue
		}

		headers[lineParts[0]] = lineParts[1]
	}

	return status, headers, body, nil
}

func (c *CgiProvider) GetName() string {
	return "CgiProvider"
}

func (c *CgiProvider) GetURL() *motan.URL {
	return c.url
}

func (c *CgiProvider) SetURL(url *motan.URL) {
	c.url = url
}

func (c *CgiProvider) IsAvailable() bool {
	//TODO Provider 是否可用
	return true
}

func (c *CgiProvider) SetService(s interface{}) {
}

func (c *CgiProvider) GetPath() string {
	return c.url.Path
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/dao/interface.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 dao

import "fmt"

type RdsService interface {
	// create tables
	SetTables(tables []interface{})
	CreateTables() error

	// base functions
	Add(item interface{}) error
	Del(item interface{}) error
	First(item interface{}) error
	Last(item interface{}) error
	Save(item interface{}) error
	FindAll(item interface{}) error
}

// add single item
func (s *RdsServiceImpl) Add(item interface{}) error {
	return s.Db.Create(item).Error
}

// del single item
func (s *RdsServiceImpl) Del(item interface{}) error {
	return s.Db.Delete(item).Error
}

// select first item order by primary key asc
func (s *RdsServiceImpl) First(item interface{}) error {
	return s.Db.First(item).Error
}

// select the last item order by primary key asc
func (s *RdsServiceImpl) Last(item interface{}) error {
	return s.Db.Last(item).Error
}

// update single item
func (s *RdsServiceImpl) Save(item interface{}) error {
	return s.Db.Save(item).Error
}

// find all items in table where primary key > 0
func (s *RdsServiceImpl) FindAll(item interface{}) error {
	return s.Db.Table("lpr_orders").Find(item, s.Db.Where("id > ", 0)).Error
}

func (s *RdsServiceImpl) SetTables(tables []interface{}) {
	s.tables = tables
}

func (s *RdsServiceImpl) CreateTables() error {
	for _, t := range s.tables {
		if ok := s.Db.HasTable(t); !ok {
			if err := s.Db.CreateTable(t).Error; err != nil {
				return fmt.Errorf("create mysql table error:%s", err.Error())
			}
		}
	}

	// auto migrate to keep schema update to date
	// AutoMigrate will ONLY create tables, missing columns and missing indexes,
	// and WON'T change existing column's type or delete unused columns to protect your data
	return s.Db.AutoMigrate(s.tables...).Error
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/kafka/consumer_register.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 kafka

import (
	"encoding/json"
	"fmt"
	"github.com/Loopring/relay-lib/log"
	"github.com/bsm/sarama-cluster"
	"reflect"
	"sync"
)

type ConsumerRegister struct {
	brokers     []string
	conf        *cluster.Config
	consumerMap map[string]map[string]*cluster.Consumer
	mutex       sync.Mutex
}

type HandlerFunc func(event interface{}) error

func (cr *ConsumerRegister) Initialize(brokerList []string) {
	config := cluster.NewConfig()
	config.Consumer.Return.Errors = true
	config.Group.Return.Notifications = true
	cr.conf = config
	cr.brokers = brokerList
	cr.consumerMap = make(map[string]map[string]*cluster.Consumer) //map[topic][groupId]
	cr.mutex = sync.Mutex{}
}

func (cr *ConsumerRegister) RegisterTopicAndHandler(topic string, groupId string, data interface{}, action HandlerFunc) error {
	cr.mutex.Lock()
	groupConsumerMap, ok := cr.consumerMap[topic]
	if ok {
		_, ok1 := groupConsumerMap[groupId]
		if ok1 {
			cr.mutex.Unlock()
			return fmt.Errorf("kafka consumer alreay registered for [%s, %s]!!\n", topic, groupId)
		}
	} else {
		cr.consumerMap[topic] = make(map[string]*cluster.Consumer)
	}
	consumer, err := cluster.NewConsumer(cr.brokers, groupId, []string{topic}, cr.conf)
	if err != nil {
		cr.mutex.Unlock()
		return err
	}
	cr.consumerMap[topic][groupId] = consumer
	log.Infof("Register kafka consumer success for [%s, %s]\n", topic, groupId)
	cr.mutex.Unlock()

	go func() {
		for err := range consumer.Errors() {
			log.Errorf("kafka consumer error [%s, %s]: %s\n", topic, groupId, err.Error())
		}
	}()

	// consume notifications
	go func() {
		for ntf := range consumer.Notifications() {
			log.Infof("Notification for [%s, %s] : %+v\n", topic, groupId, ntf)
		}
	}()

	go func() {
		for {
			select {
			case msg, ok := <-consumer.Messages():
				if ok {
					data := (reflect.New(reflect.TypeOf(data))).Interface()
					err := json.Unmarshal(msg.Value, data)
					if err != nil {
						log.Errorf("Kafka consumer for [%s, %s] failed Unmarshal data for data type : %s\n", topic, groupId, reflect.TypeOf(data).Name())
					} else {
						err := action(data)
						if err != nil {
							log.Errorf("Kafka consumer for [%s, %s], message handler execute failed : %s\n", topic, groupId, err.Error())
						}
					}
					consumer.MarkOffset(msg, "") // mark message as processed
				} else {
					log.Errorf("Kafka consumer for [%s, %s] receive message failed\n", topic, groupId)
				}
			}
		}
	}()

	return nil
}

func (cr *ConsumerRegister) Close() {
	for _, mp := range cr.consumerMap {
		for _, cm := range mp {
			cm.Close()
		}
	}
}


<|start_filename|>vendor/github.com/Loopring/motan-go/lb/roundrobinLb.go<|end_filename|>
package lb

import (
	motan "github.com/Loopring/motan-go/core"
	"sync/atomic"
)

type RoundrobinLB struct {
	url       *motan.URL
	endpoints []motan.EndPoint
	index     uint32
	weight    string
}

func (r *RoundrobinLB) OnRefresh(endpoints []motan.EndPoint) {
	r.endpoints = endpoints
}

func (r *RoundrobinLB) Select(request motan.Request) motan.EndPoint {
	eps := r.endpoints
	_, endpoint := r.roundrobinSelect(eps)
	return endpoint
}

func (r *RoundrobinLB) SelectArray(request motan.Request) []motan.EndPoint {
	eps := r.endpoints
	index, endpoint := r.roundrobinSelect(eps)
	if endpoint == nil {
		return nil
	}
	return SelectArrayFromIndex(eps, index)
}

func (r *RoundrobinLB) SetWeight(weight string) {
	r.weight = weight
}

func (r *RoundrobinLB) roundrobinSelect(eps []motan.EndPoint) (int, motan.EndPoint) {
	epsLen := len(eps)
	if epsLen == 0 {
		return -1, nil
	}
	nextIndex := atomic.AddUint32(&r.index, 1)
	if index := nextIndex % uint32(epsLen); eps[index].IsAvailable() {
		return int(index), eps[index]
	}
	return SelectOneAtRandom(eps)
}


<|start_filename|>vendor/github.com/Loopring/motan-go/serialize/gobserializer.go<|end_filename|>
package serialize

import (
	"bytes"
	"encoding/gob"
	"fmt"
)

type GobSerialization struct {
}

func (s *GobSerialization) GetSerialNum() int {
	return 8
}

func (s *GobSerialization) Serialize(v interface{}) ([]byte, error) {
	buf := bytes.NewBuffer(make([]byte, 0, 100))
	if v == nil {
		buf.WriteByte(0)
		return buf.Bytes(), nil
	}
	var coderBuf bytes.Buffer
	enc := gob.NewEncoder(&coderBuf)
	err := enc.Encode(v)
	if err != nil {
		return nil, err
	} else {
		return coderBuf.Bytes(), nil
	}
}

func (s *GobSerialization) DeSerialize(b []byte, v interface{}) (interface{}, error) {
	if len(b) == 0 {
		return nil, nil
	}
	var coderBuf bytes.Buffer
	coderBuf.Write(b)
	dec := gob.NewDecoder(&coderBuf)
	err := dec.Decode(v)
	if err != nil {
		return nil, err
	} else {
		return v, nil
	}
}

func (s *GobSerialization) SerializeMulti(v []interface{}) ([]byte, error) {
	if len(v) != 1 {
		return nil, fmt.Errorf("Not support SerializeMulti")
	}
	return s.Serialize(v[0])
}

func (s *GobSerialization) DeSerializeMulti(b []byte, v []interface{}) (ret []interface{}, err error) {
	if len(v) != 1 {
		return nil, fmt.Errorf("Not support DeSerializeMulti")
	}
	if res, err := s.DeSerialize(b, v[0]); err == nil {
		return []interface{}{res}, nil
	} else {
		return nil, fmt.Errorf("Failed DeSerializeMulti for ", err)
	}
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/event.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import (
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

type TxStatus uint8

const (
	TX_STATUS_UNKNOWN TxStatus = 0
	TX_STATUS_PENDING TxStatus = 1
	TX_STATUS_SUCCESS TxStatus = 2
	TX_STATUS_FAILED  TxStatus = 3
)

func StatusStr(status TxStatus) string {
	var ret string
	switch status {
	case TX_STATUS_PENDING:
		ret = "pending"
	case TX_STATUS_SUCCESS:
		ret = "success"
	case TX_STATUS_FAILED:
		ret = "failed"
	default:
		ret = "unknown"
	}

	return ret
}

func StrToTxStatus(txType string) TxStatus {
	var ret TxStatus
	switch txType {
	case "pending":
		ret = TX_STATUS_PENDING
	case "success":
		ret = TX_STATUS_SUCCESS
	case "failed":
		ret = TX_STATUS_FAILED
	default:
		ret = TX_STATUS_UNKNOWN
	}

	return ret
}

type TxInfo struct {
	Protocol        common.Address `json:"protocol"`
	DelegateAddress common.Address `json:"delegate"`
	From            common.Address `json:"from"`
	To              common.Address `json:"to"`
	BlockHash       common.Hash    `json:"block_hash"`
	BlockNumber     *big.Int       `json:"block_number"`
	BlockTime       int64          `json:"block_time"`
	TxHash          common.Hash    `json:"tx_hash"`
	TxIndex         int64          `json:"tx_index"`
	TxLogIndex      int64          `json:"tx_log_index"`
	Value           *big.Int       `json:"value"`
	Status          TxStatus       `json:"status"`
	GasLimit        *big.Int       `json:"gas_limit"`
	GasUsed         *big.Int       `json:"gas_used"`
	GasPrice        *big.Int       `json:"gas_price"`
	Nonce           *big.Int       `json:"nonce"`
	Identify        string         `json:"identify"`
}

type TokenRegisterEvent struct {
	TxInfo
	Token  common.Address `json:"token"`
	Symbol string         `json:"symbol"`
}

type TokenUnRegisterEvent struct {
	TxInfo
	Token  common.Address `json:"token"`
	Symbol string         `json:"symbol"`
}

type AddressAuthorizedEvent struct {
	TxInfo
	Protocol common.Address `json:"protocol"`
	Number   int            `json:"number"`
}

type AddressDeAuthorizedEvent struct {
	TxInfo
	Protocol common.Address `json:"protocol"`
	Number   int            `json:"number"`
}

type TransferEvent struct {
	TxInfo
	Sender   common.Address `json:"sender"`
	Receiver common.Address `json:"receiver"`
	Amount   *big.Int       `json:"amount"`
}

type ApprovalEvent struct {
	TxInfo
	Owner   common.Address `json:"owner"`
	Spender common.Address `json:"spender"`
	Amount  *big.Int       `json:"amount"`
}

type OrderFilledEvent struct {
	TxInfo
	Ringhash      common.Hash    `json:"ringhash"`
	PreOrderHash  common.Hash    `json:"pre_order_hash"`
	OrderHash     common.Hash    `json:"order_hash"`
	NextOrderHash common.Hash    `json:"next_order_hash"`
	Owner         common.Address `json:"owner"`
	TokenS        common.Address `json:"token_s"`
	TokenB        common.Address `json:"token_b"`
	SellTo        common.Address `json:"sell_to"`
	BuyFrom       common.Address `json:"buy_from"`
	RingIndex     *big.Int       `json:"ring_index"`
	AmountS       *big.Int       `json:"amount_s"`
	AmountB       *big.Int       `json:"amount_b"`
	LrcReward     *big.Int       `json:"lrc_reward"`
	LrcFee        *big.Int       `json:"lrc_fee"`
	SplitS        *big.Int       `json:"split_s"`
	SplitB        *big.Int       `json:"split_b"`
	Market        string         `json:"market"`
	FillIndex     *big.Int       `json:"fill_index"`
}

type OrderCancelledEvent struct {
	TxInfo
	OrderHash       common.Hash `json:"order_hash"`
	AmountCancelled *big.Int    `json:"amount_cancelled"`
}

type CutoffEvent struct {
	TxInfo
	Owner         common.Address `json:"owner"`
	Cutoff        *big.Int       `json:"cutoff"`
	OrderHashList []common.Hash  `json:"order_hash_list"`
}

type CutoffPairEvent struct {
	TxInfo
	Owner         common.Address `json:"owner"`
	Token1        common.Address `json:"token_1"`
	Token2        common.Address `json:"token_2"`
	Cutoff        *big.Int       `json:"cutoff"`
	OrderHashList []common.Hash  `json:"order_hash_list"`
}

type RingMinedEvent struct {
	TxInfo
	RingIndex    *big.Int       `json:"ring_index"`
	TotalLrcFee  *big.Int       `json:"total_lrc_fee"`
	TradeAmount  int            `json:"trade_amount"`
	Ringhash     common.Hash    `json:"ringhash"`
	Miner        common.Address `json:"miner"`
	FeeRecipient common.Address `json:"fee_recipient"`
	Err          string         `json:"err"`
}

type WethDepositEvent struct {
	TxInfo
	Dst    common.Address `json:"dst"`
	Amount *big.Int       `json:"amount"`
}

type WethWithdrawalEvent struct {
	TxInfo
	Src    common.Address `json:"src"`
	Amount *big.Int       `json:"amount"`
}

type SubmitRingMethodEvent struct {
	TxInfo
	OrderList    []Order        `json:"order_list"`
	FeeReceipt   common.Address `json:"fee_receipt"`
	FeeSelection uint16         `json:"fee_selection"`
	Err          string         `json:"err"`
}

type RingSubmitResultEvent struct {
	RecordId     int
	RingHash     common.Hash `json:"ring_hash"`
	RingUniqueId common.Hash `json:"ring_unique_id"`
	TxHash       common.Hash `json:"tx_hash"`
	Status       TxStatus    `json:"status"`
	RingIndex    *big.Int    `json:"ring_index"`
	BlockNumber  *big.Int    `json:"block_number"`
	UsedGas      *big.Int    `json:"used_gas"`
	Err          string      `json:"err"`
}

type ForkedEvent struct {
	DetectedBlock *big.Int    `json:"detected_block"`
	DetectedHash  common.Hash `json:"detected_hash"`
	ForkBlock     *big.Int    `json:"fork_block"`
	ForkHash      common.Hash `json:"fork_hash"`
}

type BlockEvent struct {
	BlockNumber *big.Int    `json:"block_number"`
	BlockHash   common.Hash `json:"block_hash"`
	BlockTime   int64       `json:"block_time"`
	IsFinished  bool        `json:"is_finished"`
}

type ExtractorWarningEvent struct{}

type EthTransferEvent struct {
	TxInfo
	Sender   common.Address `json:"sender"`
	Receiver common.Address `json:"receiver"`
	Amount   *big.Int       `json:"amount"`
}

type TransactionEvent struct {
	TxInfo
}

type UnsupportedContractEvent struct {
	TxInfo
}

type SyncCompleteEvent struct {
	BlockNumber *big.Int `json:"block_number"`
}

type DepthUpdateEvent struct {
	DelegateAddress string `json:"delegate_address"`
	Market          string `json:"market"`
}

type BalanceUpdateEvent struct {
	DelegateAddress string `json:"delegate_address"`
	Owner           string `json:"owner"`
}

type KafkaOnChainEvent struct {
	Data  string `json:"data"`
	Topic string `json:"topic"`
}

//go:generate gencodec -type RingSubmitInfoEvent -field-override ringSubmitInfoMarshaling -out gen_ringSubmitInfoEvent_json.go
type RingSubmitInfoEvent struct {
	SubmitInfoId     int
	Miner            common.Address
	ProtocolAddress  common.Address
	Ringhash         common.Hash
	UniqueId         common.Hash
	ProtocolData     string
	ProtocolGas      *big.Int
	ProtocolUsedGas  *big.Int
	ProtocolGasPrice *big.Int
	ValidSinceTime   int64
}

type ringSubmitInfoMarshaling struct {
	ProtocolGas      *Big
	ProtocolUsedGas  *Big
	ProtocolGasPrice *Big
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/user.go<|end_filename|>
/*

 Copyright 2017 Loopring Project Ltd (Loopring Foundation).

 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 types

import "github.com/ethereum/go-ethereum/common"

// 白名单用户允许广播，但是订单不允许提供给miner

//go:generate gencodec -type WhiteListUser -out gen_white_list_user_json.go
type WhiteListUser struct {
	Owner      common.Address `json:"owner"`
	CreateTime int64          `json:"create_time"`
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/numbers.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import (
	"math/big"
)

type Big big.Int

func NewBigPtr(v *big.Int) *Big {
	n := new(Big)
	n.SetInt(v)
	return n
}

func NewBigWithInt(v int) *Big {
	n := new(Big)
	n.SetInt(big.NewInt(int64(v)))
	return n
}

func (h *Big) UnmarshalText(input []byte) error {
	//length := len(input)
	//if length >= 2 && input[0] == '"' && input[length-1] == '"' {
	//	input = input[1 : length-1]
	//}

	hn := (*big.Int)(h)
	hn.Set(HexToBigint(string(input)))
	return nil
}

func (h *Big) MarshalText() ([]byte, error) {
	hn := (*big.Int)(h)
	bytes := []byte(BigintToHex(hn))
	return bytes, nil
}

func (h *Big) Int() int {
	hn := (*big.Int)(h)
	return int(hn.Int64())
}

func (h *Big) Int64() int64 {
	hn := (*big.Int)(h)
	return hn.Int64()
}

func (h *Big) Uint() uint {
	hn := (*big.Int)(h)
	return uint(hn.Uint64())
}

func (h *Big) Uint64() uint64 {
	hn := (*big.Int)(h)
	return hn.Uint64()
}

func (h *Big) BigInt() *big.Int {
	return (*big.Int)(h)
}

func (h *Big) SetInt(v *big.Int) Big {
	(*big.Int)(h).Set(v)
	return *h
}

type Rat big.Rat

func (r *Rat) UnmarshalText(input []byte) error {
	rn := (*big.Rat)(r)
	rn.SetString(string(input))
	return nil
}

func (r *Rat) MarshalText() ([]byte, error) {
	rn := (*big.Rat)(r)
	bytes := []byte(rn.RatString())
	return bytes, nil
}

func (r *Rat) BigRat() *big.Rat {
	return (*big.Rat)(r)
}
func NewBigRat(v *big.Rat) *Rat {
	r := new(Rat)
	(*big.Rat)(r).Set(v)
	return r
}

var MaxUint256 = maxUint256()

func maxUint256() *big.Int {
	maxBytes := [32]uint8{}
	for idx, _ := range maxBytes {
		maxBytes[idx] = uint8(255)
	}
	maxBig := new(big.Int).SetBytes(maxBytes[:])
	return maxBig
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/ring.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import (
	"github.com/Loopring/relay-lib/crypto"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

type NameRegistryInfo struct {
	Name          string
	Owner         common.Address
	FeeRecipient  common.Address
	Signer        common.Address
	ParticipantId *big.Int
}

// 旷工在成本节约和fee上二选一，撮合者计算出:
// 1.fee(lrc)的市场价(法币交易价格)
// 2.成本节约(savingShare)的市场价(法币交易价格)
// 撮合者在fee和savingShare中二选一，作为自己的利润，
// 如果撮合者选择fee，则成本节约分给订单发起者，如果选择成本节约，则需要返还给用户一定的lrc
// 这样一来，撮合者的利润判断公式应该是max(fee, savingShare - fee * s),s为固定比例
// 此外，在选择最优环路的时候，撮合者会在确定了选择fee/savingShare后，选择某个具有最大利润的环路
// 但是，根据谷歌竞拍法则(A出价10,B出价20,最终成交价为10)，撮合者最终获得的利润只能是利润最小的环路利润

type Ring struct {
	Orders      []*FilledOrder `json:"orderes"`
	V           uint8          `json:"v"`
	R           Bytes32        `json:"r"`
	S           Bytes32        `json:"s"`
	Hash        common.Hash    `json:"hash"`
	ReducedRate *big.Rat       `json:"reducedRate"` //成环之后，折价比例
	LegalFee    *big.Rat       `json:"legalFee"`    //法币计算的fee
	UniqueId    common.Hash    `json:"uniquedId"`

	//
	Received  *big.Rat
	LegalCost *big.Rat
	Gas       *big.Int
	GasPrice  *big.Int
}

func (ring *Ring) FeeSelections() *big.Int {
	feeSelections := big.NewInt(int64(0))
	for idx, filledOrder := range ring.Orders {
		if filledOrder.FeeSelection > 0 {
			feeSelections.Or(feeSelections, big.NewInt(int64(1<<uint(idx))))
		}
	}
	return feeSelections
}

func (ring *Ring) GenerateUniqueId() common.Hash {
	if IsZeroHash(ring.UniqueId) {
		orderHashBytes := ring.Orders[0].OrderState.RawOrder.Hash.Bytes()
		for idx, order := range ring.Orders {
			if idx > 0 {
				orderHashBytes = Xor(orderHashBytes, order.OrderState.RawOrder.Hash.Bytes())
			}
		}
		ring.UniqueId = common.BytesToHash(orderHashBytes)
	}
	return ring.UniqueId
}

func (ring *Ring) GenerateHash(feeReceipt common.Address) common.Hash {
	hashBytes := crypto.GenerateHash(
		ring.GenerateUniqueId().Bytes(),
		feeReceipt.Bytes(),
		common.LeftPadBytes(ring.FeeSelections().Bytes(), 2),
	)
	return common.BytesToHash(hashBytes)
}

//func (ring *Ring) GenerateAndSetSignature(miner common.Address) error {
//	if IsZeroHash(ring.Hash) {
//		ring.Hash = ring.GenerateHash(miner)
//	}
//
//	if sig, err := crypto.Sign(ring.Hash.Bytes(), miner); nil != err {
//		return err
//	} else {
//		v, r, s := crypto.SigToVRS(sig)
//		ring.V = uint8(v)
//		ring.R = BytesToBytes32(r)
//		ring.S = BytesToBytes32(s)
//		return nil
//	}
//}

func (ring *Ring) ValidSinceTime() int64 {
	latestValidSince := int64(0)
	if nil != ring && len(ring.Orders) > 0 {
		for _, order := range ring.Orders {
			thisTime := order.OrderState.RawOrder.ValidSince.Int64()
			if latestValidSince <= thisTime {
				latestValidSince = thisTime
			}
		}
	}

	return latestValidSince
}

//func (ring *Ring) GenerateSubmitArgs(miner common.Address) (*RingSubmitInputs, error) {
//	ringSubmitArgs := emptyRingSubmitArgs(miner)
//	authVList := []uint8{}
//	authRList := []Bytes32{}
//	authSList := []Bytes32{}
//	ring.Hash = ring.GenerateHash(miner)
//	for _, filledOrder := range ring.Orders {
//		order := filledOrder.OrderState.RawOrder
//		ringSubmitArgs.AddressList = append(ringSubmitArgs.AddressList, [4]common.Address{order.Owner, order.TokenS, order.WalletAddress, order.AuthAddr})
//		rateAmountS, _ := new(big.Int).SetString(filledOrder.RateAmountS.FloatString(0), 10)
//		ringSubmitArgs.UintArgsList = append(ringSubmitArgs.UintArgsList, [6]*big.Int{order.AmountS, order.AmountB, order.ValidSince, order.ValidUntil, order.LrcFee, rateAmountS})
//		ringSubmitArgs.Uint8ArgsList = append(ringSubmitArgs.Uint8ArgsList, [1]uint8{order.MarginSplitPercentage})
//
//		ringSubmitArgs.BuyNoMoreThanAmountBList = append(ringSubmitArgs.BuyNoMoreThanAmountBList, order.BuyNoMoreThanAmountB)
//
//		ringSubmitArgs.VList = append(ringSubmitArgs.VList, order.V)
//		ringSubmitArgs.RList = append(ringSubmitArgs.RList, order.R)
//		ringSubmitArgs.SList = append(ringSubmitArgs.SList, order.S)
//
//		//sign By authPrivateKey
//		if signBytes, err := order.AuthPrivateKey.Sign(ring.Hash.Bytes(), order.AuthPrivateKey.Address()); nil == err {
//			v, r, s := crypto.SigToVRS(signBytes)
//			authVList = append(authVList, v)
//			authRList = append(authRList, BytesToBytes32(r))
//			authSList = append(authSList, BytesToBytes32(s))
//		} else {
//			return nil, err
//		}
//	}
//
//	ringSubmitArgs.VList = append(ringSubmitArgs.VList, authVList...)
//	ringSubmitArgs.RList = append(ringSubmitArgs.RList, authRList...)
//	ringSubmitArgs.SList = append(ringSubmitArgs.SList, authSList...)
//
//	ringSubmitArgs.FeeSelections = ring.FeeSelections()
//	//if err := ring.GenerateAndSetSignature(miner); nil != err {
//	//	return nil, err
//	//} else {
//	//	ringSubmitArgs.VList = append(ringSubmitArgs.VList, ring.V)
//	//	ringSubmitArgs.RList = append(ringSubmitArgs.RList, ring.R)
//	//	ringSubmitArgs.SList = append(ringSubmitArgs.SList, ring.S)
//	//}
//
//	return ringSubmitArgs, nil
//}

type RingSubmitInfo struct {
	RawRing *Ring

	//todo:remove it
	Miner            common.Address
	ProtocolAddress  common.Address
	Ringhash         common.Hash
	OrdersCount      *big.Int
	ProtocolData     []byte
	ProtocolGas      *big.Int
	ProtocolUsedGas  *big.Int
	ProtocolGasPrice *big.Int

	SubmitTxHash common.Hash
}

//
//type RingSubmitInputs struct {
//	AddressList              [][4]common.Address
//	UintArgsList             [][6]*big.Int
//	Uint8ArgsList            [][1]uint8
//	BuyNoMoreThanAmountBList []bool
//	VList                    []uint8
//	RList                    []Bytes32
//	SList                    []Bytes32
//	Miner                    common.Address
//	FeeSelections            *big.Int
//}
//
//func emptyRingSubmitArgs(miner common.Address) *RingSubmitInputs {
//	return &RingSubmitInputs{
//		AddressList:              [][4]common.Address{},
//		UintArgsList:             [][6]*big.Int{},
//		Uint8ArgsList:            [][1]uint8{},
//		BuyNoMoreThanAmountBList: []bool{},
//		VList: []uint8{},
//		RList: []Bytes32{},
//		SList: []Bytes32{},
//		Miner: miner,
//	}
//}


<|start_filename|>vendor/github.com/Loopring/motan-go/endpoint/grpcEndpoint.go<|end_filename|>
package endpoint

import (
	"strconv"
	"time"

	motan "github.com/Loopring/motan-go/core"
	"github.com/Loopring/motan-go/log"
	"golang.org/x/net/context"
	grpc "google.golang.org/grpc"
	metadata "google.golang.org/grpc/metadata"
)

type GrpcEndPoint struct {
	url      *motan.URL
	grpcConn *grpc.ClientConn
	proxy    bool
}

const (
	GRPCSerialNum = 1
)

func (g *GrpcEndPoint) Initialize() {
	grpcconn, err := grpc.Dial((g.url.Host + ":" + strconv.Itoa((int)(g.url.Port))), grpc.WithInsecure(), grpc.WithCodec(&agentCodec{}))
	if err != nil {
		vlog.Errorf("connect to grpc fail! url:%s, err:%s\n", g.url.GetIdentity(), err.Error())
	}
	g.grpcConn = grpcconn
}

func (g *GrpcEndPoint) Destroy() {
	if g.grpcConn != nil {
		vlog.Infof("grpc endpoint %s will destroyed", g.url.GetAddressStr())
		g.grpcConn.Close()
	}
}

func (g *GrpcEndPoint) SetProxy(proxy bool) {
	g.proxy = proxy
}

func (g *GrpcEndPoint) SetSerialization(s motan.Serialization) {}

func (g *GrpcEndPoint) Call(request motan.Request) motan.Response {
	t := time.Now().UnixNano()
	var in []byte
	if dv, ok := request.GetArguments()[0].(*motan.DeserializableValue); ok {
		in = dv.Body
	} else if ba, ok := request.GetArguments()[0].([]byte); ok {
		in = ba
	} else {
		vlog.Errorf("can not process argument in grpc endpoint. argument:%v\n", request.GetArguments()[0])
		return motan.BuildExceptionResponse(request.GetRequestID(), &motan.Exception{ErrCode: 500, ErrMsg: "grpc argument must be []byte", ErrType: motan.ServiceException})
	}
	out := new(OutMsg)

	var header, trailer metadata.MD
	md := metadata.New(request.GetAttachments())
	ctx := metadata.NewOutgoingContext(context.Background(), md)
	err := grpc.Invoke(ctx, "/"+request.GetServiceName()+"/"+request.GetMethod(), in, out, g.grpcConn, grpc.Header(&header), grpc.Trailer(&trailer))
	// type MD map[string][]string
	resp := &motan.MotanResponse{Attachment: make(map[string]string)}
	resp.RequestID = request.GetRequestID()
	resp.ProcessTime = int64((time.Now().UnixNano() - t) / 1000000)
	rc := resp.GetRPCContext(true)
	rc.Serialized = true
	rc.SerializeNum = GRPCSerialNum

	// @TODO add receiving header and trailers into attachment
	if err != nil {
		errcode := int(grpc.Code(err))
		//@TODO ErrTYpe
		resp.Exception = &motan.Exception{ErrCode: errcode, ErrMsg: grpc.ErrorDesc(err), ErrType: errcode}
		return resp
	}
	resp.Value = (*out).buf
	return resp
}

func (g *GrpcEndPoint) GetName() string {
	return "grpcEndpoint"
}

func (g *GrpcEndPoint) GetURL() *motan.URL {
	return g.url
}

func (g *GrpcEndPoint) SetURL(url *motan.URL) {
	g.url = url
}

func (g *GrpcEndPoint) IsAvailable() bool {
	//TODO endpoint 是否可用
	return true
}

type agentCodec struct{}

type OutMsg struct {
	buf []byte
}

func (agentCodec) Marshal(v interface{}) ([]byte, error) {
	var err error
	rs := v.([]byte)
	return rs, err
}

func (agentCodec) Unmarshal(data []byte, v interface{}) error {
	var err error
	om := v.(*OutMsg)
	om.buf = data
	return err
}

func (agentCodec) String() string {
	return "agent"
}


<|start_filename|>vendor/github.com/Loopring/motan-go/registry/registry.go<|end_filename|>
package registry

import (
	"encoding/json"
	"io/ioutil"
	"path/filepath"
	"sync"
	"time"
	"unsafe"

	motan "github.com/Loopring/motan-go/core"
)

const (
	DefaultSnapshotInterval  = 10 * time.Second
	DefaultHeartbeatInterval = 10 * 1000 //ms
	DefaultTimeout           = 3 * 1000  //ms
	DefaultSnapshotDir       = "./snapshot"
)

//ext name
const (
	Direct = "direct"
	Consul = "consul"
	ZK     = "zookeeper"
)

type SnapShotNodeInfo struct {
	ExtInfo string `json:"extInfo"`
	Addr    string `json:"address"`
}

type ServiceNode struct {
	Group string             `json:"group"`
	Path  string             `json:"path"`
	Nodes []SnapShotNodeInfo `json:"nodes"`
}

var (
	// TODO support mulit registry
	snapshotConf       = &motan.SnapshotConf{SnapshotInterval: DefaultSnapshotInterval, SnapshotDir: DefaultSnapshotDir}
	nodeRsSnapshotLock sync.RWMutex
)

func SetSanpshotConf(snapshotInterval time.Duration, snapshotDir string) {
	snapshotConf.SnapshotDir = snapshotDir
	snapshotConf.SnapshotInterval = snapshotInterval
}

func GetSanpshotConf() *motan.SnapshotConf {
	return snapshotConf
}

func RegistDefaultRegistry(extFactory motan.ExtentionFactory) {
	extFactory.RegistExtRegistry(Direct, func(url *motan.URL) motan.Registry {
		return &DirectRegistry{url: url}
	})

	extFactory.RegistExtRegistry(ZK, func(url *motan.URL) motan.Registry {
		return &ZkRegistry{url: url}
	})

	extFactory.RegistExtRegistry(Consul, func(url *motan.URL) motan.Registry {
		return &ConsulRegistry{url: url}
	})
}

func IsAgent(url *motan.URL) bool {
	isAgent := false
	if t, ok := url.Parameters["nodeType"]; ok {
		if t == "agent" {
			isAgent = true
		}
	}
	return isAgent
}

func GetSubKey(url *motan.URL) string {
	return url.Group + "/" + url.Path + "/service"
}

func getNodeKey(url *motan.URL) string {
	return url.Group + "_" + url.Path
}

func SliceByteToString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

func StringToSliceByte(s string) []byte {
	x := (*[2]uintptr)(unsafe.Pointer(&s))
	h := [3]uintptr{x[0], x[1], x[1]}
	return *(*[]byte)(unsafe.Pointer(&h))
}

func saveSnapshot(d string, nodes map[string]ServiceNode) {
	nodeRsSnapshotLock.RLock()
	for key, node := range nodes {
		nodeRsSnapshot := JSONString(node)
		// ioutil.ReadFile(filepath.Join(d, key))
		ioutil.WriteFile(filepath.Join(d, key), StringToSliceByte(nodeRsSnapshot), 0777)
	}
	nodeRsSnapshotLock.RUnlock()
}

func JSONString(v interface{}) string {
	bytes, _ := json.Marshal(v)
	return string(bytes)
}


<|start_filename|>vendor/github.com/Loopring/motan-go/filter/filter.go<|end_filename|>
package filter

import motan "github.com/Loopring/motan-go/core"

// ext name
const (
	AccessLog      = "accessLog"
	Metrics        = "metrics"
	CircuitBreaker = "circuitbreaker"
	FailFast       = "failfast"
)

func RegistDefaultFilters(extFactory motan.ExtentionFactory) {
	extFactory.RegistExtFilter(AccessLog, func() motan.Filter {
		return &AccessLogEndPointFilter{}
	})

	extFactory.RegistExtFilter(Metrics, func() motan.Filter {
		return &MetricsFilter{}
	})

	extFactory.RegistExtFilter(CircuitBreaker, func() motan.Filter {
		return &CircuitBreakerEndPointFilter{}
	})

	extFactory.RegistExtFilter(FailFast, func() motan.Filter {
		return &FailfastFilter{}
	})
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/crypto/interface.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 crypto

import (
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"math/big"
)

var crypto Crypto

type Crypto interface {
	//签名验证
	ValidateSignatureValues(v byte, r, s []byte) bool
	//生成hash
	GenerateHash(data ...[]byte) []byte
	//签名
	Sign(hash []byte, signer common.Address) ([]byte, error)
	//签名恢复到地址
	SigToAddress(hash, sig []byte) ([]byte, error)
	//生成sig
	VRSToSig(v byte, r, s []byte) ([]byte, error)

	SigToVRS(sig []byte) (v byte, r []byte, s []byte)

	SignTx(a common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/eth/contract/common.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 contract

import (
	"github.com/Loopring/relay-lib/types"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

// sateHash contract bytes32 to common.hash
func safeHash(bytes [32]uint8) common.Hash {
	return common.Hash(bytes)
}

// safeAbsBig return abs value and isNeg
func safeBig(bytes [32]uint8) *big.Int {
	num := new(big.Int).SetBytes(bytes[:])
	if bytes[0] > uint8(128) {
		num.Xor(types.MaxUint256, num)
		num.Not(num)
	}
	return num
}

// safeAddress contract bytes32 to common.address
func safeAddress(bytes [32]uint8) common.Address {
	var newbytes []byte = bytes[0:]
	return common.BytesToAddress(newbytes)
}


<|start_filename|>dao/block.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 dao

import (
	"errors"
	"github.com/Loopring/relay-lib/types"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

type Block struct {
	ID          int    `gorm:"column:id;primary_key"`
	BlockNumber int64  `gorm:"column:block_number;type:bigint"`
	BlockHash   string `gorm:"column:block_hash;type:varchar(82)"`
	ParentHash  string `gorm:"column:parent_hash;type:varchar(82)"`
	CreateTime  int64  `gorm:"column:create_time"`
	Fork        bool   `gorm:"column:fork;"`
}

// convert types/block to dao/block
func (b *Block) ConvertDown(src *types.Block) error {
	b.BlockNumber = src.BlockNumber.Int64()
	b.BlockHash = src.BlockHash.Hex()
	b.ParentHash = src.ParentHash.Hex()
	b.CreateTime = src.CreateTime
	b.Fork = false

	return nil
}

// convert dao/block to types/block
func (b *Block) ConvertUp(dst *types.Block) error {
	dst.BlockNumber = big.NewInt(b.BlockNumber)
	dst.BlockHash = common.HexToHash(b.BlockHash)
	dst.ParentHash = common.HexToHash(b.ParentHash)
	dst.CreateTime = b.CreateTime

	return nil
}

func (s *RdsService) FindBlockByHash(blockhash common.Hash) (*Block, error) {
	var block Block
	if types.IsZeroHash(blockhash) {
		return nil, errors.New("block table findBlockByHash get an illegal hash")
	}

	err := s.Db.Where("block_hash = ?", blockhash.Hex()).Where("fork = ?", false).First(&block).Error

	return &block, err
}

func (s *RdsService) FindLatestBlock() (*Block, error) {
	var block Block
	err := s.Db.Order("create_time desc").Where("fork = ?", false).First(&block).Error
	return &block, err
}

func (s *RdsService) SetForkBlock(from, to int64) error {
	return s.Db.Model(&Block{}).Where("block_number > ? and block_number <= ?", from, to).Update("fork", true).Error
}

func (s *RdsService) SaveBlock(latest *Block) error {
	var current Block
	if err := s.Db.Where("block_hash=?", latest.BlockHash).Find(&current).Error; err == nil {
		return nil
	}

	return s.Db.Create(latest).Error
}


<|start_filename|>vendor/gopkg.in/googollee/go-engine.io.v1/transport/polling/server.go<|end_filename|>
package polling

import (
	"bytes"
	"html/template"
	"net"
	"net/http"
	"net/url"

	"gopkg.in/googollee/go-engine.io.v1/base"
	"gopkg.in/googollee/go-engine.io.v1/payload"
)

type serverConn struct {
	*payload.Payload
	supportBinary bool

	remoteHeader http.Header
	localAddr    Addr
	remoteAddr   Addr
	url          url.URL
	jsonp        string
}

func newServerConn(r *http.Request) base.Conn {
	query := r.URL.Query()
	supportBinary := query.Get("b64") == ""
	jsonp := query.Get("j")
	if jsonp != "" {
		supportBinary = false
	}
	return &serverConn{
		Payload:       payload.New(supportBinary),
		supportBinary: supportBinary,
		remoteHeader:  r.Header,
		localAddr:     Addr{r.Host},
		remoteAddr:    Addr{r.RemoteAddr},
		url:           *r.URL,
		jsonp:         jsonp,
	}
}

func (c *serverConn) URL() url.URL {
	return c.url
}

func (c *serverConn) LocalAddr() net.Addr {
	return c.localAddr
}

func (c *serverConn) RemoteAddr() net.Addr {
	return c.remoteAddr
}

func (c *serverConn) RemoteHeader() http.Header {
	return c.remoteHeader
}

func (c *serverConn) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		if jsonp := r.URL.Query().Get("j"); jsonp != "" {
			buf := bytes.NewBuffer(nil)
			if err := c.Payload.FlushOut(buf); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "text/javascript; charset=UTF-8")
			pl := template.JSEscapeString(buf.String())
			w.Write([]byte("___eio[" + jsonp + "](\""))
			w.Write([]byte(pl))
			w.Write([]byte("\");"))
			return
		}
		if c.supportBinary {
			w.Header().Set("Content-Type", "application/octet-stream")
		} else {
			w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
		}
		if err := c.Payload.FlushOut(w); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		return
	case "POST":
		mime := r.Header.Get("Content-Type")
		supportBinary, err := mimeSupportBinary(mime)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if err := c.Payload.FeedIn(r.Body, supportBinary); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		w.Write([]byte("ok"))
		return
	default:
		http.Error(w, "invalid method", http.StatusBadRequest)
	}
}


<|start_filename|>vendor/github.com/Loopring/motan-go/ha/failoverHA.go<|end_filename|>
package ha

import (
	"fmt"

	motan "github.com/Loopring/motan-go/core"
	"github.com/Loopring/motan-go/log"
)

const (
	defaultRetries = 0
)

type FailOverHA struct {
	url *motan.URL
}

func (f *FailOverHA) GetName() string {
	return "failover"
}
func (f *FailOverHA) GetURL() *motan.URL {
	return f.url
}
func (f *FailOverHA) SetURL(url *motan.URL) {
	f.url = url
}
func (f *FailOverHA) Call(request motan.Request, loadBalance motan.LoadBalance) motan.Response {
	defer func() {
		if err := recover(); err != nil {
			vlog.Warningf("FailOverHA call encount panic! url:%s, err:%v\n", f.url.GetIdentity(), err)
		}
	}()
	retries := f.url.GetMethodPositiveIntValue(request.GetMethod(), request.GetMethodDesc(), "retries", defaultRetries)
	var lastErr *motan.Exception
	for i := 0; i <= int(retries); i++ {
		ep := loadBalance.Select(request)
		if ep == nil {
			return getErrorResponse(request.GetRequestID(), fmt.Sprintf("No referers for request, RequestID: %d, Request info: %+v",
				request.GetRequestID(), request.GetAttachments()))
		}
		respnose := ep.Call(request)
		if respnose.GetException() == nil || respnose.GetException().ErrType == motan.BizException {
			return respnose
		}
		lastErr = respnose.GetException()
		vlog.Warningf("FailOverHA call fail! url:%s, err:%+v\n", ep.GetURL().GetIdentity(), lastErr)
	}
	return getErrorResponse(request.GetRequestID(), fmt.Sprintf("call fail over %d times.Exception:%s", retries, lastErr.ErrMsg))

}

func getErrorResponse(requestid uint64, errmsg string) *motan.MotanResponse {
	return motan.BuildExceptionResponse(requestid, &motan.Exception{ErrCode: 400, ErrMsg: errmsg, ErrType: motan.ServiceException})
}


<|start_filename|>usermanager/whitelist.go<|end_filename|>
/*

 Copyright 2017 Loopring Project Ltd (Loopring Foundation).

 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 usermanager

import (
	"github.com/Loopring/relay-cluster/dao"
	"github.com/Loopring/relay-lib/log"
	"github.com/Loopring/relay-lib/types"
	"github.com/ethereum/go-ethereum/common"
	gocache "github.com/patrickmn/go-cache"
	"time"
)

type WhiteListCache struct {
	cache  *gocache.Cache
	rds    *dao.RdsService
	expire time.Duration
}

func newWhiteListCache(options *UserManagerOptions, rds *dao.RdsService) *WhiteListCache {
	c := &WhiteListCache{}
	c.rds = rds

	expire := time.Duration(options.WhiteListCacheExpireTime) * time.Second
	cleanUp := time.Duration(options.WhiteListCacheCleanTime) * time.Second
	c.cache = gocache.New(expire, cleanUp)
	c.expire = expire

	c.refreshWhiteList()

	return c
}

func (c WhiteListCache) syncWhiteList() {
	if list, err := c.rds.GetWhiteList(); err == nil || len(list) == 0 {
		for _, v := range list {
			var user types.WhiteListUser
			if err := v.ConvertUp(&user); err != nil {
				log.Errorf("new white list cache error:%s", err.Error())
				continue
			}
			c.set(&user)
		}
	}
}
func (c WhiteListCache) refreshWhiteList() {
	c.syncWhiteList()
	go func() {
		for {
			select {
			case <-time.After(time.Second * 60):
				c.syncWhiteList()
			}
		}
	}()
}

func (c *WhiteListCache) AddWhiteListUser(user types.WhiteListUser) error {
	if c.InWhiteList(user.Owner) {
		log.Debugf("white list user:%s already exist in cache", user.Owner.Hex())
		return nil
	}

	c.set(&user)
	model := dao.WhiteList{}
	if err := model.ConvertDown(&user); err != nil {
		return err
	}

	return c.rds.Add(model)
}

func (c *WhiteListCache) DelWhiteListUser(user types.WhiteListUser) error {
	if !c.InWhiteList(user.Owner) {
		log.Debugf("white list user:%s already deleted in cache", user.Owner.Hex())
		return nil
	}

	c.del(user.Owner)
	model := dao.WhiteList{}
	if err := model.ConvertDown(&user); err != nil {
		return err
	}

	return c.rds.Del(model)
}

func (c *WhiteListCache) InWhiteList(address common.Address) bool {
	_, ok := c.get(address)
	return ok
}

// get get value from gocache
func (c *WhiteListCache) get(address common.Address) (*types.WhiteListUser, bool) {
	data, ok := c.cache.Get(address.Hex())
	if !ok {
		return nil, false
	}

	user := data.(*types.WhiteListUser)

	return user, true
}

// set set key-value in gocache
func (c *WhiteListCache) set(user *types.WhiteListUser) {
	address := user.Owner.Hex()
	c.cache.Set(address, user, c.expire)
}

// del delete key from gocache
func (c *WhiteListCache) del(address common.Address) {
	c.cache.Delete(address.Hex())
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/motan/config.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 motan

type MotanServerOptions struct {
	ServerInstance interface{}
	ConfFile       string
}

type MotanClientOptions struct {
	ClientId string
	ConfFile string
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/bytes.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import "github.com/ethereum/go-ethereum/common"

func Xor(bytes1, bytes2 []byte) []byte {
	bs1Length := len(bytes1)
	bs2Length := len(bytes2)
	var bytesTmp []byte
	bytesTmp = make([]byte, bs1Length)
	if bs1Length > bs2Length {
		bytes2 = common.LeftPadBytes(bytes2, bs1Length)
	} else if bs1Length < bs2Length {
		bytes1 = common.LeftPadBytes(bytes1, bs2Length)
		bytesTmp = make([]byte, bs2Length)
	}

	for idx, _ := range bytesTmp {
		bytesTmp[idx] = bytes1[idx] ^ bytes2[idx]
	}
	return bytesTmp
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/params/version.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 params

import (
	"fmt"
)

const (
	VersionMajor = 1          // Major version component of the current release
	VersionMinor = 7          // Minor version component of the current release
	VersionPatch = 0          // Patch version component of the current release
	VersionMeta  = "unstable" // Version metadata to append to the version string
)

// Version holds the textual version string.
var Version = func() string {
	v := fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
	if VersionMeta != "" {
		v += "-" + VersionMeta
	}
	return v
}()

func VersionWithCommit(gitCommit string) string {
	vsn := Version
	if len(gitCommit) >= 8 {
		vsn += "-" + gitCommit[:8]
	}
	return vsn
}

//only process order supported it
func SupportedContractAddress() map[string]bool {
	addresses := make(map[string]bool)
	addresses["0x211c9fb2c5ad60a31587a4a11b289e37ed3ea520"] = true
	return addresses
}

//only process order supported it
func SupportedEthVersion() map[string]bool {
	return make(map[string]bool)
}


<|start_filename|>usermanager/usermanager_test.go<|end_filename|>
/*

 Copyright 2017 Loopring Project Ltd (Loopring Foundation).

 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 usermanager_test

//import (
//	"github.com/Loopring/relay-cluster/test"
//	"testing"
//)
//
//func TestUserManagerImpl_InWhiteList(t *testing.T) {
//	um := test.GenerateUserManager()
//	entity := test.Entity()
//	owner := entity.Accounts[0].Address
//	ok := um.InWhiteList(owner)
//	t.Logf("user %s exist? %t", owner.Hex(), ok)
//}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/token.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import (
	"encoding/json"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
	"strconv"
)

type Token struct {
	Protocol common.Address `json:"protocol"`
	Symbol   string         `json:"symbol"`
	Name     string         `json:"name"`
	Source   string         `json:"source"`
	Time     int64          `json:"time"`
	Deny     bool           `json:"deny"`
	Decimals *big.Int       `json:"decimals"`
	IsMarket bool           `json:"isMarket"`
	IcoPrice *big.Rat       `json:"icoPrice"`
}

type CurrencyMarketCap struct {
	Id           string         `json:"id"`
	Name         string         `json:"name"`
	Symbol       string         `json:"symbol"`
	Address      common.Address `json:"address"`
	PriceUsd     *big.Rat       `json:"price_usd"`
	PriceBtc     *big.Rat       `json:"price_btc"`
	PriceCny     *big.Rat       `json:"price_cny"`
	Volume24HCNY *big.Rat       `json:"24h_volume_cny"`
	Volume24HUSD *big.Rat       `json:"24h_volume_usd"`
	LastUpdated  int64          `json:"last_updated"`
	Decimals     *big.Int
}

func (cap *CurrencyMarketCap) UnmarshalJSON(input []byte) error {
	type Cap struct {
		Id           string `json:"id"`
		Name         string `json:"name"`
		Symbol       string `json:"symbol"`
		PriceUsd     string `json:"price_usd"`
		PriceBtc     string `json:"price_btc"`
		PriceCny     string `json:"price_cny"`
		Volume24HCNY string `json:"24h_volume_cny"`
		Volume24HUSD string `json:"24h_volume_usd"`
		LastUpdated  string `json:"last_updated"`
	}
	c := &Cap{}
	if err := json.Unmarshal(input, c); nil != err {
		return err
	} else {
		cap.Id = c.Id
		cap.Symbol = c.Symbol
		cap.Name = c.Name
		if "" == c.PriceUsd {
			c.PriceUsd = "0.0"
		}
		if price, err1 := strconv.ParseFloat(c.PriceUsd, 10); nil != err1 {
			return err1
		} else {
			cap.PriceUsd = new(big.Rat).SetFloat64(price)
		}
		if "" == c.PriceBtc {
			c.PriceBtc = "0.0"
		}
		if price, err1 := strconv.ParseFloat(c.PriceBtc, 10); nil != err1 {
			return err1
		} else {
			cap.PriceBtc = new(big.Rat).SetFloat64(price)
		}
		if "" == c.PriceCny {
			c.PriceCny = "0.0"
		}
		if price, err1 := strconv.ParseFloat(c.PriceCny, 10); nil != err1 {
			return err1
		} else {
			cap.PriceCny = new(big.Rat).SetFloat64(price)
		}
		if "" == c.Volume24HCNY {
			c.Volume24HCNY = "0.0"
		}
		if price, err1 := strconv.ParseFloat(c.Volume24HCNY, 10); nil != err1 {
			return err1
		} else {
			cap.Volume24HCNY = new(big.Rat).SetFloat64(price)
		}
		if "" == c.Volume24HUSD {
			c.Volume24HUSD = "0.0"
		}
		if price, err1 := strconv.ParseFloat(c.Volume24HUSD, 10); nil != err1 {
			return err1
		} else {
			cap.Volume24HUSD = new(big.Rat).SetFloat64(price)
		}
		if "" == c.LastUpdated {
			c.LastUpdated = "0"
		}
		if lastUpdated, err1 := strconv.ParseInt(c.LastUpdated, 0, 0); nil != err1 {
			return err1
		} else {
			cap.LastUpdated = lastUpdated
		}
	}
	return nil
}


<|start_filename|>gateway/eth_forward.go<|end_filename|>
package gateway

import (
	"github.com/Loopring/relay-lib/eth/accessor"
	"github.com/Loopring/relay-lib/eth/types"
	"github.com/ethereum/go-ethereum/common"
)

type EthForwarder struct {
}

func (e *EthForwarder) GetBalance(address, blockNumber string) (result string, err error) {
	err = accessor.GetBalance(&result, common.HexToAddress(address), blockNumber)
	//err = e.Accessor.RetryCall("latest", 2, &result, "eth_getBalance", common.HexToAddress(address), blockNumber)
	return
}

func (e *EthForwarder) SendRawTransaction(tx string) (result string, err error) {
	err = accessor.SendRawTransaction(&result, tx)
	//err = e.Accessor.RetryCall("latest", 2, &result, "eth_sendRawTransaction", tx)
	return
}

func (e *EthForwarder) GetTransactionCount(address, blockNumber string) (result string, err error) {
	err = accessor.GetTransactionCount(&result, common.HexToAddress(address), blockNumber)
	return
	//err = e.Accessor.RetryCall("latest", 2, &result, "eth_getTransactionCount", common.HexToAddress(address), blockNumber)
	//return result, nil
}

func (e *EthForwarder) Call(ethCall *types.CallArg, blockNumber string) (result string, err error) {
	err = accessor.Call(&result, ethCall, blockNumber)
	return
	//err = e.Accessor.RetryCall("latest", 2, &result, "eth_call", ethCall, blockNumber)
	//return result, nil
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/gen_ringSubmitInfoEvent_json.go<|end_filename|>
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.

package types

import (
	"encoding/json"
	"math/big"

	"github.com/ethereum/go-ethereum/common"
)

var _ = (*ringSubmitInfoMarshaling)(nil)

// MarshalJSON marshals as JSON.
func (r RingSubmitInfoEvent) MarshalJSON() ([]byte, error) {
	type RingSubmitInfoEvent struct {
		SubmitInfoId     int
		Miner            common.Address
		ProtocolAddress  common.Address
		Ringhash         common.Hash
		UniqueId         common.Hash
		ProtocolData     string
		ProtocolGas      *Big
		ProtocolUsedGas  *Big
		ProtocolGasPrice *Big
		ValidSinceTime   int64
	}
	var enc RingSubmitInfoEvent
	enc.SubmitInfoId = r.SubmitInfoId
	enc.Miner = r.Miner
	enc.ProtocolAddress = r.ProtocolAddress
	enc.Ringhash = r.Ringhash
	enc.UniqueId = r.UniqueId
	enc.ProtocolData = r.ProtocolData
	enc.ProtocolGas = (*Big)(r.ProtocolGas)
	enc.ProtocolUsedGas = (*Big)(r.ProtocolUsedGas)
	enc.ProtocolGasPrice = (*Big)(r.ProtocolGasPrice)
	enc.ValidSinceTime = r.ValidSinceTime
	return json.Marshal(&enc)
}

// UnmarshalJSON unmarshals from JSON.
func (r *RingSubmitInfoEvent) UnmarshalJSON(input []byte) error {
	type RingSubmitInfoEvent struct {
		SubmitInfoId     *int
		Miner            *common.Address
		ProtocolAddress  *common.Address
		Ringhash         *common.Hash
		UniqueId         *common.Hash
		ProtocolData     *string
		ProtocolGas      *Big
		ProtocolUsedGas  *Big
		ProtocolGasPrice *Big
		ValidSinceTime   *int64
	}
	var dec RingSubmitInfoEvent
	if err := json.Unmarshal(input, &dec); err != nil {
		return err
	}
	if dec.SubmitInfoId != nil {
		r.SubmitInfoId = *dec.SubmitInfoId
	}
	if dec.Miner != nil {
		r.Miner = *dec.Miner
	}
	if dec.ProtocolAddress != nil {
		r.ProtocolAddress = *dec.ProtocolAddress
	}
	if dec.Ringhash != nil {
		r.Ringhash = *dec.Ringhash
	}
	if dec.UniqueId != nil {
		r.UniqueId = *dec.UniqueId
	}
	if dec.ProtocolData != nil {
		r.ProtocolData = *dec.ProtocolData
	}
	if dec.ProtocolGas != nil {
		r.ProtocolGas = (*big.Int)(dec.ProtocolGas)
	}
	if dec.ProtocolUsedGas != nil {
		r.ProtocolUsedGas = (*big.Int)(dec.ProtocolUsedGas)
	}
	if dec.ProtocolGasPrice != nil {
		r.ProtocolGasPrice = (*big.Int)(dec.ProtocolGasPrice)
	}
	if dec.ValidSinceTime != nil {
		r.ValidSinceTime = *dec.ValidSinceTime
	}
	return nil
}


<|start_filename|>vendor/github.com/Loopring/motan-go/cluster/command.go<|end_filename|>
package cluster

import (
	"bytes"
	"encoding/json"
	"regexp"
	"sort"
	"strings"
	"sync"

	motan "github.com/Loopring/motan-go/core"
	"github.com/Loopring/motan-go/log"
)

const (
	CMDTrafficControl = iota
	CMDDegrade        //service degrade
)

const (
	AgentCmd = iota
	ServiceCmd
)

const (
	RuleProtocol = "rule"
)

// CommandRegistryWarper warper registry for every cluster
type CommandRegistryWarper struct {
	cluster            *MotanCluster
	registry           motan.Registry
	notifyListener     motan.NotifyListener // e.g. cluster
	serviceCommandInfo string               // current service command
	agentCommandInfo   string               // current agent command
	mux                sync.Mutex
	ownGroupURLs       []*motan.URL
	otherGroupListener map[string]*serviceListener
	tcCommand          *ClientCommand //effective traffic control command
	degradeCommand     *ClientCommand //effective degrade command
}

type ClientCommand struct {
	Index       int      `json:"index"`
	Version     string   `json:"version"`
	CommandType int      `json:"commandType"`
	Dc          string   `json:"dc"`
	Pattern     string   `json:"pattern"`
	MergeGroups []string `json:"mergeGroups"`
	RouteRules  []string `json:"routeRules"`
	Remark      string   `json:"remark"`
}

type Command struct {
	ClientCommandList []ClientCommand `json:"clientCommandList"`
}

type serviceListener struct {
	referURL *motan.URL
	urls     []*motan.URL
	crw      *CommandRegistryWarper
}

func (s *serviceListener) GetIdentity() string {
	return "serviceListener-" + s.referURL.GetIdentity()
}

func (s *serviceListener) Notify(registryURL *motan.URL, urls []*motan.URL) {
	vlog.Infof("serviceListener notify urls size is %d. refer: %v, registry: %v\n", len(urls), s.referURL, registryURL)
	if s.crw == nil {
		vlog.Infof("serviceListener maybe unSubscribed. notify will ignore. s:%+v\n", s)
		return
	}
	s.urls = urls
	s.crw.getResultWithCommand(true)
}

func (s *serviceListener) unSubscribe(registry motan.Registry) {
	registry.Unsubscribe(s.referURL, s)
	s.crw = nil
	s.referURL = nil
	s.urls = nil
}

func (s *serviceListener) subscribe(registry motan.Registry) {
	// this listener should not reuse, so let it crash when this listener is resubscribe after unsubscribe.
	registry.Subscribe(s.referURL, s)
	s.urls = registry.Discover(s.referURL)
}

type CmdList []ClientCommand

func (c CmdList) Len() int {
	return len(c)
}
func (c CmdList) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}
func (c CmdList) Less(i, j int) bool {
	return c[i].Index < c[j].Index
}

func (c *ClientCommand) MatchCmdPattern(url *motan.URL) bool {
	if c.Pattern == "*" || strings.HasPrefix(url.Path, c.Pattern) {
		return true
	}
	isRegMatch, err := regexp.MatchString(c.Pattern, url.Path)
	if err != nil {
		vlog.Errorf("check regexp command pattern fail. err :%s\n", err.Error())
	}
	if isRegMatch {
		return true
	}
	return false
}

func ParseCommand(commandInfo string) *Command {
	command := new(Command)
	if err := json.Unmarshal([]byte(commandInfo), command); err != nil {
		vlog.Infof("ParseCommand error, command: %s, err:%s\n", commandInfo, err.Error())
		return nil
	}
	return command
}

func GetCommandRegistryWarper(cluster *MotanCluster, registry motan.Registry) motan.Registry {
	cmdRegistry := &CommandRegistryWarper{cluster: cluster, registry: registry}
	cmdRegistry.ownGroupURLs = make([]*motan.URL, 0)
	cmdRegistry.otherGroupListener = make(map[string]*serviceListener)
	cmdRegistry.cluster = cluster
	return cmdRegistry
}

func (c *CommandRegistryWarper) Register(serverURL *motan.URL) {
	c.registry.Register(serverURL)
}

func (c *CommandRegistryWarper) UnRegister(serverURL *motan.URL) {
	c.registry.UnRegister(serverURL)
}

func (c *CommandRegistryWarper) Available(serverURL *motan.URL) {
	c.registry.Available(serverURL)
}

func (c *CommandRegistryWarper) Unavailable(serverURL *motan.URL) {
	c.registry.Unavailable(serverURL)
}

func (c *CommandRegistryWarper) GetRegisteredServices() []*motan.URL {
	return c.registry.GetRegisteredServices()
}

func (c *CommandRegistryWarper) Subscribe(url *motan.URL, listener motan.NotifyListener) {
	c.notifyListener = listener
	c.registry.Subscribe(url, c)
	if cr, ok := c.registry.(motan.DiscoverCommand); ok {
		cr.SubscribeCommand(url, c)
	}
}

func (c *CommandRegistryWarper) Unsubscribe(url *motan.URL, listener motan.NotifyListener) {
	c.registry.Unsubscribe(url, c)
	if cr, ok := c.registry.(motan.DiscoverCommand); ok {
		cr.UnSubscribeCommand(url, c)
	}
	c.clear()
}

func (c *CommandRegistryWarper) Discover(url *motan.URL) []*motan.URL {
	c.ownGroupURLs = c.registry.Discover(url)
	var result []*motan.URL
	if cr, ok := c.registry.(motan.DiscoverCommand); ok {
		serviceCmd := cr.DiscoverCommand(url)
		c.processCommand(ServiceCmd, serviceCmd)
		result = c.getResultWithCommand(false)
	} else {
		result = c.ownGroupURLs
	}
	return result
}

func (c *CommandRegistryWarper) StartSnapshot(conf *motan.SnapshotConf) {
	c.registry.StartSnapshot(conf)
}

func (c *CommandRegistryWarper) GetURL() *motan.URL {
	return c.registry.GetURL()
}

func (c *CommandRegistryWarper) clear() {
	c.mux.Lock()
	defer c.mux.Unlock()
	c.tcCommand = nil
	c.degradeCommand = nil
	c.agentCommandInfo = ""
	c.serviceCommandInfo = ""
	c.ownGroupURLs = make([]*motan.URL, 0)
	for _, l := range c.otherGroupListener {
		l.unSubscribe(c.registry)
	}
	c.otherGroupListener = make(map[string]*serviceListener)
}

func (c *CommandRegistryWarper) getResultWithCommand(neednotify bool) []*motan.URL {
	c.mux.Lock()
	defer c.mux.Unlock()
	var result []*motan.URL = make([]*motan.URL, 0)
	if c.tcCommand != nil {
		vlog.Infof("%s get result with tc command.%+v\n", c.cluster.GetIdentity(), c.tcCommand)
		var buffer bytes.Buffer
		for _, group := range c.tcCommand.MergeGroups {
			g := strings.Split(group, ":")        //group name should not include ':'
			if c.cluster.GetURL().Group == g[0] { // own group
				vlog.Infof("%s get result from own group: %s, group result size:%d\n", c.cluster.GetIdentity(), g[0], len(c.ownGroupURLs))
				for _, u := range c.ownGroupURLs {
					result = append(result, u)
				}
			} else if l, ok := c.otherGroupListener[g[0]]; ok {
				vlog.Infof("%s get result merge group: %s, group result size:%d\n", c.cluster.GetIdentity(), g[0], len(l.urls))
				for _, u := range l.urls {
					result = append(result, u)
				}
			} else {
				vlog.Warningf("TCcommand merge group not found. refer:%s, group notfound: %s, TCcommand %v\n", c.cluster.GetURL(), g[0], c.tcCommand)
				continue
			}
			if buffer.Len() > 0 {
				buffer.WriteString(",")
			}
			buffer.WriteString(group)
		}
		if len(result) > 0 {
			url := buildRuleURL(buffer.String())
			result = append(result, url) // add command rule url to the end of result.
		}
		result = proceeRoute(result, c.tcCommand.RouteRules)
	} else {
		result = c.ownGroupURLs
	}
	if neednotify {
		c.notifyListener.Notify(c.registry.GetURL(), result)
	}
	vlog.Infof("%s get result with command. tcCommand: %t, degradeCommand:%t,  result size %d, will notify:%t\n", c.cluster.GetURL().GetIdentity(), c.tcCommand != nil, c.degradeCommand != nil, len(result), neednotify)
	return result

}

func proceeRoute(urls []*motan.URL, routers []string) []*motan.URL {
	if len(urls) > 0 && len(routers) > 0 {
		lastURLs := urls
		for _, r := range routers {
			rs := strings.Split(r, "to")
			if len(rs) != 2 {
				vlog.Warningf("worng command router:%s is ignored!\n", r)
				continue
			}
			from := strings.TrimSpace(rs[0])
			to := strings.TrimSpace(rs[1])
			if len(from) > 0 && len(to) > 0 && isMatch(from, motan.GetLocalIP()) {
				newURLs := make([]*motan.URL, 0, len(urls))
				for _, u := range lastURLs {
					if u.Protocol == RuleProtocol || isMatch(to, u.Host) {
						newURLs = append(newURLs, u)
					}
				}
				lastURLs = newURLs
			}
		}
		return lastURLs
	}
	return urls
}

// is matching the router rule
func isMatch(router string, localIP string) bool {
	inverse := strings.HasPrefix(router, "!")
	if inverse {
		router = router[1:]
	}
	match := false
	if router == "*" {
		match = true
	} else if idx := strings.Index(router, "*"); idx > -1 {
		match = strings.HasPrefix(localIP, router[0:idx])
	} else {
		match = localIP == router
	}
	if inverse {
		match = !match
	}
	return match
}

// build a rule url which contains command info like 'weight'...
func buildRuleURL(weight string) *motan.URL {
	params := make(map[string]string)
	params[motan.WeightKey] = weight
	url := &motan.URL{Protocol: RuleProtocol, Parameters: params}
	return url
}

func (c *CommandRegistryWarper) processCommand(commandType int, commandInfo string) bool {
	c.mux.Lock()
	defer c.mux.Unlock()
	needNotify := false
	switch commandType {
	case AgentCmd:
		if c.agentCommandInfo == commandInfo {
			vlog.Infoln("agent command same with current. ignored.")
			return false
		}
		c.agentCommandInfo = commandInfo
	case ServiceCmd:
		if c.serviceCommandInfo == commandInfo {
			vlog.Infoln("service command same with current. ignored.")
			return false
		}
		c.serviceCommandInfo = commandInfo
	default:
		vlog.Warningf("unknown command type %d\n", commandType)
		return false
	}

	// rebuild clientcommand
	var newTcCommand *ClientCommand
	var newDegradeCommand *ClientCommand
	if c.agentCommandInfo != "" { // agent command first
		newTcCommand, newDegradeCommand = mergeCommand(c.agentCommandInfo, c.cluster.GetURL())
	}

	if c.serviceCommandInfo != "" {
		tc, dc := mergeCommand(c.serviceCommandInfo, c.cluster.GetURL())
		if newTcCommand == nil {
			newTcCommand = tc
		}
		if newDegradeCommand == nil {
			newDegradeCommand = dc
		}
	}
	if newTcCommand != nil || (c.tcCommand != nil && newTcCommand == nil) {
		needNotify = true
	}

	//process all kinds commands
	c.tcCommand = newTcCommand
	if c.tcCommand == nil {
		vlog.Infof("%s process command result : no tc command. \n", c.cluster.GetURL().GetIdentity())
		for _, v := range c.otherGroupListener {
			v.unSubscribe(c.registry)
		}
		c.otherGroupListener = make(map[string]*serviceListener)
	} else {
		vlog.Infof("%s process command result : has tc command. tc command will enable.command : %+v\n", c.cluster.GetURL().GetIdentity(), newTcCommand)
		newOtherGroupListener := make(map[string]*serviceListener)
		for _, group := range c.tcCommand.MergeGroups {
			g := strings.Split(group, ":")
			if c.cluster.GetURL().Group == g[0] { // own group already subscribe
				continue
			}
			if listener, ok := c.otherGroupListener[g[0]]; ok { // already exist
				vlog.Infof("commandwarper %s process tc command. reuse group %s\n", c.cluster.GetURL().GetIdentity(), g[0])
				newOtherGroupListener[g[0]] = listener
				delete(c.otherGroupListener, g[0])
			} else {
				vlog.Infof("commandwarper %s process tc command. subscribe new group %s\n", c.cluster.GetURL().GetIdentity(), g[0])
				newGroupURL := c.cluster.GetURL().Copy()
				newGroupURL.Group = g[0]
				l := &serviceListener{crw: c, referURL: newGroupURL}
				l.subscribe(c.registry)
				newOtherGroupListener[g[0]] = l
			}

		}

		oldOtherGroupListener := c.otherGroupListener
		c.otherGroupListener = newOtherGroupListener
		// sync destroy
		for _, v := range oldOtherGroupListener {
			v.unSubscribe(c.registry)
		}
	}
	c.degradeCommand = newDegradeCommand
	if c.degradeCommand == nil {
		vlog.Infof("%s no degrade command. this cluster is available.\n", c.cluster.GetURL().GetIdentity())
		c.cluster.available = true
	} else {
		vlog.Infof("%s has degrade command. this cluster will degrade.\n", c.cluster.GetURL().GetIdentity())
		c.cluster.available = false
	}

	return needNotify
}

func mergeCommand(commandInfo string, url *motan.URL) (tcCommand *ClientCommand, degradeCommand *ClientCommand) {
	//only one command of a type will enable in same service. depends on the index of command
	cmd := ParseCommand(commandInfo)
	if cmd == nil {
		vlog.Warningf("pasre command fail, command is ignored. command info: %s\n", commandInfo)
	} else {
		var cmds CmdList = cmd.ClientCommandList
		sort.Sort(cmds)
		for _, c := range cmds {
			if c.MatchCmdPattern(url) {
				switch c.CommandType {
				case CMDTrafficControl:
					if tcCommand == nil {
						temp := c
						tcCommand = &temp
					} else {
						vlog.Warningf("traffic control command will igore by priority. command : %v", c)
					}
				case CMDDegrade:
					temp := c
					degradeCommand = &temp
				}
			}
		}
	}
	return tcCommand, degradeCommand
}

func (c *CommandRegistryWarper) NotifyCommand(registryURL *motan.URL, commandType int, commandInfo string) {
	vlog.Infof("%s receive Command notify. type:%d, command:%s\n", c.cluster.GetURL().GetIdentity(), commandType, commandInfo)
	neednotify := c.processCommand(commandType, commandInfo)
	if neednotify {
		c.getResultWithCommand(neednotify)
	}
}

func (c *CommandRegistryWarper) Notify(registryURL *motan.URL, urls []*motan.URL) {
	vlog.Infof("CommandRegistryWarper notify urls size is %d. refer: %v, registry: %v\n", len(urls), c.cluster.GetURL(), registryURL)
	c.ownGroupURLs = urls
	neednotify := false
	if c.tcCommand != nil {
		for _, group := range c.tcCommand.MergeGroups {
			g := strings.Split(group, ":")
			if g[0] == c.cluster.GetURL().Group {
				neednotify = true
			}
		}
	} else {
		neednotify = true
	}

	if neednotify {
		c.getResultWithCommand(neednotify)
	}
}

func (c *CommandRegistryWarper) SetURL(url *motan.URL) {
	c.registry.SetURL(url)
}

func (c *CommandRegistryWarper) GetName() string {
	return "commandwarp:" + c.registry.GetName()
}

func (c *CommandRegistryWarper) GetIdentity() string {
	return c.notifyListener.GetIdentity()
}


<|start_filename|>vendor/github.com/libp2p/go-floodsub/pb/rpc.pb.go<|end_filename|>
// Code generated by protoc-gen-gogo.
// source: rpc.proto
// DO NOT EDIT!

/*
Package floodsub_pb is a generated protocol buffer package.

It is generated from these files:
	rpc.proto

It has these top-level messages:
	RPC
	Message
	TopicDescriptor
*/
package floodsub_pb

import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

type TopicDescriptor_AuthOpts_AuthMode int32

const (
	TopicDescriptor_AuthOpts_NONE TopicDescriptor_AuthOpts_AuthMode = 0
	TopicDescriptor_AuthOpts_KEY  TopicDescriptor_AuthOpts_AuthMode = 1
	TopicDescriptor_AuthOpts_WOT  TopicDescriptor_AuthOpts_AuthMode = 2
)

var TopicDescriptor_AuthOpts_AuthMode_name = map[int32]string{
	0: "NONE",
	1: "KEY",
	2: "WOT",
}
var TopicDescriptor_AuthOpts_AuthMode_value = map[string]int32{
	"NONE": 0,
	"KEY":  1,
	"WOT":  2,
}

func (x TopicDescriptor_AuthOpts_AuthMode) Enum() *TopicDescriptor_AuthOpts_AuthMode {
	p := new(TopicDescriptor_AuthOpts_AuthMode)
	*p = x
	return p
}
func (x TopicDescriptor_AuthOpts_AuthMode) String() string {
	return proto.EnumName(TopicDescriptor_AuthOpts_AuthMode_name, int32(x))
}
func (x *TopicDescriptor_AuthOpts_AuthMode) UnmarshalJSON(data []byte) error {
	value, err := proto.UnmarshalJSONEnum(TopicDescriptor_AuthOpts_AuthMode_value, data, "TopicDescriptor_AuthOpts_AuthMode")
	if err != nil {
		return err
	}
	*x = TopicDescriptor_AuthOpts_AuthMode(value)
	return nil
}

type TopicDescriptor_EncOpts_EncMode int32

const (
	TopicDescriptor_EncOpts_NONE      TopicDescriptor_EncOpts_EncMode = 0
	TopicDescriptor_EncOpts_SHAREDKEY TopicDescriptor_EncOpts_EncMode = 1
	TopicDescriptor_EncOpts_WOT       TopicDescriptor_EncOpts_EncMode = 2
)

var TopicDescriptor_EncOpts_EncMode_name = map[int32]string{
	0: "NONE",
	1: "SHAREDKEY",
	2: "WOT",
}
var TopicDescriptor_EncOpts_EncMode_value = map[string]int32{
	"NONE":      0,
	"SHAREDKEY": 1,
	"WOT":       2,
}

func (x TopicDescriptor_EncOpts_EncMode) Enum() *TopicDescriptor_EncOpts_EncMode {
	p := new(TopicDescriptor_EncOpts_EncMode)
	*p = x
	return p
}
func (x TopicDescriptor_EncOpts_EncMode) String() string {
	return proto.EnumName(TopicDescriptor_EncOpts_EncMode_name, int32(x))
}
func (x *TopicDescriptor_EncOpts_EncMode) UnmarshalJSON(data []byte) error {
	value, err := proto.UnmarshalJSONEnum(TopicDescriptor_EncOpts_EncMode_value, data, "TopicDescriptor_EncOpts_EncMode")
	if err != nil {
		return err
	}
	*x = TopicDescriptor_EncOpts_EncMode(value)
	return nil
}

type RPC struct {
	Subscriptions    []*RPC_SubOpts `protobuf:"bytes,1,rep,name=subscriptions" json:"subscriptions,omitempty"`
	Publish          []*Message     `protobuf:"bytes,2,rep,name=publish" json:"publish,omitempty"`
	XXX_unrecognized []byte         `json:"-"`
}

func (m *RPC) Reset()         { *m = RPC{} }
func (m *RPC) String() string { return proto.CompactTextString(m) }
func (*RPC) ProtoMessage()    {}

func (m *RPC) GetSubscriptions() []*RPC_SubOpts {
	if m != nil {
		return m.Subscriptions
	}
	return nil
}

func (m *RPC) GetPublish() []*Message {
	if m != nil {
		return m.Publish
	}
	return nil
}

type RPC_SubOpts struct {
	Subscribe        *bool   `protobuf:"varint,1,opt,name=subscribe" json:"subscribe,omitempty"`
	Topicid          *string `protobuf:"bytes,2,opt,name=topicid" json:"topicid,omitempty"`
	XXX_unrecognized []byte  `json:"-"`
}

func (m *RPC_SubOpts) Reset()         { *m = RPC_SubOpts{} }
func (m *RPC_SubOpts) String() string { return proto.CompactTextString(m) }
func (*RPC_SubOpts) ProtoMessage()    {}

func (m *RPC_SubOpts) GetSubscribe() bool {
	if m != nil && m.Subscribe != nil {
		return *m.Subscribe
	}
	return false
}

func (m *RPC_SubOpts) GetTopicid() string {
	if m != nil && m.Topicid != nil {
		return *m.Topicid
	}
	return ""
}

type Message struct {
	From             []byte   `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"`
	Data             []byte   `protobuf:"bytes,2,opt,name=data" json:"data,omitempty"`
	Seqno            []byte   `protobuf:"bytes,3,opt,name=seqno" json:"seqno,omitempty"`
	TopicIDs         []string `protobuf:"bytes,4,rep,name=topicIDs" json:"topicIDs,omitempty"`
	XXX_unrecognized []byte   `json:"-"`
}

func (m *Message) Reset()         { *m = Message{} }
func (m *Message) String() string { return proto.CompactTextString(m) }
func (*Message) ProtoMessage()    {}

func (m *Message) GetFrom() []byte {
	if m != nil {
		return m.From
	}
	return nil
}

func (m *Message) GetData() []byte {
	if m != nil {
		return m.Data
	}
	return nil
}

func (m *Message) GetSeqno() []byte {
	if m != nil {
		return m.Seqno
	}
	return nil
}

func (m *Message) GetTopicIDs() []string {
	if m != nil {
		return m.TopicIDs
	}
	return nil
}

// topicID = hash(topicDescriptor); (not the topic.name)
type TopicDescriptor struct {
	Name             *string                   `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
	Auth             *TopicDescriptor_AuthOpts `protobuf:"bytes,2,opt,name=auth" json:"auth,omitempty"`
	Enc              *TopicDescriptor_EncOpts  `protobuf:"bytes,3,opt,name=enc" json:"enc,omitempty"`
	XXX_unrecognized []byte                    `json:"-"`
}

func (m *TopicDescriptor) Reset()         { *m = TopicDescriptor{} }
func (m *TopicDescriptor) String() string { return proto.CompactTextString(m) }
func (*TopicDescriptor) ProtoMessage()    {}

func (m *TopicDescriptor) GetName() string {
	if m != nil && m.Name != nil {
		return *m.Name
	}
	return ""
}

func (m *TopicDescriptor) GetAuth() *TopicDescriptor_AuthOpts {
	if m != nil {
		return m.Auth
	}
	return nil
}

func (m *TopicDescriptor) GetEnc() *TopicDescriptor_EncOpts {
	if m != nil {
		return m.Enc
	}
	return nil
}

type TopicDescriptor_AuthOpts struct {
	Mode             *TopicDescriptor_AuthOpts_AuthMode `protobuf:"varint,1,opt,name=mode,enum=floodsub.pb.TopicDescriptor_AuthOpts_AuthMode" json:"mode,omitempty"`
	Keys             [][]byte                           `protobuf:"bytes,2,rep,name=keys" json:"keys,omitempty"`
	XXX_unrecognized []byte                             `json:"-"`
}

func (m *TopicDescriptor_AuthOpts) Reset()         { *m = TopicDescriptor_AuthOpts{} }
func (m *TopicDescriptor_AuthOpts) String() string { return proto.CompactTextString(m) }
func (*TopicDescriptor_AuthOpts) ProtoMessage()    {}

func (m *TopicDescriptor_AuthOpts) GetMode() TopicDescriptor_AuthOpts_AuthMode {
	if m != nil && m.Mode != nil {
		return *m.Mode
	}
	return TopicDescriptor_AuthOpts_NONE
}

func (m *TopicDescriptor_AuthOpts) GetKeys() [][]byte {
	if m != nil {
		return m.Keys
	}
	return nil
}

type TopicDescriptor_EncOpts struct {
	Mode             *TopicDescriptor_EncOpts_EncMode `protobuf:"varint,1,opt,name=mode,enum=floodsub.pb.TopicDescriptor_EncOpts_EncMode" json:"mode,omitempty"`
	KeyHashes        [][]byte                         `protobuf:"bytes,2,rep,name=keyHashes" json:"keyHashes,omitempty"`
	XXX_unrecognized []byte                           `json:"-"`
}

func (m *TopicDescriptor_EncOpts) Reset()         { *m = TopicDescriptor_EncOpts{} }
func (m *TopicDescriptor_EncOpts) String() string { return proto.CompactTextString(m) }
func (*TopicDescriptor_EncOpts) ProtoMessage()    {}

func (m *TopicDescriptor_EncOpts) GetMode() TopicDescriptor_EncOpts_EncMode {
	if m != nil && m.Mode != nil {
		return *m.Mode
	}
	return TopicDescriptor_EncOpts_NONE
}

func (m *TopicDescriptor_EncOpts) GetKeyHashes() [][]byte {
	if m != nil {
		return m.KeyHashes
	}
	return nil
}

func init() {
	proto.RegisterType((*RPC)(nil), "floodsub.pb.RPC")
	proto.RegisterType((*RPC_SubOpts)(nil), "floodsub.pb.RPC.SubOpts")
	proto.RegisterType((*Message)(nil), "floodsub.pb.Message")
	proto.RegisterType((*TopicDescriptor)(nil), "floodsub.pb.TopicDescriptor")
	proto.RegisterType((*TopicDescriptor_AuthOpts)(nil), "floodsub.pb.TopicDescriptor.AuthOpts")
	proto.RegisterType((*TopicDescriptor_EncOpts)(nil), "floodsub.pb.TopicDescriptor.EncOpts")
	proto.RegisterEnum("floodsub.pb.TopicDescriptor_AuthOpts_AuthMode", TopicDescriptor_AuthOpts_AuthMode_name, TopicDescriptor_AuthOpts_AuthMode_value)
	proto.RegisterEnum("floodsub.pb.TopicDescriptor_EncOpts_EncMode", TopicDescriptor_EncOpts_EncMode_name, TopicDescriptor_EncOpts_EncMode_value)
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/flex_cancel.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import "github.com/ethereum/go-ethereum/common"

type FlexCancelType uint8

const (
	FLEX_CANCEL_BY_HASH   FlexCancelType = 1
	FLEX_CANCEL_BY_OWNER  FlexCancelType = 2
	FLEX_CANCEL_BY_TIME   FlexCancelType = 3
	FLEX_CANCEL_BY_MARKET FlexCancelType = 4
)

type FlexCancelOrderEvent struct {
	Owner      common.Address `json:"owner"`
	OrderHash  common.Hash    `json:"order_hash"`
	CutoffTime int64          `json:"cutoff_time"`
	TokenS     common.Address `json:"token_s"`
	TokenB     common.Address `json:"token_b"`
	Type       FlexCancelType `json:"type"`
}


<|start_filename|>vendor/github.com/Loopring/motan-go/cluster/motanCluster.go<|end_filename|>
package cluster

import (
	"errors"
	"fmt"
	"strings"
	"sync"

	motan "github.com/Loopring/motan-go/core"
	"github.com/Loopring/motan-go/log"
)

type MotanCluster struct {
	Context        *motan.Context
	url            *motan.URL
	Registrys      []motan.Registry
	HaStrategy     motan.HaStrategy
	LoadBalance    motan.LoadBalance
	Refers         []motan.EndPoint
	Filters        []motan.Filter
	clusterFilter  motan.ClusterFilter
	extFactory     motan.ExtentionFactory
	registryRefers map[string][]motan.EndPoint
	notifyLock     sync.Mutex
	available      bool
	closed         bool
	proxy          bool
}

func (m *MotanCluster) IsAvailable() bool {
	return m.available
}

func NewCluster(url *motan.URL, proxy bool) *MotanCluster {
	cluster := &MotanCluster{url: url, proxy: proxy}
	return cluster
}

func (m *MotanCluster) GetName() string {
	return "MotanCluster"
}

func (m *MotanCluster) GetURL() *motan.URL {
	return m.url
}

func (m *MotanCluster) SetURL(url *motan.URL) {
	m.url = url
}
func (m *MotanCluster) Call(request motan.Request) motan.Response {
	if m.available {
		return m.clusterFilter.Filter(m.HaStrategy, m.LoadBalance, request)
	}
	vlog.Infoln("cluster:" + m.GetIdentity() + "is not available!")
	return motan.BuildExceptionResponse(request.GetRequestID(), &motan.Exception{ErrCode: 500, ErrMsg: "service cluster not available. maybe caused by degrade.", ErrType: motan.ServiceException})
}
func (m *MotanCluster) InitCluster() bool {
	m.registryRefers = make(map[string][]motan.EndPoint)
	//ha
	m.HaStrategy = m.extFactory.GetHa(m.url)
	//lb
	m.LoadBalance = m.extFactory.GetLB(m.url)
	//filter
	m.initFilters()
	// parse registry and subscribe
	m.parseRegistry()

	if m.clusterFilter == nil {
		m.clusterFilter = motan.GetLastClusterFilter()
	}
	if m.Filters == nil {
		m.Filters = make([]motan.Filter, 0)
	}
	//TODO weather has available refers
	m.available = true
	m.closed = false
	vlog.Infof("init MotanCluster %s\n", m.GetIdentity())

	return true
}
func (m *MotanCluster) SetLoadBalance(loadBalance motan.LoadBalance) {
	m.LoadBalance = loadBalance
}
func (m *MotanCluster) SetHaStrategy(haStrategy motan.HaStrategy) {
	m.HaStrategy = haStrategy
}
func (m *MotanCluster) GetRefers() []motan.EndPoint {
	return m.Refers
}
func (m *MotanCluster) refresh() {
	newRefers := make([]motan.EndPoint, 0, 32)
	for _, v := range m.registryRefers {
		for _, e := range v {
			newRefers = append(newRefers, e)
		}
	}
	m.Refers = newRefers
	m.LoadBalance.OnRefresh(newRefers)
}
func (m *MotanCluster) AddRegistry(registry motan.Registry) {
	m.Registrys = append(m.Registrys, registry)
}
func (m *MotanCluster) Notify(registryURL *motan.URL, urls []*motan.URL) {
	vlog.Infof("cluster %s receive notify size %d. \n", m.GetIdentity(), len(urls))
	m.notifyLock.Lock()
	defer m.notifyLock.Unlock()
	// process weight if has
	urls = processWeight(m, urls)
	endpoints := make([]motan.EndPoint, 0, len(urls))
	endpointMap := make(map[string]motan.EndPoint)
	if eps, ok := m.registryRefers[registryURL.GetIdentity()]; ok {
		for _, ep := range eps {
			endpointMap[ep.GetURL().GetIdentity()] = ep
		}
	}

	for _, u := range urls {
		if u == nil {
			vlog.Errorln("cluster receive nil url!")
			continue
		}
		vlog.Infof("cluster %s received notify url:%s:%d\n", m.GetIdentity(), u.Host, u.Port)
		if !u.CanServe(m.url) {
			vlog.Infof("cluster notify:can not use server:%+v\n", u)
			continue
		}
		var ep motan.EndPoint
		if tempEp, ok := endpointMap[u.GetIdentity()]; ok {
			ep = tempEp
			delete(endpointMap, u.GetIdentity())
		}
		if ep == nil {
			newURL := u.Copy()
			newURL.MergeParams(m.url.Parameters)
			ep = m.extFactory.GetEndPoint(newURL)

			if ep != nil {
				ep.SetProxy(m.proxy)
				serialization := motan.GetSerialization(newURL, m.extFactory)
				if serialization == nil {
					vlog.Warningf("MotanCluster can not find Serialization in DefaultExtentionFactory! url:%+v\n", m.url)
				} else {
					ep.SetSerialization(serialization)
				}
				motan.Initialize(ep)
				ep = m.addFilter(ep, m.Filters)
			}
		}

		if ep != nil {
			endpoints = append(endpoints, ep)
		}
	}
	if len(endpoints) == 0 {
		if len(m.registryRefers) > 1 {
			delete(m.registryRefers, registryURL.GetIdentity())
		} else {
			// notify will ignored if endpoints size is 0 in single regisry mode
			vlog.Infof("cluster %s notify endpoint is 0. notify ignored.\n", m.GetIdentity())
			return
		}
	} else {
		m.registryRefers[registryURL.GetIdentity()] = endpoints
	}
	m.refresh()
	for _, ep := range endpointMap {
		ep.Destroy()
	}
}

// remove rule protocol && set weight
func processWeight(m *MotanCluster, urls []*motan.URL) []*motan.URL {
	weight := ""
	if len(urls) > 0 && urls[len(urls)-1] != nil && urls[len(urls)-1].Protocol == "rule" {
		url := urls[len(urls)-1]
		weight = url.Parameters["weight"]
		urls = urls[:len(urls)-1]
	}
	m.LoadBalance.SetWeight(weight)
	return urls
}

func (m *MotanCluster) addFilter(ep motan.EndPoint, filters []motan.Filter) motan.EndPoint {
	fep := &motan.FilterEndPoint{URL: ep.GetURL(), Caller: ep}
	statusFilters := make([]motan.Status, 0, len(filters))
	var lastf motan.EndPointFilter
	lastf = motan.GetLastEndPointFilter()
	for _, f := range filters {
		if ef, ok := f.NewFilter(ep.GetURL()).(motan.EndPointFilter); ok {
			motan.CanSetContext(ef, m.Context)
			ef.SetNext(lastf)
			lastf = ef
			if sf, ok := ef.(motan.Status); ok {
				statusFilters = append(statusFilters, sf)
			}
		}
	}
	fep.StatusFilters = statusFilters
	fep.Filter = lastf
	return fep
}
func (m *MotanCluster) GetIdentity() string {
	return m.url.GetIdentity()
}
func (m *MotanCluster) Destroy() {
	if !m.closed {
		m.notifyLock.Lock()
		defer m.notifyLock.Unlock()
		vlog.Infof("cluster %s will destroy.\n", m.url.GetIdentity())
		for _, r := range m.Registrys {
			vlog.Infof("unsubscribe from registry %s .\n", r.GetURL().GetIdentity())
			r.Unsubscribe(m.url, m)
		}
		for _, e := range m.Refers {
			vlog.Infof("destroy endpoint %s .\n", e.GetURL().GetIdentity())
			e.Destroy()
		}
		m.closed = true
	}
}

func (m *MotanCluster) SetExtFactory(factory motan.ExtentionFactory) {
	m.extFactory = factory
}

func (m *MotanCluster) parseRegistry() (err error) {
	regs, ok := m.url.Parameters[motan.RegistryKey]
	if !ok {
		errInfo := fmt.Sprintf("registry not found! url %+v", m.url)
		err = errors.New(errInfo)
		vlog.Errorln(errInfo)
	}
	arr := strings.Split(regs, ",")
	registries := make([]motan.Registry, 0, len(arr))
	for _, r := range arr {
		if registryURL, ok := m.Context.RegistryURLs[r]; ok {
			registry := m.extFactory.GetRegistry(registryURL)
			if registry != nil {
				if _, ok := registry.(motan.DiscoverCommand); ok {
					registry = GetCommandRegistryWarper(m, registry)
				}
				registry.Subscribe(m.url, m)
				registries = append(registries, registry)
				urls := registry.Discover(m.url)
				m.Notify(registryURL, urls)
			}
		} else {
			err = errors.New("registry is invalid: " + r)
			vlog.Errorln("registry is invalid: " + r)
		}

	}
	m.Registrys = registries
	return err
}

func (m *MotanCluster) initFilters() {
	clusterFilter, endpointFilters := motan.GetURLFilters(m.url, m.extFactory)
	if clusterFilter != nil {
		m.clusterFilter = clusterFilter
	}
	if len(endpointFilters) > 0 {
		m.Filters = endpointFilters
	}
}

func (m *MotanCluster) NotifyAgentCommand(commandInfo string) {
	for _, reg := range m.Registrys {
		if notifyRegisry, ok := reg.(motan.CommandNotifyListener); ok {
			notifyRegisry.NotifyCommand(m.url, AgentCmd, commandInfo)
		}
	}
}


<|start_filename|>gateway/socket_node.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 gateway

type SocketNode struct {
	clients    map[*SocketClient]bool
	broadcast  chan []byte
	register   chan *SocketClient
	unregister chan *SocketClient
}

func newSocketNode() *SocketNode {
	return &SocketNode{
		broadcast:  make(chan []byte),
		register:   make(chan *SocketClient),
		unregister: make(chan *SocketClient),
		clients:    make(map[*SocketClient]bool),
	}
}

func (h *SocketNode) run() {
	for {
		select {
		case client := <-h.register:
			h.clients[client] = true
		case client := <-h.unregister:
			if _, ok := h.clients[client]; ok {
				delete(h.clients, client)
				close(client.send)
			}
		case message := <-h.broadcast:
			for client := range h.clients {
				select {
				case client.send <- message:
				default:
					close(client.send)
					delete(h.clients, client)
				}
			}
		}
	}
}


<|start_filename|>market/trendmanager_test.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 market_test

//import (
//	"fmt"
//	"github.com/Loopring/relay-cluster/dao"
//	//"github.com/Loopring/relay-cluster/eventemiter"
//	"github.com/Loopring/relay-cluster/market"
//	"github.com/Loopring/relay-cluster/test"
//	//"github.com/Loopring/relay-cluster/types"
//	//"github.com/ethereum/go-ethereum/common"
//	//"math/big"
//	"testing"
//	//"time"
//	"time"
//	//"github.com/ethereum/go-ethereum/common"
//	"github.com/Loopring/relay-cluster/gateway"
//	"github.com/Loopring/relay-cluster/market/util"
//	"github.com/Loopring/relay-cluster/marketcap"
//	"github.com/Loopring/relay-cluster/ordermanager"
//	"github.com/Loopring/relay-cluster/types"
//	"github.com/Loopring/relay-cluster/usermanager"
//	"math/big"
//)
//
//var (
//	tm *market.TrendManager
//	bf *gateway.BaseFilter
//)
//
//func prepare() {
//	//fmt.Println("yyyyyyyyyy")
//	globalConfig := test.LoadConfig()
//	//fmt.Println(globalConfig)
//	fmt.Println("11111111111======================================")
//	rdsService := dao.NewRdsService(globalConfig.Mysql)
//	userManager := usermanager.NewUserManager(&globalConfig.UserManager, rdsService)
//	marketCapProvider := marketcap.NewMarketCapProvider(globalConfig.MarketCap)
//	orderManager := ordermanager.NewOrderManager(&globalConfig.OrderManager, rdsService, userManager, marketCapProvider)
//	gateway.Initialize(&globalConfig.GatewayFilters, &globalConfig.Gateway, &globalConfig.Ipfs, orderManager, marketCapProvider)
//	baseFilter := &gateway.BaseFilter{
//		MinLrcFee:             big.NewInt(globalConfig.GatewayFilters.BaseFilter.MinLrcFee),
//		MaxPrice:              big.NewInt(globalConfig.GatewayFilters.BaseFilter.MaxPrice),
//		MinSplitPercentage:    globalConfig.GatewayFilters.BaseFilter.MinSplitPercentage,
//		MaxSplitPercentage:    globalConfig.GatewayFilters.BaseFilter.MaxSplitPercentage,
//		MinTokeSAmount:        make(map[string]*big.Int),
//		MinTokenSUsdAmount:    globalConfig.GatewayFilters.BaseFilter.MinTokenSUsdAmount,
//		MaxValidSinceInterval: globalConfig.GatewayFilters.BaseFilter.MaxValidSinceInterval,
//	}
//	for k, v := range globalConfig.GatewayFilters.BaseFilter.MinTokeSAmount {
//		minAmount := big.NewInt(0)
//		amount, succ := minAmount.SetString(v, 10)
//		if succ {
//			baseFilter.MinTokeSAmount[k] = amount
//		}
//	}
//
//	fmt.Println("ksdfjlsdjflksdjfkjdsklfjklsdjf")
//	fmt.Println(baseFilter)
//	bf = baseFilter
//
//}
//
//func TestTrendManager_GetTicker(t *testing.T) {
//
//	//fmt.Println("ZZZZZZZZZZZZZZZZZZZZZZZZZZ")
//	prepare()
//
//	order := types.Order{}
//	order.AmountS = big.NewInt(1000000)
//	order.LrcFee = big.NewInt(500000000000000000)
//	order.TokenS = util.AllTokens["RDN"].Protocol
//	order.TokenB = util.AllTokens["WETH"].Protocol
//	amountS := big.NewInt(0)
//	amountS.SetString("3800000000000000000", 10)
//	order.AmountS = amountS
//	order.AmountB = big.NewInt(100000000000000)
//	now := time.Now().Unix() + 3558
//	order.ValidUntil = big.NewInt(time.Now().Unix() + 3)
//	order.ValidSince = big.NewInt(now)
//	order.GeneratePrice()
//	order.MarginSplitPercentage = 20
//
//	fmt.Println(bf.Filter(&order))
//
//	//fmt.Println(tm.GetTrends("RDN-WETH", "1Hr"))
//	//fmt.Println(tm.GetTrends("LRC-WETH", "1Hr"))
//	//fmt.Println(tm.GetTrends("LRC-WETH", "2Hr"))
//	//fill := &types.OrderFilledEvent{}
//	//fill.Market = "LRC-WETH"
//	//fill.TxInfo.Protocol = common.HexToAddress("0xC01172a87f6cC20E1E3b9aD13a9E715Fbc2D5AA9")
//	//fill.Owner = common.HexToAddress("0x750aD4351bB728ceC7d639A9511F9D6488f1E259")
//	//fill.RingIndex = big.NewInt(26)
//	//fill.TxInfo.BlockNumber = big.NewInt(38811)
//	//fill.TokenS = common.HexToAddress("0xfe5aFA7BfF3394359af2D277aCc9f00065CdBe2f")
//	//fill.TokenB = common.HexToAddress("0x88699e7FEE2Da0462981a08a15A3B940304CC516")
//	//fill.SplitS = big.NewInt(0)
//	//fill.SplitB = big.NewInt(0)
//	//fill.LrcReward = big.NewInt(0)
//	//fill.LrcFee = big.NewInt(0)
//	//fill.AmountS = big.NewInt(11000000000000)
//	//fill.AmountB = big.NewInt(22000000000000000)
//	//fill.OrderHash = common.HexToHash("0xc9b1edd3af78055d565731846ca7f43d0fb1985898ac1c77b6a7723f7df5491e")
//	//fill.NextOrderHash = common.HexToHash("0x739a06fc7db957605a8727b21e273606bbfe1ebbbf7d5c758e8f87ae6a05657f")
//	//fill.PreOrderHash = common.HexToHash("0x739a06fc7db957605a8727b21e273606bbfe1ebbbf7d5c758e8f87ae6a05657f")
//	//fill.TxHash = common.HexToHash("0xc91f52ccfc73f592706ac30108dbb5853cf4a380a2ff3407c78f8b8b59599e6c")
//	//fill.Ringhash = common.HexToHash("0xa3ebd7c6b39aea8beaf6554ca167bf41be69ab78f347cfbc9a7a11e61f40e8be")
//	//fill.FillIndex = big.NewInt(10)
//	//
//	//eventemitter.Emit(eventemitter.OrderManagerExtractorFill, fill)
//	//time.Sleep(3 * time.Second)
//	//fill.AmountS = big.NewInt(10000000000000)
//	//fill.AmountB = big.NewInt(25000000000000000)
//	//eventemitter.Emit(eventemitter.OrderManagerExtractorFill, fill)
//	//time.Sleep(3 * time.Second)
//	////tm.InsertTrend()
//	//fmt.Println("xxxxxxxxxxx")
//	//tds, _ := tm.GetTrends("LRC-WETH", "2Hr")
//	//fmt.Println(tds)
//	//fmt.Println(tm.GetTicker())
//
//	fmt.Println("------------------------------------------> check finished")
//	time.Sleep(60 * 60 * time.Second)
//
//}


<|start_filename|>market/tickercollector.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 market

import (
	"encoding/json"
	"fmt"
	"github.com/Loopring/relay-lib/cache"
	"github.com/Loopring/relay-lib/log"
	util "github.com/Loopring/relay-lib/marketutil"
	"github.com/Loopring/relay-lib/sns"
	"github.com/Loopring/relay-lib/zklock"
	gocache "github.com/patrickmn/go-cache"
	"github.com/robfig/cron"
	"io/ioutil"
	"net/http"
	"qiniupkg.com/x/errors.v7"
	"strconv"
	"strings"
	"time"
)

type ExchangeType string

const (
	binance = "binance"
	okex    = "okex"
	huobi   = "huobi"
)

// only support eth market now
var supportedMarkets = make([]string, 0)

const cachePreKey = "TICKER_EX_"

//TODO (xiaolu)  add more exchanges to this list
var exchanges = map[string]string{
	binance: "https://api.binance.com/api/v1/ticker/24hr?symbol=%s",
	okex:    "https://www.okex.com/api/v1/ticker.do?symbol=%s",
	huobi:   "https://api.huobi.pro/market/detail/merged?symbol=%s",
}

const defaultSyncInterval = 5 // minutes
const tickerCollectorCronJobZkLock = "tickerCollectorZkLock"
const tryLockFailedMsg = "ticker collector try lock failed"

type Exchange interface {
	updateCache()
}

type TickerField struct {
	key   []byte
	value []byte
}

type ExchangeImpl struct {
	name      string
	tickerUrl string
}

type Collector interface {
	getTickers(market string) ([]Ticker, error)
	Start()
}

type CollectorImpl struct {
	exs          []ExchangeImpl
	syncInterval int
	cron         *cron.Cron
	localCache   *gocache.Cache
}

func NewExchange(name, tickerUrl string) ExchangeImpl {
	return ExchangeImpl{name, tickerUrl}
}

func (e *ExchangeImpl) updateCache() {
	log.Info("step in update cache method........")

	switch e.name {
	case binance:
		updateCacheByExchange(e.name, GetTickerFromBinance)
	case okex:
		updateCacheByExchange(e.name, GetTickerFromOkex)
	case huobi:
		updateCacheByExchange(e.name, GetTickerFromHuobi)
	}
}

func mockUpdateCache() {
	tickers := make([]Ticker, 0)
	t1 := Ticker{Market: "LRC-WETH", Amount: 0.001}
	t2 := Ticker{Market: "LRC-WETH", Amount: 0.003}
	t3 := Ticker{Market: "FOO-BAR", Amount: 0.002}
	tickers = append(tickers, t1)
	tickers = append(tickers, t2)
	tickers = append(tickers, t3)
	var err error
	if err == nil && len(tickers) > 0 {
		tkFields := make([]TickerField, 0)
		for _, t := range tickers {
			tkField, err := buildTickerField(t.Market, t)
			if err == nil {
				tkFields = append(tkFields, tkField)
			}
			//setCache(binance, t.Market, t)
		}
		setHMCache(binance, tkFields)
		t11, _ := buildTickerField(t1.Market, t1)
		setHMCache(okex, []TickerField{t11})
	}
}

func updateBinanceCache() {
	//updateCacheByExchange("binance", GetTickerFromBinance)
	tickers, err := GetAllTickerFromBinance()
	if err == nil && len(tickers) > 0 {
		tkFields := make([]TickerField, 0)
		for _, t := range tickers {
			tkField, err := buildTickerField(t.Market, t)
			if err == nil {
				tkFields = append(tkFields, tkField)
			}
			//setCache(binance, t.Market, t)
		}
		setHMCache(binance, tkFields)
	}
}
func updateOkexCache() {
	tickers, err := GetAllTickerFromOkex()
	if err == nil && len(tickers) > 0 {
		tkFields := make([]TickerField, 0)
		for _, t := range tickers {
			tkField, err := buildTickerField(t.Market, t)
			if err == nil {
				tkFields = append(tkFields, tkField)
			}
			//setCache(okex, t.Market, t)
		}
		setHMCache(okex, tkFields)
	}
}
func updateHuobiCache() {
	updateCacheByExchange(huobi, GetTickerFromHuobi)
}

func updateCacheByExchange(exchange string, getter func(mkt string) (ticker Ticker, err error)) {

	tkFields := make([]TickerField, 0)
	for _, v := range util.AllMarkets {

		if !stringInSlice(v, supportedMarkets) {
			continue
		}

		vv := strings.ToUpper(v)
		vv = strings.Replace(vv, "WETH", "ETH", 1)
		ticker, err := getter(vv)
		if err != nil {
			//log.Debug("get ticker error " + err.Error())
		} else {
			//setCache(exchange, v, ticker)
			tkField, err := buildTickerField(v, ticker)
			if err == nil {
				tkFields = append(tkFields, tkField)
			}
		}
	}
	setHMCache(exchange, tkFields)
}

func setCache(exchange, market string, ticker Ticker) {
	cacheKey := cachePreKey + exchange
	tickerByte, err := json.Marshal(ticker)
	if err != nil {
		log.Info("marshal ticker json error " + err.Error())
	} else {
		cache.Set(cacheKey, tickerByte, 3600)
	}
}

func buildTickerField(market string, ticker Ticker) (tf TickerField, err error) {

	if len(market) == 0 {
		return tf, errors.New("market is nil")
	}

	tickerByte, err := json.Marshal(ticker)
	if err != nil {
		log.Info("marshal ticker json error " + err.Error())
		return tf, err
	} else {
		return TickerField{key: []byte(market), value: tickerByte}, nil
	}
}

func setHMCache(exchange string, tickers []TickerField) {

	data := [][]byte{}

	for _, tk := range tickers {
		data = append(data, tk.key)
		data = append(data, tk.value)
	}

	cacheKey := cachePreKey + exchange
	cache.HMSet(cacheKey, 3600*24*30, data...)
}

func NewCollector() *CollectorImpl {
	rst := &CollectorImpl{exs: make([]ExchangeImpl, 0), syncInterval: defaultSyncInterval, cron: cron.New()}
	rst.localCache = gocache.New(5*time.Second, 5*time.Minute)
	for _, v := range util.AllMarkets {
		if strings.HasSuffix(v, "ETH") {
			supportedMarkets = append(supportedMarkets, v)
		}
	}

	for k, v := range exchanges {
		exchange := NewExchange(k, v)
		rst.exs = append(rst.exs, exchange)
	}
	return rst
}

func (c *CollectorImpl) Start() {
	go func() {
		if zklock.TryLock(tickerCollectorCronJobZkLock) == nil {
			updateBinanceCache()
			updateOkexCache()
			updateHuobiCache()
			c.cron.AddFunc("@every 20s", updateBinanceCache)
			c.cron.AddFunc("@every 5s", updateOkexCache)
			c.cron.AddFunc("@every 5s", updateHuobiCache)
			log.Info("start collect cron jobs......... ")
			c.cron.Start()
		} else {
			err := sns.PublishSns(tryLockFailedMsg, tryLockFailedMsg)
			if err != nil {
				log.Error(err.Error())
			}
		}
	}()
}

func (c *CollectorImpl) GetTickers(market string) ([]Ticker, error) {

	result := make([]Ticker, 0)

	if len(market) <= 0 {
		return nil, errors.New("market can't be null")
	}

	for _, e := range c.exs {

		tkByteInLocal, ok := c.localCache.Get(e.name)
		if ok {
			//log.Infof("get ticker from local cache, ex : %s, market : %s", e.name, market)
			localTickers := tkByteInLocal.(map[string]Ticker)
			if _, ok := localTickers[market]; ok {
				result = append(result, localTickers[market])
			}
		} else {

			//log.Infof("get ticker from redis cache, ex : %s, market : %s", e.name, market)
			tickerMap, err := getAllMarketFromRedis(e.name)
			if err != nil {
				continue
			}

			v, ok := tickerMap[market]
			if ok {
				result = append(result, v)
			}

			c.localCache.Set(e.name, tickerMap, 5*time.Second)

			//cacheKey := cachePreKey + e.name + "_" + market
			//byteRst, err := cache.Get(cacheKey)
			//cacheKey := cachePreKey + e.name
			//byteRst, err := cache.HMGet(cacheKey, []byte(market))
			//if err == nil && len(byteRst) == 1 && len(byteRst[0]) > 0 {
			//	var unmarshalRst Ticker
			//	json.Unmarshal(byteRst[0], &unmarshalRst)
			//	result = append(result, unmarshalRst)
			//} else {
			//	//log.Info("get ticker from redis error" + err.Error())
			//}
		}

	}
	return result, nil
}

func getAllMarketFromRedis(exchange string) (tickers map[string]Ticker, err error) {
	keys := make([][]byte, 0)
	for _, m := range supportedMarkets {
		keys = append(keys, []byte(m))
	}

	if len(keys) == 0 {
		return nil, errors.New("no supported market found")
	}

	byteRst, err := cache.HMGet(cachePreKey+exchange, keys...)

	if err != nil {
		return nil, err
	}
	tickers = make(map[string]Ticker)
	if err == nil && len(byteRst) > 1 {
		for _, tb := range byteRst {
			if len(tb) == 0 {
				continue
			}
			var unmarshalRst Ticker
			json.Unmarshal(tb, &unmarshalRst)
			if len(unmarshalRst.Market) > 0 {
				tickers[unmarshalRst.Market] = unmarshalRst
			}
		}
	}
	return
}

type HuobiTicker struct {
	Timestamp int64            `json:"ts"`
	ErrorCode string           `json:"err-code"`
	Status    string           `json:"status"`
	Tick      HuobiInnerTicker `json:"tick"`
}

type HuobiInnerTicker struct {
	Close  float64   `json:"close"`
	Open   float64   `json:"open"`
	High   float64   `json:"high"`
	Low    float64   `json:"low"`
	Amount float64   `json:"amount"`
	Count  int       `json:"count"`
	Vol    float64   `json:"vol"`
	Ask    []float64 `json:"ask"`
	Bid    []float64 `json:"bid"`
}

type BinanceTicker struct {
	Symbol    string `json:"symbol"`
	Change    string `json:"priceChangePercent"`
	Close     string `json:"prevClosePrice"`
	Open      string `json:"openPrice"`
	High      string `json:"highPrice"`
	Low       string `json:"lowPrice"`
	LastPrice string `json:"lastPrice"`
	Amount    string `json:"volume"`
	Vol       string `json:"quoteVolume"`
	Ask       string `json:"askPrice"`
	Bid       string `json:"bidPrice"`
}

type OkexTicker struct {
	Date   string          `json:"date"`
	Ticker OkexInnerTicker `json:"ticker"`
}

type OkexInnerTicker struct {
	High      string `json:"high"`
	Low       string `json:"low"`
	LastPrice string `json:"last"`
	Vol       string `json:"vol"`
	Ask       string `json:"sell"`
	Bid       string `json:"buy"`
}

func GetTickerFromHuobi(market string) (ticker Ticker, err error) {

	huobiMarket := strings.Replace(market, "-", "", 1)
	huobiMarket = strings.ToLower(huobiMarket)
	url := fmt.Sprintf(exchanges[huobi], huobiMarket)
	resp, err := http.Get(url)
	if err != nil {
		return ticker, err
	}
	defer func() {
		if nil != resp && nil != resp.Body {
			resp.Body.Close()
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if nil != err {
		return ticker, err
	} else {
		var huobiTicker *HuobiTicker
		if err := json.Unmarshal(body, &huobiTicker); nil != err {
			return ticker, err
		} else {

			if huobiTicker.Status == "error" {
				return ticker, errors.New("get ticker from huobi error" + huobiTicker.ErrorCode)
			}

			ticker = Ticker{}
			innerTicker := huobiTicker.Tick
			ticker.Market = market
			ticker.Amount = innerTicker.Amount
			ticker.Open = innerTicker.Open
			ticker.Close = innerTicker.Close
			if len(innerTicker.Bid) > 0 {
				ticker.Last = innerTicker.Bid[0]
			}
			if ticker.Last-ticker.Open > 0 {
				ticker.Change = fmt.Sprintf("+%.2f%%", 100*(ticker.Last-ticker.Open)/ticker.Open)
			} else {
				ticker.Change = fmt.Sprintf("%.2f%%", 100*(ticker.Last-ticker.Open)/ticker.Open)
			}
			ticker.Exchange = huobi
			ticker.Vol = innerTicker.Vol
			ticker.High = innerTicker.High
			ticker.Low = innerTicker.Low

			return ticker, nil
		}
	}
}

func GetTickerFromBinance(market string) (ticker Ticker, err error) {

	binanceMarket := strings.Replace(market, "-", "", 1)
	binanceMarket = strings.ToUpper(binanceMarket)
	url := fmt.Sprintf(exchanges[binance], binanceMarket)

	resp, err := http.Get(url)
	if err != nil {
		return ticker, err
	}
	defer func() {
		if nil != resp && nil != resp.Body {
			resp.Body.Close()
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if nil != err {
		return ticker, err
	} else {
		var binanceTicker *BinanceTicker
		if err := json.Unmarshal(body, &binanceTicker); nil != err {
			return ticker, err
		} else {
			ticker = Ticker{}
			//ticker.Market = market
			ticker.Market = market
			ticker.Amount, _ = strconv.ParseFloat(binanceTicker.Amount, 64)
			ticker.Open, _ = strconv.ParseFloat(binanceTicker.Open, 64)
			ticker.Close, _ = strconv.ParseFloat(binanceTicker.Close, 64)
			ticker.Last, _ = strconv.ParseFloat(binanceTicker.LastPrice, 64)
			change, _ := strconv.ParseFloat(binanceTicker.Change, 64)
			if change > 0 {
				ticker.Change = fmt.Sprintf("+%.2f%%", change)
			} else {
				ticker.Change = fmt.Sprintf("%.2f%%", change)
			}
			ticker.Exchange = binance
			ticker.Vol, _ = strconv.ParseFloat(binanceTicker.Vol, 64)
			ticker.High, _ = strconv.ParseFloat(binanceTicker.High, 64)
			ticker.Low, _ = strconv.ParseFloat(binanceTicker.Low, 64)
			return ticker, nil
		}
	}
}

func GetAllTickerFromBinance() (tickers []Ticker, err error) {

	resp, err := http.Get("https://api.binance.com/api/v1/ticker/24hr")
	if err != nil {
		return tickers, err
	}
	defer func() {
		if nil != resp && nil != resp.Body {
			resp.Body.Close()
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if nil != err {
		return tickers, err
	} else {
		var binanceTickers []BinanceTicker
		if err := json.Unmarshal(body, &binanceTickers); nil != err {
			return tickers, err
		} else {

			if len(binanceTickers) == 0 {
				return tickers, errors.New("fetch ticker from binance failed")
			}

			tickers = make([]Ticker, 0)
			for _, binanceTicker := range binanceTickers {

				if !strings.HasSuffix(binanceTicker.Symbol, "ETH") {
					// only handle eth market tickers
					continue
				}

				ticker := Ticker{}
				//ticker.Market = market
				marketPre := binanceTicker.Symbol[0 : len(binanceTicker.Symbol)-len("ETH")]

				ticker.Market = marketPre + "-" + "WETH"
				ticker.Amount, _ = strconv.ParseFloat(binanceTicker.Amount, 64)
				ticker.Open, _ = strconv.ParseFloat(binanceTicker.Open, 64)
				ticker.Close, _ = strconv.ParseFloat(binanceTicker.Close, 64)
				ticker.Last, _ = strconv.ParseFloat(binanceTicker.LastPrice, 64)
				change, _ := strconv.ParseFloat(binanceTicker.Change, 64)
				if change > 0 {
					ticker.Change = fmt.Sprintf("+%.2f%%", change)
				} else {
					ticker.Change = fmt.Sprintf("%.2f%%", change)
				}
				ticker.Exchange = binance
				ticker.Vol, _ = strconv.ParseFloat(binanceTicker.Vol, 64)
				ticker.High, _ = strconv.ParseFloat(binanceTicker.High, 64)
				ticker.Low, _ = strconv.ParseFloat(binanceTicker.Low, 64)
				tickers = append(tickers, ticker)
			}
			return tickers, nil
		}
	}
}

func GetTickerFromOkex(market string) (ticker Ticker, err error) {

	okexMarket := strings.Replace(market, "-", "_", 1)
	okexMarket = strings.ToLower(okexMarket)
	url := fmt.Sprintf(exchanges[okex], okexMarket)

	resp, err := http.Get(url)
	if err != nil {
		return ticker, err
	}
	defer func() {
		if nil != resp && nil != resp.Body {
			resp.Body.Close()
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if nil != err {
		return ticker, err
	} else {
		var okexOutTicker *OkexTicker
		if err := json.Unmarshal(body, &okexOutTicker); nil != err {
			return ticker, err
		} else {
			ticker = Ticker{}
			okexTicker := okexOutTicker.Ticker
			ticker.Market = market
			ticker.Last, _ = strconv.ParseFloat(okexTicker.LastPrice, 64)
			if 100*(ticker.Last-ticker.Open)/ticker.Open > 0 {
				ticker.Change = fmt.Sprintf("+%.2f%%", 100*(ticker.Last-ticker.Open)/ticker.Open)
			} else {
				ticker.Change = fmt.Sprintf("%.2f%%", 100*(ticker.Last-ticker.Open)/ticker.Open)
			}
			ticker.Exchange = okex
			ticker.Amount, _ = strconv.ParseFloat(okexTicker.Vol, 64)
			ticker.Vol = ticker.Amount * ticker.Last
			ticker.High, _ = strconv.ParseFloat(okexTicker.High, 64)
			ticker.Low, _ = strconv.ParseFloat(okexTicker.Low, 64)
			return ticker, nil
		}
	}
}

type OkexFullTicker struct {
	Code int              `json:"code"`
	Data []OkexTickerElem `json:"data"`
	Msg  string           `json:"msg"`
}

type OkexTickerElem struct {
	Buy    string `json:"buy"`
	Last   string `json:"last"`
	Vol    string `json:"volume"`
	Symbol string `json:"symbol"`
	High   string `json:"high"`
	Low    string `json:"low"`
	Change string `json:"changePercentage"`
}

func GetAllTickerFromOkex() (tickers []Ticker, err error) {
	tickers = make([]Ticker, 0)
	resp, err := http.Get("https://www.okex.com/v2/markets/tickers")
	if err != nil {
		return tickers, err
	}
	defer func() {
		if nil != resp && nil != resp.Body {
			resp.Body.Close()
		}
	}()

	body, err := ioutil.ReadAll(resp.Body)
	if nil != err {
		return tickers, err
	} else {
		var okexOutTicker *OkexFullTicker
		if err := json.Unmarshal(body, &okexOutTicker); nil != err {
			return tickers, err
		} else {

			for _, v := range okexOutTicker.Data {
				ticker := Ticker{}
				okexMarket := strings.Replace(v.Symbol, "_", "-", 1)
				okexMarket = strings.ToUpper(okexMarket)
				okexMarket = strings.Replace(okexMarket, "ETH", "WETH", 1)
				if stringInSlice(okexMarket, supportedMarkets) {
					ticker.Market = okexMarket
					ticker.Last, _ = strconv.ParseFloat(v.Last, 64)
					ticker.Change = v.Change
					ticker.Exchange = okex
					ticker.Amount, _ = strconv.ParseFloat(v.Vol, 64)
					ticker.Vol = ticker.Amount * ticker.Last
					ticker.High, _ = strconv.ParseFloat(v.High, 64)
					ticker.Low, _ = strconv.ParseFloat(v.Low, 64)
					tickers = append(tickers, ticker)
				}
			}

			return tickers, nil
		}
	}
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/eth/loopringaccessor/batch.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 loopringaccessor

import (
	ethtyp "github.com/Loopring/relay-lib/eth/types"
	"github.com/Loopring/relay-lib/types"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/rpc"
)

type BatchErc20Req struct {
	Owner          common.Address
	Token          common.Address
	Symbol         string
	Spender        common.Address
	BlockParameter string
	Balance        types.Big
	Allowance      types.Big
	BalanceErr     error
	AllowanceErr   error
}

type BatchBalanceReq struct {
	Owner          common.Address
	Token          common.Address
	BlockParameter string
	Balance        types.Big
	BalanceErr     error
}

type BatchBalanceReqs []*BatchBalanceReq

func (reqs BatchBalanceReqs) ToBatchElem() []rpc.BatchElem {
	reqElems := make([]rpc.BatchElem, len(reqs))
	erc20Abi := loopringParams.Erc20Abi

	for idx, req := range reqs {
		if types.IsZeroAddress(req.Token) {
			reqElems[idx] = rpc.BatchElem{
				Method: "eth_getBalance",
				Args:   []interface{}{req.Owner.Hex(), req.BlockParameter},
				Result: &req.Balance,
			}
		} else {
			balanceOfData, _ := erc20Abi.Pack("balanceOf", req.Owner)
			balanceOfArg := &ethtyp.CallArg{}
			balanceOfArg.To = req.Token
			balanceOfArg.Data = common.ToHex(balanceOfData)

			reqElems[idx] = rpc.BatchElem{
				Method: "eth_call",
				Args:   []interface{}{balanceOfArg, req.BlockParameter},
				Result: &req.Balance,
			}
		}
	}
	return reqElems
}

func (reqs BatchBalanceReqs) FromBatchElem(elems []rpc.BatchElem) {
	for idx, req := range elems {
		reqs[idx].BalanceErr = req.Error
	}
}

type BatchErc20AllowanceReq struct {
	Owner          common.Address
	Token          common.Address
	BlockParameter string
	Spender        common.Address
	Allowance      types.Big
	AllowanceErr   error
}

type BatchErc20AllowanceReqs []*BatchErc20AllowanceReq

func (reqs BatchErc20AllowanceReqs) ToBatchElem() []rpc.BatchElem {
	reqElems := make([]rpc.BatchElem, len(reqs))
	erc20Abi := loopringParams.Erc20Abi

	for idx, req := range reqs {
		balanceOfData, _ := erc20Abi.Pack("allowance", req.Owner, req.Spender)
		balanceOfArg := &ethtyp.CallArg{}
		balanceOfArg.To = req.Token
		balanceOfArg.Data = common.ToHex(balanceOfData)

		reqElems[idx] = rpc.BatchElem{
			Method: "eth_call",
			Args:   []interface{}{balanceOfArg, req.BlockParameter},
			Result: &req.Allowance,
		}
	}
	return reqElems
}

func (reqs BatchErc20AllowanceReqs) FromBatchElem(elems []rpc.BatchElem) {
	for idx, req := range elems {
		reqs[idx].AllowanceErr = req.Error
	}
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/gen_orderTxRecord_json.go<|end_filename|>
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.

package types

import (
	"encoding/json"

	"github.com/ethereum/go-ethereum/common"
)

// MarshalJSON marshals as JSON.
func (o OrderTxRecord) MarshalJSON() ([]byte, error) {
	type OrderTxRecord struct {
		Owner       common.Address `json:"owner"`
		TxHash      common.Hash    `json:"tx_hash"`
		OrderHash   common.Hash    `json:"order_hash"`
		OrderStatus OrderStatus    `json:"order_status"`
		Nonce       int64          `json:"nonce"`
	}
	var enc OrderTxRecord
	enc.Owner = o.Owner
	enc.TxHash = o.TxHash
	enc.OrderHash = o.OrderHash
	enc.OrderStatus = o.OrderStatus
	enc.Nonce = o.Nonce
	return json.Marshal(&enc)
}

// UnmarshalJSON unmarshals from JSON.
func (o *OrderTxRecord) UnmarshalJSON(input []byte) error {
	type OrderTxRecord struct {
		Owner       *common.Address `json:"owner"`
		TxHash      *common.Hash    `json:"tx_hash"`
		OrderHash   *common.Hash    `json:"order_hash"`
		OrderStatus *OrderStatus    `json:"order_status"`
		Nonce       *int64          `json:"nonce"`
	}
	var dec OrderTxRecord
	if err := json.Unmarshal(input, &dec); err != nil {
		return err
	}
	if dec.Owner != nil {
		o.Owner = *dec.Owner
	}
	if dec.TxHash != nil {
		o.TxHash = *dec.TxHash
	}
	if dec.OrderHash != nil {
		o.OrderHash = *dec.OrderHash
	}
	if dec.OrderStatus != nil {
		o.OrderStatus = *dec.OrderStatus
	}
	if dec.Nonce != nil {
		o.Nonce = *dec.Nonce
	}
	return nil
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/eth/accessor/types.go<|end_filename|>
package accessor

import "math/big"

type BlockIterator struct {
	startNumber   *big.Int
	endNumber     *big.Int
	currentNumber *big.Int
	ethClient     *ethNodeAccessor
	withTxData    bool
	confirms      uint64
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/utils/network.go<|end_filename|>
package utils

import (
	"net"
	"strings"
)

func GetLocalIp() string {
	var res = "unknown"
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return res
	}
	for _, a := range addrs {
		if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				res = ipnet.IP.To4().String()
			}
		}
	}
	return res
}

func GetLocalIpByPrefix(prefix string) string {
	var res = "unknown"
	interfaces, err := net.Interfaces()
	if err != nil {
		return res
	}

	for _, i := range interfaces {
		if addresses, err := i.Addrs(); err == nil {
			for _, v := range addresses {
				parts := strings.Split(v.String(), ":")
				if len(parts) > 1 { //ipv6 address
					continue
				} else {
					parts := strings.Split(v.String(), "/")
					if len(parts) == 2 && strings.HasPrefix(parts[0], prefix) {
						return parts[0]
					} else {
						continue
					}
				}
			}
		}
	}
	return res
}


<|start_filename|>vendor/gopkg.in/googollee/go-engine.io.v1/util.go<|end_filename|>
package engineio

import (
	"io"
	"io/ioutil"
	"sync"
)

type writer struct {
	io.WriteCloser
	locker    *sync.RWMutex
	closeOnce sync.Once
}

func newWriter(w io.WriteCloser, locker *sync.RWMutex) *writer {
	return &writer{
		WriteCloser: w,
		locker:      locker,
	}
}

func (w *writer) Close() error {
	err := w.WriteCloser.Close()
	w.closeOnce.Do(func() {
		w.locker.RUnlock()
	})
	return err
}

type reader struct {
	io.ReadCloser
	locker    *sync.RWMutex
	closeOnce sync.Once
}

func newReader(r io.ReadCloser, locker *sync.RWMutex) *reader {
	return &reader{
		ReadCloser: r,
		locker:     locker,
	}
}

func (r *reader) Close() error {
	io.Copy(ioutil.Discard, r.ReadCloser)
	err := r.ReadCloser.Close()
	r.closeOnce.Do(func() {
		r.locker.RUnlock()
	})
	return err
}


<|start_filename|>dao/cancel.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 dao

import (
	"github.com/Loopring/relay-lib/types"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

type CancelEvent struct {
	ID              int    `gorm:"column:id;primary_key;"`
	Protocol        string `gorm:"column:contract_address;type:varchar(42)"`
	DelegateAddress string `gorm:"column:delegate_address;type:varchar(42)"`
	OrderHash       string `gorm:"column:order_hash;type:varchar(82)"`
	TxHash          string `gorm:"column:tx_hash;type:varchar(82)"`
	BlockNumber     int64  `gorm:"column:block_number"`
	CreateTime      int64  `gorm:"column:create_time"`
	AmountCancelled string `gorm:"column:amount_cancelled;type:varchar(40)"`
	LogIndex        int64  `gorm:"column:log_index"`
	Status          uint8  `gorm:"column:status"`
	Fork            bool   `gorm:"column:fork"`
}

// convert chainClient/orderCancelledEvent to dao/CancelEvent
func (e *CancelEvent) ConvertDown(src *types.OrderCancelledEvent) error {
	e.AmountCancelled = src.AmountCancelled.String()
	e.OrderHash = src.OrderHash.Hex()
	e.TxHash = src.TxHash.Hex()
	e.Protocol = src.Protocol.Hex()
	e.DelegateAddress = src.DelegateAddress.Hex()
	e.CreateTime = src.BlockTime
	e.BlockNumber = src.BlockNumber.Int64()
	e.LogIndex = src.TxLogIndex
	e.Status = uint8(src.Status)

	return nil
}

// convert dao/cancelEvent to types/cancelEvent
func (e *CancelEvent) ConvertUp(dst *types.OrderCancelledEvent) error {
	dst.AmountCancelled, _ = new(big.Int).SetString(e.AmountCancelled, 0)
	dst.OrderHash = common.HexToHash(e.OrderHash)
	dst.TxHash = common.HexToHash(e.TxHash)
	dst.Protocol = common.HexToAddress(e.Protocol)
	dst.DelegateAddress = common.HexToAddress(e.DelegateAddress)
	dst.BlockTime = e.CreateTime
	dst.BlockNumber = big.NewInt(e.BlockNumber)
	dst.TxLogIndex = e.LogIndex
	dst.Status = types.TxStatus(e.Status)

	return nil
}

func (s *RdsService) GetCancelEvent(txhash common.Hash) (CancelEvent, error) {
	var event CancelEvent
	err := s.Db.Where("tx_hash=?", txhash.Hex()).Where("fork=?", false).First(&event).Error
	return event, err
}

func (s *RdsService) GetCancelForkEvents(from, to int64) ([]CancelEvent, error) {
	var (
		list []CancelEvent
		err  error
	)

	err = s.Db.Where("block_number > ? and block_number <= ?", from, to).
		Where("fork=?", false).
		Find(&list).Error

	return list, err
}

func (s *RdsService) RollBackCancel(from, to int64) error {
	return s.Db.Model(&CancelEvent{}).Where("block_number > ? and block_number <= ?", from, to).Update("fork", true).Error
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/common.go<|end_filename|>
package types

import (
	"github.com/ethereum/go-ethereum/common/hexutil"
	"math/big"
)

func Int2BlockNumHex(height int) string {
	data := big.NewInt(int64(height))
	return hexutil.EncodeBig(data) //common.Bytes2Hex(height.Bytes())
}


<|start_filename|>dao/trend.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 dao

// order amountS 上限1e30
type Trend struct {
	ID         int     `gorm:"column:id;primary_key;"`
	Market     string  `gorm:"column:market;type:varchar(42);unique_index:market_intervals_start"`
	Intervals  string  `gorm:"column:intervals;type:varchar(42);unique_index:market_intervals_start"`
	Vol        float64 `gorm:"column:vol;type:float"`
	Amount     float64 `gorm:"column:amount;type:float"`
	CreateTime int64   `gorm:"column:create_time;type:bigint"`
	UpdateTime int64   `gorm:"column:update_time;type:bigint"`
	Open       float64 `gorm:"column:open;type:float"`
	Close      float64 `gorm:"column:close;type:float"`
	High       float64 `gorm:"column:high;type:float"`
	Low        float64 `gorm:"column:low;type:float"`
	Start      int64   `gorm:"column:start;type:bigint;unique_index:market_intervals_start"`
	End        int64   `gorm:"column:end;type:bigint"`
}

func (s *RdsService) TrendQueryLatest(query Trend, pageIndex, pageSize int) (trends []Trend, err error) {
	trends = make([]Trend, 0)

	if pageIndex <= 0 {
		pageIndex = 1
	}

	if pageSize <= 0 {
		pageSize = 50
	}

	err = s.Db.Model(&Trend{}).Where(query).Order("start desc").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&trends).Error
	return
}

func (s *RdsService) TrendQueryByTime(intervals, market string, start, end int64) (trends []Trend, err error) {
	err = s.Db.Model(&Trend{}).Where("intervals = ? and market = ? and start = ? and end = ?", intervals, market, start, end).Order("start desc").Find(&trends).Error
	return
}

func (s *RdsService) TrendQueryByInterval(intervals, market string, start, end int64) (trends []Trend, err error) {
	err = s.Db.Model(&Trend{}).Where("intervals = ? and market = ? and start >= ? and end <= ?", intervals, market, start, end).Order("start").Find(&trends).Error
	return
}

func (s *RdsService) TrendQueryForProof(mkt, interval string, start int64) (trends []Trend, err error) {
	trends = make([]Trend, 0)
	err = s.Db.Model(&Trend{}).Where("intervals = ? and market = ? and start >= ?", interval, mkt, start).Find(&trends).Error
	return
}


<|start_filename|>vendor/github.com/Loopring/motan-go/filter/metrics.go<|end_filename|>
package filter

import (
	"fmt"
	"strings"
	"sync"
	"time"

	motan "github.com/Loopring/motan-go/core"

	"github.com/Loopring/motan-go/metrics"
)

var initSync sync.Once

type MetricsFilter struct {
	next motan.EndPointFilter
}

func (m *MetricsFilter) GetIndex() int {
	return 2
}

func (m *MetricsFilter) NewFilter(url *motan.URL) motan.Filter {
	return &MetricsFilter{}
}

func (m *MetricsFilter) GetName() string {
	return "metrics"
}

func (m *MetricsFilter) HasNext() bool {
	if m.next != nil {
		return true
	}
	return false
}

func (m *MetricsFilter) GetType() int32 {
	return motan.EndPointFilterType
}

func (m *MetricsFilter) SetNext(e motan.EndPointFilter) {
	m.next = e
	return
}

func (m *MetricsFilter) GetNext() motan.EndPointFilter {
	if m.next != nil {
		return m.next
	}
	return nil
}

func (m *MetricsFilter) Filter(caller motan.Caller, request motan.Request) motan.Response {
	role := "server"
	switch caller.(type) {
	case motan.Provider:
		role = "server-agent"
	case motan.EndPoint:
		role = "client-agent"
	}

	start := time.Now()

	response := m.GetNext().Filter(caller, request)
	var key string
	if role == "server-agent" {
		application := caller.GetURL().GetParam(motan.ApplicationKey, "")
		key = strings.Map(func(r rune) rune {
			if metrics.Charmap[r] {
				return '_'
			}
			return r
		}, fmt.Sprintf("motan-%s:%s:%s:%s:%s", role, application, request.GetAttachments()["M_g"], request.GetAttachments()["M_p"], request.GetMethod()))
	} else {
		key = strings.Map(func(r rune) rune {
			if metrics.Charmap[r] {
				return '_'
			}
			return r
		}, fmt.Sprintf("motan-%s:%s:%s:%s:%s", role, request.GetAttachments()["M_s"], request.GetAttachments()["M_g"], request.GetAttachments()["M_p"], request.GetMethod()))
	}
	keyCount := key + ".total_count"
	metrics.AddCounter(keyCount, 1) //total_count

	if response.GetException() != nil { //err_count
		exception := response.GetException()
		if exception.ErrType == motan.BizException {
			bizErrCountKey := key + ".biz_error_count"
			metrics.AddCounter(bizErrCountKey, 1)
		} else {
			otherErrCountKey := key + ".other_error_count"
			metrics.AddCounter(otherErrCountKey, 1)
		}
	}

	end := time.Now()
	cost := end.Sub(start).Nanoseconds() / 1e6
	metrics.AddCounter((key + "." + metrics.ElapseTimeString(cost)), 1)

	if cost > 200 {
		metrics.AddCounter(key+".slow_count", 1)
	}

	metrics.AddHistograms(key, cost)
	return response
}

func (m *MetricsFilter) SetContext(context *motan.Context) {
	initSync.Do(func() {
		metrics.Run(context.Config)
	})
}


<|start_filename|>ordermanager/common/config.go<|end_filename|>
package common

type OrderManagerOptions struct {
	CutoffCacheExpireTime int64
	CutoffCacheCleanTime  int64
}


<|start_filename|>vendor/gopkg.in/googollee/go-engine.io.v1/transport/websocket/wrapper.go<|end_filename|>
package websocket

import (
	"io"
	"io/ioutil"

	"github.com/gorilla/websocket"
	"gopkg.in/googollee/go-engine.io.v1/base"
	"gopkg.in/googollee/go-engine.io.v1/transport"
)

type wrapper struct {
	*websocket.Conn
}

func newWrapper(conn *websocket.Conn) wrapper {
	return wrapper{
		Conn: conn,
	}
}

func (w wrapper) NextReader() (base.FrameType, io.ReadCloser, error) {
	typ, r, err := w.Conn.NextReader()
	if err != nil {
		return 0, nil, err
	}
	ret := ioutil.NopCloser(r)
	switch typ {
	case websocket.TextMessage:
		return base.FrameString, ret, nil
	case websocket.BinaryMessage:
		return base.FrameBinary, ret, nil
	}
	return 0, nil, transport.ErrInvalidFrame
}

func (w wrapper) NextWriter(typ base.FrameType) (io.WriteCloser, error) {
	var t int
	switch typ {
	case base.FrameString:
		t = websocket.TextMessage
	case base.FrameBinary:
		t = websocket.BinaryMessage
	default:
		return nil, transport.ErrInvalidFrame
	}
	return w.Conn.NextWriter(t)
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/crypto/crypto.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 crypto

import (
	"crypto/ecdsa"
	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	ethCrypto "github.com/ethereum/go-ethereum/crypto"
	"math/big"
	"strings"
)

type EthCrypto struct {
	homestead bool
}

//签名验证
func (c EthCrypto) ValidateSignatureValues(v byte, r, s []byte) bool {
	return ethCrypto.ValidateSignatureValues(v, new(big.Int).SetBytes(r), new(big.Int).SetBytes(s), c.homestead)
}

//生成hash
func (c EthCrypto) GenerateHash(data ...[]byte) []byte {
	return ethCrypto.Keccak256(data...)
}

//签名回复到地址
func (c EthCrypto) SigToAddress(hashPre, sig []byte) ([]byte, error) {
	hash := c.GenerateHash([]byte("\x19Ethereum Signed Message:\n32"), hashPre)
	pubKey, err := ethCrypto.SigToPub(hash, sig)
	if nil != err {
		return nil, err
	} else {
		return ethCrypto.PubkeyToAddress(*pubKey).Bytes(), nil
	}
}

func (c EthCrypto) VRSToSig(v byte, r, s []byte) (sig []byte, err error) {
	sig = make([]byte, 65)
	vUint8 := uint8(v)
	if vUint8 >= 27 {
		vUint8 -= 27
	}
	copy(sig[32-len(r):32], r)
	copy(sig[64-len(s):64], s)
	sig[64] = byte(vUint8)
	return sig, nil
}

func (c EthCrypto) SigToVRS(sig []byte) (v byte, r []byte, s []byte) {
	r = make([]byte, 32)
	s = make([]byte, 32)
	v = byte(uint8(sig[64]) + uint8(27))
	copy(r, sig[0:32])
	copy(s, sig[32:64])
	return v, r, s
}

type EthKSCrypto struct {
	EthCrypto
	ks               *keystore.KeyStore
	unlockedAccounts map[common.Address]bool
}

func (c EthKSCrypto) Sign(hashPre []byte, signerAddr common.Address) ([]byte, error) {
	signer := accounts.Account{Address: signerAddr}
	hash := c.GenerateHash([]byte("\x19Ethereum Signed Message:\n32"), hashPre)
	return c.ks.SignHash(signer, hash)
}

func (c EthKSCrypto) UnlockAccount(acc accounts.Account, passphrase string) error {
	c.unlockedAccounts[acc.Address] = true
	return c.ks.Unlock(acc, passphrase)
}

func (c EthKSCrypto) IsUnlocked(addr common.Address) bool {
	_, exists := c.unlockedAccounts[addr]
	return exists
}

func (c EthKSCrypto) SignTx(addr common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
	a := accounts.Account{Address: addr}
	return c.ks.SignTx(a, tx, chainID)
}

func NewKSCrypto(homestead bool, ks *keystore.KeyStore) EthKSCrypto {
	return EthKSCrypto{EthCrypto: EthCrypto{homestead: homestead}, ks: ks, unlockedAccounts: make(map[common.Address]bool)}
}

type EthPrivateKeyCrypto struct {
	EthCrypto
	privateKey *ecdsa.PrivateKey
}

func (c EthPrivateKeyCrypto) Sign(hashPre []byte, signerAddr common.Address) ([]byte, error) {
	hash := c.GenerateHash([]byte("\x19Ethereum Signed Message:\n32"), hashPre)
	return ethCrypto.Sign(hash, c.privateKey)
}

func (c EthPrivateKeyCrypto) Address() common.Address {
	return ethCrypto.PubkeyToAddress(c.privateKey.PublicKey)
}

func (c EthPrivateKeyCrypto) SignTx(addr common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
	var signer types.Signer
	if chainID != nil {
		signer = types.NewEIP155Signer(chainID)
	} else {
		signer = types.HomesteadSigner{}
	}
	if signature, err := ethCrypto.Sign(signer.Hash(tx).Bytes(), c.privateKey); nil != err {
		return tx, err
	} else {
		return tx.WithSignature(signer, signature)
	}
}

func NewPrivateKeyCrypto(homestead bool, privateKeyHex string) (EthPrivateKeyCrypto, error) {
	if privateKey, err := toECDSA(privateKeyHex); nil != err {
		return EthPrivateKeyCrypto{}, err
	} else {
		return EthPrivateKeyCrypto{EthCrypto: EthCrypto{homestead: homestead}, privateKey: privateKey}, nil
	}
}

func (h *EthPrivateKeyCrypto) UnmarshalText(input []byte) error {
	privateKeyHex := string(input)
	if privateKey, err := toECDSA(privateKeyHex); nil != err {
		return err
	} else {
		h.homestead = true
		h.privateKey = privateKey
		return nil
	}
}

func toECDSA(privateKeyHex string) (*ecdsa.PrivateKey, error) {
	privateKeyHex = strings.TrimPrefix(privateKeyHex, "0x")
	if len(privateKeyHex) == 0 {
		return &ecdsa.PrivateKey{}, nil
	}
	return ethCrypto.ToECDSA(common.Hex2Bytes(privateKeyHex))
}

func (h *EthPrivateKeyCrypto) MarshalText() ([]byte, error) {
	if h.privateKey == nil || nil == h.privateKey.D {
		return []byte{}, nil
	}
	return []byte(common.ToHex(common.LeftPadBytes(h.privateKey.D.Bytes(), 32))), nil
}

func (h *EthPrivateKeyCrypto) GobEncode() ([]byte, error) {
	if h.privateKey == nil || nil == h.privateKey.D {
		return []byte{}, nil
	}
	return []byte(common.ToHex(common.LeftPadBytes(h.privateKey.D.Bytes(), 32))), nil
}

func (h *EthPrivateKeyCrypto) GobDecode(input []byte) error {
	privateKeyHex := string(input)
	if privateKey, err := toECDSA(privateKeyHex); nil != err {
		return err
	} else {
		h.homestead = true
		h.privateKey = privateKey
		return nil
	}
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/motan/types.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 motan

import (
	"github.com/Loopring/relay-lib/types"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

type AccountBalanceAndAllowanceReq struct {
	Owner   common.Address
	Token   common.Address
	Spender common.Address
}

type AccountBalanceAndAllowanceRes struct {
	Balance, Allowance *big.Int
	Err                string
}

type MinerOrdersReq struct {
	Delegate             common.Address
	TokenS               common.Address
	TokenB               common.Address
	Length               int
	ReservedTime         int64
	StartBlockNumber     int64
	EndBlockNumber       int64
	FilterOrderHashLists []*types.OrderDelayList
}

type MinerOrdersRes struct {
	List []*types.OrderState
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/types/types.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 types

import (
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"math/big"
)

const (
	Bytes32Length = 32
)

type Bytes32 [Bytes32Length]byte

func BitToBytes32(b *big.Int) Bytes32 { return BytesToBytes32(b.Bytes()[:]) }
func HexToBytes32(s string) Bytes32   { return BytesToBytes32(common.FromHex(s)) }

//MarshalJson
func (a *Bytes32) MarshalText() ([]byte, error) {
	return []byte(a.Hex()), nil
}

func (a *Bytes32) UnmarshalText(input []byte) error {
	a.SetBytes(HexToBytes32(string(input)).Bytes())
	return nil
}

func (s Bytes32) Str() string       { return string(s[:]) }
func (s Bytes32) Bytes() []byte     { return s[:] }
func (s Bytes32) Bytes32() [32]byte { return s }
func (s Bytes32) Big() *big.Int     { return new(big.Int).SetBytes(s[:]) }
func (s Bytes32) Hex() string       { return common.ToHex(s[:]) }

func BytesToBytes32(b []byte) Bytes32 {
	var s Bytes32
	s.SetBytes(b)
	return s
}

func (s *Bytes32) SetBytes(b []byte) {
	if len(b) > len(s) {
		b = b[len(b)-Bytes32Length:]
	}
	copy(s[Bytes32Length-len(b):], b)
}

func IsZeroHash(hash common.Hash) bool {
	return hash == common.HexToHash("0x")
}

func IsZeroAddress(addr common.Address) bool {
	return addr == common.HexToAddress("0x")
}

func BigintToHex(b *big.Int) string {
	if nil == b {
		b = big.NewInt(0)
	}
	return fmt.Sprintf("%#x", b)
}

func HexToBigint(h string) *big.Int {
	return new(big.Int).SetBytes(common.FromHex(h))
}

type CheckNull interface {
	IsNull() bool
}

var (
	NilHash    = common.HexToHash("0x")
	NilAddress = common.HexToAddress("0x")
)


<|start_filename|>vendor/github.com/Loopring/motan-go/lb/lb.go<|end_filename|>
package lb

import (
	"strconv"
	"strings"
	"sync"
	"sync/atomic"

	motan "github.com/Loopring/motan-go/core"
	"math/rand"
)

// ext name
const (
	Random     = "random"
	Roundrobin = "roundrobin"
)

const (
	MaxSelectArraySize = 3
	defaultWeight      = 1
)

var (
	lbmutex sync.Mutex
)

func RegistDefaultLb(extFactory motan.ExtentionFactory) {
	extFactory.RegistExtLb(Random, NewWeightLbFunc(func(url *motan.URL) motan.LoadBalance {
		return &RandomLB{url: url}
	}))

	extFactory.RegistExtLb(Roundrobin, NewWeightLbFunc(func(url *motan.URL) motan.LoadBalance {
		return &RoundrobinLB{url: url}
	}))
}

// WeightedLbWraper support multi group weighted LB
type WeightedLbWraper struct {
	url          *motan.URL
	weightstring string
	refers       innerRefers
	newLb        motan.NewLbFunc
}

func NewWeightLbFunc(newLb motan.NewLbFunc) motan.NewLbFunc {
	return func(url *motan.URL) motan.LoadBalance {
		return &WeightedLbWraper{url: url, newLb: newLb, refers: &singleGroupRefers{lb: newLb(url)}}
	}
}

func (w *WeightedLbWraper) OnRefresh(endpoints []motan.EndPoint) {
	if w.weightstring == "" { //not weighted lb
		if sgr, ok := w.refers.(*singleGroupRefers); ok {
			sgr.lb.OnRefresh(endpoints)
		} else {
			lb := w.newLb(w.url)
			lb.OnRefresh(endpoints)
			w.refers = &singleGroupRefers{lb: lb}
		}
		return
	}

	// weighted lb
	lbmutex.Lock()
	defer lbmutex.Unlock()
	groupEp := make(map[string][]motan.EndPoint)
	for _, ep := range endpoints {
		ges := groupEp[ep.GetURL().Group]
		if ges == nil {
			ges = make([]motan.EndPoint, 0, 32)
		}
		groupEp[ep.GetURL().Group] = append(ges, ep)
	}

	weights := strings.Split(w.weightstring, ",")
	gws := make(map[string]int)
	for _, w := range weights {
		if w != "" {
			groupWeight := strings.Split(w, ":")
			if len(groupWeight) == 1 {
				gws[groupWeight[0]] = defaultWeight
			} else {
				w, err := strconv.Atoi(groupWeight[1])
				if err == nil {
					gws[groupWeight[0]] = w
				} else {
					gws[groupWeight[0]] = defaultWeight
				}
			}
		}
	}
	weightsArray := make([]int, 0, 16)
	wr := newWeightRefers()
	for g, e := range groupEp {
		//build lb
		lb := w.newLb(w.url)
		lb.OnRefresh(e)
		wr.groupLb[g] = lb
		//build real weight
		wi := gws[g]
		if wi < 1 || wi > 100 { //weight normalization
			wi = defaultWeight
		}
		wr.groupWeight[g] = wi
		weightsArray = append(weightsArray, wi)
	}

	gcd := findGcd(weightsArray)
	ring := make([]string, 0, 128)
	for k, v := range wr.groupWeight {
		ringweight := v / gcd
		wr.groupWeight[k] = ringweight
		for i := 0; i < ringweight; i++ {
			ring = append(ring, k)
		}
	}
	wr.weightRing = motan.SliceShuffle(ring)
	wr.ringSize = len(wr.weightRing)
	w.refers = wr
}

func (w *WeightedLbWraper) Select(request motan.Request) motan.EndPoint {
	return w.refers.selectNext(request)
}

func (w *WeightedLbWraper) SelectArray(request motan.Request) []motan.EndPoint {
	return w.refers.selectNextArray(request)
}

func (w *WeightedLbWraper) SetWeight(weight string) {
	w.weightstring = weight
}

type innerRefers interface {
	selectNext(request motan.Request) motan.EndPoint
	selectNextArray(request motan.Request) []motan.EndPoint
}

type singleGroupRefers struct {
	lb motan.LoadBalance
}

func (s *singleGroupRefers) selectNext(request motan.Request) motan.EndPoint {
	return s.lb.Select(request)
}

func (s *singleGroupRefers) selectNextArray(request motan.Request) []motan.EndPoint {
	return s.lb.SelectArray(request)
}

type weightedRefers struct {
	groupWeight map[string]int
	weightRing  []string //real group ring according to endpoints.
	ringSize    int
	groupLb     map[string]motan.LoadBalance
	index       uint32
}

func (w *weightedRefers) selectNext(request motan.Request) motan.EndPoint {
	nextIndex := atomic.AddUint32(&w.index, 1)
	g := w.weightRing[nextIndex%uint32(w.ringSize)]
	return w.groupLb[g].Select(request)
}

func (w *weightedRefers) selectNextArray(request motan.Request) []motan.EndPoint {
	nextIndex := atomic.AddUint32(&w.index, 1)
	g := w.weightRing[nextIndex%uint32(w.ringSize)]
	return w.groupLb[g].SelectArray(request)
}

func newWeightRefers() *weightedRefers {
	wr := &weightedRefers{}
	wr.groupWeight = make(map[string]int, 16)
	wr.weightRing = make([]string, 0, 32)
	wr.groupLb = make(map[string]motan.LoadBalance, 16)
	return wr
}

func findGcd(v []int) int {
	var gcd int
	gcd = v[0]
	for i := 1; i < len(v); i++ {
		gcd = basegcd(gcd, v[i])
	}
	return gcd
}

func basegcd(n int, m int) int {
	if n == 0 || m == 0 {
		return m + n
	}
	return basegcd(m, n%m)
}

func SelectArrayFromIndex(endpoints []motan.EndPoint, fromIndex int) []motan.EndPoint {
	if len(endpoints) == 0 || fromIndex < 0 {
		return make([]motan.EndPoint, 0)
	}
	epsLen := len(endpoints)
	epList := make([]motan.EndPoint, 0, MaxSelectArraySize)
	for idx := 0; idx < epsLen && len(epList) < MaxSelectArraySize; idx++ {
		if ep := endpoints[(fromIndex+idx)%epsLen]; ep.IsAvailable() {
			epList = append(epList, ep)
		}
	}
	return epList
}

// SelectOneAtRandom to prevent put pressure to the next node when a node being unavailable, then need to do two random
func SelectOneAtRandom(endpoints []motan.EndPoint) (int, motan.EndPoint) {
	epsLen := len(endpoints)
	if epsLen == 0 {
		return -1, nil
	}
	index := rand.Intn(epsLen)
	if endpoints[index].IsAvailable() {
		return index, endpoints[index]
	}
	random := rand.Intn(epsLen)
	for idx := 0; idx < epsLen; idx++ {
		if rndIndex := (random + idx) % epsLen; endpoints[rndIndex].IsAvailable() {
			return rndIndex, endpoints[rndIndex]
		}
	}
	return -1, nil
}


<|start_filename|>vendor/github.com/Loopring/relay-lib/eth/abi/numbers.go<|end_filename|>
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package abi

import (
	"math/big"
	"reflect"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/math"
)

var (
	big_t      = reflect.TypeOf(&big.Int{})
	derefbig_t = reflect.TypeOf(big.Int{})
	uint8_t    = reflect.TypeOf(uint8(0))
	uint16_t   = reflect.TypeOf(uint16(0))
	uint32_t   = reflect.TypeOf(uint32(0))
	uint64_t   = reflect.TypeOf(uint64(0))
	int_t      = reflect.TypeOf(int(0))
	int8_t     = reflect.TypeOf(int8(0))
	int16_t    = reflect.TypeOf(int16(0))
	int32_t    = reflect.TypeOf(int32(0))
	int64_t    = reflect.TypeOf(int64(0))
	address_t  = reflect.TypeOf(common.Address{})
	int_ts     = reflect.TypeOf([]int(nil))
	int8_ts    = reflect.TypeOf([]int8(nil))
	int16_ts   = reflect.TypeOf([]int16(nil))
	int32_ts   = reflect.TypeOf([]int32(nil))
	int64_ts   = reflect.TypeOf([]int64(nil))
)

// U256 converts a big Int into a 256bit EVM number.
func U256(n *big.Int) []byte {
	return math.PaddedBigBytes(math.U256(n), 32)
}

// checks whether the given reflect value is signed. This also works for slices with a number type
func isSigned(v reflect.Value) bool {
	switch v.Type() {
	case int_ts, int8_ts, int16_ts, int32_ts, int64_ts, int_t, int8_t, int16_t, int32_t, int64_t:
		return true
	}
	return false
}


<|start_filename|>vendor/github.com/Loopring/motan-go/core/motan.go<|end_filename|>
package core

import (
	"strconv"
	"strings"
	"sync"
	"time"

	"errors"
	"github.com/Loopring/motan-go/log"
)

//-----------interface-------------

// Name is a interface can get and set name. especially for extension implements
type Name interface {
	GetName() string
}

// Identity : get id
type Identity interface {
	GetIdentity() string
}

// WithURL : can set and get URL
type WithURL interface {
	GetURL() *URL
	SetURL(url *URL)
}

// Attachment : can get, set attachments.
type Attachment interface {
	GetAttachments() map[string]string
	GetAttachment(key string) string
	SetAttachment(key string, value string)
}

// Destroyable : can destroy ....
type Destroyable interface {
	Destroy()
}

// Caller : can process a motan request. the call maybe process from remote by endpoint, maybe process by some kinds of provider
type Caller interface {
	WithURL
	Status
	Call(request Request) Response
	Destroyable
}

// Request : motan request
type Request interface {
	Attachment
	GetServiceName() string // service name  e.g. request path.or interface name
	GetMethod() string
	GetMethodDesc() string
	GetArguments() []interface{}
	GetRequestID() uint64
	GetRPCContext(canCreate bool) *RPCContext
	ProcessDeserializable(toTypes []interface{}) error
}

// Response : motan response
type Response interface {
	Attachment
	GetValue() interface{}
	GetException() *Exception
	GetRequestID() uint64
	GetProcessTime() int64
	SetProcessTime(time int64)
	GetRPCContext(canCreate bool) *RPCContext
	ProcessDeserializable(toType interface{}) error
}

// Status : for cluster or endpoint to check is available
type Status interface {
	IsAvailable() bool
}

// EndPoint : can process a remote rpc call
type EndPoint interface {
	Name
	Caller
	SetSerialization(s Serialization)
	SetProxy(proxy bool)
}

// HaStrategy : high availability strategy
type HaStrategy interface {
	Name
	WithURL
	Call(request Request, loadBalance LoadBalance) Response
}

// LoadBalance : loadBalance for cluster
type LoadBalance interface {
	OnRefresh(endpoints []EndPoint)

	Select(request Request) EndPoint

	SelectArray(request Request) []EndPoint

	SetWeight(weight string)
}

// DiscoverService : discover service for cluster
type DiscoverService interface {
	Subscribe(url *URL, listener NotifyListener)

	Unsubscribe(url *URL, listener NotifyListener)

	Discover(url *URL) []*URL
}

// DiscoverCommand : discover command for client or agent
type DiscoverCommand interface {
	SubscribeCommand(url *URL, listener CommandNotifyListener)
	UnSubscribeCommand(url *URL, listener CommandNotifyListener)
	DiscoverCommand(url *URL) string
}

// RegisterService : register service for rpc server
type RegisterService interface {
	Register(serverURL *URL)
	UnRegister(serverURL *URL)
	Available(serverURL *URL)
	Unavailable(serverURL *URL)
	GetRegisteredServices() []*URL
}

// SnapshotService : start registry snapshot
type SnapshotService interface {
	StartSnapshot(conf *SnapshotConf)
}

// Registry : can subscribe or register service
type Registry interface {
	Name
	WithURL
	DiscoverService
	RegisterService
	SnapshotService
}

// NotifyListener : NotifyListener
type NotifyListener interface {
	Identity
	Notify(registryURL *URL, urls []*URL)
}

// CommandNotifyListener : support command notify
type CommandNotifyListener interface {
	Identity
	NotifyCommand(registryURL *URL, commandType int, commandInfo string)
}

// Filter : filter request or response in a call processing
type Filter interface {
	Name
	// filter must be prototype
	NewFilter(url *URL) Filter
	HasNext() bool
	GetIndex() int
	GetType() int32
}

// EndPointFilter : filter for endpoint
type EndPointFilter interface {
	Filter
	SetNext(nextFilter EndPointFilter)
	GetNext() EndPointFilter
	//Filter for endpoint
	Filter(caller Caller, request Request) Response
}

// ClusterFilter : filter for cluster
type ClusterFilter interface {
	Filter
	SetNext(nextFilter ClusterFilter)
	GetNext() ClusterFilter
	//Filter for Cluster
	Filter(haStrategy HaStrategy, loadBalance LoadBalance, request Request) Response
}

// Server : rpc server which listen port and process request
type Server interface {
	WithURL
	Name
	Destroyable
	SetMessageHandler(mh MessageHandler)
	GetMessageHandler() MessageHandler
	Open(block bool, proxy bool, handler MessageHandler, extFactory ExtentionFactory) error
}

// Exporter : export and manage a service. one exporter bind with a service
type Exporter interface {
	Export(server Server) error
	Unexport() error
	SetProvider(provider Provider)
	GetProvider() Provider
	WithURL
}

// Provider : service provider
type Provider interface {
	SetService(s interface{})
	Caller
	GetPath() string
}

// MessageHandler : handler message(request) for Server
type MessageHandler interface {
	Call(request Request) (res Response)
	AddProvider(p Provider) error
	RmProvider(p Provider)
	GetProvider(serviceName string) Provider
}

// Serialization : Serialization
type Serialization interface {
	GetSerialNum() int
	Serialize(v interface{}) ([]byte, error)
	DeSerialize(b []byte, v interface{}) (interface{}, error)
	SerializeMulti(v []interface{}) ([]byte, error)
	DeSerializeMulti(b []byte, v []interface{}) ([]interface{}, error)
}

// ExtentionFactory : can regiser and get all kinds of extension implements.
type ExtentionFactory interface {
	GetHa(url *URL) HaStrategy
	GetLB(url *URL) LoadBalance
	GetFilter(name string) Filter
	GetRegistry(url *URL) Registry
	GetEndPoint(url *URL) EndPoint
	GetProvider(url *URL) Provider
	GetServer(url *URL) Server
	GetMessageHandler(name string) MessageHandler
	GetSerialization(name string, id int) Serialization
	RegistExtFilter(name string, newFilter DefaultFilterFunc)
	RegistExtHa(name string, newHa NewHaFunc)
	RegistExtLb(name string, newLb NewLbFunc)
	RegistExtEndpoint(name string, newEndpoint NewEndpointFunc)
	RegistExtProvider(name string, newProvider NewProviderFunc)
	RegistExtRegistry(name string, newRegistry NewRegistryFunc)
	RegistExtServer(name string, newServer NewServerFunc)
	RegistryExtMessageHandler(name string, newMessage NewMessageHandlerFunc)
	RegistryExtSerialization(name string, id int, newSerialization NewSerializationFunc)
}

// Initializable :Initializable
type Initializable interface {
	Initialize()
}

// SetContext :SetContext
type SetContext interface {
	SetContext(context *Context)
}

// Initialize : Initialize if implement Initializable
func Initialize(s interface{}) {
	if init, ok := s.(Initializable); ok {
		init.Initialize()
	}
}

// CanSetContext :CanSetContext
func CanSetContext(s interface{}, context *Context) {
	if sc, ok := s.(SetContext); ok {
		sc.SetContext(context)
	}
}

//-------------models--------------

// SnapshotConf is model for registry snapshot config.
type SnapshotConf struct {
	// SnapshotInterval is the interval of creating snapshot
	SnapshotInterval time.Duration
	SnapshotDir      string
}

// Exception :Exception
type Exception struct {
	ErrCode int    `json:"errcode"`
	ErrMsg  string `json:"errmsg"`
	ErrType int    `json:"errtype"`
}

// RPCContext : Context for RPC call
type RPCContext struct {
	ExtFactory      ExtentionFactory
	OriginalMessage interface{}
	Oneway          bool
	Proxy           bool
	GzipSize        int
	SerializeNum    int
	Serialized      bool

	// for call
	AsyncCall bool
	Result    *AsyncResult
	Reply     interface{}
}

// AsyncResult : async call result
type AsyncResult struct {
	StartTime int64
	Done      chan *AsyncResult
	Reply     interface{}
	Error     error
}

// DeserializableValue : for lazy deserialize
type DeserializableValue struct {
	Serialization Serialization
	Body          []byte
}

// Deserialize : Deserialize
func (d *DeserializableValue) Deserialize(v interface{}) (interface{}, error) {
	if d.Serialization == nil {
		return nil, errors.New("deserialize fail in DeserializableValue, Serialization is nil")
	}
	return d.Serialization.DeSerialize(d.Body, v)
}

// DeserializeMulti : DeserializeMulti
func (d *DeserializableValue) DeserializeMulti(v []interface{}) ([]interface{}, error) {
	if d.Serialization == nil {
		return nil, errors.New("deserialize fail in DeserializableValue, Serialization is nil")
	}
	return d.Serialization.DeSerializeMulti(d.Body, v)
}

// MotanRequest : Request default implement
type MotanRequest struct {
	RequestID   uint64
	ServiceName string
	Method      string
	MethodDesc  string
	Arguments   []interface{}
	Attachment  map[string]string
	RPCContext  *RPCContext
}

// GetAttachment GetAttachment
func (m *MotanRequest) GetAttachment(key string) string {
	if m.Attachment == nil {
		return ""
	}
	return m.Attachment[key]
}

// SetAttachment : SetAttachment
func (m *MotanRequest) SetAttachment(key string, value string) {
	if m.Attachment == nil {
		m.Attachment = make(map[string]string)
	}
	m.Attachment[key] = value
}

// GetServiceName GetServiceName
func (m *MotanRequest) GetServiceName() string {
	return m.ServiceName
}

// GetMethod GetMethod
func (m *MotanRequest) GetMethod() string {
	return m.Method
}

// GetMethodDesc GetMethodDesc
func (m *MotanRequest) GetMethodDesc() string {
	return m.MethodDesc
}

func (m *MotanRequest) GetArguments() []interface{} {
	return m.Arguments
}
func (m *MotanRequest) GetRequestID() uint64 {
	return m.RequestID
}

func (m *MotanRequest) SetArguments(arguments []interface{}) {
	m.Arguments = arguments
}

func (m *MotanRequest) GetAttachments() map[string]string {
	return m.Attachment
}

func (m *MotanRequest) GetRPCContext(canCreate bool) *RPCContext {
	if m.RPCContext == nil && canCreate {
		m.RPCContext = &RPCContext{}
	}
	return m.RPCContext
}

// ProcessDeserializable : DeserializableValue to real params according toType
// some serialization can deserialize without toType, so nil toType can be accepted in these serializations
func (m *MotanRequest) ProcessDeserializable(toTypes []interface{}) error {
	if m.GetArguments() != nil && len(m.GetArguments()) == 1 {
		if d, ok := m.GetArguments()[0].(*DeserializableValue); ok {
			v, err := d.DeserializeMulti(toTypes)
			if err != nil {
				return err
			}
			m.SetArguments(v)
		}
	}
	return nil
}

type MotanResponse struct {
	RequestID   uint64
	Value       interface{}
	Exception   *Exception
	ProcessTime int64
	Attachment  map[string]string
	RPCContext  *RPCContext
}

func (m *MotanResponse) GetAttachment(key string) string {
	if m.Attachment == nil {
		return ""
	}
	return m.Attachment[key]
}

func (m *MotanResponse) SetAttachment(key string, value string) {
	if m.Attachment == nil {
		m.Attachment = make(map[string]string)
	}
	m.Attachment[key] = value
}

func (m *MotanResponse) GetValue() interface{} {
	return m.Value
}

func (m *MotanResponse) GetException() *Exception {
	return m.Exception
}

func (m *MotanResponse) GetRequestID() uint64 {
	return m.RequestID
}

func (m *MotanResponse) GetProcessTime() int64 {
	return m.ProcessTime
}

func (m *MotanResponse) GetAttachments() map[string]string {
	return m.Attachment
}

func (m *MotanResponse) GetRPCContext(canCreate bool) *RPCContext {
	if m.RPCContext == nil && canCreate {
		m.RPCContext = &RPCContext{}
	}
	return m.RPCContext
}

func (m *MotanResponse) SetProcessTime(time int64) {
	m.ProcessTime = time
}

// ProcessDeserializable : same with MotanRequest
func (m *MotanResponse) ProcessDeserializable(toType interface{}) error {
	if m.GetValue() != nil {
		if d, ok := m.GetValue().(*DeserializableValue); ok {
			v, err := d.Deserialize(toType)
			if err != nil {
				return err
			}
			m.Value = v
		}
	}
	return nil
}

func BuildExceptionResponse(requestid uint64, e *Exception) *MotanResponse {
	return &MotanResponse{RequestID: requestid, Exception: e}
}

// extensions factory-func

type DefaultFilterFunc func() Filter
type NewHaFunc func(url *URL) HaStrategy
type NewLbFunc func(url *URL) LoadBalance
type NewEndpointFunc func(url *URL) EndPoint
type NewProviderFunc func(url *URL) Provider
type NewRegistryFunc func(url *URL) Registry
type NewServerFunc func(url *URL) Server
type NewMessageHandlerFunc func() MessageHandler
type NewSerializationFunc func() Serialization

type DefaultExtentionFactory struct {
	// factories
	filterFactories   map[string]DefaultFilterFunc
	haFactories       map[string]NewHaFunc
	lbFactories       map[string]NewLbFunc
	endpointFactories map[string]NewEndpointFunc
	providerFactories map[string]NewProviderFunc
	registryFactories map[string]NewRegistryFunc
	servers           map[string]NewServerFunc
	messageHandlers   map[string]NewMessageHandlerFunc
	serializations    map[string]NewSerializationFunc

	// singleton instance
	registries      map[string]Registry
	newRegistryLock sync.Mutex
}

func (d *DefaultExtentionFactory) GetHa(url *URL) HaStrategy {
	haName := url.GetParam(Hakey, "failover")
	if newHa, ok := d.haFactories[haName]; ok {
		return newHa(url)
	}
	vlog.Errorf("HaStrategy name %s is not found in DefaultExtentionFactory!\n", haName)
	return nil
}

func (d *DefaultExtentionFactory) GetLB(url *URL) LoadBalance {
	lbName := url.GetParam(Lbkey, "random")
	if newLb, ok := d.lbFactories[lbName]; ok {
		return newLb(url)
	}
	vlog.Errorf("LoadBalance name %s is not found in DefaultExtentionFactory!\n", lbName)
	return nil
}

func (d *DefaultExtentionFactory) GetFilter(name string) Filter {
	if newDefualt, ok := d.filterFactories[strings.TrimSpace(name)]; ok {
		return newDefualt()
	}
	vlog.Errorf("filter name %s is not found in DefaultExtentionFactory!\n", name)
	return nil
}

func (d *DefaultExtentionFactory) GetRegistry(url *URL) Registry {
	key := url.GetIdentity()
	if registry, exist := d.registries[key]; exist {
		return registry
	}
	d.newRegistryLock.Lock()
	defer d.newRegistryLock.Unlock()
	if registry, exist := d.registries[key]; exist {
		return registry
	} else if newRegistry, ok := d.registryFactories[url.Protocol]; ok {
		registry := newRegistry(url)
		Initialize(registry)
		d.registries[key] = registry
		return registry
	}
	vlog.Errorf("Registry name %s is not found in DefaultExtentionFactory!\n", url.Protocol)
	return nil
}

func (d *DefaultExtentionFactory) GetEndPoint(url *URL) EndPoint {
	if newEp, ok := d.endpointFactories[url.Protocol]; ok {
		endpoint := newEp(url)
		return endpoint
	}
	vlog.Errorf("EndPoint(protocol) name %s is not found in DefaultExtentionFactory!\n", url.Protocol)
	return nil
}

func (d *DefaultExtentionFactory) GetProvider(url *URL) Provider {
	if newProviderFunc, ok := d.providerFactories[url.GetParam(ProviderKey, "default")]; ok {
		provider := newProviderFunc(url)
		return provider
	}
	vlog.Errorf("provider(protocol) name %s is not found in DefaultExtentionFactory!\n", url.Protocol)
	return nil
}

func (d *DefaultExtentionFactory) GetServer(url *URL) Server {
	sname := url.Protocol
	if sname == "" {
		sname = "motan2"
		vlog.Warningln("not find server key. motan2 server will used.")
	}
	if f, ok := d.servers[sname]; ok {
		s := f(url)
		Initialize(s)
		return s
	}
	vlog.Errorf("server name %s is not found in DefaultExtentionFactory!\n", sname)
	return nil
}

func (d *DefaultExtentionFactory) GetMessageHandler(name string) MessageHandler {
	if newMessageHandler, ok := d.messageHandlers[strings.TrimSpace(name)]; ok {
		handler := newMessageHandler()
		Initialize(handler)
		return handler
	}
	vlog.Errorf("messageHandler name %s is not found in DefaultExtentionFactory!\n", name)
	return nil
}

func (d *DefaultExtentionFactory) GetSerialization(name string, id int) Serialization {
	if name != "" {
		if newSerialization, ok := d.serializations[strings.TrimSpace(name)]; ok {
			return newSerialization()
		}
	} else if id > -1 {
		if newSerialization, ok := d.serializations[strconv.Itoa(id)]; ok {
			return newSerialization()
		}
	}
	return nil
}

func (d *DefaultExtentionFactory) RegistExtFilter(name string, newFilter DefaultFilterFunc) {
	// 覆盖方式
	d.filterFactories[name] = newFilter
}

func (d *DefaultExtentionFactory) RegistExtHa(name string, newHa NewHaFunc) {
	d.haFactories[name] = newHa
}

func (d *DefaultExtentionFactory) RegistExtLb(name string, newLb NewLbFunc) {
	d.lbFactories[name] = newLb
}

func (d *DefaultExtentionFactory) RegistExtEndpoint(name string, newEndpoint NewEndpointFunc) {
	d.endpointFactories[name] = newEndpoint
}

func (d *DefaultExtentionFactory) RegistExtProvider(name string, newProvider NewProviderFunc) {
	d.providerFactories[name] = newProvider
}

func (d *DefaultExtentionFactory) RegistExtRegistry(name string, newRegistry NewRegistryFunc) {
	d.registryFactories[name] = newRegistry
}

func (d *DefaultExtentionFactory) RegistExtServer(name string, newServer NewServerFunc) {
	d.servers[name] = newServer
}

func (d *DefaultExtentionFactory) RegistryExtMessageHandler(name string, newMessage NewMessageHandlerFunc) {
	d.messageHandlers[name] = newMessage
}

func (d *DefaultExtentionFactory) RegistryExtSerialization(name string, id int, newSerialization NewSerializationFunc) {
	d.serializations[name] = newSerialization
	d.serializations[strconv.Itoa(id)] = newSerialization
}

func (d *DefaultExtentionFactory) Initialize() {
	d.filterFactories = make(map[string]DefaultFilterFunc)
	d.haFactories = make(map[string]NewHaFunc)
	d.lbFactories = make(map[string]NewLbFunc)
	d.endpointFactories = make(map[string]NewEndpointFunc)
	d.providerFactories = make(map[string]NewProviderFunc)
	d.registryFactories = make(map[string]NewRegistryFunc)
	d.servers = make(map[string]NewServerFunc)
	d.registries = make(map[string]Registry)
	d.messageHandlers = make(map[string]NewMessageHandlerFunc)
	d.serializations = make(map[string]NewSerializationFunc)
}

var (
	lef *lastEndPointFilter
	lcf *lastClusterFilter
)

func GetLastEndPointFilter() EndPointFilter {
	if lef == nil {
		lef = new(lastEndPointFilter)
	}
	return lef
}

func GetLastClusterFilter() ClusterFilter {
	if lcf == nil {
		lcf = new(lastClusterFilter)
	}
	return lcf
}

type lastEndPointFilter struct{}

func (l *lastEndPointFilter) GetName() string {
	return "lastEndPointFilter"
}

func (l *lastEndPointFilter) NewFilter(url *URL) Filter {
	return GetLastEndPointFilter()
}

func (l *lastEndPointFilter) Filter(caller Caller, request Request) Response {
	return caller.Call(request)
}

func (l *lastEndPointFilter) HasNext() bool {
	return false
}

func (l *lastEndPointFilter) SetNext(nextFilter EndPointFilter) {
	vlog.Errorf("should not set next in lastEndPointFilter! filer:%s\n", nextFilter.GetName())
}
func (l *lastEndPointFilter) GetNext() EndPointFilter {
	return nil
}
func (l *lastEndPointFilter) GetIndex() int {
	return 100
}
func (l *lastEndPointFilter) GetType() int32 {
	return EndPointFilterType
}

type lastClusterFilter struct{}

func (l *lastClusterFilter) GetName() string {
	return "lastClusterFilter"
}
func (l *lastClusterFilter) NewFilter(url *URL) Filter {
	return GetLastClusterFilter()
}

func (l *lastClusterFilter) Filter(haStrategy HaStrategy, loadBalance LoadBalance, request Request) Response {
	return haStrategy.Call(request, loadBalance)
}

func (l *lastClusterFilter) HasNext() bool {
	return false
}
func (l *lastClusterFilter) SetNext(nextFilter ClusterFilter) {
	vlog.Errorf("should not set next in lastClusterFilter! filer:%s\n", nextFilter.GetName())
}
func (l *lastClusterFilter) GetNext() ClusterFilter {
	return nil
}
func (l *lastClusterFilter) GetIndex() int {
	return 100
}
func (l *lastClusterFilter) GetType() int32 {
	return ClusterFilterType
}

type FilterEndPoint struct {
	URL           *URL
	Filter        EndPointFilter
	StatusFilters []Status
	Caller        Caller
}

func (f *FilterEndPoint) Call(request Request) Response {
	return f.Filter.Filter(f.Caller, request)
}
func (f *FilterEndPoint) GetURL() *URL {
	return f.URL
}
func (f *FilterEndPoint) SetURL(url *URL) {
	f.URL = url
}
func (f *FilterEndPoint) GetName() string {
	return "FilterEndPoint"
}

func (f *FilterEndPoint) Destroy() {
	if f.Caller != nil {
		f.Caller.Destroy()
	}
}

func (f *FilterEndPoint) SetProxy(proxy bool) {}

func (f *FilterEndPoint) SetSerialization(s Serialization) {}

func (f *FilterEndPoint) IsAvailable() bool {
	if f.StatusFilters != nil && len(f.StatusFilters) > 0 {
		for i := len(f.StatusFilters) - 1; i >= 0; i-- {
			if !f.StatusFilters[i].IsAvailable() {
				return false
			}
		}
	}
	return f.Caller.IsAvailable()
}


<|start_filename|>Makefile<|end_filename|>
#

.PHONY: prepare relay clean vendor relay-darwin

GOCMD=go
GOBUILD=$(GOCMD) build -ldflags -s -v
BINARY_NAME=relay

prepare:
	/bin/sh build/prepare.sh

relay:prepare
	$(GOBUILD) -o build/bin/$(BINARY_NAME) cmd/main.go
	@echo "It's done. You can run build/bin/$(BINARY_NAME) now."

clean:
	rm build/bin/*

vendor:
	/bin/bash vendor.sh

relay-darwin:prepare
	GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 $(GOBUILD) -o build/bin/$(BINARY_NAME)_darwin cmd/main.go
	@echo "done"

relay-linux-amd64:prepare
	GOOS=linux CGO_ENABLED=1 GOARCH=amd64 $(GOBUILD) -o build/bin/$(BINARY_NAME)_linux_amd64 cmd/main.gp
	@echo "done"

relay-linux-386:prepare
	GOOS=linux GOARCH=386 CGO_ENABLED=1 $(GOBUILD) -o build/bin/$(BINARY_NAME)_linux_386 cmd/main.gp
	@echo "done"

relay-windows-amd64:prepare
	GOOS=windows GOARCH=amd64 CGO_ENABLED=1 $(GOBUILD) -o build/bin/$(BINARY_NAME)_windows_amd64 cmd/main.go
	@echo "done"

relay-windows-386:prepare
	GOOS=windows GOARCH=386 CGO_ENABLED=1 $(GOBUILD) -o build/bin/$(BINARY_NAME)_windows_386 cmd/main.go
	@echo "done"



<|start_filename|>dao/order_view.go<|end_filename|>
/*

  Copyright 2017 Loopring Project Ltd (Loopring Foundation).

  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 dao

// 用于前端查询

type OrderView struct {
	ID              int     `gorm:"column:id;primary_key;"`
	OrderId         int     `gorm:"column:order_id"`
	Protocol        string  `gorm:"column:protocol;type:varchar(42)"`
	DelegateAddress string  `gorm:"column:delegate_address;type:varchar(42)"`
	Owner           string  `gorm:"column:owner;type:varchar(42)"`
	OrderHash       string  `gorm:"column:order_hash;type:varchar(82)"`
	TokenS          string  `gorm:"column:token_s;type:varchar(42)"`
	TokenB          string  `gorm:"column:token_b;type:varchar(42)"`
	CreateTime      int64   `gorm:"column:create_time;type:bigint"`
	Price           float64 `gorm:"column:price;type:decimal(28,16);"`
	Status          uint8   `gorm:"column:status;type:tinyint(4)"`
	BroadcastTime   int     `gorm:"column:broadcast_time;type:bigint"`
	Market          string  `gorm:"column:market;type:varchar(40)"`
	Side            string  `gorm:"column:side;type:varchar(40)"`
	OrderType       string  `gorm:"column:order_type;type:varchar(40)"`
}


<|start_filename|>vendor/gopkg.in/googollee/go-engine.io.v1/transport/polling/client.go<|end_filename|>
package polling

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"sync/atomic"

	"gopkg.in/googollee/go-engine.io.v1/base"
	"gopkg.in/googollee/go-engine.io.v1/payload"
)

type clientConn struct {
	*payload.Payload

	httpClient   *http.Client
	request      http.Request
	remoteHeader atomic.Value
}

func dial(client *http.Client, url *url.URL, requestHeader http.Header) (*clientConn, error) {
	if client == nil {
		client = &http.Client{}
	}
	req, err := http.NewRequest("", url.String(), nil)
	if err != nil {
		return nil, err
	}
	for k, v := range requestHeader {
		req.Header[k] = v
	}
	supportBinary := req.URL.Query().Get("b64") == ""
	if supportBinary {
		req.Header.Set("Content-Type", "application/octet-stream")
	} else {
		req.Header.Set("Content-Type", "text/plain;charset=UTF-8")
	}

	ret := &clientConn{
		Payload:    payload.New(supportBinary),
		httpClient: client,
		request:    *req,
	}
	return ret, nil
}

func (c *clientConn) Open() (base.ConnParameters, error) {
	go c.getOpen()

	_, pt, r, err := c.NextReader()
	if err != nil {
		return base.ConnParameters{}, err
	}
	if pt != base.OPEN {
		return base.ConnParameters{}, errors.New("invalid open")
	}
	conn, err := base.ReadConnParameters(r)
	if err != nil {
		return base.ConnParameters{}, err
	}
	err = r.Close()
	if err != nil {
		return base.ConnParameters{}, err
	}
	query := c.request.URL.Query()
	query.Set("sid", conn.SID)
	c.request.URL.RawQuery = query.Encode()

	go c.serveGet()
	go c.servePost()

	return conn, nil
}

func (c *clientConn) URL() url.URL {
	return *c.request.URL
}

func (c *clientConn) LocalAddr() net.Addr {
	return Addr{""}
}

func (c *clientConn) RemoteAddr() net.Addr {
	return Addr{c.request.Host}
}

func (c *clientConn) RemoteHeader() http.Header {
	ret := c.remoteHeader.Load()
	if ret == nil {
		return nil
	}
	return ret.(http.Header)
}

func (c *clientConn) Resume() {
	c.Payload.Resume()
	go c.serveGet()
	go c.servePost()
}

func (c *clientConn) servePost() {
	var buf bytes.Buffer
	req := c.request
	url := *req.URL
	req.URL = &url
	query := url.Query()
	req.Method = "POST"
	req.Body = ioutil.NopCloser(&buf)
	for {
		buf.Reset()
		if err := c.Payload.FlushOut(&buf); err != nil {
			return
		}
		query.Set("t", base.Timestamp())
		req.URL.RawQuery = query.Encode()
		resp, err := c.httpClient.Do(&req)
		if err != nil {
			c.Payload.Store("post", err)
			c.Close()
			return
		}
		io.Copy(ioutil.Discard, resp.Body)
		resp.Body.Close()
		if resp.StatusCode != http.StatusOK {
			c.Payload.Store("post", fmt.Errorf("invalid response: %s(%d)", resp.Status, resp.StatusCode))
			c.Close()
			return
		}
		c.remoteHeader.Store(resp.Header)
	}
}

func (c *clientConn) getOpen() {
	req := c.request
	query := req.URL.Query()
	url := *req.URL
	req.URL = &url
	req.Method = "GET"
	query.Set("t", base.Timestamp())
	req.URL.RawQuery = query.Encode()
	resp, err := c.httpClient.Do(&req)
	if err != nil {
		c.Payload.Store("get", err)
		c.Close()
		return
	}
	defer func() {
		io.Copy(ioutil.Discard, resp.Body)
		resp.Body.Close()
	}()
	if resp.StatusCode != http.StatusOK {
		err = fmt.Errorf("invalid request: %s(%d)", resp.Status, resp.StatusCode)
	}
	var supportBinary bool
	if err == nil {
		mime := resp.Header.Get("Content-Type")
		supportBinary, err = mimeSupportBinary(mime)
	}
	if err != nil {
		c.Payload.Store("get", err)
		c.Close()
		return
	}
	c.remoteHeader.Store(resp.Header)
	if err = c.Payload.FeedIn(resp.Body, supportBinary); err != nil {
		return
	}
}

func (c *clientConn) serveGet() {
	req := c.request
	query := req.URL.Query()
	url := *req.URL
	req.URL = &url
	req.Method = "GET"
	for {
		query.Set("t", base.Timestamp())
		req.URL.RawQuery = query.Encode()
		resp, err := c.httpClient.Do(&req)
		if err != nil {
			c.Payload.Store("get", err)
			c.Close()
			return
		}
		if resp.StatusCode != http.StatusOK {
			err = fmt.Errorf("invalid request: %s(%d)", resp.Status, resp.StatusCode)
		}
		var supportBinary bool
		if err == nil {
			mime := resp.Header.Get("Content-Type")
			supportBinary, err = mimeSupportBinary(mime)
		}
		if err != nil {
			io.Copy(ioutil.Discard, resp.Body)
			resp.Body.Close()
			c.Payload.Store("get", err)
			c.Close()
			return
		}
		if err = c.Payload.FeedIn(resp.Body, supportBinary); err != nil {
			io.Copy(ioutil.Discard, resp.Body)
			resp.Body.Close()
			return
		}
		c.remoteHeader.Store(resp.Header)
	}
}


<|start_filename|>vendor/github.com/Loopring/motan-go/registry/directRegistry.go<|end_filename|>
package registry

import (
	"strconv"
	"strings"

	motan "github.com/Loopring/motan-go/core"
	"github.com/Loopring/motan-go/log"
)

type DirectRegistry struct {
	url  *motan.URL
	urls []*motan.URL
}

func (d *DirectRegistry) GetURL() *motan.URL {
	return d.url
}
func (d *DirectRegistry) SetURL(url *motan.URL) {
	d.url = url
	d.urls = parseURLs(url)
}
func (d *DirectRegistry) GetName() string {
	return "direct"
}

func (d *DirectRegistry) InitRegistry() {
}
func (d *DirectRegistry) Subscribe(url *motan.URL, listener motan.NotifyListener) {
}

func (d *DirectRegistry) Unsubscribe(url *motan.URL, listener motan.NotifyListener) {
}
func (d *DirectRegistry) Discover(url *motan.URL) []*motan.URL {
	if d.urls == nil {
		d.urls = parseURLs(d.url)
	}
	result := make([]*motan.URL, 0, len(d.urls))
	for _, u := range d.urls {
		newURL := *url
		newURL.Host = u.Host
		newURL.Port = u.Port
		result = append(result, &newURL)
	}
	return result
}
func (d *DirectRegistry) Register(serverURL *motan.URL) {
	vlog.Infof("direct registry:register url :%+v\n", serverURL)
}
func (d *DirectRegistry) UnRegister(serverURL *motan.URL) {

}
func (d *DirectRegistry) Available(serverURL *motan.URL) {

}
func (d *DirectRegistry) Unavailable(serverURL *motan.URL) {

}
func (d *DirectRegistry) GetRegisteredServices() []*motan.URL {
	return nil
}
func (d *DirectRegistry) StartSnapshot(conf *motan.SnapshotConf) {}
func parseURLs(url *motan.URL) []*motan.URL {
	urls := make([]*motan.URL, 0)
	if len(url.Host) > 0 && url.Port > 0 {
		urls = append(urls, url)
	} else if address, exist := url.Parameters[motan.AddressKey]; exist {
		for _, add := range strings.Split(address, ",") {
			hostport := strings.Split(add, ":")
			if len(hostport) == 2 {
				port, err := strconv.Atoi(hostport[1])
				if err == nil {
					u := &motan.URL{Host: hostport[0], Port: port}
					urls = append(urls, u)
				}
			}
		}
	} else {
		vlog.Warningf("direct registry parse fail.url:L %+v", url)
	}
	return urls
}
