aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/frontend.go8
-rw-r--r--xeth/xeth.go78
2 files changed, 55 insertions, 31 deletions
diff --git a/ui/frontend.go b/ui/frontend.go
deleted file mode 100644
index 413a24259..000000000
--- a/ui/frontend.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package ui
-
-import "github.com/ethereum/go-ethereum/core/types"
-
-type Interface interface {
- UnlockAccount(address []byte) bool
- ConfirmTransaction(tx *types.Transaction) bool
-}
diff --git a/xeth/xeth.go b/xeth/xeth.go
index a0491506b..f8b537321 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -1,12 +1,10 @@
+// eXtended ETHereum
package xeth
-/*
- * eXtended ETHereum
- */
-
import (
"bytes"
"encoding/json"
+ "fmt"
"math/big"
"github.com/ethereum/go-ethereum/accounts"
@@ -19,7 +17,6 @@ import (
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/state"
- "github.com/ethereum/go-ethereum/ui"
"github.com/ethereum/go-ethereum/whisper"
)
@@ -41,6 +38,26 @@ type Backend interface {
Miner() *miner.Miner
}
+// Frontend should be implemented by users of XEth. Its methods are
+// called whenever XEth makes a decision that requires user input.
+type Frontend interface {
+ // UnlockAccount is called when a transaction needs to be signed
+ // but the key corresponding to the transaction's sender is
+ // locked.
+ //
+ // It should unlock the account with the given address and return
+ // true if unlocking succeeded.
+ UnlockAccount(address []byte) bool
+
+ // This is called for all transactions inititated through
+ // Transact. It should prompt the user to confirm the transaction
+ // and return true if the transaction was acknowledged.
+ //
+ // ConfirmTransaction is not used for Call transactions
+ // because they cannot change any state.
+ ConfirmTransaction(tx *types.Transaction) bool
+}
+
type XEth struct {
eth Backend
blockProcessor *core.BlockProcessor
@@ -50,15 +67,20 @@ type XEth struct {
whisper *Whisper
miner *miner.Miner
- frontend ui.Interface
+ frontend Frontend
}
-type TmpFrontend struct{}
+// dummyFrontend is a non-interactive frontend that allows all
+// transactions but cannot not unlock any keys.
+type dummyFrontend struct{}
-func (TmpFrontend) UnlockAccount([]byte) bool { panic("UNLOCK ACCOUNT") }
-func (TmpFrontend) ConfirmTransaction(*types.Transaction) bool { panic("CONFIRM TRANSACTION") }
+func (dummyFrontend) UnlockAccount([]byte) bool { return false }
+func (dummyFrontend) ConfirmTransaction(*types.Transaction) bool { return true }
-func New(eth Backend, frontend ui.Interface) *XEth {
+// New creates an XEth that uses the given frontend.
+// If a nil Frontend is provided, a default frontend which
+// confirms all transactions will be used.
+func New(eth Backend, frontend Frontend) *XEth {
xeth := &XEth{
eth: eth,
blockProcessor: eth.BlockProcessor(),
@@ -66,14 +88,12 @@ func New(eth Backend, frontend ui.Interface) *XEth {
accountManager: eth.AccountManager(),
whisper: NewWhisper(eth.Whisper()),
miner: eth.Miner(),
+ frontend: frontend,
}
-
if frontend == nil {
- xeth.frontend = TmpFrontend{}
+ xeth.frontend = dummyFrontend{}
}
-
xeth.state = NewState(xeth, xeth.chainManager.TransState())
-
return xeth
}
@@ -283,7 +303,6 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
}
func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
-
var (
from []byte
to []byte
@@ -310,16 +329,12 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
state := self.chainManager.TransState()
nonce := state.GetNonce(from)
-
tx.SetNonce(nonce)
- sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash())
- if err != nil {
+
+ if err := self.sign(tx, from, false); err != nil {
return "", err
}
- tx.SetSignatureValues(sig)
-
- err = self.eth.TxPool().Add(tx)
- if err != nil {
+ if err := self.eth.TxPool().Add(tx); err != nil {
return "", err
}
state.SetNonce(from, nonce+1)
@@ -332,10 +347,27 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
if types.IsContractAddr(to) {
return toHex(core.AddressFromMessage(tx)), nil
}
-
return toHex(tx.Hash()), nil
}
+func (self *XEth) sign(tx *types.Transaction, from []byte, didUnlock bool) error {
+ sig, err := self.accountManager.Sign(accounts.Account{Address: from}, tx.Hash())
+ if err == accounts.ErrLocked {
+ if didUnlock {
+ return fmt.Errorf("sender account still locked after successful unlock")
+ }
+ if !self.frontend.UnlockAccount(from) {
+ return fmt.Errorf("could not unlock sender account")
+ }
+ // retry signing, the account should now be unlocked.
+ self.sign(tx, from, true)
+ } else if err != nil {
+ return err
+ }
+ tx.SetSignatureValues(sig)
+ return nil
+}
+
// callmsg is the message type used for call transations.
type callmsg struct {
from *state.StateObject