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" | ||||
| 	expSource := source | ||||
| 
 | ||||
| 	xeth := xeth.NewTest(ð.Ethereum{}, nil) | ||||
| 	api := NewEthApi(xeth, codec.JSON) | ||||
| 	eth := ð.Ethereum{} | ||||
| 	xeth := xeth.NewTest(eth, nil) | ||||
| 	api := NewEthApi(xeth, eth, codec.JSON) | ||||
| 
 | ||||
| 	var rpcRequest shared.Request | ||||
| 	json.Unmarshal([]byte(jsonstr), &rpcRequest) | ||||
|  | ||||
| @ -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 ðApi{xeth, ethMapping, codec.New(nil)} | ||||
| func NewEthApi(xeth *xeth.XEth, eth *eth.Ethereum, codec codec.Codec) *ethApi { | ||||
| 	return ðApi{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 | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
|  | ||||
| @ -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; } | ||||
| 		}) | ||||
| 	] | ||||
| }); | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user