forked from cerc-io/plugeth
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
This commit is contained in:
parent
e64f727529
commit
bc45e5c6de
@ -190,6 +190,11 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: "Generate key"
|
||||
shortcut: "Ctrl+k"
|
||||
onTriggered: gui.generateKey()
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
|
@ -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
|
||||
|
@ -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"))
|
||||
|
@ -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"],
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
||||
|
30
rpc/api.go
30
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
|
||||
}
|
||||
|
@ -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"`
|
||||
|
40
xeth/xeth.go
40
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
|
||||
|
Loading…
Reference in New Issue
Block a user