Merge pull request #861 from obscuren/transaction_pool_fixes
core: transaction pool fixes & resending transactions
This commit is contained in:
commit
323216ed85
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
@ -15,6 +16,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
"github.com/robertkrimen/otto"
|
"github.com/robertkrimen/otto"
|
||||||
|
"gopkg.in/fatih/set.v0"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -22,6 +24,11 @@ node admin bindings
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
func (js *jsre) adminBindings() {
|
func (js *jsre) adminBindings() {
|
||||||
|
ethO, _ := js.re.Get("eth")
|
||||||
|
eth := ethO.Object()
|
||||||
|
eth.Set("pendingTransactions", js.pendingTransactions)
|
||||||
|
eth.Set("resend", js.resend)
|
||||||
|
|
||||||
js.re.Set("admin", struct{}{})
|
js.re.Set("admin", struct{}{})
|
||||||
t, _ := js.re.Get("admin")
|
t, _ := js.re.Get("admin")
|
||||||
admin := t.Object()
|
admin := t.Object()
|
||||||
@ -74,6 +81,70 @@ func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
|
|||||||
return nil, errors.New("requires block number or block hash as argument")
|
return nil, errors.New("requires block number or block hash as argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
|
||||||
|
txs := js.ethereum.TxPool().GetTransactions()
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
gp = call.Argument(1).String()
|
||||||
|
}
|
||||||
|
if len(call.ArgumentList) > 2 {
|
||||||
|
gl = 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 {
|
func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
|
||||||
block, err := js.getBlock(call)
|
block, err := js.getBlock(call)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -421,3 +492,35 @@ func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
|
|||||||
return js.re.ToVal(dump)
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -40,7 +40,7 @@ type plugin struct {
|
|||||||
func (gui *Gui) Transact(from, recipient, value, gas, gasPrice, d string) (string, error) {
|
func (gui *Gui) Transact(from, recipient, value, gas, gasPrice, d string) (string, error) {
|
||||||
d = common.Bytes2Hex(utils.FormatTransactionData(d))
|
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) {
|
func (self *Gui) AddPlugin(pluginPath string) {
|
||||||
|
@ -119,6 +119,7 @@ func (self *UiLib) Transact(params map[string]interface{}) (string, error) {
|
|||||||
return self.XEth.Transact(
|
return self.XEth.Transact(
|
||||||
object["from"],
|
object["from"],
|
||||||
object["to"],
|
object["to"],
|
||||||
|
"",
|
||||||
object["value"],
|
object["value"],
|
||||||
object["gas"],
|
object["gas"],
|
||||||
object["gasPrice"],
|
object["gasPrice"],
|
||||||
|
@ -24,11 +24,11 @@ var HashRegContractAddress string = "0000000000000000000000000000000000000000000
|
|||||||
|
|
||||||
func CreateContracts(xeth *xe.XEth, addr string) {
|
func CreateContracts(xeth *xe.XEth, addr string) {
|
||||||
var err error
|
var err error
|
||||||
URLHintContractAddress, err = xeth.Transact(addr, "", "100000000000", "1000000", "100000", ContractCodeURLhint)
|
URLHintContractAddress, err = xeth.Transact(addr, "", "", "100000000000", "1000000", "100000", ContractCodeURLhint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
HashRegContractAddress, err = xeth.Transact(addr, "", "100000000000", "1000000", "100000", ContractCodeHashReg)
|
HashRegContractAddress, err = xeth.Transact(addr, "", "", "100000000000", "1000000", "100000", ContractCodeHashReg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -235,7 +235,7 @@ func (self *TxPool) RemoveTransactions(txs types.Transactions) {
|
|||||||
defer self.mu.Unlock()
|
defer self.mu.Unlock()
|
||||||
|
|
||||||
for _, tx := range txs {
|
for _, tx := range txs {
|
||||||
delete(self.txs, tx.Hash())
|
self.removeTx(tx.Hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +173,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
|
|||||||
return fmt.Errorf("Transaction not confirmed")
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
10
rpc/args.go
10
rpc/args.go
@ -157,6 +157,7 @@ func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
type NewTxArgs struct {
|
type NewTxArgs struct {
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
|
Nonce *big.Int
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
Gas *big.Int
|
Gas *big.Int
|
||||||
GasPrice *big.Int
|
GasPrice *big.Int
|
||||||
@ -170,6 +171,7 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
var ext struct {
|
var ext struct {
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
|
Nonce interface{}
|
||||||
Value interface{}
|
Value interface{}
|
||||||
Gas interface{}
|
Gas interface{}
|
||||||
GasPrice interface{}
|
GasPrice interface{}
|
||||||
@ -200,6 +202,14 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
args.Data = ext.Data
|
args.Data = ext.Data
|
||||||
|
|
||||||
var num *big.Int
|
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 {
|
if ext.Value == nil {
|
||||||
num = big.NewInt(0)
|
num = big.NewInt(0)
|
||||||
} else {
|
} else {
|
||||||
|
10
xeth/xeth.go
10
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 (
|
var (
|
||||||
from = common.HexToAddress(fromStr)
|
from = common.HexToAddress(fromStr)
|
||||||
to = common.HexToAddress(toStr)
|
to = common.HexToAddress(toStr)
|
||||||
@ -704,7 +704,13 @@ func (self *XEth) Transact(fromStr, toStr, valueStr, gasStr, gasPriceStr, codeSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
state := self.backend.ChainManager().TxState()
|
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)
|
tx.SetNonce(nonce)
|
||||||
|
|
||||||
if err := self.sign(tx, from, false); err != nil {
|
if err := self.sign(tx, from, false); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user