mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Merge 4d1a9cb835 into 643eda5c2d
This commit is contained in:
commit
3a6aeac6fc
9 changed files with 178 additions and 43 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
10
rpc/args.go
10
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"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
|
|
|||
80
xeth/xeth.go
80
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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue