From 4d1a9cb8356254a731a3369ad8654835540489ce Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Sun, 15 Feb 2015 00:39:50 +0100 Subject: [PATCH] Add first take on new transact and wallet creation RPC calls --- core/types/transaction.go | 8 ++++ eth/backend.go | 14 +++++++ rpc/args.go | 10 +++++ rpc/http/server.go | 2 +- rpc/packages.go | 16 +++++++- rpc/util.go | 2 +- xeth/xeth.go | 80 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 3 deletions(-) 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 43e7574358..324889261a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -5,6 +5,7 @@ import ( "net" "sync" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" @@ -54,6 +55,7 @@ type Ethereum struct { blockProcessor *core.BlockProcessor txPool *core.TxPool chainManager *core.ChainManager + accountManager *accounts.AccountManager blockPool *BlockPool whisper *whisper.Whisper @@ -90,6 +92,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 { @@ -121,6 +124,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) @@ -170,6 +180,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 84b076d4ad..bc393fd647 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 10c8fa8138..c642021370 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 ac3127356a..e731ebd1a0 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 0e71a0ed92..c7b0e1c700 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 @@ -41,6 +43,7 @@ type XEth struct { eth Backend blockProcessor *core.BlockProcessor chainManager *core.ChainManager + accountManager *accounts.AccountManager state *State whisper *Whisper } @@ -50,6 +53,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) @@ -301,3 +305,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 +}