diff --git a/accounts/account_manager.go b/accounts/account_manager.go
index da0bd89004..a42a846a9b 100644
--- a/accounts/account_manager.go
+++ b/accounts/account_manager.go
@@ -35,61 +35,65 @@ package accounts
import (
crand "crypto/rand"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/syndtr/goleveldb/leveldb"
)
-// TODO: better name for this struct?
+/*
type Account struct {
- Address []byte
+ Address []byte
+ AssociatedAddress []byte // e.g. a wallet contract "owned" by the account
}
+*/
type AccountManager struct {
- keyStore crypto.KeyStore2
+ keyStore crypto.KeyStore2
+ accountsDb *ethdb.LDBDatabase
}
// TODO: get key by addr - modify KeyStore2 GetKey to work with addr
// TODO: pass through passphrase for APIs which require access to private key?
-func NewAccountManager(keyStore crypto.KeyStore2) AccountManager {
- am := &AccountManager{
- keyStore: keyStore,
+func NewAccountManager(keyStore crypto.KeyStore2) (AccountManager, error) {
+ db, err := ethdb.NewLDBDatabase("accounts")
+ if err != nil {
+ panic(err)
}
- return *am
+ am := &AccountManager{
+ keyStore: keyStore,
+ accountsDb: db,
+ }
+ return *am, nil
}
-func (am *AccountManager) Sign(fromAccount *Account, keyAuth string, toSign []byte) (signature []byte, err error) {
- key, err := am.keyStore.GetKey(fromAccount.Address, keyAuth)
+func (am AccountManager) NewAccount(auth string) ([]byte, error) {
+ newKey, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
if err != nil {
return nil, err
}
- signature, err = crypto.Sign(toSign, key.PrivateKey)
+ return newKey.Address, err
+}
+
+func (am AccountManager) AssociateContract(ownerAddr []byte, associateAddr []byte) error {
+ am.accountsDb.Put(ownerAddr, associateAddr)
+ am.accountsDb.Put(associateAddr, ownerAddr)
+ return nil
+}
+
+func (am *AccountManager) GetAssociatedAddr(addr []byte) ([]byte, error) {
+ res, err := am.accountsDb.Get(addr)
+ if err == leveldb.ErrNotFound {
+ return []byte{}, nil
+ } else {
+ return res, nil
+ }
+}
+
+func (am *AccountManager) Sign(fromAddr []byte, keyAuth string, toSign []byte) ([]byte, error) {
+ key, err := am.keyStore.GetKey(fromAddr, keyAuth)
+ if err != nil {
+ return nil, err
+ }
+ signature, err := crypto.Sign(toSign, key.PrivateKey)
return signature, err
}
-
-func (am AccountManager) NewAccount(auth string) (*Account, error) {
- key, err := am.keyStore.GenerateNewKey(crand.Reader, auth)
- if err != nil {
- return nil, err
- }
- ua := &Account{
- Address: key.Address,
- }
- return ua, err
-}
-
-// set of accounts == set of keys in given key store
-// TODO: do we need persistence of accounts as well?
-func (am *AccountManager) Accounts() ([]Account, error) {
- addresses, err := am.keyStore.GetKeyAddresses()
- if err != nil {
- return nil, err
- }
-
- accounts := make([]Account, len(addresses))
-
- for i, addr := range addresses {
- accounts[i] = Account{
- Address: addr,
- }
- }
- return accounts, err
-}
diff --git a/accounts/accounts_test.go b/accounts/accounts_test.go
index da9406ebe8..52ef1fb16d 100644
--- a/accounts/accounts_test.go
+++ b/accounts/accounts_test.go
@@ -2,12 +2,17 @@ package accounts
import (
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
"testing"
)
+func init() {
+ ethutil.ReadConfig("/tmp/ethtest", "/tmp", "ETH")
+}
+
func TestAccountManager(t *testing.T) {
ks := crypto.NewKeyStorePlain(crypto.DefaultDataDir())
- am := NewAccountManager(ks)
+ am, _ := NewAccountManager(ks)
pass := "" // not used but required by API
a1, err := am.NewAccount(pass)
toSign := crypto.GetEntropyCSPRNG(32)
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 7a1d6104e4..7d34c86f47 100644
--- a/core/types/transaction.go
+++ b/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))
}
diff --git a/eth/backend.go b/eth/backend.go
index 8c20735749..8f07de7efe 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
+ "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@@ -88,6 +89,7 @@ type Ethereum struct {
blockProcessor *core.BlockProcessor
txPool *core.TxPool
chainManager *core.ChainManager
+ accountManager *accounts.AccountManager
blockPool *BlockPool
whisper *whisper.Whisper
@@ -120,6 +122,7 @@ func New(config *Config) (*Ethereum, error) {
return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
}
+ // TODO: remove keymanager & keyring once accountManager is integrated
// Create new keymanager
var keyManager *crypto.KeyManager
switch config.KeyStore {
@@ -147,6 +150,13 @@ func New(config *Config) (*Ethereum, error) {
}
eth.chainManager = core.NewChainManager(db, eth.EventMux())
+ // TODO: add config flag and case on plain/protected key store
+ ks := crypto.NewKeyStorePlain(crypto.DefaultDataDir())
+ am, err := accounts.NewAccountManager(ks)
+ if err != nil {
+ return nil, err
+ }
+ eth.accountManager = &am
eth.txPool = core.NewTxPool(eth.EventMux())
eth.blockProcessor = core.NewBlockProcessor(db, eth.txPool, eth.chainManager, eth.EventMux())
eth.chainManager.SetProcessor(eth.blockProcessor)
@@ -197,6 +207,10 @@ func (s *Ethereum) ChainManager() *core.ChainManager {
return s.chainManager
}
+func (s *Ethereum) AccountManager() *accounts.AccountManager {
+ return s.accountManager
+}
+
func (s *Ethereum) BlockProcessor() *core.BlockProcessor {
return s.blockProcessor
}
diff --git a/rpc/args.go b/rpc/args.go
index 12e3103bcf..544e7dcbef 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -37,6 +37,16 @@ type NewTxArgs struct {
Data string `json:"data"`
}
+type NewTxArgs2 struct {
+ From string `json:"from"`
+ Pass string `json:"pass"`
+ To string `json:"to"`
+ Value string `json:"value"`
+ Gas string `json:"gas"`
+ GasPrice string `json:"gasPrice"`
+ Data string `json:"data"`
+}
+
type PushTxArgs struct {
Tx string `json:"tx"`
}
diff --git a/rpc/http/server.go b/rpc/http/server.go
index dd6ba68e32..1ba9f2afcc 100644
--- a/rpc/http/server.go
+++ b/rpc/http/server.go
@@ -9,7 +9,7 @@
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see .
diff --git a/rpc/packages.go b/rpc/packages.go
index ef31ff1e11..6be72c0a0c 100644
--- a/rpc/packages.go
+++ b/rpc/packages.go
@@ -9,7 +9,7 @@
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see .
@@ -154,6 +154,20 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
return nil
}
+func (p *EthereumApi) Transact2(args *NewTxArgs2, reply *interface{}) error {
+ if len(args.Gas) == 0 {
+ args.Gas = defaultGas
+ }
+
+ if len(args.GasPrice) == 0 {
+ args.GasPrice = defaultGasPrice
+ }
+
+ result, _ := p.xeth.Transact2(args.From, args.Pass, args.To, args.Value, args.Gas, args.GasPrice, args.Data)
+ *reply = result
+ return nil
+}
+
func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error {
result, err := p.xeth.Call( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data)
if err != nil {
diff --git a/rpc/util.go b/rpc/util.go
index 679d83754d..982b777ab8 100644
--- a/rpc/util.go
+++ b/rpc/util.go
@@ -9,7 +9,7 @@
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see .
diff --git a/xeth/xeth.go b/xeth/xeth.go
index 75d83f80b0..e0249a38dd 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/json"
+ "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"
@@ -25,6 +26,7 @@ var pipelogger = logger.NewLogger("XETH")
type Backend interface {
BlockProcessor() *core.BlockProcessor
ChainManager() *core.ChainManager
+ AccountManager() *accounts.AccountManager
TxPool() *core.TxPool
PeerCount() int
IsMining() bool
@@ -40,6 +42,7 @@ type XEth struct {
eth Backend
blockProcessor *core.BlockProcessor
chainManager *core.ChainManager
+ accountManager *accounts.AccountManager
state *State
whisper *Whisper
}
@@ -49,6 +52,7 @@ func New(eth Backend) *XEth {
eth: eth,
blockProcessor: eth.BlockProcessor(),
chainManager: eth.ChainManager(),
+ accountManager: eth.AccountManager(),
whisper: NewWhisper(eth.Whisper()),
}
xeth.state = NewState(xeth)
@@ -291,3 +295,79 @@ func (self *XEth) Transact(toStr, valueStr, gasStr, gasPriceStr, codeStr string)
return toHex(tx.Hash()), nil
}
+
+func (self *XEth) Transact2(fromStr, fromPassStr, 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
+ contractCreation bool
+ )
+
+ from = fromHex(fromStr)
+ data = fromHex(codeStr)
+ to = fromHex(toStr)
+ if len(to) == 0 {
+ contractCreation = true
+ }
+
+ var tx *types.Transaction
+ if contractCreation {
+ tx = types.NewContractCreationTx(value.BigInt(), gas.BigInt(), price.BigInt(), data)
+ } else {
+ tx = types.NewTransactionMessage(to, value.BigInt(), gas.BigInt(), price.BigInt(), data)
+ }
+
+ state := self.chainManager.TransState()
+ nonce := state.GetNonce(from)
+
+ tx.SetNonce(nonce)
+ sig, err := self.accountManager.Sign(from, fromPassStr, tx.Hash())
+ if err != nil {
+ return "", err
+ }
+ tx.SetSignatureValues(sig)
+ // Do some pre processing for our "pre" events and hooks
+ block := self.chainManager.NewBlock(from)
+ coinbase := state.GetOrNewStateObject(from)
+ coinbase.SetGasPool(block.GasLimit())
+ self.blockProcessor.ApplyTransactions(coinbase, state, block, types.Transactions{tx}, true)
+
+ err = self.eth.TxPool().Add(tx)
+ if err != nil {
+ return "", err
+ }
+ 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
+ }
+
+ return toHex(tx.Hash()), nil
+}
+
+// TODO: clarify what is amount, gas and gas price when creating a new wallet contract?
+func (self *XEth) NewWallet(fromStr, fromPassStr, valueStr, gasStr, gasPriceStr, walletContractDataStr string) (newAddrHex string, newWalletContractAddrHex string, err error) {
+ from := fromHex(fromStr)
+ newAddr, err := self.accountManager.NewAccount(fromPassStr)
+ if err != nil {
+ return "", "", err
+ }
+ err = self.accountManager.AssociateContract(from, newAddr)
+ if err != nil {
+ return "", "", err
+ }
+
+ // TODO: how to add newAddr as authorised signer to the wallet contract code?
+ newWalletContractAddrHex, err = self.Transact2(fromStr, fromPassStr, "", valueStr, gasStr, gasPriceStr, walletContractDataStr)
+ return toHex(newAddr), newWalletContractAddrHex, nil
+}