فهرست منبع

Integrate eth_accounts and eth_transact to use new account manager

* Add from to eth_transact / xeth.Transact and add static pass in lieu
  of integrating with native Mist window for user passphrase entry
* Make eth_accounts return AccountManager.Accounts()
* Add a Generate Key menu item in Mist
Gustav Simonsson 10 سال پیش
والد
کامیت
bc45e5c6de
10فایلهای تغییر یافته به همراه83 افزوده شده و 58 حذف شده
  1. 5 0
      cmd/mist/assets/qml/main.qml
  2. 2 2
      cmd/mist/bindings.go
  3. 7 0
      cmd/mist/gui.go
  4. 1 0
      cmd/mist/ui_lib.go
  5. 8 0
      core/types/transaction.go
  6. 24 17
      eth/backend.go
  7. 2 2
      javascript/types.go
  8. 5 25
      rpc/api.go
  9. 1 0
      rpc/args.go
  10. 28 12
      xeth/xeth.go

+ 5 - 0
cmd/mist/assets/qml/main.qml

@@ -190,6 +190,11 @@ ApplicationWindow {
                 }
             }
 
+            MenuItem {
+                text: "Generate key"
+                shortcut: "Ctrl+k"
+                onTriggered: gui.generateKey()
+            }
         }
 
         Menu {

+ 2 - 2
cmd/mist/bindings.go

@@ -49,7 +49,7 @@ func (gui *Gui) LogPrint(level logger.LogLevel, msg string) {
 		}
 	*/
 }
-func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (string, error) {
+func (gui *Gui) Transact(from, recipient, value, gas, gasPrice, d string) (string, error) {
 	var data string
 	if len(recipient) == 0 {
 		code, err := ethutil.Compile(d, false)
@@ -61,7 +61,7 @@ func (gui *Gui) Transact(recipient, value, gas, gasPrice, d string) (string, err
 		data = ethutil.Bytes2Hex(utils.FormatTransactionData(d))
 	}
 
-	return gui.xeth.Transact(recipient, value, gas, gasPrice, data)
+	return gui.xeth.Transact(from, recipient, value, gas, gasPrice, data)
 }
 
 // functions that allow Gui to implement interface guilogger.LogSystem

+ 7 - 0
cmd/mist/gui.go

@@ -175,6 +175,13 @@ func (gui *Gui) showWallet(context *qml.Context) (*qml.Window, error) {
 func (gui *Gui) ImportKey(filePath string) {
 }
 
+func (gui *Gui) GenerateKey() {
+	_, err := gui.eth.AccountManager().NewAccount("hurr")
+	if err != nil {
+		// TODO: UI feedback?
+	}
+}
+
 func (gui *Gui) showKeyImport(context *qml.Context) (*qml.Window, error) {
 	context.SetVar("lib", gui)
 	component, err := gui.engine.LoadFile(gui.uiLib.AssetPath("qml/first_run.qml"))

+ 1 - 0
cmd/mist/ui_lib.go

@@ -171,6 +171,7 @@ func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
 	object := mapToTxParams(params)
 
 	return self.XEth.Transact(
+		object["from"],
 		object["to"],
 		object["value"],
 		object["gas"],

+ 8 - 0
core/types/transaction.go

@@ -129,6 +129,7 @@ func (tx *Transaction) sender() []byte {
 	return crypto.Sha3(pubkey[1:])[12:]
 }
 
+// TODO: deprecate after new accounts & key stores are integrated
 func (tx *Transaction) Sign(privk []byte) error {
 
 	sig := tx.Signature(privk)
@@ -140,6 +141,13 @@ func (tx *Transaction) Sign(privk []byte) error {
 	return nil
 }
 
+func (tx *Transaction) SetSignatureValues(sig []byte) error {
+	tx.R = sig[:32]
+	tx.S = sig[32:64]
+	tx.V = uint64(sig[64] + 27)
+	return nil
+}
+
 func (tx *Transaction) SignECDSA(key *ecdsa.PrivateKey) error {
 	return tx.Sign(crypto.FromECDSA(key))
 }

+ 24 - 17
eth/backend.go

@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/ethereum/ethash"
+	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/blockpool"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/crypto"
@@ -117,6 +118,7 @@ type Ethereum struct {
 	txPool         *core.TxPool
 	chainManager   *core.ChainManager
 	blockPool      *blockpool.BlockPool
+	accountManager *accounts.AccountManager
 	whisper        *whisper.Whisper
 
 	net      *p2p.Server
@@ -176,9 +178,13 @@ func New(config *Config) (*Ethereum, error) {
 		DataDir:      config.DataDir,
 	}
 
+	// TODO: add config flag and case on plain/protected key store
+	ks := crypto.NewKeyStorePlain(ethutil.DefaultDataDir())
+	am := accounts.NewAccountManager(ks, 300000) // keys unlocked for 300s
+	eth.accountManager = &am
+
 	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)
@@ -215,22 +221,23 @@ func New(config *Config) (*Ethereum, error) {
 	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
+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) AccountManager() *accounts.AccountManager { return s.accountManager }
+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 {

+ 2 - 2
javascript/types.go

@@ -70,8 +70,8 @@ func (self *JSEthereum) GetStateObject(addr string) otto.Value {
 	return self.toVal(&JSStateObject{self.XEth.State().SafeGet(addr), self})
 }
 
-func (self *JSEthereum) Transact(key, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
-	r, err := self.XEth.Transact(recipient, valueStr, gasStr, gasPriceStr, dataStr)
+func (self *JSEthereum) Transact(fromStr, recipient, valueStr, gasStr, gasPriceStr, dataStr string) otto.Value {
+	r, err := self.XEth.Transact(fromStr, recipient, valueStr, gasStr, gasPriceStr, dataStr)
 	if err != nil {
 		fmt.Println(err)
 

+ 5 - 25
rpc/api.go

@@ -252,38 +252,18 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
 }
 
 func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
-	if len(args.Gas) == 0 {
+	// TODO: align default values to have the same type, e.g. not depend on
+	// ethutil.Value conversions later on
+	if ethutil.Big(args.Gas).Cmp(big.NewInt(0)) == 0 {
 		args.Gas = defaultGas.String()
 	}
 
-	if len(args.GasPrice) == 0 {
+	if ethutil.Big(args.GasPrice).Cmp(big.NewInt(0)) == 0 {
 		args.GasPrice = defaultGasPrice.String()
 	}
 
-	// TODO if no_private_key then
-	//if _, exists := p.register[args.From]; exists {
-	//	p.register[args.From] = append(p.register[args.From], args)
-	//} else {
-	/*
-		account := accounts.Get(fromHex(args.From))
-		if account != nil {
-			if account.Unlocked() {
-				if !unlockAccount(account) {
-					return
-				}
-			}
-
-			result, _ := account.Transact(fromHex(args.To), fromHex(args.Value), fromHex(args.Gas), fromHex(args.GasPrice), fromHex(args.Data))
-			if len(result) > 0 {
-				*reply = toHex(result)
-			}
-		} else if _, exists := p.register[args.From]; exists {
-			p.register[ags.From] = append(p.register[args.From], args)
-		}
-	*/
-	result, _ := p.xeth().Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data)
+	result, _ := p.xeth().Transact(args.From, args.To, args.Value, args.Gas, args.GasPrice, args.Data)
 	*reply = result
-	//}
 
 	return nil
 }

+ 1 - 0
rpc/args.go

@@ -24,6 +24,7 @@ func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) {
 
 type NewTxArgs struct {
 	From     string `json:"from"`
+	Pass     string `json:"pass"`
 	To       string `json:"to"`
 	Value    string `json:"value"`
 	Gas      string `json:"gas"`

+ 28 - 12
xeth/xeth.go

@@ -7,8 +7,8 @@ package xeth
 import (
 	"bytes"
 	"encoding/json"
-	"fmt"
 
+	"github.com/ethereum/go-ethereum/accounts"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/core/types"
 	"github.com/ethereum/go-ethereum/crypto"
@@ -27,6 +27,7 @@ var pipelogger = logger.NewLogger("XETH")
 type Backend interface {
 	BlockProcessor() *core.BlockProcessor
 	ChainManager() *core.ChainManager
+	AccountManager() *accounts.AccountManager
 	TxPool() *core.TxPool
 	PeerCount() int
 	IsListening() bool
@@ -42,6 +43,7 @@ type XEth struct {
 	eth            Backend
 	blockProcessor *core.BlockProcessor
 	chainManager   *core.ChainManager
+	accountManager *accounts.AccountManager
 	state          *State
 	whisper        *Whisper
 	miner          *miner.Miner
@@ -52,6 +54,7 @@ func New(eth Backend) *XEth {
 		eth:            eth,
 		blockProcessor: eth.BlockProcessor(),
 		chainManager:   eth.ChainManager(),
+		accountManager: eth.AccountManager(),
 		whisper:        NewWhisper(eth.Whisper()),
 		miner:          eth.Miner(),
 	}
@@ -106,7 +109,13 @@ func (self *XEth) Block(v interface{}) *Block {
 }
 
 func (self *XEth) Accounts() []string {
-	return []string{toHex(self.eth.KeyManager().Address())}
+	// TODO: check err?
+	accounts, _ := self.eth.AccountManager().Accounts()
+	accountAddresses := make([]string, len(accounts))
+	for i, ac := range accounts {
+		accountAddresses[i] = toHex(ac.Address)
+	}
+	return accountAddresses
 }
 
 func (self *XEth) PeerCount() int {
@@ -266,17 +275,19 @@ func (self *XEth) Call(toStr, valueStr, gasStr, gasPriceStr, dataStr string) (st
 	return toHex(res), nil
 }
 
-func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
+func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) {
+
 	var (
+		from             []byte
 		to               []byte
 		value            = ethutil.NewValue(valueStr)
 		gas              = ethutil.NewValue(gasStr)
 		price            = ethutil.NewValue(gasPriceStr)
 		data             []byte
-		key              = self.eth.KeyManager().KeyPair()
 		contractCreation bool
 	)
 
+	from = fromHex(fromStr)
 	data = fromHex(codeStr)
 	to = fromHex(toStr)
 	if len(to) == 0 {
@@ -290,21 +301,26 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string)
 		tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
 	}
 
-	var err error
-	state := self.eth.ChainManager().TxState()
-	if balance := state.GetBalance(key.Address()); balance.Cmp(tx.Value()) < 0 {
-		return "", fmt.Errorf("insufficient balance. balance=%v tx=%v", balance, tx.Value())
-	}
-	nonce := state.GetNonce(key.Address())
+	state := self.chainManager.TransState()
+	nonce := state.GetNonce(from)
 
 	tx.SetNonce(nonce)
-	tx.Sign(key.PrivateKey)
+	sig, err := self.accountManager.Sign(&accounts.Account{Address: from}, tx.Hash())
+	if err != nil {
+		return "", err
+	}
+	tx.SetSignatureValues(sig)
 
 	err = self.eth.TxPool().Add(tx)
 	if err != nil {
 		return "", err
 	}
-	state.SetNonce(key.Address(), nonce+1)
+	state.SetNonce(from, nonce+1)
+
+	if contractCreation {
+		addr := core.AddressFromMessage(tx)
+		pipelogger.Infof("Contract addr %x\n", addr)
+	}
 
 	if types.IsContractAddr(to) {
 		return toHex(core.AddressFromMessage(tx)), nil