Example #1
0
// NewProtocolManager returns a new expanse sub protocol manager. The Expanse sub protocol manages peers capable
// with the expanse network.
func NewProtocolManager(networkId int, mux *event.TypeMux, txpool txPool, pow pow.PoW, chainman *core.ChainManager) *ProtocolManager {
	// Create the protocol manager with the base fields
	manager := &ProtocolManager{
		eventMux:  mux,
		txpool:    txpool,
		chainman:  chainman,
		peers:     newPeerSet(),
		newPeerCh: make(chan *peer, 1),
		txsyncCh:  make(chan *txsync),
		quitSync:  make(chan struct{}),
		netId:     networkId,
	}
	// Initiate a sub-protocol for every implemented version we can handle
	manager.SubProtocols = make([]p2p.Protocol, len(ProtocolVersions))
	for i := 0; i < len(manager.SubProtocols); i++ {
		version := ProtocolVersions[i]

		manager.SubProtocols[i] = p2p.Protocol{
			Name:    "exp",
			Version: version,
			Length:  ProtocolLengths[i],
			Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
				peer := manager.newPeer(int(version), networkId, p, rw)
				manager.newPeerCh <- peer
				return manager.handle(peer)
			},
		}
	}
	// Construct the different synchronisation mechanisms
	manager.downloader = downloader.New(manager.eventMux, manager.chainman.HasBlock, manager.chainman.GetBlock, manager.chainman.CurrentBlock, manager.chainman.InsertChain, manager.removePeer)

	validator := func(block *types.Block, parent *types.Block) error {
		return core.ValidateHeader(pow, block.Header(), parent, true, false)
	}
	heighter := func() uint64 {
		return manager.chainman.CurrentBlock().NumberU64()
	}
	manager.fetcher = fetcher.New(manager.chainman.GetBlock, validator, manager.BroadcastBlock, heighter, manager.chainman.InsertChain, manager.removePeer)

	return manager
}
Example #2
0
func (self *debugApi) ProcessBlock(req *shared.Request) (interface{}, error) {
	args := new(BlockNumArg)
	if err := self.codec.Decode(req.Params, &args); err != nil {
		return nil, shared.NewDecodeParamError(err.Error())
	}

	block := self.xeth.EthBlockByNumber(args.BlockNumber)
	if block == nil {
		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
	}

	old := vm.Debug
	defer func() { vm.Debug = old }()
	vm.Debug = true

	var (
		blockchain = self.expanse.BlockChain()
		validator  = blockchain.Validator()
		processor  = blockchain.Processor()
	)

	err := core.ValidateHeader(blockchain.AuxValidator(), block.Header(), blockchain.GetHeader(block.ParentHash()), true, false)
	if err != nil {
		return false, err
	}
	statedb, err := state.New(blockchain.GetBlock(block.ParentHash()).Root(), self.expanse.ChainDb())
	if err != nil {
		return false, err
	}
	receipts, _, usedGas, err := processor.Process(block, statedb)
	if err != nil {
		return false, err
	}
	err = validator.ValidateState(block, blockchain.GetBlock(block.ParentHash()), statedb, receipts, usedGas)
	if err != nil {
		return false, err
	}

	return true, nil
}
Example #3
0
func (self *worker) wait() {
	for {
		for result := range self.recv {
			atomic.AddInt32(&self.atWork, -1)

			if result == nil {
				continue
			}
			block := result.Block
			work := result.Work

			work.state.Sync()
			if self.fullValidation {
				if _, err := self.chain.InsertChain(types.Blocks{block}); err != nil {
					glog.V(logger.Error).Infoln("mining err", err)
					continue
				}
				go self.mux.Post(core.NewMinedBlockEvent{block})
			} else {
				parent := self.chain.GetBlock(block.ParentHash())
				if parent == nil {
					glog.V(logger.Error).Infoln("Invalid block found during mining")
					continue
				}
				if err := core.ValidateHeader(self.exp.BlockProcessor().Pow, block.Header(), parent, true, false); err != nil && err != core.BlockFutureErr {
					glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
					continue
				}

				stat, err := self.chain.WriteBlock(block, false)
				if err != nil {
					glog.V(logger.Error).Infoln("error writing block to chain", err)
					continue
				}
				// check if canon block and write transactions
				if stat == core.CanonStatTy {
					// This puts transactions in a extra db for rpc
					core.PutTransactions(self.chainDb, block, block.Transactions())
					// store the receipts
					core.PutReceipts(self.chainDb, work.receipts)
				}

				// broadcast before waiting for validation
				go func(block *types.Block, logs state.Logs, receipts []*types.Receipt) {
					self.mux.Post(core.NewMinedBlockEvent{block})
					self.mux.Post(core.ChainEvent{block, block.Hash(), logs})
					if stat == core.CanonStatTy {
						self.mux.Post(core.ChainHeadEvent{block})
						self.mux.Post(logs)
					}
					if err := core.PutBlockReceipts(self.chainDb, block, receipts); err != nil {
						glog.V(logger.Warn).Infoln("error writing block receipts:", err)
					}
				}(block, work.state.Logs(), work.receipts)
			}

			// check staleness and display confirmation
			var stale, confirm string
			canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
			if canonBlock != nil && canonBlock.Hash() != block.Hash() {
				stale = "stale "
			} else {
				confirm = "Wait 5 blocks for confirmation"
				work.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), work.localMinedBlocks)
			}
			glog.V(logger.Info).Infof("🔨  Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)

			self.commitNewWork()
		}
	}
}
Example #4
0
func (self *worker) wait() {
	for {
		for result := range self.recv {
			atomic.AddInt32(&self.atWork, -1)

			if result == nil {
				continue
			}
			block := result.Block
			work := result.Work

			if self.fullValidation {
				if _, err := self.chain.InsertChain(types.Blocks{block}); err != nil {
					glog.V(logger.Error).Infoln("mining err", err)
					continue
				}
				go self.mux.Post(core.NewMinedBlockEvent{block})
			} else {
				work.state.Commit()
				parent := self.chain.GetBlock(block.ParentHash())
				if parent == nil {
					glog.V(logger.Error).Infoln("Invalid block found during mining")
					continue
				}

				auxValidator := self.exp.BlockChain().AuxValidator()
				if err := core.ValidateHeader(auxValidator, block.Header(), parent.Header(), true, false); err != nil && err != core.BlockFutureErr {
					glog.V(logger.Error).Infoln("Invalid header on mined block:", err)
					continue
				}

				stat, err := self.chain.WriteBlock(block)
				if err != nil {
					glog.V(logger.Error).Infoln("error writing block to chain", err)
					continue
				}

				// update block hash since it is now available and not when the receipt/log of individual transactions were created
				for _, r := range work.receipts {
					for _, l := range r.Logs {
						l.BlockHash = block.Hash()
					}
				}
				for _, log := range work.state.Logs() {
					log.BlockHash = block.Hash()
				}

				// check if canon block and write transactions
				if stat == core.CanonStatTy {
					// This puts transactions in a extra db for rpc
					core.WriteTransactions(self.chainDb, block)
					// store the receipts
					core.WriteReceipts(self.chainDb, work.receipts)
					// Write map map bloom filters
					core.WriteMipmapBloom(self.chainDb, block.NumberU64(), work.receipts)
				}

				// broadcast before waiting for validation
				go func(block *types.Block, logs vm.Logs, receipts []*types.Receipt) {
					self.mux.Post(core.NewMinedBlockEvent{block})
					self.mux.Post(core.ChainEvent{block, block.Hash(), logs})
					if stat == core.CanonStatTy {
						self.mux.Post(core.ChainHeadEvent{block})
						self.mux.Post(logs)
					}
					if err := core.WriteBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil {
						glog.V(logger.Warn).Infoln("error writing block receipts:", err)
					}
				}(block, work.state.Logs(), work.receipts)
			}

			// check staleness and display confirmation
			var stale, confirm string
			canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
			if canonBlock != nil && canonBlock.Hash() != block.Hash() {
				stale = "stale "
			} else {
				confirm = "Wait 5 blocks for confirmation"
				work.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), work.localMinedBlocks)
			}
			glog.V(logger.Info).Infof("🔨  Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)

			self.commitNewWork()
		}
	}
}
Example #5
0
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
func NewProtocolManager(fastSync bool, networkId int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
	// Figure out whether to allow fast sync or not
	if fastSync && blockchain.CurrentBlock().NumberU64() > 0 {
		glog.V(logger.Info).Infof("blockchain not empty, fast sync disabled")
		fastSync = false
	}
	// Create the protocol manager with the base fields
	manager := &ProtocolManager{
		networkId:  networkId,
		fastSync:   fastSync,
		eventMux:   mux,
		txpool:     txpool,
		blockchain: blockchain,
		chaindb:    chaindb,
		peers:      newPeerSet(),
		newPeerCh:  make(chan *peer, 1),
		txsyncCh:   make(chan *txsync),
		quitSync:   make(chan struct{}),
	}
	// Initiate a sub-protocol for every implemented version we can handle

	manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions))
	for i, version := range ProtocolVersions {
		// Skip protocol version if incompatible with the mode of operation
		if fastSync && version < eth63 {
			continue
		}
		// Compatible; initialise the sub-protocol
		version := version // Closure for the run
		manager.SubProtocols = append(manager.SubProtocols, p2p.Protocol{

			Name:    ProtocolName,
			Version: version,
			Length:  ProtocolLengths[i],
			Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
				peer := manager.newPeer(int(version), p, rw)
				manager.newPeerCh <- peer
				return manager.handle(peer)
			},
			NodeInfo: func() interface{} {
				return manager.NodeInfo()
			},
			PeerInfo: func(id discover.NodeID) interface{} {
				if p := manager.peers.Peer(fmt.Sprintf("%x", id[:8])); p != nil {
					return p.Info()
				}
				return nil
			},
		})
	}
	if len(manager.SubProtocols) == 0 {
		return nil, errIncompatibleConfig
	}
	// Construct the different synchronisation mechanisms
	manager.downloader = downloader.New(chaindb, manager.eventMux, blockchain.HasHeader, blockchain.HasBlockAndState, blockchain.GetHeader,
		blockchain.GetBlock, blockchain.CurrentHeader, blockchain.CurrentBlock, blockchain.CurrentFastBlock, blockchain.FastSyncCommitHead,
		blockchain.GetTd, blockchain.InsertHeaderChain, blockchain.InsertChain, blockchain.InsertReceiptChain, blockchain.Rollback,
		manager.removePeer)

	validator := func(block *types.Block, parent *types.Block) error {
		return core.ValidateHeader(pow, block.Header(), parent.Header(), true, false)
	}
	heighter := func() uint64 {
		return blockchain.CurrentBlock().NumberU64()
	}
	manager.fetcher = fetcher.New(blockchain.GetBlock, validator, manager.BroadcastBlock, heighter, blockchain.InsertChain, manager.removePeer)

	return manager, nil
}