From 03bb88dec0163abd99d0fd6c86ab5852c59669cb Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 May 2015 23:08:52 +0200 Subject: [PATCH 1/6] xeth, rpc: added nonce setting through RPC and xeth transact --- common/resolver/resolver.go | 4 ++-- rpc/api.go | 8 +++++++- rpc/args.go | 10 ++++++++++ xeth/xeth.go | 10 ++++++++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/common/resolver/resolver.go b/common/resolver/resolver.go index 1e6d03ffb..42348a89c 100644 --- a/common/resolver/resolver.go +++ b/common/resolver/resolver.go @@ -24,11 +24,11 @@ var HashRegContractAddress string = "0000000000000000000000000000000000000000000 func CreateContracts(xeth *xe.XEth, addr string) { var err error - URLHintContractAddress, err = xeth.Transact(addr, "", "100000000000", "1000000", "100000", ContractCodeURLhint) + URLHintContractAddress, err = xeth.Transact(addr, "", "", "100000000000", "1000000", "100000", ContractCodeURLhint) if err != nil { panic(err) } - HashRegContractAddress, err = xeth.Transact(addr, "", "100000000000", "1000000", "100000", ContractCodeHashReg) + HashRegContractAddress, err = xeth.Transact(addr, "", "", "100000000000", "1000000", "100000", ContractCodeHashReg) if err != nil { panic(err) } diff --git a/rpc/api.go b/rpc/api.go index 6d3a20bfa..b79a1306e 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -173,7 +173,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err return fmt.Errorf("Transaction not confirmed") } - v, err := api.xeth().Transact(args.From, args.To, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data) + // nonce may be nil ("guess" mode) + var nonce string + if args.Nonce != nil { + nonce = args.Nonce.String() + } + + v, err := api.xeth().Transact(args.From, args.To, nonce, args.Value.String(), args.Gas.String(), args.GasPrice.String(), args.Data) if err != nil { return err } diff --git a/rpc/args.go b/rpc/args.go index 4bd48e6d6..e61f28c4f 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -157,6 +157,7 @@ func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) { type NewTxArgs struct { From string To string + Nonce *big.Int Value *big.Int Gas *big.Int GasPrice *big.Int @@ -170,6 +171,7 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { var ext struct { From string To string + Nonce interface{} Value interface{} Gas interface{} GasPrice interface{} @@ -200,6 +202,14 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { args.Data = ext.Data var num *big.Int + if ext.Nonce != nil { + num, err = numString(ext.Nonce) + if err != nil { + return err + } + } + args.Nonce = num + if ext.Value == nil { num = big.NewInt(0) } else { diff --git a/xeth/xeth.go b/xeth/xeth.go index 692fb338c..ac59069d5 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -648,7 +648,7 @@ func (self *XEth) ConfirmTransaction(tx string) bool { } -func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { +func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceStr, codeStr string) (string, error) { var ( from = common.HexToAddress(fromStr) to = common.HexToAddress(toStr) @@ -704,7 +704,13 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt } state := self.backend.ChainManager().TxState() - nonce := state.NewNonce(from) + + var nonce uint64 + if len(nonceStr) != 0 { + nonce = common.Big(nonceStr).Uint64() + } else { + nonce = state.NewNonce(from) + } tx.SetNonce(nonce) if err := self.sign(tx, from, false); err != nil { From 92f998c7ef52f233457cd7bb789395cf3b978e74 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 May 2015 23:09:18 +0200 Subject: [PATCH 2/6] core: use removeTx instead of delete --- core/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 22a804e1d..bac6b7f0b 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -235,7 +235,7 @@ func (self *TxPool) RemoveTransactions(txs types.Transactions) { defer self.mu.Unlock() for _, tx := range txs { - delete(self.txs, tx.Hash()) + self.removeTx(tx.Hash()) } } From 7fed4244353bb9b95b6c18fb26c039d7274bd2c8 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 May 2015 23:09:46 +0200 Subject: [PATCH 3/6] cmd/geth: implemented resending transaction with different gas settings --- cmd/geth/admin.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go index 31f8d4400..13efe5dd6 100644 --- a/cmd/geth/admin.go +++ b/cmd/geth/admin.go @@ -3,6 +3,7 @@ package main import ( "errors" "fmt" + "strconv" "time" "github.com/ethereum/go-ethereum/cmd/utils" @@ -22,6 +23,11 @@ node admin bindings */ func (js *jsre) adminBindings() { + ethO, _ := js.re.Get("eth") + eth := ethO.Object() + eth.Set("transactions", js.transactions) + eth.Set("resend", js.resend) + js.re.Set("admin", struct{}{}) t, _ := js.re.Get("admin") admin := t.Object() @@ -74,6 +80,83 @@ func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) { return nil, errors.New("requires block number or block hash as argument") } +type tx struct { + tx *types.Transaction + + To string + From string + Nonce string + Value string + Data string + GasLimit string + GasPrice string +} + +func newTx(t *types.Transaction) *tx { + from, _ := t.From() + var to string + if t := t.To(); t != nil { + to = t.Hex() + } + + return &tx{ + tx: t, + To: to, + From: from.Hex(), + Value: t.Amount.String(), + Nonce: strconv.Itoa(int(t.Nonce())), + Data: "0x" + common.Bytes2Hex(t.Data()), + GasLimit: t.GasLimit.String(), + GasPrice: t.GasPrice().String(), + } +} + +func (js *jsre) transactions(call otto.FunctionCall) otto.Value { + txs := js.ethereum.TxPool().GetTransactions() + + ltxs := make([]*tx, len(txs)) + for i, tx := range txs { + ltxs[i] = newTx(tx) + } + + return js.re.ToVal(ltxs) +} + +func (js *jsre) resend(call otto.FunctionCall) otto.Value { + if len(call.ArgumentList) == 0 { + fmt.Println("first argument must be a transaction") + return otto.FalseValue() + } + + v, err := call.Argument(0).Export() + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + + if tx, ok := v.(*tx); ok { + gl, gp := tx.GasLimit, tx.GasPrice + if len(call.ArgumentList) > 1 { + gl = call.Argument(1).String() + } + if len(call.ArgumentList) > 2 { + gp = call.Argument(2).String() + } + + ret, err := js.xeth.Transact(tx.From, tx.To, tx.Nonce, tx.Value, gl, gp, tx.Data) + if err != nil { + fmt.Println(err) + return otto.FalseValue() + } + js.ethereum.TxPool().RemoveTransactions(types.Transactions{tx.tx}) + + return js.re.ToVal(ret) + } + + fmt.Println("first argument must be a transaction") + return otto.FalseValue() +} + func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value { block, err := js.getBlock(call) if err != nil { From 5ebc22807c1faa9fc6dddd79aebc974f4510af20 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 5 May 2015 23:19:59 +0200 Subject: [PATCH 4/6] cmd/geth: admin, switched price with limit in arguments --- cmd/geth/admin.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go index 13efe5dd6..2ee316580 100644 --- a/cmd/geth/admin.go +++ b/cmd/geth/admin.go @@ -137,10 +137,10 @@ func (js *jsre) resend(call otto.FunctionCall) otto.Value { if tx, ok := v.(*tx); ok { gl, gp := tx.GasLimit, tx.GasPrice if len(call.ArgumentList) > 1 { - gl = call.Argument(1).String() + gp = call.Argument(1).String() } if len(call.ArgumentList) > 2 { - gp = call.Argument(2).String() + gl = call.Argument(2).String() } ret, err := js.xeth.Transact(tx.From, tx.To, tx.Nonce, tx.Value, gl, gp, tx.Data) From eb4029257a3166c94fdf82623283e6f946bf19f2 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 6 May 2015 00:13:44 +0200 Subject: [PATCH 5/6] cmd/mist: updated xeth transact --- cmd/mist/bindings.go | 2 +- cmd/mist/ui_lib.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index e7ce50c35..7512421a1 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -40,7 +40,7 @@ type plugin struct { func (gui *Gui) Transact(from, recipient, value, gas, gasPrice, d string) (string, error) { d = common.Bytes2Hex(utils.FormatTransactionData(d)) - return gui.xeth.Transact(from, recipient, value, gas, gasPrice, d) + return gui.xeth.Transact(from, recipient, "", value, gas, gasPrice, d) } func (self *Gui) AddPlugin(pluginPath string) { diff --git a/cmd/mist/ui_lib.go b/cmd/mist/ui_lib.go index 34ce56e77..2de71491c 100644 --- a/cmd/mist/ui_lib.go +++ b/cmd/mist/ui_lib.go @@ -119,6 +119,7 @@ func (self *UiLib) Transact(params map[string]interface{}) (string, error) { return self.XEth.Transact( object["from"], object["to"], + "", object["value"], object["gas"], object["gasPrice"], From 05ac1209c731722a486fb54d3b5cc9282c760c81 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 6 May 2015 14:53:20 +0200 Subject: [PATCH 6/6] cmd/geth: limit `pendingTransactions` to owned accounts. --- cmd/geth/admin.go | 92 ++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/cmd/geth/admin.go b/cmd/geth/admin.go index 2ee316580..e7cc96ddb 100644 --- a/cmd/geth/admin.go +++ b/cmd/geth/admin.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/xeth" "github.com/robertkrimen/otto" + "gopkg.in/fatih/set.v0" ) /* @@ -25,7 +26,7 @@ node admin bindings func (js *jsre) adminBindings() { ethO, _ := js.re.Get("eth") eth := ethO.Object() - eth.Set("transactions", js.transactions) + eth.Set("pendingTransactions", js.pendingTransactions) eth.Set("resend", js.resend) js.re.Set("admin", struct{}{}) @@ -80,43 +81,30 @@ func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) { return nil, errors.New("requires block number or block hash as argument") } -type tx struct { - tx *types.Transaction - - To string - From string - Nonce string - Value string - Data string - GasLimit string - GasPrice string -} - -func newTx(t *types.Transaction) *tx { - from, _ := t.From() - var to string - if t := t.To(); t != nil { - to = t.Hex() - } - - return &tx{ - tx: t, - To: to, - From: from.Hex(), - Value: t.Amount.String(), - Nonce: strconv.Itoa(int(t.Nonce())), - Data: "0x" + common.Bytes2Hex(t.Data()), - GasLimit: t.GasLimit.String(), - GasPrice: t.GasPrice().String(), - } -} - -func (js *jsre) transactions(call otto.FunctionCall) otto.Value { +func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value { txs := js.ethereum.TxPool().GetTransactions() - ltxs := make([]*tx, len(txs)) - for i, tx := range txs { - ltxs[i] = newTx(tx) + // grab the accounts from the account manager. This will help with determening which + // transactions should be returned. + accounts, err := js.ethereum.AccountManager().Accounts() + if err != nil { + fmt.Println(err) + return otto.UndefinedValue() + } + + // Add the accouns to a new set + accountSet := set.New() + for _, account := range accounts { + accountSet.Add(common.BytesToAddress(account.Address)) + } + + //ltxs := make([]*tx, len(txs)) + var ltxs []*tx + for _, tx := range txs { + // no need to check err + if from, _ := tx.From(); accountSet.Has(from) { + ltxs = append(ltxs, newTx(tx)) + } } return js.re.ToVal(ltxs) @@ -504,3 +492,35 @@ func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value { return js.re.ToVal(dump) } + +// internal transaction type which will allow us to resend transactions using `eth.resend` +type tx struct { + tx *types.Transaction + + To string + From string + Nonce string + Value string + Data string + GasLimit string + GasPrice string +} + +func newTx(t *types.Transaction) *tx { + from, _ := t.From() + var to string + if t := t.To(); t != nil { + to = t.Hex() + } + + return &tx{ + tx: t, + To: to, + From: from.Hex(), + Value: t.Amount.String(), + Nonce: strconv.Itoa(int(t.Nonce())), + Data: "0x" + common.Bytes2Hex(t.Data()), + GasLimit: t.GasLimit.String(), + GasPrice: t.GasPrice().String(), + } +}