Merge pull request #1328 from bas-vk/issue1327
Add pendingTransactions and resend
This commit is contained in:
commit
ba95e445e1
@ -76,8 +76,9 @@ func TestCompileSolidity(t *testing.T) {
|
|||||||
expLanguageVersion := "0"
|
expLanguageVersion := "0"
|
||||||
expSource := source
|
expSource := source
|
||||||
|
|
||||||
xeth := xeth.NewTest(ð.Ethereum{}, nil)
|
eth := ð.Ethereum{}
|
||||||
api := NewEthApi(xeth, codec.JSON)
|
xeth := xeth.NewTest(eth, nil)
|
||||||
|
api := NewEthApi(xeth, eth, codec.JSON)
|
||||||
|
|
||||||
var rpcRequest shared.Request
|
var rpcRequest shared.Request
|
||||||
json.Unmarshal([]byte(jsonstr), &rpcRequest)
|
json.Unmarshal([]byte(jsonstr), &rpcRequest)
|
||||||
|
@ -6,9 +6,12 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/rpc/codec"
|
"github.com/ethereum/go-ethereum/rpc/codec"
|
||||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
"github.com/ethereum/go-ethereum/xeth"
|
"github.com/ethereum/go-ethereum/xeth"
|
||||||
|
"gopkg.in/fatih/set.v0"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -19,6 +22,7 @@ const (
|
|||||||
// See https://github.com/ethereum/wiki/wiki/JSON-RPC
|
// See https://github.com/ethereum/wiki/wiki/JSON-RPC
|
||||||
type ethApi struct {
|
type ethApi struct {
|
||||||
xeth *xeth.XEth
|
xeth *xeth.XEth
|
||||||
|
ethereum *eth.Ethereum
|
||||||
methods map[string]ethhandler
|
methods map[string]ethhandler
|
||||||
codec codec.ApiCoder
|
codec codec.ApiCoder
|
||||||
}
|
}
|
||||||
@ -71,12 +75,14 @@ var (
|
|||||||
"eth_hashrate": (*ethApi).Hashrate,
|
"eth_hashrate": (*ethApi).Hashrate,
|
||||||
"eth_getWork": (*ethApi).GetWork,
|
"eth_getWork": (*ethApi).GetWork,
|
||||||
"eth_submitWork": (*ethApi).SubmitWork,
|
"eth_submitWork": (*ethApi).SubmitWork,
|
||||||
|
"eth_resend": (*ethApi).Resend,
|
||||||
|
"eth_pendingTransactions": (*ethApi).PendingTransactions,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// create new ethApi instance
|
// create new ethApi instance
|
||||||
func NewEthApi(xeth *xeth.XEth, codec codec.Codec) *ethApi {
|
func NewEthApi(xeth *xeth.XEth, eth *eth.Ethereum, codec codec.Codec) *ethApi {
|
||||||
return ðApi{xeth, ethMapping, codec.New(nil)}
|
return ðApi{xeth, eth, ethMapping, codec.New(nil)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// collection with supported methods
|
// collection with supported methods
|
||||||
@ -548,3 +554,45 @@ func (self *ethApi) SubmitWork(req *shared.Request) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
return self.xeth.RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header)), nil
|
return self.xeth.RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *ethApi) Resend(req *shared.Request) (interface{}, error) {
|
||||||
|
args := new(ResendArgs)
|
||||||
|
if err := self.codec.Decode(req.Params, &args); err != nil {
|
||||||
|
return nil, shared.NewDecodeParamError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err := self.xeth.Transact(args.Tx.From, args.Tx.To, args.Tx.Nonce, args.Tx.Value, args.GasLimit, args.GasPrice, args.Tx.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ethereum.TxPool().RemoveTransactions(types.Transactions{args.Tx.tx})
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *ethApi) PendingTransactions(req *shared.Request) (interface{}, error) {
|
||||||
|
txs := self.ethereum.TxPool().GetTransactions()
|
||||||
|
|
||||||
|
// grab the accounts from the account manager. This will help with determining which
|
||||||
|
// transactions should be returned.
|
||||||
|
accounts, err := self.ethereum.AccountManager().Accounts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the accouns to a new set
|
||||||
|
accountSet := set.New()
|
||||||
|
for _, account := range accounts {
|
||||||
|
accountSet.Add(account.Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ltxs []*tx
|
||||||
|
for _, tx := range txs {
|
||||||
|
if from, _ := tx.From(); accountSet.Has(from) {
|
||||||
|
ltxs = append(ltxs, newTx(tx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ltxs, nil
|
||||||
|
}
|
||||||
|
@ -4,9 +4,12 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rpc/shared"
|
"github.com/ethereum/go-ethereum/rpc/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -858,3 +861,178 @@ func (args *SubmitWorkArgs) UnmarshalJSON(b []byte) (err error) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.Value().String(),
|
||||||
|
Nonce: strconv.Itoa(int(t.Nonce())),
|
||||||
|
Data: "0x" + common.Bytes2Hex(t.Data()),
|
||||||
|
GasLimit: t.Gas().String(),
|
||||||
|
GasPrice: t.GasPrice().String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResendArgs struct {
|
||||||
|
Tx *tx
|
||||||
|
GasPrice string
|
||||||
|
GasLimit string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *tx) UnmarshalJSON(b []byte) (err error) {
|
||||||
|
var fields map[string]interface{}
|
||||||
|
if err := json.Unmarshal(b, &fields); err != nil {
|
||||||
|
return shared.NewDecodeParamError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
nonce uint64
|
||||||
|
to common.Address
|
||||||
|
amount = new(big.Int).Set(common.Big0)
|
||||||
|
gasLimit = new(big.Int).Set(common.Big0)
|
||||||
|
gasPrice = new(big.Int).Set(common.Big0)
|
||||||
|
data []byte
|
||||||
|
contractCreation = true
|
||||||
|
)
|
||||||
|
|
||||||
|
if val, found := fields["To"]; found {
|
||||||
|
if strVal, ok := val.(string); ok && len(strVal) > 0 {
|
||||||
|
tx.To = strVal
|
||||||
|
to = common.HexToAddress(strVal)
|
||||||
|
contractCreation = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, found := fields["From"]; found {
|
||||||
|
if strVal, ok := val.(string); ok {
|
||||||
|
tx.From = strVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, found := fields["Nonce"]; found {
|
||||||
|
if strVal, ok := val.(string); ok {
|
||||||
|
tx.Nonce = strVal
|
||||||
|
if nonce, err = strconv.ParseUint(strVal, 10, 64); err != nil {
|
||||||
|
return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.Nonce - %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return shared.NewDecodeParamError("tx.Nonce not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseOk bool
|
||||||
|
if val, found := fields["Value"]; found {
|
||||||
|
if strVal, ok := val.(string); ok {
|
||||||
|
tx.Value = strVal
|
||||||
|
if _, parseOk = amount.SetString(strVal, 0); !parseOk {
|
||||||
|
return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.Amount - %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, found := fields["Data"]; found {
|
||||||
|
if strVal, ok := val.(string); ok {
|
||||||
|
tx.Data = strVal
|
||||||
|
if strings.HasPrefix(strVal, "0x") {
|
||||||
|
data = common.Hex2Bytes(strVal[2:])
|
||||||
|
} else {
|
||||||
|
data = common.Hex2Bytes(strVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, found := fields["GasLimit"]; found {
|
||||||
|
if strVal, ok := val.(string); ok {
|
||||||
|
tx.GasLimit = strVal
|
||||||
|
if _, parseOk = gasLimit.SetString(strVal, 0); !parseOk {
|
||||||
|
return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.GasLimit - %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if val, found := fields["GasPrice"]; found {
|
||||||
|
if strVal, ok := val.(string); ok {
|
||||||
|
tx.GasPrice = strVal
|
||||||
|
if _, parseOk = gasPrice.SetString(strVal, 0); !parseOk {
|
||||||
|
return shared.NewDecodeParamError(fmt.Sprintf("Unable to decode tx.GasPrice - %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if contractCreation {
|
||||||
|
tx.tx = types.NewContractCreation(nonce, amount, gasLimit, gasPrice, data)
|
||||||
|
} else {
|
||||||
|
tx.tx = types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (args *ResendArgs) UnmarshalJSON(b []byte) (err error) {
|
||||||
|
var obj []interface{}
|
||||||
|
if err = json.Unmarshal(b, &obj); err != nil {
|
||||||
|
return shared.NewDecodeParamError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(obj) < 1 {
|
||||||
|
return shared.NewInsufficientParamsError(len(obj), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(obj[0])
|
||||||
|
if err != nil {
|
||||||
|
return shared.NewDecodeParamError("Unable to parse transaction object")
|
||||||
|
}
|
||||||
|
|
||||||
|
trans := new(tx)
|
||||||
|
err = json.Unmarshal(data, trans)
|
||||||
|
if err != nil {
|
||||||
|
return shared.NewDecodeParamError("Unable to parse transaction object")
|
||||||
|
}
|
||||||
|
|
||||||
|
if trans == nil || trans.tx == nil {
|
||||||
|
return shared.NewDecodeParamError("Unable to parse transaction object")
|
||||||
|
}
|
||||||
|
|
||||||
|
gasLimit, gasPrice := trans.GasLimit, trans.GasPrice
|
||||||
|
|
||||||
|
if len(obj) > 1 && obj[1] != nil {
|
||||||
|
if gp, ok := obj[1].(string); ok {
|
||||||
|
gasPrice = gp
|
||||||
|
} else {
|
||||||
|
return shared.NewInvalidTypeError("gasPrice", "not a string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(obj) > 2 && obj[2] != nil {
|
||||||
|
if gl, ok := obj[2].(string); ok {
|
||||||
|
gasLimit = gl
|
||||||
|
} else {
|
||||||
|
return shared.NewInvalidTypeError("gasLimit", "not a string")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Tx = trans
|
||||||
|
args.GasPrice = gasPrice
|
||||||
|
args.GasLimit = gasLimit
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -14,6 +14,21 @@ web3._extend({
|
|||||||
params: 2,
|
params: 2,
|
||||||
inputFormatter: [web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString],
|
inputFormatter: [web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString],
|
||||||
outputFormatter: web3._extend.formatters.formatOutputString
|
outputFormatter: web3._extend.formatters.formatOutputString
|
||||||
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'resend',
|
||||||
|
call: 'eth_resend',
|
||||||
|
params: 3,
|
||||||
|
inputFormatter: [function(obj) { return obj; },web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString],
|
||||||
|
outputFormatter: web3._extend.formatters.formatOutputString
|
||||||
|
})
|
||||||
|
],
|
||||||
|
properties:
|
||||||
|
[
|
||||||
|
new web3._extend.Property({
|
||||||
|
name: 'pendingTransactions',
|
||||||
|
getter: 'eth_pendingTransactions',
|
||||||
|
outputFormatter: function(obj) { return obj; }
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -84,6 +84,8 @@ var (
|
|||||||
"hashrate",
|
"hashrate",
|
||||||
"getWork",
|
"getWork",
|
||||||
"submitWork",
|
"submitWork",
|
||||||
|
"pendingTransactions",
|
||||||
|
"resend",
|
||||||
},
|
},
|
||||||
"miner": []string{
|
"miner": []string{
|
||||||
"hashrate",
|
"hashrate",
|
||||||
@ -149,7 +151,7 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
|
|||||||
case shared.DbApiName:
|
case shared.DbApiName:
|
||||||
apis[i] = NewDbApi(xeth, eth, codec)
|
apis[i] = NewDbApi(xeth, eth, codec)
|
||||||
case shared.EthApiName:
|
case shared.EthApiName:
|
||||||
apis[i] = NewEthApi(xeth, codec)
|
apis[i] = NewEthApi(xeth, eth, codec)
|
||||||
case shared.MinerApiName:
|
case shared.MinerApiName:
|
||||||
apis[i] = NewMinerApi(eth, codec)
|
apis[i] = NewMinerApi(eth, codec)
|
||||||
case shared.NetApiName:
|
case shared.NetApiName:
|
||||||
|
Loading…
Reference in New Issue
Block a user