aboutsummaryrefslogtreecommitdiffstats
path: root/rpc/api
diff options
context:
space:
mode:
authorJeffrey Wilcke <jeffrey@ethereum.org>2015-06-30 23:27:03 +0800
committerJeffrey Wilcke <jeffrey@ethereum.org>2015-06-30 23:27:03 +0800
commitba95e445e16481ea7a94a462347def19b0c2bf2c (patch)
tree23b3b86b1828819f6fffe411567824c2f227e147 /rpc/api
parent130f3b270a9b2f7bd680188c67013695d5f9412b (diff)
parent8c4d493c66cf14f0bcb8b650045a644722ad8d90 (diff)
downloadgo-tangerine-ba95e445e16481ea7a94a462347def19b0c2bf2c.tar.gz
go-tangerine-ba95e445e16481ea7a94a462347def19b0c2bf2c.tar.zst
go-tangerine-ba95e445e16481ea7a94a462347def19b0c2bf2c.zip
Merge pull request #1328 from bas-vk/issue1327
Add pendingTransactions and resend
Diffstat (limited to 'rpc/api')
-rw-r--r--rpc/api/api_test.go5
-rw-r--r--rpc/api/eth.go58
-rw-r--r--rpc/api/eth_args.go178
-rw-r--r--rpc/api/eth_js.go15
-rw-r--r--rpc/api/utils.go4
5 files changed, 252 insertions, 8 deletions
diff --git a/rpc/api/api_test.go b/rpc/api/api_test.go
index 7e273ef28..2ac8bcd45 100644
--- a/rpc/api/api_test.go
+++ b/rpc/api/api_test.go
@@ -76,8 +76,9 @@ func TestCompileSolidity(t *testing.T) {
expLanguageVersion := "0"
expSource := source
- xeth := xeth.NewTest(&eth.Ethereum{}, nil)
- api := NewEthApi(xeth, codec.JSON)
+ eth := &eth.Ethereum{}
+ xeth := xeth.NewTest(eth, nil)
+ api := NewEthApi(xeth, eth, codec.JSON)
var rpcRequest shared.Request
json.Unmarshal([]byte(jsonstr), &rpcRequest)
diff --git a/rpc/api/eth.go b/rpc/api/eth.go
index 962c8d0f9..db0b4b024 100644
--- a/rpc/api/eth.go
+++ b/rpc/api/eth.go
@@ -6,9 +6,12 @@ import (
"math/big"
"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/shared"
"github.com/ethereum/go-ethereum/xeth"
+ "gopkg.in/fatih/set.v0"
)
const (
@@ -18,9 +21,10 @@ const (
// eth api provider
// See https://github.com/ethereum/wiki/wiki/JSON-RPC
type ethApi struct {
- xeth *xeth.XEth
- methods map[string]ethhandler
- codec codec.ApiCoder
+ xeth *xeth.XEth
+ ethereum *eth.Ethereum
+ methods map[string]ethhandler
+ codec codec.ApiCoder
}
// eth callback handler
@@ -71,12 +75,14 @@ var (
"eth_hashrate": (*ethApi).Hashrate,
"eth_getWork": (*ethApi).GetWork,
"eth_submitWork": (*ethApi).SubmitWork,
+ "eth_resend": (*ethApi).Resend,
+ "eth_pendingTransactions": (*ethApi).PendingTransactions,
}
)
// create new ethApi instance
-func NewEthApi(xeth *xeth.XEth, codec codec.Codec) *ethApi {
- return &ethApi{xeth, ethMapping, codec.New(nil)}
+func NewEthApi(xeth *xeth.XEth, eth *eth.Ethereum, codec codec.Codec) *ethApi {
+ return &ethApi{xeth, eth, ethMapping, codec.New(nil)}
}
// 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
}
+
+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
+}
diff --git a/rpc/api/eth_args.go b/rpc/api/eth_args.go
index bf8ffead6..8f64280d3 100644
--- a/rpc/api/eth_args.go
+++ b/rpc/api/eth_args.go
@@ -4,9 +4,12 @@ import (
"encoding/json"
"fmt"
"math/big"
+ "strconv"
+ "strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc/shared"
)
@@ -858,3 +861,178 @@ func (args *SubmitWorkArgs) UnmarshalJSON(b []byte) (err error) {
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
+}
diff --git a/rpc/api/eth_js.go b/rpc/api/eth_js.go
index e1268eb76..4512cc147 100644
--- a/rpc/api/eth_js.go
+++ b/rpc/api/eth_js.go
@@ -14,6 +14,21 @@ web3._extend({
params: 2,
inputFormatter: [web3._extend.formatters.formatInputString,web3._extend.formatters.formatInputString],
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; }
})
]
});
diff --git a/rpc/api/utils.go b/rpc/api/utils.go
index 6e4835de6..e6a01d3d6 100644
--- a/rpc/api/utils.go
+++ b/rpc/api/utils.go
@@ -84,6 +84,8 @@ var (
"hashrate",
"getWork",
"submitWork",
+ "pendingTransactions",
+ "resend",
},
"miner": []string{
"hashrate",
@@ -149,7 +151,7 @@ func ParseApiString(apistr string, codec codec.Codec, xeth *xeth.XEth, eth *eth.
case shared.DbApiName:
apis[i] = NewDbApi(xeth, eth, codec)
case shared.EthApiName:
- apis[i] = NewEthApi(xeth, codec)
+ apis[i] = NewEthApi(xeth, eth, codec)
case shared.MinerApiName:
apis[i] = NewMinerApi(eth, codec)
case shared.NetApiName: