<commit_before>package eth

import (
	"crypto/ecdsa"
	"fmt"
	"io/ioutil"
	"path"
	"strings"

	"github.com/ethereum/ethash"
	"github.com/ethereum/go-ethereum/blockpool"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/miner"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/p2p/discover"
	"github.com/ethereum/go-ethereum/p2p/nat"
	"github.com/ethereum/go-ethereum/pow/ezp"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/ethereum/go-ethereum/whisper"
)

var (
	ethlogger  = logger.NewLogger("SERV")
	jsonlogger = logger.NewJsonLogger()

	defaultBootNodes = []*discover.Node{
		// ETH/DEV cmd/bootnode
		discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"),
		// ETH/DEV cpp-ethereum (poc-8.ethdev.com)
		discover.MustParseNode("enode://4a44599974518ea5b0f14c31c4463692ac0329cb84851f3435e6d1b18ee4eae4aa495f846a0fa1219bd58035671881d44423876e57db2abd57254d0197da0ebe@5.1.83.226:30303"),
	}
)

type Config struct {
	Name      string
	KeyStore  string
	DataDir   string
	LogFile   string
	LogLevel  int
	KeyRing   string
	LogFormat string

	MaxPeers int
	Port     string

	// This should be a space-separated list of
	// discovery node URLs.
	BootNodes string

	// This key is used to identify the node on the network.
	// If nil, an ephemeral key is used.
	NodeKey *ecdsa.PrivateKey

	NAT  nat.Interface
	Shh  bool
	Dial bool

	MinerThreads int

	KeyManager *crypto.KeyManager
}

func (cfg *Config) parseBootNodes() []*discover.Node {
	if cfg.BootNodes == "" {
		return defaultBootNodes
	}
	var ns []*discover.Node
	for _, url := range strings.Split(cfg.BootNodes, " ") {
		if url == "" {
			continue
		}
		n, err := discover.ParseNode(url)
		if err != nil {
			ethlogger.Errorf("Bootstrap URL %s: %v\n", url, err)
			continue
		}
		ns = append(ns, n)
	}
	return ns
}

func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
	// use explicit key from command line args if set
	if cfg.NodeKey != nil {
		return cfg.NodeKey, nil
	}
	// use persistent key if present
	keyfile := path.Join(cfg.DataDir, "nodekey")
	key, err := crypto.LoadECDSA(keyfile)
	if err == nil {
		return key, nil
	}
	// no persistent key, generate and store a new one
	if key, err = crypto.GenerateKey(); err != nil {
		return nil, fmt.Errorf("could not generate server key: %v", err)
	}
	if err := ioutil.WriteFile(keyfile, crypto.FromECDSA(key), 0600); err != nil {
		ethlogger.Errorln("could not persist nodekey: ", err)
	}
	return key, nil
}

type Ethereum struct {
	// Channel for shutting down the ethereum
	shutdownChan chan bool
	quit         chan bool

	// DB interface
	db        ethutil.Database
	blacklist p2p.Blacklist

	//*** SERVICES ***
	// State manager for processing new blocks and managing the over all states
	blockProcessor *core.BlockProcessor
	txPool         *core.TxPool
	chainManager   *core.ChainManager
	blockPool      *blockpool.BlockPool
	whisper        *whisper.Whisper

	net      *p2p.Server
	eventMux *event.TypeMux
	txSub    event.Subscription
	blockSub event.Subscription
	miner    *miner.Miner

	RpcServer  rpc.RpcServer
	keyManager *crypto.KeyManager

	logger logger.LogSystem

	Mining bool
}

func New(config *Config) (*Ethereum, error) {
	// Boostrap database
	ethlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
	db, err := ethdb.NewLDBDatabase("blockchain")
	if err != nil {
		return nil, err
	}

	// Perform database sanity checks
	d, _ := db.Get([]byte("ProtocolVersion"))
	protov := ethutil.NewValue(d).Uint()
	if protov != ProtocolVersion && protov != 0 {
		path := path.Join(config.DataDir, "blockchain")
		return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
	}

	// Create new keymanager
	var keyManager *crypto.KeyManager
	switch config.KeyStore {
	case "db":
		keyManager = crypto.NewDBKeyManager(db)
	case "file":
		keyManager = crypto.NewFileKeyManager(config.DataDir)
	default:
		return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore)
	}
	// Initialise the keyring
	keyManager.Init(config.KeyRing, 0, false)

	saveProtocolVersion(db)
	//ethutil.Config.Db = db

	eth := &Ethereum{
		shutdownChan: make(chan bool),
		quit:         make(chan bool),
		db:           db,
		keyManager:   keyManager,
		blacklist:    p2p.NewBlacklist(),
		eventMux:     &event.TypeMux{},
		logger:       ethlogger,
	}

	eth.chainManager = core.NewChainManager(db, eth.EventMux())
	pow := ethash.New(eth.chainManager)

	eth.txPool = core.NewTxPool(eth.EventMux())
	eth.blockProcessor = core.NewBlockProcessor(db, pow, eth.txPool, eth.chainManager, eth.EventMux())
	eth.chainManager.SetProcessor(eth.blockProcessor)
	eth.whisper = whisper.New()
	eth.miner = miner.New(keyManager.Address(), eth, pow, config.MinerThreads)

	hasBlock := eth.chainManager.HasBlock
	insertChain := eth.chainManager.InsertChain
	eth.blockPool = blockpool.New(hasBlock, insertChain, ezp.Verify)

	netprv, err := config.nodeKey()
	if err != nil {
		return nil, err
	}
	ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
	protocols := []p2p.Protocol{ethProto}
	if config.Shh {
		protocols = append(protocols, eth.whisper.Protocol())
	}

	eth.net = &p2p.Server{
		PrivateKey:     netprv,
		Name:           config.Name,
		MaxPeers:       config.MaxPeers,
		Protocols:      protocols,
		Blacklist:      eth.blacklist,
		NAT:            config.NAT,
		NoDial:         !config.Dial,
		BootstrapNodes: config.parseBootNodes(),
	}
	if len(config.Port) > 0 {
		eth.net.ListenAddr = ":" + config.Port
	}

	return eth, nil
}

func (s *Ethereum) KeyManager() *crypto.KeyManager       { return s.keyManager }
func (s *Ethereum) Logger() logger.LogSystem             { return s.logger }
func (s *Ethereum) Name() string                         { return s.net.Name }
func (s *Ethereum) ChainManager() *core.ChainManager     { return s.chainManager }
func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
func (s *Ethereum) TxPool() *core.TxPool                 { return s.txPool }
func (s *Ethereum) BlockPool() *blockpool.BlockPool      { return s.blockPool }
func (s *Ethereum) Whisper() *whisper.Whisper            { return s.whisper }
func (s *Ethereum) EventMux() *event.TypeMux             { return s.eventMux }
func (s *Ethereum) Db() ethutil.Database                 { return s.db }
func (s *Ethereum) Miner() *miner.Miner                  { return s.miner }
func (s *Ethereum) IsListening() bool                    { return true } // Always listening
func (s *Ethereum) PeerCount() int                       { return s.net.PeerCount() }
func (s *Ethereum) Peers() []*p2p.Peer                   { return s.net.Peers() }
func (s *Ethereum) MaxPeers() int                        { return s.net.MaxPeers }
func (s *Ethereum) Coinbase() []byte                     { return nil } // TODO

// Start the ethereum
func (s *Ethereum) Start() error {
	jsonlogger.LogJson(&logger.LogStarting{
		ClientString:    s.net.Name,
		ProtocolVersion: ProtocolVersion,
	})

	err := s.net.Start()
	if err != nil {
		return err
	}

	// Start services
	s.txPool.Start()
	s.blockPool.Start()

	if s.whisper != nil {
		s.whisper.Start()
	}

	// broadcast transactions
	s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
	go s.txBroadcastLoop()

	// broadcast mined blocks
	s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
	go s.blockBroadcastLoop()

	ethlogger.Infoln("Server started")
	return nil
}

func (self *Ethereum) SuggestPeer(nodeURL string) error {
	n, err := discover.ParseNode(nodeURL)
	if err != nil {
		return fmt.Errorf("invalid node URL: %v", err)
	}
	self.net.SuggestPeer(n)
	return nil
}

func (s *Ethereum) Stop() {
	// Close the database
	defer s.db.Close()

	close(s.quit)

	s.txSub.Unsubscribe()    // quits txBroadcastLoop
	s.blockSub.Unsubscribe() // quits blockBroadcastLoop

	if s.RpcServer != nil {
		s.RpcServer.Stop()
	}

	s.txPool.Stop()
	s.eventMux.Stop()
	s.blockPool.Stop()
	if s.whisper != nil {
		s.whisper.Stop()
	}

	ethlogger.Infoln("Server stopped")
	close(s.shutdownChan)
}

// This function will wait for a shutdown and resumes main thread execution
func (s *Ethereum) WaitForShutdown() {
	<-s.shutdownChan
}

// now tx broadcasting is taken out of txPool
// handled here via subscription, efficiency?
func (self *Ethereum) txBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.txSub.Chan() {
		event := obj.(core.TxPreEvent)
		self.net.Broadcast("eth", TxMsg, event.Tx.RlpData())
	}
}

func (self *Ethereum) blockBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.blockSub.Chan() {
		switch ev := obj.(type) {
		case core.NewMinedBlockEvent:
			self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td)
		}
	}
}

func saveProtocolVersion(db ethutil.Database) {
	d, _ := db.Get([]byte("ProtocolVersion"))
	protocolVersion := ethutil.NewValue(d).Uint()

	if protocolVersion == 0 {
		db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes())
	}
}
<commit_msg>use ethash.Verify in blockpool<commit_after>package eth

import (
	"crypto/ecdsa"
	"fmt"
	"io/ioutil"
	"path"
	"strings"

	"github.com/ethereum/ethash"
	"github.com/ethereum/go-ethereum/blockpool"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/miner"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/p2p/discover"
	"github.com/ethereum/go-ethereum/p2p/nat"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/ethereum/go-ethereum/whisper"
)

var (
	ethlogger  = logger.NewLogger("SERV")
	jsonlogger = logger.NewJsonLogger()

	defaultBootNodes = []*discover.Node{
		// ETH/DEV cmd/bootnode
		discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"),
		// ETH/DEV cpp-ethereum (poc-8.ethdev.com)
		discover.MustParseNode("enode://4a44599974518ea5b0f14c31c4463692ac0329cb84851f3435e6d1b18ee4eae4aa495f846a0fa1219bd58035671881d44423876e57db2abd57254d0197da0ebe@5.1.83.226:30303"),
	}
)

type Config struct {
	Name      string
	KeyStore  string
	DataDir   string
	LogFile   string
	LogLevel  int
	KeyRing   string
	LogFormat string

	MaxPeers int
	Port     string

	// This should be a space-separated list of
	// discovery node URLs.
	BootNodes string

	// This key is used to identify the node on the network.
	// If nil, an ephemeral key is used.
	NodeKey *ecdsa.PrivateKey

	NAT  nat.Interface
	Shh  bool
	Dial bool

	MinerThreads int

	KeyManager *crypto.KeyManager
}

func (cfg *Config) parseBootNodes() []*discover.Node {
	if cfg.BootNodes == "" {
		return defaultBootNodes
	}
	var ns []*discover.Node
	for _, url := range strings.Split(cfg.BootNodes, " ") {
		if url == "" {
			continue
		}
		n, err := discover.ParseNode(url)
		if err != nil {
			ethlogger.Errorf("Bootstrap URL %s: %v\n", url, err)
			continue
		}
		ns = append(ns, n)
	}
	return ns
}

func (cfg *Config) nodeKey() (*ecdsa.PrivateKey, error) {
	// use explicit key from command line args if set
	if cfg.NodeKey != nil {
		return cfg.NodeKey, nil
	}
	// use persistent key if present
	keyfile := path.Join(cfg.DataDir, "nodekey")
	key, err := crypto.LoadECDSA(keyfile)
	if err == nil {
		return key, nil
	}
	// no persistent key, generate and store a new one
	if key, err = crypto.GenerateKey(); err != nil {
		return nil, fmt.Errorf("could not generate server key: %v", err)
	}
	if err := ioutil.WriteFile(keyfile, crypto.FromECDSA(key), 0600); err != nil {
		ethlogger.Errorln("could not persist nodekey: ", err)
	}
	return key, nil
}

type Ethereum struct {
	// Channel for shutting down the ethereum
	shutdownChan chan bool
	quit         chan bool

	// DB interface
	db        ethutil.Database
	blacklist p2p.Blacklist

	//*** SERVICES ***
	// State manager for processing new blocks and managing the over all states
	blockProcessor *core.BlockProcessor
	txPool         *core.TxPool
	chainManager   *core.ChainManager
	blockPool      *blockpool.BlockPool
	whisper        *whisper.Whisper

	net      *p2p.Server
	eventMux *event.TypeMux
	txSub    event.Subscription
	blockSub event.Subscription
	miner    *miner.Miner

	RpcServer  rpc.RpcServer
	keyManager *crypto.KeyManager

	logger logger.LogSystem

	Mining bool
}

func New(config *Config) (*Ethereum, error) {
	// Boostrap database
	ethlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
	db, err := ethdb.NewLDBDatabase("blockchain")
	if err != nil {
		return nil, err
	}

	// Perform database sanity checks
	d, _ := db.Get([]byte("ProtocolVersion"))
	protov := ethutil.NewValue(d).Uint()
	if protov != ProtocolVersion && protov != 0 {
		path := path.Join(config.DataDir, "blockchain")
		return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, path)
	}

	// Create new keymanager
	var keyManager *crypto.KeyManager
	switch config.KeyStore {
	case "db":
		keyManager = crypto.NewDBKeyManager(db)
	case "file":
		keyManager = crypto.NewFileKeyManager(config.DataDir)
	default:
		return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore)
	}
	// Initialise the keyring
	keyManager.Init(config.KeyRing, 0, false)

	saveProtocolVersion(db)
	//ethutil.Config.Db = db

	eth := &Ethereum{
		shutdownChan: make(chan bool),
		quit:         make(chan bool),
		db:           db,
		keyManager:   keyManager,
		blacklist:    p2p.NewBlacklist(),
		eventMux:     &event.TypeMux{},
		logger:       ethlogger,
	}

	eth.chainManager = core.NewChainManager(db, eth.EventMux())
	pow := ethash.New(eth.chainManager)

	eth.txPool = core.NewTxPool(eth.EventMux())
	eth.blockProcessor = core.NewBlockProcessor(db, pow, eth.txPool, eth.chainManager, eth.EventMux())
	eth.chainManager.SetProcessor(eth.blockProcessor)
	eth.whisper = whisper.New()
	eth.miner = miner.New(keyManager.Address(), eth, pow, config.MinerThreads)

	hasBlock := eth.chainManager.HasBlock
	insertChain := eth.chainManager.InsertChain
	eth.blockPool = blockpool.New(hasBlock, insertChain, pow.Verify)

	netprv, err := config.nodeKey()
	if err != nil {
		return nil, err
	}
	ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
	protocols := []p2p.Protocol{ethProto}
	if config.Shh {
		protocols = append(protocols, eth.whisper.Protocol())
	}

	eth.net = &p2p.Server{
		PrivateKey:     netprv,
		Name:           config.Name,
		MaxPeers:       config.MaxPeers,
		Protocols:      protocols,
		Blacklist:      eth.blacklist,
		NAT:            config.NAT,
		NoDial:         !config.Dial,
		BootstrapNodes: config.parseBootNodes(),
	}
	if len(config.Port) > 0 {
		eth.net.ListenAddr = ":" + config.Port
	}

	return eth, nil
}

func (s *Ethereum) KeyManager() *crypto.KeyManager       { return s.keyManager }
func (s *Ethereum) Logger() logger.LogSystem             { return s.logger }
func (s *Ethereum) Name() string                         { return s.net.Name }
func (s *Ethereum) ChainManager() *core.ChainManager     { return s.chainManager }
func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcessor }
func (s *Ethereum) TxPool() *core.TxPool                 { return s.txPool }
func (s *Ethereum) BlockPool() *blockpool.BlockPool      { return s.blockPool }
func (s *Ethereum) Whisper() *whisper.Whisper            { return s.whisper }
func (s *Ethereum) EventMux() *event.TypeMux             { return s.eventMux }
func (s *Ethereum) Db() ethutil.Database                 { return s.db }
func (s *Ethereum) Miner() *miner.Miner                  { return s.miner }
func (s *Ethereum) IsListening() bool                    { return true } // Always listening
func (s *Ethereum) PeerCount() int                       { return s.net.PeerCount() }
func (s *Ethereum) Peers() []*p2p.Peer                   { return s.net.Peers() }
func (s *Ethereum) MaxPeers() int                        { return s.net.MaxPeers }
func (s *Ethereum) Coinbase() []byte                     { return nil } // TODO

// Start the ethereum
func (s *Ethereum) Start() error {
	jsonlogger.LogJson(&logger.LogStarting{
		ClientString:    s.net.Name,
		ProtocolVersion: ProtocolVersion,
	})

	err := s.net.Start()
	if err != nil {
		return err
	}

	// Start services
	s.txPool.Start()
	s.blockPool.Start()

	if s.whisper != nil {
		s.whisper.Start()
	}

	// broadcast transactions
	s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
	go s.txBroadcastLoop()

	// broadcast mined blocks
	s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
	go s.blockBroadcastLoop()

	ethlogger.Infoln("Server started")
	return nil
}

func (self *Ethereum) SuggestPeer(nodeURL string) error {
	n, err := discover.ParseNode(nodeURL)
	if err != nil {
		return fmt.Errorf("invalid node URL: %v", err)
	}
	self.net.SuggestPeer(n)
	return nil
}

func (s *Ethereum) Stop() {
	// Close the database
	defer s.db.Close()

	close(s.quit)

	s.txSub.Unsubscribe()    // quits txBroadcastLoop
	s.blockSub.Unsubscribe() // quits blockBroadcastLoop

	if s.RpcServer != nil {
		s.RpcServer.Stop()
	}

	s.txPool.Stop()
	s.eventMux.Stop()
	s.blockPool.Stop()
	if s.whisper != nil {
		s.whisper.Stop()
	}

	ethlogger.Infoln("Server stopped")
	close(s.shutdownChan)
}

// This function will wait for a shutdown and resumes main thread execution
func (s *Ethereum) WaitForShutdown() {
	<-s.shutdownChan
}

// now tx broadcasting is taken out of txPool
// handled here via subscription, efficiency?
func (self *Ethereum) txBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.txSub.Chan() {
		event := obj.(core.TxPreEvent)
		self.net.Broadcast("eth", TxMsg, event.Tx.RlpData())
	}
}

func (self *Ethereum) blockBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.blockSub.Chan() {
		switch ev := obj.(type) {
		case core.NewMinedBlockEvent:
			self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td)
		}
	}
}

func saveProtocolVersion(db ethutil.Database) {
	d, _ := db.Get([]byte("ProtocolVersion"))
	protocolVersion := ethutil.NewValue(d).Uint()

	if protocolVersion == 0 {
		db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes())
	}
}
<|endoftext|>


<commit_before>package eth

import (
	"fmt"
	"math"
	"math/big"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/eth/downloader"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/rlp"
)

const (
	forceSyncCycle      = 10 * time.Second       // Time interval to force syncs, even if few peers are available
	blockProcCycle      = 500 * time.Millisecond // Time interval to check for new blocks to process
	minDesiredPeerCount = 5                      // Amount of peers desired to start syncing
	blockProcAmount     = 256
)

func errResp(code errCode, format string, v ...interface{}) error {
	return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
}

type hashFetcherFn func(common.Hash) error
type blockFetcherFn func([]common.Hash) error

// extProt is an interface which is passed around so we can expose GetHashes and GetBlock without exposing it to the rest of the protocol
// extProt is passed around to peers which require to GetHashes and GetBlocks
type extProt struct {
	getHashes hashFetcherFn
	getBlocks blockFetcherFn
}

func (ep extProt) GetHashes(hash common.Hash) error    { return ep.getHashes(hash) }
func (ep extProt) GetBlock(hashes []common.Hash) error { return ep.getBlocks(hashes) }

type ProtocolManager struct {
	protVer, netId int
	txpool         txPool
	chainman       *core.ChainManager
	downloader     *downloader.Downloader
	peers          *peerSet

	SubProtocol p2p.Protocol

	eventMux      *event.TypeMux
	txSub         event.Subscription
	minedBlockSub event.Subscription

	newPeerCh chan *peer
	quitSync  chan struct{}
	// wait group is used for graceful shutdowns during downloading
	// and processing
	wg   sync.WaitGroup
	quit bool
}

// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
func NewProtocolManager(protocolVersion, networkId int, mux *event.TypeMux, txpool txPool, chainman *core.ChainManager, downloader *downloader.Downloader) *ProtocolManager {
	manager := &ProtocolManager{
		eventMux:   mux,
		txpool:     txpool,
		chainman:   chainman,
		downloader: downloader,
		peers:      newPeerSet(),
		newPeerCh:  make(chan *peer, 1),
		quitSync:   make(chan struct{}),
	}

	manager.SubProtocol = p2p.Protocol{
		Name:    "eth",
		Version: uint(protocolVersion),
		Length:  ProtocolLength,
		Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
			peer := manager.newPeer(protocolVersion, networkId, p, rw)

			manager.newPeerCh <- peer

			return manager.handle(peer)
		},
	}

	return manager
}

func (pm *ProtocolManager) removePeer(id string) {
	// Short circuit if the peer was already removed
	peer := pm.peers.Peer(id)
	if peer == nil {
		return
	}
	glog.V(logger.Debug).Infoln("Removing peer", id)

	// Unregister the peer from the downloader and Ethereum peer set
	pm.downloader.UnregisterPeer(id)
	if err := pm.peers.Unregister(id); err != nil {
		glog.V(logger.Error).Infoln("Removal failed:", err)
	}
	// Hard disconnect at the networking layer
	if peer != nil {
		peer.Peer.Disconnect(p2p.DiscUselessPeer)
	}
}

func (pm *ProtocolManager) Start() {
	// broadcast transactions
	pm.txSub = pm.eventMux.Subscribe(core.TxPreEvent{})
	go pm.txBroadcastLoop()

	// broadcast mined blocks
	pm.minedBlockSub = pm.eventMux.Subscribe(core.NewMinedBlockEvent{})
	go pm.minedBroadcastLoop()

	go pm.update()
}

func (pm *ProtocolManager) Stop() {
	// Showing a log message. During download / process this could actually
	// take between 5 to 10 seconds and therefor feedback is required.
	glog.V(logger.Info).Infoln("Stopping ethereum protocol handler...")

	pm.quit = true
	pm.txSub.Unsubscribe()         // quits txBroadcastLoop
	pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
	close(pm.quitSync)             // quits the sync handler

	// Wait for any process action
	pm.wg.Wait()

	glog.V(logger.Info).Infoln("Ethereum protocol handler stopped")
}

func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
	td, current, genesis := pm.chainman.Status()

	return newPeer(pv, nv, genesis, current, td, p, rw)
}

func (pm *ProtocolManager) handle(p *peer) error {
	// Execute the Ethereum handshake, short circuit if fails
	if err := p.handleStatus(); err != nil {
		return err
	}
	// Register the peer locally and in the downloader too
	glog.V(logger.Detail).Infoln("Adding peer", p.id)
	if err := pm.peers.Register(p); err != nil {
		glog.V(logger.Error).Infoln("Addition failed:", err)
		return err
	}
	defer pm.removePeer(p.id)

	if err := pm.downloader.RegisterPeer(p.id, p.recentHash, p.requestHashes, p.requestBlocks); err != nil {
		return err
	}
	// propagate existing transactions. new transactions appearing
	// after this will be sent via broadcasts.
	if err := p.sendTransactions(pm.txpool.GetTransactions()); err != nil {
		return err
	}
	// main loop. handle incoming messages.
	for {
		if err := pm.handleMsg(p); err != nil {
			return err
		}
	}
	return nil
}

func (self *ProtocolManager) handleMsg(p *peer) error {
	msg, err := p.rw.ReadMsg()
	if err != nil {
		return err
	}
	if msg.Size > ProtocolMaxMsgSize {
		return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
	}
	// make sure that the payload has been fully consumed
	defer msg.Discard()

	switch msg.Code {
	case GetTxMsg: // ignore
	case StatusMsg:
		return errResp(ErrExtraStatusMsg, "uncontrolled status message")

	case TxMsg:
		// TODO: rework using lazy RLP stream
		var txs []*types.Transaction
		if err := msg.Decode(&txs); err != nil {
			return errResp(ErrDecode, "msg %v: %v", msg, err)
		}
		for i, tx := range txs {
			if tx == nil {
				return errResp(ErrDecode, "transaction %d is nil", i)
			}
			jsonlogger.LogJson(&logger.EthTxReceived{
				TxHash:   tx.Hash().Hex(),
				RemoteId: p.ID().String(),
			})
		}
		self.txpool.AddTransactions(txs)

	case GetBlockHashesMsg:
		var request getBlockHashesMsgData
		if err := msg.Decode(&request); err != nil {
			return errResp(ErrDecode, "->msg %v: %v", msg, err)
		}

		if request.Amount > downloader.MaxHashFetch {
			request.Amount = downloader.MaxHashFetch
		}

		hashes := self.chainman.GetBlockHashesFromHash(request.Hash, request.Amount)

		if glog.V(logger.Debug) {
			if len(hashes) == 0 {
				glog.Infof("invalid block hash %x", request.Hash.Bytes()[:4])
			}
		}

		// returns either requested hashes or nothing (i.e. not found)
		return p.sendBlockHashes(hashes)
	case BlockHashesMsg:
		msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))

		var hashes []common.Hash
		if err := msgStream.Decode(&hashes); err != nil {
			break
		}
		err := self.downloader.DeliverHashes(p.id, hashes)
		if err != nil {
			glog.V(logger.Debug).Infoln(err)
		}

	case GetBlocksMsg:
		var blocks []*types.Block

		msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
		if _, err := msgStream.List(); err != nil {
			return err
		}
		var i int
		for {
			i++
			var hash common.Hash
			err := msgStream.Decode(&hash)
			if err == rlp.EOL {
				break
			} else if err != nil {
				return errResp(ErrDecode, "msg %v: %v", msg, err)
			}

			block := self.chainman.GetBlock(hash)
			if block != nil {
				blocks = append(blocks, block)
			}
			if i == downloader.MaxBlockFetch {
				break
			}
		}
		return p.sendBlocks(blocks)
	case BlocksMsg:
		var blocks []*types.Block

		msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
		if err := msgStream.Decode(&blocks); err != nil {
			glog.V(logger.Detail).Infoln("Decode error", err)
			blocks = nil
		}
		self.downloader.DeliverBlocks(p.id, blocks)

	case NewBlockMsg:
		var request newBlockMsgData
		if err := msg.Decode(&request); err != nil {
			return errResp(ErrDecode, "%v: %v", msg, err)
		}
		if err := request.Block.ValidateFields(); err != nil {
			return errResp(ErrDecode, "block validation %v: %v", msg, err)
		}
		request.Block.ReceivedAt = msg.ReceivedAt

		hash := request.Block.Hash()
		// Add the block hash as a known hash to the peer. This will later be used to determine
		// who should receive this.
		p.blockHashes.Add(hash)
		// update the peer info
		p.recentHash = hash
		p.td = request.TD

		_, chainHead, _ := self.chainman.Status()

		jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
			BlockHash:     hash.Hex(),
			BlockNumber:   request.Block.Number(), // this surely must be zero
			ChainHeadHash: chainHead.Hex(),
			BlockPrevHash: request.Block.ParentHash().Hex(),
			RemoteId:      p.ID().String(),
		})

		// Make sure the block isn't already known. If this is the case simply drop
		// the message and move on. If the TD is < currentTd; drop it as well. If this
		// chain at some point becomes canonical, the downloader will fetch it.
		if self.chainman.HasBlock(hash) {
			break
		}
		if self.chainman.Td().Cmp(request.TD) > 0 && new(big.Int).Add(request.Block.Number(), big.NewInt(7)).Cmp(self.chainman.CurrentBlock().Number()) < 0 {
			glog.V(logger.Debug).Infof("[%s] dropped block %v due to low TD %v\n", p.id, request.Block.Number(), request.TD)
			break
		}

		// Attempt to insert the newly received by checking if the parent exists.
		// if the parent exists we process the block and propagate to our peers
		// otherwise synchronize with the peer
		if self.chainman.HasBlock(request.Block.ParentHash()) {
			if _, err := self.chainman.InsertChain(types.Blocks{request.Block}); err != nil {
				glog.V(logger.Error).Infoln("removed peer (", p.id, ") due to block error")

				self.removePeer(p.id)

				return nil
			}

			if err := self.verifyTd(p, request); err != nil {
				glog.V(logger.Error).Infoln(err)
				// XXX for now return nil so it won't disconnect (we should in the future)
				return nil
			}
			self.BroadcastBlock(hash, request.Block)
		} else {
			go self.synchronise(p)
		}
	default:
		return errResp(ErrInvalidMsgCode, "%v", msg.Code)
	}
	return nil
}

func (pm *ProtocolManager) verifyTd(peer *peer, request newBlockMsgData) error {
	if request.Block.Td.Cmp(request.TD) != 0 {
		glog.V(logger.Detail).Infoln(peer)

		return fmt.Errorf("invalid TD on block(%v) from peer(%s): block.td=%v, request.td=%v", request.Block.Number(), peer.id, request.Block.Td, request.TD)
	}

	return nil
}

// BroadcastBlock will propagate the block to its connected peers. It will sort
// out which peers do not contain the block in their block set and will do a
// sqrt(peers) to determine the amount of peers we broadcast to.
func (pm *ProtocolManager) BroadcastBlock(hash common.Hash, block *types.Block) {
	// Broadcast block to a batch of peers not knowing about it
	peers := pm.peers.PeersWithoutBlock(hash)
	peers = peers[:int(math.Sqrt(float64(len(peers))))]
	for _, peer := range peers {
		peer.sendNewBlock(block)
	}
	glog.V(logger.Detail).Infoln("broadcast block to", len(peers), "peers. Total processing time:", time.Since(block.ReceivedAt))
}

// BroadcastTx will propagate the block to its connected peers. It will sort
// out which peers do not contain the block in their block set and will do a
// sqrt(peers) to determine the amount of peers we broadcast to.
func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction) {
	// Broadcast transaction to a batch of peers not knowing about it
	peers := pm.peers.PeersWithoutTx(hash)
	//FIXME include this again: peers = peers[:int(math.Sqrt(float64(len(peers))))]
	for _, peer := range peers {
		peer.sendTransaction(tx)
	}
	glog.V(logger.Detail).Infoln("broadcast tx to", len(peers), "peers")
}

// Mined broadcast loop
func (self *ProtocolManager) minedBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.minedBlockSub.Chan() {
		switch ev := obj.(type) {
		case core.NewMinedBlockEvent:
			self.BroadcastBlock(ev.Block.Hash(), ev.Block)
		}
	}
}

func (self *ProtocolManager) txBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.txSub.Chan() {
		event := obj.(core.TxPreEvent)
		self.BroadcastTx(event.Tx.Hash(), event.Tx)
	}
}
<commit_msg>eth: 100% block propogation<commit_after>package eth

import (
	"fmt"
	"math/big"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/eth/downloader"
	"github.com/ethereum/go-ethereum/event"
	"github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/logger/glog"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/rlp"
)

const (
	forceSyncCycle      = 10 * time.Second       // Time interval to force syncs, even if few peers are available
	blockProcCycle      = 500 * time.Millisecond // Time interval to check for new blocks to process
	minDesiredPeerCount = 5                      // Amount of peers desired to start syncing
	blockProcAmount     = 256
)

func errResp(code errCode, format string, v ...interface{}) error {
	return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
}

type hashFetcherFn func(common.Hash) error
type blockFetcherFn func([]common.Hash) error

// extProt is an interface which is passed around so we can expose GetHashes and GetBlock without exposing it to the rest of the protocol
// extProt is passed around to peers which require to GetHashes and GetBlocks
type extProt struct {
	getHashes hashFetcherFn
	getBlocks blockFetcherFn
}

func (ep extProt) GetHashes(hash common.Hash) error    { return ep.getHashes(hash) }
func (ep extProt) GetBlock(hashes []common.Hash) error { return ep.getBlocks(hashes) }

type ProtocolManager struct {
	protVer, netId int
	txpool         txPool
	chainman       *core.ChainManager
	downloader     *downloader.Downloader
	peers          *peerSet

	SubProtocol p2p.Protocol

	eventMux      *event.TypeMux
	txSub         event.Subscription
	minedBlockSub event.Subscription

	newPeerCh chan *peer
	quitSync  chan struct{}
	// wait group is used for graceful shutdowns during downloading
	// and processing
	wg   sync.WaitGroup
	quit bool
}

// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
func NewProtocolManager(protocolVersion, networkId int, mux *event.TypeMux, txpool txPool, chainman *core.ChainManager, downloader *downloader.Downloader) *ProtocolManager {
	manager := &ProtocolManager{
		eventMux:   mux,
		txpool:     txpool,
		chainman:   chainman,
		downloader: downloader,
		peers:      newPeerSet(),
		newPeerCh:  make(chan *peer, 1),
		quitSync:   make(chan struct{}),
	}

	manager.SubProtocol = p2p.Protocol{
		Name:    "eth",
		Version: uint(protocolVersion),
		Length:  ProtocolLength,
		Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
			peer := manager.newPeer(protocolVersion, networkId, p, rw)

			manager.newPeerCh <- peer

			return manager.handle(peer)
		},
	}

	return manager
}

func (pm *ProtocolManager) removePeer(id string) {
	// Short circuit if the peer was already removed
	peer := pm.peers.Peer(id)
	if peer == nil {
		return
	}
	glog.V(logger.Debug).Infoln("Removing peer", id)

	// Unregister the peer from the downloader and Ethereum peer set
	pm.downloader.UnregisterPeer(id)
	if err := pm.peers.Unregister(id); err != nil {
		glog.V(logger.Error).Infoln("Removal failed:", err)
	}
	// Hard disconnect at the networking layer
	if peer != nil {
		peer.Peer.Disconnect(p2p.DiscUselessPeer)
	}
}

func (pm *ProtocolManager) Start() {
	// broadcast transactions
	pm.txSub = pm.eventMux.Subscribe(core.TxPreEvent{})
	go pm.txBroadcastLoop()

	// broadcast mined blocks
	pm.minedBlockSub = pm.eventMux.Subscribe(core.NewMinedBlockEvent{})
	go pm.minedBroadcastLoop()

	go pm.update()
}

func (pm *ProtocolManager) Stop() {
	// Showing a log message. During download / process this could actually
	// take between 5 to 10 seconds and therefor feedback is required.
	glog.V(logger.Info).Infoln("Stopping ethereum protocol handler...")

	pm.quit = true
	pm.txSub.Unsubscribe()         // quits txBroadcastLoop
	pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
	close(pm.quitSync)             // quits the sync handler

	// Wait for any process action
	pm.wg.Wait()

	glog.V(logger.Info).Infoln("Ethereum protocol handler stopped")
}

func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
	td, current, genesis := pm.chainman.Status()

	return newPeer(pv, nv, genesis, current, td, p, rw)
}

func (pm *ProtocolManager) handle(p *peer) error {
	// Execute the Ethereum handshake, short circuit if fails
	if err := p.handleStatus(); err != nil {
		return err
	}
	// Register the peer locally and in the downloader too
	glog.V(logger.Detail).Infoln("Adding peer", p.id)
	if err := pm.peers.Register(p); err != nil {
		glog.V(logger.Error).Infoln("Addition failed:", err)
		return err
	}
	defer pm.removePeer(p.id)

	if err := pm.downloader.RegisterPeer(p.id, p.recentHash, p.requestHashes, p.requestBlocks); err != nil {
		return err
	}
	// propagate existing transactions. new transactions appearing
	// after this will be sent via broadcasts.
	if err := p.sendTransactions(pm.txpool.GetTransactions()); err != nil {
		return err
	}
	// main loop. handle incoming messages.
	for {
		if err := pm.handleMsg(p); err != nil {
			return err
		}
	}
	return nil
}

func (self *ProtocolManager) handleMsg(p *peer) error {
	msg, err := p.rw.ReadMsg()
	if err != nil {
		return err
	}
	if msg.Size > ProtocolMaxMsgSize {
		return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
	}
	// make sure that the payload has been fully consumed
	defer msg.Discard()

	switch msg.Code {
	case GetTxMsg: // ignore
	case StatusMsg:
		return errResp(ErrExtraStatusMsg, "uncontrolled status message")

	case TxMsg:
		// TODO: rework using lazy RLP stream
		var txs []*types.Transaction
		if err := msg.Decode(&txs); err != nil {
			return errResp(ErrDecode, "msg %v: %v", msg, err)
		}
		for i, tx := range txs {
			if tx == nil {
				return errResp(ErrDecode, "transaction %d is nil", i)
			}
			jsonlogger.LogJson(&logger.EthTxReceived{
				TxHash:   tx.Hash().Hex(),
				RemoteId: p.ID().String(),
			})
		}
		self.txpool.AddTransactions(txs)

	case GetBlockHashesMsg:
		var request getBlockHashesMsgData
		if err := msg.Decode(&request); err != nil {
			return errResp(ErrDecode, "->msg %v: %v", msg, err)
		}

		if request.Amount > downloader.MaxHashFetch {
			request.Amount = downloader.MaxHashFetch
		}

		hashes := self.chainman.GetBlockHashesFromHash(request.Hash, request.Amount)

		if glog.V(logger.Debug) {
			if len(hashes) == 0 {
				glog.Infof("invalid block hash %x", request.Hash.Bytes()[:4])
			}
		}

		// returns either requested hashes or nothing (i.e. not found)
		return p.sendBlockHashes(hashes)
	case BlockHashesMsg:
		msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))

		var hashes []common.Hash
		if err := msgStream.Decode(&hashes); err != nil {
			break
		}
		err := self.downloader.DeliverHashes(p.id, hashes)
		if err != nil {
			glog.V(logger.Debug).Infoln(err)
		}

	case GetBlocksMsg:
		var blocks []*types.Block

		msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
		if _, err := msgStream.List(); err != nil {
			return err
		}
		var i int
		for {
			i++
			var hash common.Hash
			err := msgStream.Decode(&hash)
			if err == rlp.EOL {
				break
			} else if err != nil {
				return errResp(ErrDecode, "msg %v: %v", msg, err)
			}

			block := self.chainman.GetBlock(hash)
			if block != nil {
				blocks = append(blocks, block)
			}
			if i == downloader.MaxBlockFetch {
				break
			}
		}
		return p.sendBlocks(blocks)
	case BlocksMsg:
		var blocks []*types.Block

		msgStream := rlp.NewStream(msg.Payload, uint64(msg.Size))
		if err := msgStream.Decode(&blocks); err != nil {
			glog.V(logger.Detail).Infoln("Decode error", err)
			blocks = nil
		}
		self.downloader.DeliverBlocks(p.id, blocks)

	case NewBlockMsg:
		var request newBlockMsgData
		if err := msg.Decode(&request); err != nil {
			return errResp(ErrDecode, "%v: %v", msg, err)
		}
		if err := request.Block.ValidateFields(); err != nil {
			return errResp(ErrDecode, "block validation %v: %v", msg, err)
		}
		request.Block.ReceivedAt = msg.ReceivedAt

		hash := request.Block.Hash()
		// Add the block hash as a known hash to the peer. This will later be used to determine
		// who should receive this.
		p.blockHashes.Add(hash)
		// update the peer info
		p.recentHash = hash
		p.td = request.TD

		_, chainHead, _ := self.chainman.Status()

		jsonlogger.LogJson(&logger.EthChainReceivedNewBlock{
			BlockHash:     hash.Hex(),
			BlockNumber:   request.Block.Number(), // this surely must be zero
			ChainHeadHash: chainHead.Hex(),
			BlockPrevHash: request.Block.ParentHash().Hex(),
			RemoteId:      p.ID().String(),
		})

		// Make sure the block isn't already known. If this is the case simply drop
		// the message and move on. If the TD is < currentTd; drop it as well. If this
		// chain at some point becomes canonical, the downloader will fetch it.
		if self.chainman.HasBlock(hash) {
			break
		}
		if self.chainman.Td().Cmp(request.TD) > 0 && new(big.Int).Add(request.Block.Number(), big.NewInt(7)).Cmp(self.chainman.CurrentBlock().Number()) < 0 {
			glog.V(logger.Debug).Infof("[%s] dropped block %v due to low TD %v\n", p.id, request.Block.Number(), request.TD)
			break
		}

		// Attempt to insert the newly received by checking if the parent exists.
		// if the parent exists we process the block and propagate to our peers
		// otherwise synchronize with the peer
		if self.chainman.HasBlock(request.Block.ParentHash()) {
			if _, err := self.chainman.InsertChain(types.Blocks{request.Block}); err != nil {
				glog.V(logger.Error).Infoln("removed peer (", p.id, ") due to block error")

				self.removePeer(p.id)

				return nil
			}

			if err := self.verifyTd(p, request); err != nil {
				glog.V(logger.Error).Infoln(err)
				// XXX for now return nil so it won't disconnect (we should in the future)
				return nil
			}
			self.BroadcastBlock(hash, request.Block)
		} else {
			go self.synchronise(p)
		}
	default:
		return errResp(ErrInvalidMsgCode, "%v", msg.Code)
	}
	return nil
}

func (pm *ProtocolManager) verifyTd(peer *peer, request newBlockMsgData) error {
	if request.Block.Td.Cmp(request.TD) != 0 {
		glog.V(logger.Detail).Infoln(peer)

		return fmt.Errorf("invalid TD on block(%v) from peer(%s): block.td=%v, request.td=%v", request.Block.Number(), peer.id, request.Block.Td, request.TD)
	}

	return nil
}

// BroadcastBlock will propagate the block to its connected peers. It will sort
// out which peers do not contain the block in their block set and will do a
// sqrt(peers) to determine the amount of peers we broadcast to.
func (pm *ProtocolManager) BroadcastBlock(hash common.Hash, block *types.Block) {
	// Broadcast block to a batch of peers not knowing about it
	peers := pm.peers.PeersWithoutBlock(hash)
	//peers = peers[:int(math.Sqrt(float64(len(peers))))]
	for _, peer := range peers {
		peer.sendNewBlock(block)
	}
	glog.V(logger.Detail).Infoln("broadcast block to", len(peers), "peers. Total processing time:", time.Since(block.ReceivedAt))
}

// BroadcastTx will propagate the block to its connected peers. It will sort
// out which peers do not contain the block in their block set and will do a
// sqrt(peers) to determine the amount of peers we broadcast to.
func (pm *ProtocolManager) BroadcastTx(hash common.Hash, tx *types.Transaction) {
	// Broadcast transaction to a batch of peers not knowing about it
	peers := pm.peers.PeersWithoutTx(hash)
	//FIXME include this again: peers = peers[:int(math.Sqrt(float64(len(peers))))]
	for _, peer := range peers {
		peer.sendTransaction(tx)
	}
	glog.V(logger.Detail).Infoln("broadcast tx to", len(peers), "peers")
}

// Mined broadcast loop
func (self *ProtocolManager) minedBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.minedBlockSub.Chan() {
		switch ev := obj.(type) {
		case core.NewMinedBlockEvent:
			self.BroadcastBlock(ev.Block.Hash(), ev.Block)
		}
	}
}

func (self *ProtocolManager) txBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.txSub.Chan() {
		event := obj.(core.TxPreEvent)
		self.BroadcastTx(event.Tx.Hash(), event.Tx)
	}
}
<|endoftext|>


<commit_before>package amalgam

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha256"
	"database/sql/driver"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"hash/crc32"
	"math"
	"net"
	"net/http"
	"strconv"
	"strings"

	"github.com/juju/errors"
)

//Custom data type for easy mapping of jsonB DB column to a GO struct member.
type PgJson map[string]interface{}

// This is the only method of the interface Valuer under the sql/driver package.
// Types implementing this interface can convert themselves to a driver
// acceptable value.
func (p PgJson) Value() (driver.Value, error) {
	j, err := json.Marshal(p)
	return j, err
}

// Scan is the only method of the Scanner interface under the sql package.
// Scan assigns a value from the DB driver to the object that calls it
func (p *PgJson) Scan(src interface{}) error {
	source, ok := src.([]byte)
	if !ok {
		return errors.New("Type assertion .([]byte) failed.")
	}

	err := json.Unmarshal(source, p)
	if err != nil {
		return err
	}

	return nil
}

type NullPgJson struct {
	PgJson PgJson
	Valid  bool
}

func (p NullPgJson) Value() (driver.Value, error) {
	if !p.Valid {
		return nil, nil
	}
	j, err := json.Marshal(p)
	return j, err
}

func (p *NullPgJson) Scan(src interface{}) error {
	if src == nil {
		p.Valid = false
		return nil
	}
	source, ok := src.([]byte)
	if !ok {
		return errors.New("Type assertion .([]byte) failed.")
	}

	js := PgJson{}
	err := json.Unmarshal(source, &js)
	if err != nil {
		return err
	}

	p.Valid = true
	p.PgJson = js

	return nil
}

func GetIPFromRequest(r *http.Request) (string, error) {
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return "", errors.Trace(err)
	}

	return ip, nil
}

func EncodeID(id int64, model string) string {
	crc := crc32.ChecksumIEEE(make([]byte, id)) & 0xffffffff
	message := make([]byte, 0)

	mm := make([]byte, 4)
	binary.LittleEndian.PutUint32(mm, crc)
	message = append(message, mm...)

	mm = make([]byte, 8)
	binary.LittleEndian.PutUint64(mm, uint64(id))
	message = append(message, mm...)

	mm = make([]byte, 4)
	message = append(message, mm...)

	block, err := aes.NewCipher([]byte(Secret[:32]))
	if err != nil {
		panic(err)
	}

	t := sha256.Sum256([]byte(Secret + model))
	iv := t[:16]

	blockmode := cipher.NewCBCEncrypter(block, iv)

	blockmode.CryptBlocks(message, message)

	tt := make([]byte, 32)
	base64.URLEncoding.Encode(tt, message)

	eid := strings.Replace(string(tt), "=", "", -1)

	return eid

}

func DecodeEID(eid string, model string) (string, error) {
	if len(eid)%3 != 0 {
		rem := len(eid) % 3
		for i := 3; i > rem; i-- {
			eid = eid + "="
		}
	}

	e, err := base64.URLEncoding.DecodeString(eid)
	if err != nil {
		return "", errors.Trace(err)
	}

	block, err := aes.NewCipher([]byte(Secret[:32]))
	if err != nil {
		return "", errors.Trace(err)
	}

	t := sha256.Sum256([]byte(Secret + model))
	iv := t[:16]

	blockmode := cipher.NewCBCDecrypter(block, iv)

	blockmode.CryptBlocks(e, e)

	b := int(e[4])
	var exp = 1
	for i := 5; i < len(e); i++ {
		if int(e[i]) != 0 {
			b += int(math.Pow(float64(256), float64(exp))) * int(e[i])
		}
		exp++
	}

	tracker := strconv.Itoa(b)

	return tracker, nil
}

func GetTrackerFromRequest(r *http.Request) string {
	var tracker string = ""
	cookies := r.Cookies()
	for i := 0; i < len(cookies); i++ {
		cookie := cookies[i]
		if cookie.Name == "trackerid" {
			tracker = cookie.Value
			break
		}
	}

	return tracker
}
<commit_msg>minor fixes<commit_after>package amalgam

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha256"
	"database/sql/driver"
	"encoding/base64"
	"encoding/binary"
	"encoding/json"
	"hash/crc32"
	"math"
	"net"
	"net/http"
	"strconv"
	"strings"

	"github.com/juju/errors"
)

//Custom data type for easy mapping of jsonB DB column to a GO struct member.
type PgJson map[string]interface{}

// This is the only method of the interface Valuer under the sql/driver package.
// Types implementing this interface can convert themselves to a driver
// acceptable value.
func (p PgJson) Value() (driver.Value, error) {
	j, err := json.Marshal(p)
	return j, err
}

// Scan is the only method of the Scanner interface under the sql package.
// Scan assigns a value from the DB driver to the object that calls it
func (p *PgJson) Scan(src interface{}) error {
	source, ok := src.([]byte)
	if !ok {
		return errors.New("Type assertion .([]byte) failed.")
	}

	err := json.Unmarshal(source, p)
	if err != nil {
		return err
	}

	return nil
}

type NullPgJson struct {
	PgJson PgJson
	Valid  bool
}

func (p NullPgJson) Value() (driver.Value, error) {
	if !p.Valid {
		return nil, nil
	}
	j, err := json.Marshal(p)
	return j, err
}

func (p *NullPgJson) Scan(src interface{}) error {
	if src == nil {
		p.Valid = false
		return nil
	}
	source, ok := src.([]byte)
	if !ok {
		return errors.New("Type assertion .([]byte) failed.")
	}

	js := PgJson{}
	err := json.Unmarshal(source, &js)
	if err != nil {
		return err
	}

	p.Valid = true
	p.PgJson = js

	return nil
}

func GetIPFromRequest(r *http.Request) (string, error) {
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return "", errors.Trace(err)
	}

	return ip, nil
}

func EncodeID(id int64, model string) string {
	crc := crc32.ChecksumIEEE(make([]byte, id)) & 0xffffffff
	message := make([]byte, 0)

	mm := make([]byte, 4)
	binary.LittleEndian.PutUint32(mm, crc)
	message = append(message, mm...)

	mm = make([]byte, 8)
	binary.LittleEndian.PutUint64(mm, uint64(id))
	message = append(message, mm...)

	mm = make([]byte, 4)
	message = append(message, mm...)

	block, err := aes.NewCipher([]byte(Secret[:32]))
	if err != nil {
		panic(err)
	}

	t := sha256.Sum256([]byte(Secret + model))
	iv := t[:16]

	blockmode := cipher.NewCBCEncrypter(block, iv)

	blockmode.CryptBlocks(message, message)

	tt := base64.URLEncoding.EncodeToString(message)

	eid := strings.Replace(string(tt), "=", "", -1)

	return eid

}

func DecodeEID(eid string, model string) (string, error) {
	if len(eid)%3 != 0 {
		rem := len(eid) % 3
		for i := 3; i > rem; i-- {
			eid = eid + "="
		}
	}

	e, err := base64.URLEncoding.DecodeString(eid)
	if err != nil {
		return "", errors.Trace(err)
	}

	block, err := aes.NewCipher([]byte(Secret[:32]))
	if err != nil {
		return "", errors.Trace(err)
	}

	t := sha256.Sum256([]byte(Secret + model))
	iv := t[:16]

	blockmode := cipher.NewCBCDecrypter(block, iv)

	blockmode.CryptBlocks(e, e)

	b := int(e[4])
	var exp = 1
	for i := 5; i < len(e); i++ {
		if int(e[i]) != 0 {
			b += int(math.Pow(float64(256), float64(exp))) * int(e[i])
		}
		exp++
	}

	tracker := strconv.Itoa(b)

	return tracker, nil
}

func GetTrackerFromRequest(r *http.Request) string {
	var tracker string = ""
	cookies := r.Cookies()
	for i := 0; i < len(cookies); i++ {
		cookie := cookies[i]
		if cookie.Name == "trackerid" {
			tracker = cookie.Value
			break
		}
	}

	return tracker
}
<|endoftext|>


<commit_before>package zmq2

import (
	"fmt"
)

/*
Send multi-part message on socket.

Any `[]string' or `[][]byte' is split into separate `string's or `[]byte's

Any other part that isn't a `string' or `[]byte' is converted
to `string' with `fmt.Sprintf("%v", part)'.

Returns total bytes sent.
*/
func (soc *Socket) SendMessage(parts ...interface{}) (total int, err error) {
	return soc.sendMessage(0, parts...)
}

/*
Like SendMessage(), but adding the NOBLOCK flag.
*/
func (soc *Socket) SendMessageDontwait(parts ...interface{}) (total int, err error) {
	return soc.sendMessage(NOBLOCK, parts...)
}

func (soc *Socket) sendMessage(dontwait Flag, parts ...interface{}) (total int, err error) {
	// TODO: make this faster

	// flatten first, just in case the last part may be an empty []string or [][]byte
	pp := make([]interface{}, 0)
	for _, p := range parts {
		switch t := p.(type) {
		case []string:
			for _, s := range t {
				pp = append(pp, s)
			}
		case [][]byte:
			for _, b := range t {
				pp = append(pp, b)
			}
		default:
			pp = append(pp, t)
		}
	}

	n := len(pp)
	if n == 0 {
		return
	}
	opt := SNDMORE | dontwait
	for i, p := range pp {
		if i == n-1 {
			opt = dontwait
		}
		switch t := p.(type) {
		case string:
			j, e := soc.Send(t, opt)
			if e == nil {
				total += j
			} else {
				return -1, e
			}
		case []byte:
			j, e := soc.SendBytes(t, opt)
			if e == nil {
				total += j
			} else {
				return -1, e
			}
		default:
			j, e := soc.Send(fmt.Sprintf("%v", t), opt)
			if e == nil {
				total += j
			} else {
				return -1, e
			}
		}
	}
	return
}

/*
Receive parts as message from socket.

Returns last non-nil error code.
*/
func (soc *Socket) RecvMessage(flags Flag) (msg []string, err error) {
	msg = make([]string, 0)
	for {
		s, e := soc.Recv(flags)
		if e == nil {
			msg = append(msg, s)
		} else {
			return msg[0:0], e
		}
		more, e := soc.GetRcvmore()
		if e == nil {
			if !more {
				break
			}
		} else {
			return msg[0:0], e
		}
	}
	return
}

/*
Receive parts as message from socket.

Returns last non-nil error code.
*/
func (soc *Socket) RecvMessageBytes(flags Flag) (msg [][]byte, err error) {
	msg = make([][]byte, 0)
	for {
		b, e := soc.RecvBytes(flags)
		if e == nil {
			msg = append(msg, b)
		} else {
			return msg[0:0], e
		}
		more, e := soc.GetRcvmore()
		if e == nil {
			if !more {
				break
			}
		} else {
			return msg[0:0], e
		}
	}
	return
}
<commit_msg>faster SendMessage() and SendMessageDontwait()<commit_after>package zmq2

import (
	"fmt"
)

/*
Send multi-part message on socket.

Any `[]string' or `[][]byte' is split into separate `string's or `[]byte's

Any other part that isn't a `string' or `[]byte' is converted
to `string' with `fmt.Sprintf("%v", part)'.

Returns total bytes sent.
*/
func (soc *Socket) SendMessage(parts ...interface{}) (total int, err error) {
	return soc.sendMessage(0, parts...)
}

/*
Like SendMessage(), but adding the NOBLOCK flag.
*/
func (soc *Socket) SendMessageDontwait(parts ...interface{}) (total int, err error) {
	return soc.sendMessage(NOBLOCK, parts...)
}

func (soc *Socket) sendMessage(dontwait Flag, parts ...interface{}) (total int, err error) {

	var last int
PARTS:
	for last = len(parts) - 1; last >= 0; last-- {
		switch t := parts[last].(type) {
		case []string:
			if len(t) > 0 {
				break PARTS
			}
		case [][]byte:
			if len(t) > 0 {
				break PARTS
			}
		default:
			break PARTS
		}
	}

	opt := SNDMORE | dontwait
	for i := 0; i <= last; i++ {
		if i == last {
			opt = dontwait
		}
		switch t := parts[i].(type) {
		case []string:
			opt = SNDMORE | dontwait
			n := len(t) - 1
			for j, s := range t {
				if j == n && i == last {
					opt = dontwait
				}
				c, e := soc.Send(s, opt)
				if e == nil {
					total += c
				} else {
					return -1, e
				}
			}
		case [][]byte:
			opt = SNDMORE | dontwait
			n := len(t) - 1
			for j, b := range t {
				if j == n && i == last {
					opt = dontwait
				}
				c, e := soc.SendBytes(b, opt)
				if e == nil {
					total += c
				} else {
					return -1, e
				}
			}
		case string:
			c, e := soc.Send(t, opt)
			if e == nil {
				total += c
			} else {
				return -1, e
			}
		case []byte:
			c, e := soc.SendBytes(t, opt)
			if e == nil {
				total += c
			} else {
				return -1, e
			}
		default:
			c, e := soc.Send(fmt.Sprintf("%v", t), opt)
			if e == nil {
				total += c
			} else {
				return -1, e
			}
		}
	}
	return
}

/*
Receive parts as message from socket.

Returns last non-nil error code.
*/
func (soc *Socket) RecvMessage(flags Flag) (msg []string, err error) {
	msg = make([]string, 0)
	for {
		s, e := soc.Recv(flags)
		if e == nil {
			msg = append(msg, s)
		} else {
			return msg[0:0], e
		}
		more, e := soc.GetRcvmore()
		if e == nil {
			if !more {
				break
			}
		} else {
			return msg[0:0], e
		}
	}
	return
}

/*
Receive parts as message from socket.

Returns last non-nil error code.
*/
func (soc *Socket) RecvMessageBytes(flags Flag) (msg [][]byte, err error) {
	msg = make([][]byte, 0)
	for {
		b, e := soc.RecvBytes(flags)
		if e == nil {
			msg = append(msg, b)
		} else {
			return msg[0:0], e
		}
		more, e := soc.GetRcvmore()
		if e == nil {
			if !more {
				break
			}
		} else {
			return msg[0:0], e
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// 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.

// author           sigu-399
// author-github    https://github.com/sigu-399
// author-mail      sigu.399@gmail.com
//
// repository-name  gojsonschema
// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
//
// description      Various utility functions.
//
// created          26-02-2013

package gojsonschema

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"reflect"
)

func isKind(what interface{}, kind reflect.Kind) bool {
	return reflect.ValueOf(what).Kind() == kind
}

func existsMapKey(m map[string]interface{}, k string) bool {
	_, ok := m[k]
	return ok
}

func isStringInSlice(s []string, what string) bool {
	for i := range s {
		if s[i] == what {
			return true
		}
	}
	return false
}

// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
const (
	max_json_float = float64(1<<53 - 1) // 9007199254740991.0 	 	 2^53 - 1
	min_json_float = -float64(1 << 53 - 1)  //-9007199254740991.0	-2^53 - 1
)

// allow for integers [-2^53, 2^53-1] inclusive
func isFloat64AnInteger(f float64) bool {

	if math.IsNaN(f) || math.IsInf(f, 0) || f < min_json_float || f > max_json_float {
		return false
	}

	return f == float64(int64(f)) || f == float64(uint64(f))
}

// formats a number so that it is displayed as the smallest string possible
func validationErrorFormatNumber(n float64) string {

	if isFloat64AnInteger(n) {
		return fmt.Sprintf("%d", int64(n))
	}

	return fmt.Sprintf("%g", n)
}

func marshalToJsonString(value interface{}) (*string, error) {

	mBytes, err := json.Marshal(value)
	if err != nil {
		return nil, err
	}

	sBytes := string(mBytes)
	return &sBytes, nil
}

const internalLogEnabled = false

func internalLog(message string) {
	if internalLogEnabled {
		log.Print(message)
	}
}
<commit_msg>Added utility routines for common patterns<commit_after>// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// 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.

// author           sigu-399
// author-github    https://github.com/sigu-399
// author-mail      sigu.399@gmail.com
//
// repository-name  gojsonschema
// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
//
// description      Various utility functions.
//
// created          26-02-2013

package gojsonschema

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"reflect"
)

func mustBeInteger(what interface{}) *float64 {
	var number float64
	if isKind(what, reflect.Float64) {
		number = what.(float64)
		if isFloat64AnInteger(number) {
			return &number
		} else {
			return nil
		}
	} else if isKind(what, reflect.Int) {
		number = float64(what.(int))
		return &number
	}
	return nil
}

func mustBeNumber(what interface{}) *float64 {
	var number float64

	if isKind(what, reflect.Float64) {
		number = what.(float64)
		return &number
	} else if isKind(what, reflect.Int) {
		number = float64(what.(int))
		return &number
	}
	return nil
}

func isKind(what interface{}, kind reflect.Kind) bool {
	return reflect.ValueOf(what).Kind() == kind
}

func existsMapKey(m map[string]interface{}, k string) bool {
	_, ok := m[k]
	return ok
}

func isStringInSlice(s []string, what string) bool {
	for i := range s {
		if s[i] == what {
			return true
		}
	}
	return false
}

// same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER
const (
	max_json_float = float64(1<<53 - 1)  // 9007199254740991.0 	 	 2^53 - 1
	min_json_float = -float64(1<<53 - 1) //-9007199254740991.0	-2^53 - 1
)

// allow for integers [-2^53, 2^53-1] inclusive
func isFloat64AnInteger(f float64) bool {

	if math.IsNaN(f) || math.IsInf(f, 0) || f < min_json_float || f > max_json_float {
		return false
	}

	return f == float64(int64(f)) || f == float64(uint64(f))
}

// formats a number so that it is displayed as the smallest string possible
func validationErrorFormatNumber(n float64) string {

	if isFloat64AnInteger(n) {
		return fmt.Sprintf("%d", int64(n))
	}

	return fmt.Sprintf("%g", n)
}

func marshalToJsonString(value interface{}) (*string, error) {

	mBytes, err := json.Marshal(value)
	if err != nil {
		return nil, err
	}

	sBytes := string(mBytes)
	return &sBytes, nil
}

const internalLogEnabled = false

func internalLog(message string) {
	if internalLogEnabled {
		log.Print(message)
	}
}
<|endoftext|>


<commit_before>package signals

// convert to internal y representation, 1 -> maxY
func Y(d interface{}) y {
	return MultiplyY(d, unitY)
}

// multiply anything by an y quantity
func MultiplyY(m interface{}, d y) y {
	switch mt := m.(type) {
	case int:
		return d * y(mt)
	case uint:
		return d * y(mt)
	case int8:
		return d * y(mt)
	case uint8:
		return d * y(mt)
	case int16:
		return d * y(mt)
	case uint16:
		return d * y(mt)
	case int32:
		return d * y(mt)
	case uint32:
		return d * y(mt)
	case int64:
		return d * y(mt)
	case uint64:
		return d * y(mt)
	case float32:
		return y(float32(d)*mt + .5)
	case float64:
		return y(float64(d)*mt + .5)
	default:
		return d
	}
}

// convert to internal x representation, 1 -> UnitX
func X(d interface{}) x {
	return MultiplyX(d, unitX)
}

// multiply anything by an x quantity
func MultiplyX(m interface{}, d x) x {
	switch mt := m.(type) {
	case int:
		return d * x(mt)
	case uint:
		return d * x(mt)
	case int8:
		return d * x(mt)
	case uint8:
		return d * x(mt)
	case int16:
		return d * x(mt)
	case uint16:
		return d * x(mt)
	case int32:
		return d * x(mt)
	case uint32:
		return d * x(mt)
	case int64:
		return d * x(mt)
	case uint64:
		return d * x(mt)
	case float32:
		return x(float32(d)*mt + .5)
	case float64:
		return x(float64(d)*mt + .5)
	default:
		return d
	}
}
<commit_msg>comment<commit_after>package signals

// convert to internal y representation, 1 -> unitY
func Y(d interface{}) y {
	return MultiplyY(d, unitY)
}

// multiply anything by an y quantity
func MultiplyY(m interface{}, d y) y {
	switch mt := m.(type) {
	case int:
		return d * y(mt)
	case uint:
		return d * y(mt)
	case int8:
		return d * y(mt)
	case uint8:
		return d * y(mt)
	case int16:
		return d * y(mt)
	case uint16:
		return d * y(mt)
	case int32:
		return d * y(mt)
	case uint32:
		return d * y(mt)
	case int64:
		return d * y(mt)
	case uint64:
		return d * y(mt)
	case float32:
		return y(float32(d)*mt + .5)
	case float64:
		return y(float64(d)*mt + .5)
	default:
		return d
	}
}

// convert to internal x representation, 1 -> UnitX
func X(d interface{}) x {
	return MultiplyX(d, unitX)
}

// multiply anything by an x quantity
func MultiplyX(m interface{}, d x) x {
	switch mt := m.(type) {
	case int:
		return d * x(mt)
	case uint:
		return d * x(mt)
	case int8:
		return d * x(mt)
	case uint8:
		return d * x(mt)
	case int16:
		return d * x(mt)
	case uint16:
		return d * x(mt)
	case int32:
		return d * x(mt)
	case uint32:
		return d * x(mt)
	case int64:
		return d * x(mt)
	case uint64:
		return d * x(mt)
	case float32:
		return x(float32(d)*mt + .5)
	case float64:
		return x(float64(d)*mt + .5)
	default:
		return d
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Luke Ho All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ackley

import (
	"encoding/json"
	"fmt"
	"github.com/golang/glog"
	"io/ioutil"
	"math/rand"
	"net/http"
	"reflect"
	"time"
)

func (ackley *Ackley) update_bot_presence() {
	// Update the presence of the bot itself
	presence_url := fmt.Sprintf("https://slack.com/api/users.setPresence?%v=%v&%v=%v", "token", ackley.slack_auth_token, "presence", "auto")
	resp, err := http.Get(presence_url)
	if err != nil {
		glog.Errorf("Error while trying to set presence:%v\n", err)
		return
	}
	if resp.StatusCode != http.StatusOK {
		glog.Errorf("Error while trying to set presence, status code not OK:%v\n", resp.StatusCode)
		return
	}
	pres_resp_buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Errorf("Error while trying to read from presence response body:%v\n", err)
		return
	}
	resp.Body.Close()
	slack_response := &SlackResponse{}
	err = json.Unmarshal(pres_resp_buf, slack_response)
	if err != nil {
		glog.Errorf("Error while trying to unmarshal slack response for presence:%v\n", err)
		return
	}
	if slack_response.Ok == false {
		glog.Errorf("Error while trying to set presence: slack response not ok\n")
		return
	}
}

func (ackley *Ackley) store_slack_channel_info(rtm_start_json map[string]interface{}) {
	glog.Infof("Type of channels:%v\n", reflect.TypeOf(rtm_start_json["channels"]))
	if cv, ok := rtm_start_json["channels"].([]interface{}); ok {
		glog.Infof("channels value:%v\n", cv)
		for _, entry := range cv {
			cur_slack_channel := &SlackChannel{}
			glog.Infof("Entry type: %v\n", reflect.TypeOf(entry))
			cur_map, err := entry.(map[string]interface{})
			if err == false {
				glog.Errorf("Cur_map error:%v\n", err)
				return
			}
			for k, v := range cur_map {
				switch k {
				case "id":
					cur_slack_channel.Id = v.(string)
				case "name":
					cur_slack_channel.Name = v.(string)
				case "is_channel":
					cur_slack_channel.Is_channel = v.(bool)
				case "created":
					cur_slack_channel.Created = v.(float64)
				case "creator":
					cur_slack_channel.Creator = v.(string)
				case "is_archived":
					cur_slack_channel.Is_archived = v.(bool)
				case "is_general":
					cur_slack_channel.Is_general = v.(bool)
				case "has_pins":
					cur_slack_channel.Has_pins = v.(bool)
				case "is_member":
					cur_slack_channel.Is_member = v.(bool)
				default:
					glog.Infof("Unknown attribute: %v = %v\n", k, v)
				}
			}
			ackley.slack_channels = append(ackley.slack_channels, *cur_slack_channel)
		}
	} else {
		glog.Errorf("Error while getting list of slack channels from rtm.Start: ok resp: %v\n", ok)
		return
	}
}

func (ackley *Ackley) store_slack_users(rtm_start_json map[string]interface{}) {
	// Populate users
	if cv, ok := rtm_start_json["users"].([]interface{}); ok {
		glog.Infof("users:%v\n", cv)
		for _, entry := range cv {
			cur_slack_user := &SlackUser{}
			glog.Infof("Entry type: %v\n", reflect.TypeOf(entry))
			cur_map, err := entry.(map[string]interface{})
			if err == false {
				glog.Errorf("Cur_map error:%v\n", err)
				return
			}
			for k, v := range cur_map {
				switch k {
				case "id":
					cur_slack_user.Id = v.(string)
				case "team_id":
					cur_slack_user.Team_id = v.(string)
				case "name":
					cur_slack_user.Name = v.(string)
				default:
					glog.Infof("Ignoring attribute: %v = %v\n", k, v)
				}
			}
			ackley.slack_users = append(ackley.slack_users, *cur_slack_user)
			ackley.slack_user_id_to_user[cur_slack_user.Id] = &ackley.slack_users[len(ackley.slack_users)-1]
		}
	} else {
		glog.Errorf("Error while getting list of slack channels from rtm.Start: ok resp: %v\n", ok)
		return
	}
}

func (ackley *Ackley) store_slack_ims_info(rtm_start_json map[string]interface{}) {
	// Populate users
	if cv, ok := rtm_start_json["ims"].([]interface{}); ok {
		glog.Infof("ims:%v\n", cv)
		for _, entry := range cv {
			cur_slack_im := &SlackIm{}
			glog.Infof("Entry type: %v\n", reflect.TypeOf(entry))
			cur_map, err := entry.(map[string]interface{})
			if err == false {
				glog.Errorf("Cur_map error:%v\n", err)
				return
			}
			for k, v := range cur_map {
				switch k {
				case "id":
					cur_slack_im.Id = v.(string)
				case "user":
					cur_slack_im.User_id = v.(string)
				default:
					glog.Infof("Ignoring attribute: %v = %v\n", k, v)
				}
			}
			ackley.slack_user_id_to_im[cur_slack_im.User_id] = cur_slack_im.Id
		}
	} else {
		glog.Errorf("Error while getting list of slack ims from rtm.Start: ok resp: %v\n", ok)
		return
	}
}

func (ackley *Ackley) listen_for_interrupts() {
	for {
		select {
		case <-ackley.interrupt_channel:
			ackley.cleanup()
			ackley.interrupt_channel_resp <- true
		}
	}
}

// TBD: Remove this
func (ackley *Ackley) randomly_disconnect() {
	rand_seconds := rand.Int31n(5)
	glog.Errorf("Randomly disconnect: About to sleep for %v seconds\n", rand_seconds)
	time.Sleep(time.Second * time.Duration(rand_seconds))
	glog.Errorf("Randomly disconnect: Begin flap\n")
	ackley.flap_connection()
}

func (ackley *Ackley) make_default_response(info *SlackMessageInfo) ([]byte, error) {
	text_response := fmt.Sprintf("Hi, %v!\n", info.User.Name)

	info.Msg.Text = text_response
	response_bytes, err := json.Marshal(info.Msg)
	if err != nil {
		return nil, err
	}
	return response_bytes, nil
}
func (ackley *Ackley) send_typing_event(channel string) {
	ste := SlackTypingEvent{Id: 1, Type: "typing", Channel: channel}
	ste_bytes, err := json.Marshal(&ste)
	if err != nil {
		glog.Errorf("Error while trying to Marshal typing event (%v):%v\n", ste, err.Error())
	}
	_, err = ackley.slack_web_socket.Write(ste_bytes)
	if err != nil {
		glog.Errorf("Error while writing to web socket(%v):%v\n", string(ste_bytes), err.Error())
	}
}
<commit_msg>typing event: check for nil websocket<commit_after>// Copyright 2016 Luke Ho All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ackley

import (
	"encoding/json"
	"fmt"
	"github.com/golang/glog"
	"io/ioutil"
	"math/rand"
	"net/http"
	"reflect"
	"time"
)

func (ackley *Ackley) update_bot_presence() {
	// Update the presence of the bot itself
	presence_url := fmt.Sprintf("https://slack.com/api/users.setPresence?%v=%v&%v=%v", "token", ackley.slack_auth_token, "presence", "auto")
	resp, err := http.Get(presence_url)
	if err != nil {
		glog.Errorf("Error while trying to set presence:%v\n", err)
		return
	}
	if resp.StatusCode != http.StatusOK {
		glog.Errorf("Error while trying to set presence, status code not OK:%v\n", resp.StatusCode)
		return
	}
	pres_resp_buf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		glog.Errorf("Error while trying to read from presence response body:%v\n", err)
		return
	}
	resp.Body.Close()
	slack_response := &SlackResponse{}
	err = json.Unmarshal(pres_resp_buf, slack_response)
	if err != nil {
		glog.Errorf("Error while trying to unmarshal slack response for presence:%v\n", err)
		return
	}
	if slack_response.Ok == false {
		glog.Errorf("Error while trying to set presence: slack response not ok\n")
		return
	}
}

func (ackley *Ackley) store_slack_channel_info(rtm_start_json map[string]interface{}) {
	glog.Infof("Type of channels:%v\n", reflect.TypeOf(rtm_start_json["channels"]))
	if cv, ok := rtm_start_json["channels"].([]interface{}); ok {
		glog.Infof("channels value:%v\n", cv)
		for _, entry := range cv {
			cur_slack_channel := &SlackChannel{}
			glog.Infof("Entry type: %v\n", reflect.TypeOf(entry))
			cur_map, err := entry.(map[string]interface{})
			if err == false {
				glog.Errorf("Cur_map error:%v\n", err)
				return
			}
			for k, v := range cur_map {
				switch k {
				case "id":
					cur_slack_channel.Id = v.(string)
				case "name":
					cur_slack_channel.Name = v.(string)
				case "is_channel":
					cur_slack_channel.Is_channel = v.(bool)
				case "created":
					cur_slack_channel.Created = v.(float64)
				case "creator":
					cur_slack_channel.Creator = v.(string)
				case "is_archived":
					cur_slack_channel.Is_archived = v.(bool)
				case "is_general":
					cur_slack_channel.Is_general = v.(bool)
				case "has_pins":
					cur_slack_channel.Has_pins = v.(bool)
				case "is_member":
					cur_slack_channel.Is_member = v.(bool)
				default:
					glog.Infof("Unknown attribute: %v = %v\n", k, v)
				}
			}
			ackley.slack_channels = append(ackley.slack_channels, *cur_slack_channel)
		}
	} else {
		glog.Errorf("Error while getting list of slack channels from rtm.Start: ok resp: %v\n", ok)
		return
	}
}

func (ackley *Ackley) store_slack_users(rtm_start_json map[string]interface{}) {
	// Populate users
	if cv, ok := rtm_start_json["users"].([]interface{}); ok {
		glog.Infof("users:%v\n", cv)
		for _, entry := range cv {
			cur_slack_user := &SlackUser{}
			glog.Infof("Entry type: %v\n", reflect.TypeOf(entry))
			cur_map, err := entry.(map[string]interface{})
			if err == false {
				glog.Errorf("Cur_map error:%v\n", err)
				return
			}
			for k, v := range cur_map {
				switch k {
				case "id":
					cur_slack_user.Id = v.(string)
				case "team_id":
					cur_slack_user.Team_id = v.(string)
				case "name":
					cur_slack_user.Name = v.(string)
				default:
					glog.Infof("Ignoring attribute: %v = %v\n", k, v)
				}
			}
			ackley.slack_users = append(ackley.slack_users, *cur_slack_user)
			ackley.slack_user_id_to_user[cur_slack_user.Id] = &ackley.slack_users[len(ackley.slack_users)-1]
		}
	} else {
		glog.Errorf("Error while getting list of slack channels from rtm.Start: ok resp: %v\n", ok)
		return
	}
}

func (ackley *Ackley) store_slack_ims_info(rtm_start_json map[string]interface{}) {
	// Populate users
	if cv, ok := rtm_start_json["ims"].([]interface{}); ok {
		glog.Infof("ims:%v\n", cv)
		for _, entry := range cv {
			cur_slack_im := &SlackIm{}
			glog.Infof("Entry type: %v\n", reflect.TypeOf(entry))
			cur_map, err := entry.(map[string]interface{})
			if err == false {
				glog.Errorf("Cur_map error:%v\n", err)
				return
			}
			for k, v := range cur_map {
				switch k {
				case "id":
					cur_slack_im.Id = v.(string)
				case "user":
					cur_slack_im.User_id = v.(string)
				default:
					glog.Infof("Ignoring attribute: %v = %v\n", k, v)
				}
			}
			ackley.slack_user_id_to_im[cur_slack_im.User_id] = cur_slack_im.Id
		}
	} else {
		glog.Errorf("Error while getting list of slack ims from rtm.Start: ok resp: %v\n", ok)
		return
	}
}

func (ackley *Ackley) listen_for_interrupts() {
	for {
		select {
		case <-ackley.interrupt_channel:
			ackley.cleanup()
			ackley.interrupt_channel_resp <- true
		}
	}
}

// TBD: Remove this
func (ackley *Ackley) randomly_disconnect() {
	rand_seconds := rand.Int31n(5)
	glog.Errorf("Randomly disconnect: About to sleep for %v seconds\n", rand_seconds)
	time.Sleep(time.Second * time.Duration(rand_seconds))
	glog.Errorf("Randomly disconnect: Begin flap\n")
	ackley.flap_connection()
}

func (ackley *Ackley) make_default_response(info *SlackMessageInfo) ([]byte, error) {
	text_response := fmt.Sprintf("Hi, %v!\n", info.User.Name)

	info.Msg.Text = text_response
	response_bytes, err := json.Marshal(info.Msg)
	if err != nil {
		return nil, err
	}
	return response_bytes, nil
}
func (ackley *Ackley) send_typing_event(channel string) {
	ste := SlackTypingEvent{Id: 1, Type: "typing", Channel: channel}
	ste_bytes, err := json.Marshal(&ste)
	if err != nil {
		glog.Errorf("Error while trying to Marshal typing event (%v):%v\n", ste, err.Error())
	}
	if ackley.slack_web_socket != nil {
		_, err = ackley.slack_web_socket.Write(ste_bytes)
	} else {
		err = fmt.Errorf("Unable to send typing event as slack web socket is nil")
	}
	if err != nil {
		glog.Errorf("Error while writing to web socket(%v):%v\n", string(ste_bytes), err.Error())
	}
}
<|endoftext|>


<commit_before>/*Package crud crud

SOURCE FILE LICENSE(utils.go)
The MIT License (MIT)

Copyright (c) 2013-NOW  Jinzhu <wosmvp@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

FILE MODIFIED BY shesuyo <shesuyo@gmail.com>
*/
package crud

import (
	"bytes"
	"database/sql/driver"
	"fmt"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"sync"
	"time"
)

// NowFunc returns current time, this function is exported in order to be able
// to give the flexibility to the developer to customize it according to their
// needs, e.g:
//    gorm.NowFunc = func() time.Time {
//      return time.Now().UTC()
//    }
var NowFunc = func() time.Time {
	return time.Now()
}

// Copied from golint
var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}
var commonInitialismsReplacer *strings.Replacer

var goSrcRegexp = regexp.MustCompile(`jinzhu/gorm/.*.go`)
var goTestRegexp = regexp.MustCompile(`jinzhu/gorm/.*test.go`)

func init() {
	var commonInitialismsForReplacer []string
	for _, initialism := range commonInitialisms {
		commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
	}
	commonInitialismsReplacer = strings.NewReplacer(commonInitialismsForReplacer...)
}

type safeMap struct {
	m  map[string]string
	rm map[string]string
	l  *sync.RWMutex
}

func (s *safeMap) Set(key string, value string) {
	s.l.Lock()
	defer s.l.Unlock()
	s.m[key] = value
	s.rm[value] = key
}

func (s *safeMap) Get(key string) string {
	s.l.RLock()
	defer s.l.RUnlock()
	return s.m[key]
}

func (s *safeMap) RGet(key string) string {
	return s.rm[key]
}

func newSafeMap() *safeMap {
	return &safeMap{l: new(sync.RWMutex), m: make(map[string]string), rm: make(map[string]string)}
}

var smap = newSafeMap()

type strCase bool

const (
	lower strCase = false
	upper strCase = true
)

// ToStructName convert string to struct name
func ToStructName(name string) string {
	return smap.RGet(name)
}

// ToDBName convert string to db name
func ToDBName(name string) string {
	if v := smap.Get(name); v != "" {
		return v
	}

	if name == "" {
		return ""
	}

	var (
		value                        = commonInitialismsReplacer.Replace(name)
		buf                          = bytes.NewBufferString("")
		lastCase, currCase, nextCase strCase
	)

	for i, v := range value[:len(value)-1] {
		nextCase = strCase(value[i+1] >= 'A' && value[i+1] <= 'Z')
		if i > 0 {
			if currCase == upper {
				if lastCase == upper && nextCase == upper {
					buf.WriteRune(v)
				} else {
					if value[i-1] != '_' && value[i+1] != '_' {
						buf.WriteRune('_')
					}
					buf.WriteRune(v)
				}
			} else {
				buf.WriteRune(v)
				if i == len(value)-2 && nextCase == upper {
					buf.WriteRune('_')
				}
			}
		} else {
			currCase = upper
			buf.WriteRune(v)
		}
		lastCase = currCase
		currCase = nextCase
	}

	buf.WriteByte(value[len(value)-1])

	s := strings.ToLower(buf.String())
	smap.Set(name, s)
	return s
}

func indirect(reflectValue reflect.Value) reflect.Value {
	for reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	return reflectValue
}

func toQueryMarks(primaryValues [][]interface{}) string {
	var results []string

	for _, primaryValue := range primaryValues {
		var marks []string
		for range primaryValue {
			marks = append(marks, "?")
		}

		if len(marks) > 1 {
			results = append(results, fmt.Sprintf("(%v)", strings.Join(marks, ",")))
		} else {
			results = append(results, strings.Join(marks, ""))
		}
	}
	return strings.Join(results, ",")
}

func toQueryValues(values [][]interface{}) (results []interface{}) {
	for _, value := range values {
		for _, v := range value {
			results = append(results, v)
		}
	}
	return
}

func fileWithLineNum() string {
	for i := 2; i < 15; i++ {
		_, file, line, ok := runtime.Caller(i)
		if ok && (!goSrcRegexp.MatchString(file) || goTestRegexp.MatchString(file)) {
			return fmt.Sprintf("%v:%v", file, line)
		}
	}
	return ""
}

func toSearchableMap(attrs ...interface{}) (result interface{}) {
	if len(attrs) > 1 {
		if str, ok := attrs[0].(string); ok {
			result = map[string]interface{}{str: attrs[1]}
		}
	} else if len(attrs) == 1 {
		if attr, ok := attrs[0].(map[string]interface{}); ok {
			result = attr
		}

		if attr, ok := attrs[0].(interface{}); ok {
			result = attr
		}
	}
	return
}

func equalAsString(a interface{}, b interface{}) bool {
	return toString(a) == toString(b)
}

func toString(str interface{}) string {
	if values, ok := str.([]interface{}); ok {
		var results []string
		for _, value := range values {
			results = append(results, toString(value))
		}
		return strings.Join(results, "_")
	} else if bytes, ok := str.([]byte); ok {
		return string(bytes)
	} else if reflectValue := reflect.Indirect(reflect.ValueOf(str)); reflectValue.IsValid() {
		return fmt.Sprintf("%v", reflectValue.Interface())
	}
	return ""
}

func makeSlice(elemType reflect.Type) interface{} {
	if elemType.Kind() == reflect.Slice {
		elemType = elemType.Elem()
	}
	sliceType := reflect.SliceOf(elemType)
	slice := reflect.New(sliceType)
	slice.Elem().Set(reflect.MakeSlice(sliceType, 0, 0))
	return slice.Interface()
}

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

// getValueFromFields return given fields's value
func getValueFromFields(value reflect.Value, fieldNames []string) (results []interface{}) {
	// If value is a nil pointer, Indirect returns a zero Value!
	// Therefor we need to check for a zero value,
	// as FieldByName could panic
	if indirectValue := reflect.Indirect(value); indirectValue.IsValid() {
		for _, fieldName := range fieldNames {
			if fieldValue := indirectValue.FieldByName(fieldName); fieldValue.IsValid() {
				result := fieldValue.Interface()
				if r, ok := result.(driver.Valuer); ok {
					result, _ = r.Value()
				}
				results = append(results, result)
			}
		}
	}
	return
}

func addExtraSpaceIfExist(str string) string {
	if str != "" {
		return " " + str
	}
	return ""
}

func ksvs(m map[string]interface{}, keyTail ...string) ([]string, []interface{}) {
	kt := ""
	ks := []string{}
	vs := []interface{}{}
	if len(keyTail) > 0 {
		kt = keyTail[0]
	}
	for k, v := range m {
		ks = append(ks, " `"+k+"`"+kt)
		vs = append(vs, v)
	}
	return ks, vs
}

func argslice(l int) string {
	s := []string{}
	for i := 0; i < l; i++ {
		s = append(s, "?")
	}
	return strings.Join(s, ",")
}
<commit_msg>移除GORM的ToDBName，新的速度快一倍。<commit_after>package crud

import (
	"strings"

	"ekt.com/ekt/x/safemap"
)

var (
	fullTitles         = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS", "PY"}
	fullTitlesReplacer *strings.Replacer
	//m和rm公用同一个
	dbNameMap = safemap.NewMapStringString()
)

func init() {
	var oldnew []string
	for _, title := range fullTitles {
		oldnew = append(oldnew, title, "_"+strings.ToLower(title))
	}
	for i := 'A'; i < 'Z'; i++ {
		oldnew = append(oldnew, string(i), "_"+string(i+32))
	}
	fullTitlesReplacer = strings.NewReplacer(oldnew...)
}

//ToDBName 将结构体的字段名字转换成对应数据库字段名
//比gorm速度快一倍
func ToDBName(name string) string {
	val, ok := dbNameMap.Get(name)
	if ok {
		return val
	}
	return toDBName(name)
}

//ToStructName 数据库字段名转换成对应结构体名
func ToStructName(name string) string {
	val, ok := dbNameMap.Get(name)
	if ok {
		return val
	}
	return ""
}

func toDBName(name string) string {
	dbName := fullTitlesReplacer.Replace(name)
	if len(dbName) >= 1 {
		dbNameMap.Set(name, dbName[1:])
		dbNameMap.Set(dbName[1:], name)
		return dbName[1:]
	}
	return ""
}
func ksvs(m map[string]interface{}, keyTail ...string) ([]string, []interface{}) {
	kt := ""
	ks := []string{}
	vs := []interface{}{}
	if len(keyTail) > 0 {
		kt = keyTail[0]
	}
	for k, v := range m {
		ks = append(ks, " `"+k+"`"+kt)
		vs = append(vs, v)
	}
	return ks, vs
}

func argslice(l int) string {
	s := []string{}
	for i := 0; i < l; i++ {
		s = append(s, "?")
	}
	return strings.Join(s, ",")
}
<|endoftext|>