diff options
Diffstat (limited to 'xeth')
-rw-r--r-- | xeth/frontend.go | 4 | ||||
-rw-r--r-- | xeth/xeth.go | 176 |
2 files changed, 97 insertions, 83 deletions
diff --git a/xeth/frontend.go b/xeth/frontend.go index e89282242..70d99ebc4 100644 --- a/xeth/frontend.go +++ b/xeth/frontend.go @@ -19,6 +19,9 @@ package xeth // Frontend should be implemented by users of XEth. Its methods are // called whenever XEth makes a decision that requires user input. type Frontend interface { + // AskPassword is called when a new account is created or updated + AskPassword() (string, bool) + // UnlockAccount is called when a transaction needs to be signed // but the key corresponding to the transaction's sender is // locked. @@ -40,5 +43,6 @@ type Frontend interface { // transactions but cannot not unlock any keys. type dummyFrontend struct{} +func (dummyFrontend) AskPassword() (string, bool) { return "", false } func (dummyFrontend) UnlockAccount([]byte) bool { return false } func (dummyFrontend) ConfirmTransaction(string) bool { return true } diff --git a/xeth/xeth.go b/xeth/xeth.go index 623b3a963..35e6dd52d 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -33,9 +33,10 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/event/filter" + "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/miner" @@ -58,24 +59,8 @@ const ( LogFilterTy ) -func DefaultGas() *big.Int { return new(big.Int).Set(defaultGas) } - -func (self *XEth) DefaultGasPrice() *big.Int { - if self.gpo == nil { - self.gpo = eth.NewGasPriceOracle(self.backend) - } - return self.gpo.SuggestPrice() -} - type XEth struct { - backend *eth.Ethereum - frontend Frontend - - state *State - whisper *Whisper - - quit chan struct{} - filterManager *filter.FilterManager + quit chan struct{} logMu sync.RWMutex logQueue map[int]*logQueue @@ -91,16 +76,18 @@ type XEth struct { transactMu sync.Mutex - agent *miner.RemoteAgent - - gpo *eth.GasPriceOracle + // read-only fields + backend *eth.Ethereum + frontend Frontend + agent *miner.RemoteAgent + gpo *eth.GasPriceOracle + state *State + whisper *Whisper + filterManager *filters.FilterSystem } func NewTest(eth *eth.Ethereum, frontend Frontend) *XEth { - return &XEth{ - backend: eth, - frontend: frontend, - } + return &XEth{backend: eth, frontend: frontend} } // New creates an XEth that uses the given frontend. @@ -111,12 +98,13 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth { backend: ethereum, frontend: frontend, quit: make(chan struct{}), - filterManager: filter.NewFilterManager(ethereum.EventMux()), + filterManager: filters.NewFilterSystem(ethereum.EventMux()), logQueue: make(map[int]*logQueue), blockQueue: make(map[int]*hashQueue), transactionQueue: make(map[int]*hashQueue), messages: make(map[int]*whisperFilter), agent: miner.NewRemoteAgent(), + gpo: eth.NewGasPriceOracle(ethereum), } if ethereum.Whisper() != nil { xeth.whisper = NewWhisper(ethereum.Whisper()) @@ -125,16 +113,15 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth { if frontend == nil { xeth.frontend = dummyFrontend{} } - xeth.state = NewState(xeth, xeth.backend.ChainManager().State()) - + state, _ := xeth.backend.BlockChain().State() + xeth.state = NewState(xeth, state) go xeth.start() - go xeth.filterManager.Start() - return xeth } func (self *XEth) start() { timer := time.NewTicker(2 * time.Second) + defer timer.Stop() done: for { select { @@ -142,7 +129,7 @@ done: self.logMu.Lock() for id, filter := range self.logQueue { if time.Since(filter.timeout) > filterTickerTime { - self.filterManager.UninstallFilter(id) + self.filterManager.Remove(id) delete(self.logQueue, id) } } @@ -151,7 +138,7 @@ done: self.blockMu.Lock() for id, filter := range self.blockQueue { if time.Since(filter.timeout) > filterTickerTime { - self.filterManager.UninstallFilter(id) + self.filterManager.Remove(id) delete(self.blockQueue, id) } } @@ -160,7 +147,7 @@ done: self.transactionMu.Lock() for id, filter := range self.transactionQueue { if time.Since(filter.timeout) > filterTickerTime { - self.filterManager.UninstallFilter(id) + self.filterManager.Remove(id) delete(self.transactionQueue, id) } } @@ -180,8 +167,12 @@ done: } } -func (self *XEth) stop() { +// Stop releases any resources associated with self. +// It may not be called more than once. +func (self *XEth) Stop() { close(self.quit) + self.filterManager.Stop() + self.backend.Miner().Unregister(self.agent) } func cAddress(a []string) []common.Address { @@ -203,18 +194,31 @@ func cTopics(t [][]string) [][]common.Hash { return topics } +func DefaultGas() *big.Int { return new(big.Int).Set(defaultGas) } + +func (self *XEth) DefaultGasPrice() *big.Int { + return self.gpo.SuggestPrice() +} + func (self *XEth) RemoteMining() *miner.RemoteAgent { return self.agent } func (self *XEth) AtStateNum(num int64) *XEth { var st *state.StateDB + var err error switch num { case -2: st = self.backend.Miner().PendingState().Copy() default: if block := self.getBlockByHeight(num); block != nil { - st = state.New(block.Root(), self.backend.ChainDb()) + st, err = state.New(block.Root(), self.backend.ChainDb()) + if err != nil { + return nil + } } else { - st = state.New(self.backend.ChainManager().GetBlockByNumber(0).Root(), self.backend.ChainDb()) + st, err = state.New(self.backend.BlockChain().GetBlockByNumber(0).Root(), self.backend.ChainDb()) + if err != nil { + return nil + } } } @@ -244,30 +248,41 @@ func (self *XEth) State() *State { return self.state } func (self *XEth) UpdateState() (wait chan *big.Int) { wait = make(chan *big.Int) go func() { - sub := self.backend.EventMux().Subscribe(core.ChainHeadEvent{}) + eventSub := self.backend.EventMux().Subscribe(core.ChainHeadEvent{}) + defer eventSub.Unsubscribe() + var m, n *big.Int var ok bool - out: + + eventCh := eventSub.Chan() for { select { - case event := <-sub.Chan(): - ev, ok := event.(core.ChainHeadEvent) - if ok { - m = ev.Block.Number() + case event, ok := <-eventCh: + if !ok { + // Event subscription closed, set the channel to nil to stop spinning + eventCh = nil + continue + } + // A real event arrived, process if new head block assignment + if event, ok := event.Data.(core.ChainHeadEvent); ok { + m = event.Block.Number() if n != nil && n.Cmp(m) < 0 { wait <- n n = nil } - statedb := state.New(ev.Block.Root(), self.backend.ChainDb()) + statedb, err := state.New(event.Block.Root(), self.backend.ChainDb()) + if err != nil { + glog.V(logger.Error).Infoln("Could not create new state: %v", err) + return + } self.state = NewState(self, statedb) } case n, ok = <-wait: if !ok { - break out + return } } } - sub.Unsubscribe() }() return } @@ -290,19 +305,19 @@ func (self *XEth) getBlockByHeight(height int64) *types.Block { num = uint64(height) } - return self.backend.ChainManager().GetBlockByNumber(num) + return self.backend.BlockChain().GetBlockByNumber(num) } func (self *XEth) BlockByHash(strHash string) *Block { hash := common.HexToHash(strHash) - block := self.backend.ChainManager().GetBlock(hash) + block := self.backend.BlockChain().GetBlock(hash) return NewBlock(block) } func (self *XEth) EthBlockByHash(strHash string) *types.Block { hash := common.HexToHash(strHash) - block := self.backend.ChainManager().GetBlock(hash) + block := self.backend.BlockChain().GetBlock(hash) return block } @@ -356,11 +371,11 @@ func (self *XEth) EthBlockByNumber(num int64) *types.Block { } func (self *XEth) Td(hash common.Hash) *big.Int { - return self.backend.ChainManager().GetTd(hash) + return self.backend.BlockChain().GetTd(hash) } func (self *XEth) CurrentBlock() *types.Block { - return self.backend.ChainManager().CurrentBlock() + return self.backend.BlockChain().CurrentBlock() } func (self *XEth) GetBlockReceipts(bhash common.Hash) types.Receipts { @@ -372,7 +387,7 @@ func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt { } func (self *XEth) GasLimit() *big.Int { - return self.backend.ChainManager().GasLimit() + return self.backend.BlockChain().GasLimit() } func (self *XEth) Block(v interface{}) *Block { @@ -452,7 +467,7 @@ func (self *XEth) ClientVersion() string { func (self *XEth) SetMining(shouldmine bool, threads int) bool { ismining := self.backend.IsMining() if shouldmine && !ismining { - err := self.backend.StartMining(threads) + err := self.backend.StartMining(threads, "") return err == nil } if ismining && !shouldmine { @@ -504,7 +519,7 @@ func (self *XEth) IsContract(address string) bool { } func (self *XEth) UninstallFilter(id int) bool { - defer self.filterManager.UninstallFilter(id) + defer self.filterManager.Remove(id) if _, ok := self.logQueue[id]; ok { self.logMu.Lock() @@ -532,17 +547,15 @@ func (self *XEth) NewLogFilter(earliest, latest int64, skip, max int, address [] self.logMu.Lock() defer self.logMu.Unlock() - filter := core.NewFilter(self.backend) - id := self.filterManager.InstallFilter(filter) + filter := filters.New(self.backend.ChainDb()) + id := self.filterManager.Add(filter) self.logQueue[id] = &logQueue{timeout: time.Now()} - filter.SetEarliestBlock(earliest) - filter.SetLatestBlock(latest) - filter.SetSkip(skip) - filter.SetMax(max) - filter.SetAddress(cAddress(address)) + filter.SetBeginBlock(earliest) + filter.SetEndBlock(latest) + filter.SetAddresses(cAddress(address)) filter.SetTopics(cTopics(topics)) - filter.LogsCallback = func(logs state.Logs) { + filter.LogsCallback = func(logs vm.Logs) { self.logMu.Lock() defer self.logMu.Unlock() @@ -558,8 +571,8 @@ func (self *XEth) NewTransactionFilter() int { self.transactionMu.Lock() defer self.transactionMu.Unlock() - filter := core.NewFilter(self.backend) - id := self.filterManager.InstallFilter(filter) + filter := filters.New(self.backend.ChainDb()) + id := self.filterManager.Add(filter) self.transactionQueue[id] = &hashQueue{timeout: time.Now()} filter.TransactionCallback = func(tx *types.Transaction) { @@ -577,11 +590,11 @@ func (self *XEth) NewBlockFilter() int { self.blockMu.Lock() defer self.blockMu.Unlock() - filter := core.NewFilter(self.backend) - id := self.filterManager.InstallFilter(filter) + filter := filters.New(self.backend.ChainDb()) + id := self.filterManager.Add(filter) self.blockQueue[id] = &hashQueue{timeout: time.Now()} - filter.BlockCallback = func(block *types.Block, logs state.Logs) { + filter.BlockCallback = func(block *types.Block, logs vm.Logs) { self.blockMu.Lock() defer self.blockMu.Unlock() @@ -604,7 +617,7 @@ func (self *XEth) GetFilterType(id int) byte { return UnknownFilterTy } -func (self *XEth) LogFilterChanged(id int) state.Logs { +func (self *XEth) LogFilterChanged(id int) vm.Logs { self.logMu.Lock() defer self.logMu.Unlock() @@ -634,8 +647,8 @@ func (self *XEth) TransactionFilterChanged(id int) []common.Hash { return nil } -func (self *XEth) Logs(id int) state.Logs { - filter := self.filterManager.GetFilter(id) +func (self *XEth) Logs(id int) vm.Logs { + filter := self.filterManager.Get(id) if filter != nil { return filter.Find() } @@ -643,13 +656,11 @@ func (self *XEth) Logs(id int) state.Logs { return nil } -func (self *XEth) AllLogs(earliest, latest int64, skip, max int, address []string, topics [][]string) state.Logs { - filter := core.NewFilter(self.backend) - filter.SetEarliestBlock(earliest) - filter.SetLatestBlock(latest) - filter.SetSkip(skip) - filter.SetMax(max) - filter.SetAddress(cAddress(address)) +func (self *XEth) AllLogs(earliest, latest int64, skip, max int, address []string, topics [][]string) vm.Logs { + filter := filters.New(self.backend.ChainDb()) + filter.SetBeginBlock(earliest) + filter.SetEndBlock(latest) + filter.SetAddresses(cAddress(address)) filter.SetTopics(cTopics(topics)) return filter.Find() @@ -832,7 +843,6 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st } from.SetBalance(common.MaxBig) - from.SetGasLimit(common.MaxBig) msg := callmsg{ from: from, @@ -855,9 +865,9 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st } header := self.CurrentBlock().Header() - vmenv := core.NewEnv(statedb, self.backend.ChainManager(), msg, header) - - res, gas, err := core.ApplyMessage(vmenv, msg, from) + vmenv := core.NewEnv(statedb, self.backend.BlockChain(), msg, header) + gp := new(core.GasPool).AddGas(common.MaxBig) + res, gas, err := core.ApplyMessage(vmenv, msg, gp) return common.ToHex(res), gas.String(), err } @@ -1030,19 +1040,19 @@ func (m callmsg) Data() []byte { return m.data } type logQueue struct { mu sync.Mutex - logs state.Logs + logs vm.Logs timeout time.Time id int } -func (l *logQueue) add(logs ...*state.Log) { +func (l *logQueue) add(logs ...*vm.Log) { l.mu.Lock() defer l.mu.Unlock() l.logs = append(l.logs, logs...) } -func (l *logQueue) get() state.Logs { +func (l *logQueue) get() vm.Logs { l.mu.Lock() defer l.mu.Unlock() |