forked from mirror/go-ethereum
parent
4366fdfc13
commit
02017ed0e0
@ -0,0 +1,357 @@ |
|||||||
|
package eth |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"net" |
||||||
|
"path" |
||||||
|
"sync" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/core" |
||||||
|
"github.com/ethereum/go-ethereum/core/types" |
||||||
|
"github.com/ethereum/go-ethereum/crypto" |
||||||
|
"github.com/ethereum/go-ethereum/ethutil" |
||||||
|
"github.com/ethereum/go-ethereum/event" |
||||||
|
ethlogger "github.com/ethereum/go-ethereum/logger" |
||||||
|
"github.com/ethereum/go-ethereum/p2p" |
||||||
|
"github.com/ethereum/go-ethereum/rpc" |
||||||
|
"github.com/ethereum/go-ethereum/state" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
seedNodeAddress = "poc-7.ethdev.com:30300" |
||||||
|
) |
||||||
|
|
||||||
|
var logger = ethlogger.NewLogger("SERV") |
||||||
|
|
||||||
|
type Ethereum struct { |
||||||
|
// Channel for shutting down the ethereum
|
||||||
|
shutdownChan chan bool |
||||||
|
quit chan bool |
||||||
|
|
||||||
|
// DB interface
|
||||||
|
db ethutil.Database |
||||||
|
// State manager for processing new blocks and managing the over all states
|
||||||
|
blockManager *core.BlockManager |
||||||
|
|
||||||
|
// The transaction pool. Transaction can be pushed on this pool
|
||||||
|
// for later including in the blocks
|
||||||
|
txPool *core.TxPool |
||||||
|
// The canonical chain
|
||||||
|
chainManager *core.ChainManager |
||||||
|
// The block pool
|
||||||
|
blockPool *BlockPool |
||||||
|
// Event
|
||||||
|
eventMux *event.TypeMux |
||||||
|
|
||||||
|
// Nonce
|
||||||
|
Nonce uint64 |
||||||
|
|
||||||
|
ListenAddr string |
||||||
|
|
||||||
|
blacklist p2p.Blacklist |
||||||
|
server *p2p.Server |
||||||
|
txSub event.Subscription |
||||||
|
blockSub event.Subscription |
||||||
|
|
||||||
|
// Capabilities for outgoing peers
|
||||||
|
// serverCaps Caps
|
||||||
|
peersFile string |
||||||
|
|
||||||
|
Mining bool |
||||||
|
|
||||||
|
RpcServer *rpc.JsonRpcServer |
||||||
|
|
||||||
|
keyManager *crypto.KeyManager |
||||||
|
|
||||||
|
clientIdentity p2p.ClientIdentity |
||||||
|
|
||||||
|
synclock sync.Mutex |
||||||
|
syncGroup sync.WaitGroup |
||||||
|
|
||||||
|
filterMu sync.RWMutex |
||||||
|
filterId int |
||||||
|
filters map[int]*core.Filter |
||||||
|
} |
||||||
|
|
||||||
|
func New(db ethutil.Database, identity p2p.ClientIdentity, keyManager *crypto.KeyManager, nat p2p.NAT, port string, maxPeers int) (*Ethereum, error) { |
||||||
|
|
||||||
|
saveProtocolVersion(db) |
||||||
|
ethutil.Config.Db = db |
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
blacklist := p2p.NewBlacklist() |
||||||
|
// Sorry Py person. I must blacklist. you perform badly
|
||||||
|
blacklist.Put(ethutil.Hex2Bytes("64656330303561383532336435376331616537643864663236623336313863373537353163636634333530626263396330346237336262623931383064393031")) |
||||||
|
|
||||||
|
peersFile := path.Join(ethutil.Config.ExecPath, "known_peers.json") |
||||||
|
|
||||||
|
nonce, _ := ethutil.RandomUint64() |
||||||
|
|
||||||
|
listenAddr := ":" + port |
||||||
|
|
||||||
|
eth := &Ethereum{ |
||||||
|
shutdownChan: make(chan bool), |
||||||
|
quit: make(chan bool), |
||||||
|
db: db, |
||||||
|
Nonce: nonce, |
||||||
|
// serverCaps: caps,
|
||||||
|
peersFile: peersFile, |
||||||
|
ListenAddr: listenAddr, |
||||||
|
keyManager: keyManager, |
||||||
|
clientIdentity: identity, |
||||||
|
blacklist: blacklist, |
||||||
|
eventMux: &event.TypeMux{}, |
||||||
|
filters: make(map[int]*core.Filter), |
||||||
|
} |
||||||
|
|
||||||
|
eth.txPool = core.NewTxPool(eth) |
||||||
|
eth.chainManager = core.NewChainManager(eth.EventMux()) |
||||||
|
eth.blockManager = core.NewBlockManager(eth) |
||||||
|
eth.chainManager.SetProcessor(eth.blockManager) |
||||||
|
|
||||||
|
hasBlock := eth.chainManager.HasBlock |
||||||
|
insertChain := eth.chainManager.InsertChain |
||||||
|
// pow := ezp.New()
|
||||||
|
// verifyPoW := pow.Verify
|
||||||
|
verifyPoW := func(*types.Block) bool { return true } |
||||||
|
eth.blockPool = NewBlockPool(hasBlock, insertChain, verifyPoW) |
||||||
|
|
||||||
|
// Start the tx pool
|
||||||
|
eth.txPool.Start() |
||||||
|
|
||||||
|
ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool) |
||||||
|
protocols := []p2p.Protocol{ethProto} |
||||||
|
|
||||||
|
server := &p2p.Server{ |
||||||
|
Identity: identity, |
||||||
|
MaxPeers: maxPeers, |
||||||
|
Protocols: protocols, |
||||||
|
ListenAddr: listenAddr, |
||||||
|
Blacklist: blacklist, |
||||||
|
NAT: nat, |
||||||
|
} |
||||||
|
|
||||||
|
eth.server = server |
||||||
|
|
||||||
|
return eth, nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) KeyManager() *crypto.KeyManager { |
||||||
|
return s.keyManager |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) ClientIdentity() p2p.ClientIdentity { |
||||||
|
return s.clientIdentity |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) ChainManager() *core.ChainManager { |
||||||
|
return s.chainManager |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) BlockManager() *core.BlockManager { |
||||||
|
return s.blockManager |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) TxPool() *core.TxPool { |
||||||
|
return s.txPool |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) BlockPool() *BlockPool { |
||||||
|
return s.blockPool |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) EventMux() *event.TypeMux { |
||||||
|
return s.eventMux |
||||||
|
} |
||||||
|
func (self *Ethereum) Db() ethutil.Database { |
||||||
|
return self.db |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) IsMining() bool { |
||||||
|
return s.Mining |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) IsListening() bool { |
||||||
|
if s.ListenAddr == "" { |
||||||
|
return false |
||||||
|
} else { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) PeerCount() int { |
||||||
|
return s.server.PeerCount() |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) Peers() []*p2p.Peer { |
||||||
|
return s.server.Peers() |
||||||
|
} |
||||||
|
|
||||||
|
// Start the ethereum
|
||||||
|
func (s *Ethereum) Start(seed bool) error { |
||||||
|
err := s.server.Start() |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
s.blockPool.Start() |
||||||
|
s.blockManager.Start() |
||||||
|
|
||||||
|
go s.filterLoop() |
||||||
|
|
||||||
|
// 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() |
||||||
|
|
||||||
|
// TODO: read peers here
|
||||||
|
if seed { |
||||||
|
logger.Infof("Connect to seed node %v", seedNodeAddress) |
||||||
|
if err := s.SuggestPeer(seedNodeAddress); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
logger.Infoln("Server started") |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Ethereum) SuggestPeer(addr string) error { |
||||||
|
netaddr, err := net.ResolveTCPAddr("tcp", addr) |
||||||
|
if err != nil { |
||||||
|
logger.Errorf("couldn't resolve %s:", addr, err) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
self.server.SuggestPeer(netaddr.IP, netaddr.Port, nil) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Ethereum) Stop() { |
||||||
|
// Close the database
|
||||||
|
defer s.db.Close() |
||||||
|
|
||||||
|
//
|
||||||
|
// WritePeers(s.peersFile, s.server.PeerAddresses())
|
||||||
|
close(s.quit) |
||||||
|
|
||||||
|
s.txSub.Unsubscribe() // quits txBroadcastLoop
|
||||||
|
s.blockSub.Unsubscribe() // quits blockBroadcastLoop
|
||||||
|
|
||||||
|
if s.RpcServer != nil { |
||||||
|
s.RpcServer.Stop() |
||||||
|
} |
||||||
|
s.txPool.Stop() |
||||||
|
s.blockManager.Stop() |
||||||
|
s.eventMux.Stop() |
||||||
|
s.blockPool.Stop() |
||||||
|
|
||||||
|
logger.Infoln("Server stopped") |
||||||
|
close(s.shutdownChan) |
||||||
|
} |
||||||
|
|
||||||
|
// This function will wait for a shutdown and resumes main thread execution
|
||||||
|
func (s *Ethereum) WaitForShutdown() { |
||||||
|
<-s.shutdownChan |
||||||
|
} |
||||||
|
|
||||||
|
func WritePeers(path string, addresses []string) { |
||||||
|
if len(addresses) > 0 { |
||||||
|
data, _ := json.MarshalIndent(addresses, "", " ") |
||||||
|
ethutil.WriteFile(path, data) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func ReadPeers(path string) (ips []string, err error) { |
||||||
|
var data string |
||||||
|
data, err = ethutil.ReadAllFile(path) |
||||||
|
if err != nil { |
||||||
|
json.Unmarshal([]byte(data), &ips) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 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.server.Broadcast("eth", TxMsg, []interface{}{event.Tx.RlpData()}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Ethereum) blockBroadcastLoop() { |
||||||
|
// automatically stops if unsubscribe
|
||||||
|
for obj := range self.txSub.Chan() { |
||||||
|
event := obj.(core.NewMinedBlockEvent) |
||||||
|
self.server.Broadcast("eth", NewBlockMsg, event.Block.Value().Val) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
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()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// InstallFilter adds filter for blockchain events.
|
||||||
|
// The filter's callbacks will run for matching blocks and messages.
|
||||||
|
// The filter should not be modified after it has been installed.
|
||||||
|
func (self *Ethereum) InstallFilter(filter *core.Filter) (id int) { |
||||||
|
self.filterMu.Lock() |
||||||
|
id = self.filterId |
||||||
|
self.filters[id] = filter |
||||||
|
self.filterId++ |
||||||
|
self.filterMu.Unlock() |
||||||
|
return id |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Ethereum) UninstallFilter(id int) { |
||||||
|
self.filterMu.Lock() |
||||||
|
delete(self.filters, id) |
||||||
|
self.filterMu.Unlock() |
||||||
|
} |
||||||
|
|
||||||
|
// GetFilter retrieves a filter installed using InstallFilter.
|
||||||
|
// The filter may not be modified.
|
||||||
|
func (self *Ethereum) GetFilter(id int) *core.Filter { |
||||||
|
self.filterMu.RLock() |
||||||
|
defer self.filterMu.RUnlock() |
||||||
|
return self.filters[id] |
||||||
|
} |
||||||
|
|
||||||
|
func (self *Ethereum) filterLoop() { |
||||||
|
// Subscribe to events
|
||||||
|
events := self.eventMux.Subscribe(core.NewBlockEvent{}, state.Messages(nil)) |
||||||
|
for event := range events.Chan() { |
||||||
|
switch event.(type) { |
||||||
|
case core.NewBlockEvent: |
||||||
|
self.filterMu.RLock() |
||||||
|
for _, filter := range self.filters { |
||||||
|
if filter.BlockCallback != nil { |
||||||
|
e := event.(core.NewBlockEvent) |
||||||
|
filter.BlockCallback(e.Block) |
||||||
|
} |
||||||
|
} |
||||||
|
self.filterMu.RUnlock() |
||||||
|
case state.Messages: |
||||||
|
self.filterMu.RLock() |
||||||
|
for _, filter := range self.filters { |
||||||
|
if filter.MessageCallback != nil { |
||||||
|
e := event.(state.Messages) |
||||||
|
msgs := filter.FilterMessages(e) |
||||||
|
if len(msgs) > 0 { |
||||||
|
filter.MessageCallback(msgs) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
self.filterMu.RUnlock() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue