removed old rpc structure and added new inproc api client

This commit is contained in:
Bas van Kervel
2015-06-17 16:22:35 +02:00
parent 3e1d635f8d
commit a4a4e9fcf8
22 changed files with 393 additions and 4427 deletions

View File

@ -1,646 +0,0 @@
package rpc
import (
"bytes"
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/xeth"
)
type EthereumApi struct {
eth *xeth.XEth
}
func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
api := &EthereumApi{
eth: xeth,
}
return api
}
func (api *EthereumApi) xeth() *xeth.XEth {
return api.eth
}
func (api *EthereumApi) xethAtStateNum(num int64) *xeth.XEth {
return api.xeth().AtStateNum(num)
}
func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/JSON-RPC
glog.V(logger.Debug).Infof("%s %s", req.Method, req.Params)
switch req.Method {
case "web3_sha3":
args := new(Sha3Args)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = common.ToHex(crypto.Sha3(common.FromHex(args.Data)))
case "web3_clientVersion":
*reply = api.xeth().ClientVersion()
case "net_version":
*reply = api.xeth().NetworkVersion()
case "net_listening":
*reply = api.xeth().IsListening()
case "net_peerCount":
*reply = newHexNum(api.xeth().PeerCount())
case "eth_protocolVersion":
*reply = api.xeth().EthVersion()
case "eth_coinbase":
*reply = newHexData(api.xeth().Coinbase())
case "eth_mining":
*reply = api.xeth().IsMining()
case "eth_gasPrice":
v := api.xeth().DefaultGasPrice()
*reply = newHexNum(v.Bytes())
case "eth_accounts":
*reply = api.xeth().Accounts()
case "eth_blockNumber":
v := api.xeth().CurrentBlock().Number()
*reply = newHexNum(v.Bytes())
case "eth_getBalance":
args := new(GetBalanceArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xethAtStateNum(args.BlockNumber).BalanceAt(args.Address)
//v := api.xethAtStateNum(args.BlockNumber).State().SafeGet(args.Address).Balance()
//*reply = common.ToHex(v.Bytes())
case "eth_getStorage", "eth_storageAt":
args := new(GetStorageArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xethAtStateNum(args.BlockNumber).State().SafeGet(args.Address).Storage()
case "eth_getStorageAt":
args := new(GetStorageAtArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xethAtStateNum(args.BlockNumber).StorageAt(args.Address, args.Key)
case "eth_getTransactionCount":
args := new(GetTxCountArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
count := api.xethAtStateNum(args.BlockNumber).TxCountAt(args.Address)
*reply = newHexNum(big.NewInt(int64(count)).Bytes())
case "eth_getBlockTransactionCountByHash":
args := new(HashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := NewBlockRes(api.xeth().EthBlockByHash(args.Hash), false)
if block == nil {
*reply = nil
} else {
*reply = newHexNum(big.NewInt(int64(len(block.Transactions))).Bytes())
}
case "eth_getBlockTransactionCountByNumber":
args := new(BlockNumArg)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := NewBlockRes(api.xeth().EthBlockByNumber(args.BlockNumber), false)
if block == nil {
*reply = nil
break
}
*reply = newHexNum(big.NewInt(int64(len(block.Transactions))).Bytes())
case "eth_getUncleCountByBlockHash":
args := new(HashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByHash(args.Hash)
br := NewBlockRes(block, false)
if br == nil {
*reply = nil
break
}
*reply = newHexNum(big.NewInt(int64(len(br.Uncles))).Bytes())
case "eth_getUncleCountByBlockNumber":
args := new(BlockNumArg)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByNumber(args.BlockNumber)
br := NewBlockRes(block, false)
if br == nil {
*reply = nil
break
}
*reply = newHexNum(big.NewInt(int64(len(br.Uncles))).Bytes())
case "eth_getData", "eth_getCode":
args := new(GetDataArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v := api.xethAtStateNum(args.BlockNumber).CodeAtBytes(args.Address)
*reply = newHexData(v)
case "eth_sign":
args := new(NewSigArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := api.xeth().Sign(args.From, args.Data, false)
if err != nil {
return err
}
*reply = v
case "eth_sendRawTransaction":
args := new(NewDataArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
v, err := api.xeth().PushTx(args.Data)
if err != nil {
return err
}
*reply = v
case "eth_sendTransaction", "eth_transact":
args := new(NewTxArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
// nonce may be nil ("guess" mode)
var nonce string
if args.Nonce != nil {
nonce = args.Nonce.String()
}
var gas string
if args.Gas == nil {
gas = ""
} else {
gas = args.Gas.String()
}
var gasprice string
if args.GasPrice == nil {
gasprice = ""
} else {
gasprice = args.GasPrice.String()
}
v, err := api.xeth().Transact(args.From, args.To, nonce, args.Value.String(), gas, gasprice, args.Data)
if err != nil {
return err
}
*reply = v
case "eth_estimateGas":
_, gas, err := api.doCall(req.Params)
if err != nil {
return err
}
// TODO unwrap the parent method's ToHex call
if len(gas) == 0 {
*reply = newHexNum(0)
} else {
*reply = newHexNum(gas)
}
case "eth_call":
v, _, err := api.doCall(req.Params)
if err != nil {
return err
}
// TODO unwrap the parent method's ToHex call
if v == "0x0" {
*reply = newHexData([]byte{})
} else {
*reply = newHexData(common.FromHex(v))
}
case "eth_flush":
return NewNotImplementedError(req.Method)
case "eth_getBlockByHash":
args := new(GetBlockByHashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByHash(args.BlockHash)
br := NewBlockRes(block, args.IncludeTxs)
*reply = br
case "eth_getBlockByNumber":
args := new(GetBlockByNumberArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByNumber(args.BlockNumber)
br := NewBlockRes(block, args.IncludeTxs)
// If request was for "pending", nil nonsensical fields
if args.BlockNumber == -2 {
br.BlockHash = nil
br.BlockNumber = nil
br.Miner = nil
br.Nonce = nil
br.LogsBloom = nil
}
*reply = br
case "eth_getTransactionByHash":
args := new(HashArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
tx, bhash, bnum, txi := api.xeth().EthTransactionByHash(args.Hash)
if tx != nil {
v := NewTransactionRes(tx)
// if the blockhash is 0, assume this is a pending transaction
if bytes.Compare(bhash.Bytes(), bytes.Repeat([]byte{0}, 32)) != 0 {
v.BlockHash = newHexData(bhash)
v.BlockNumber = newHexNum(bnum)
v.TxIndex = newHexNum(txi)
}
*reply = v
}
case "eth_getTransactionByBlockHashAndIndex":
args := new(HashIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByHash(args.Hash)
br := NewBlockRes(block, true)
if br == nil {
*reply = nil
break
}
if args.Index >= int64(len(br.Transactions)) || args.Index < 0 {
// return NewValidationError("Index", "does not exist")
*reply = nil
} else {
*reply = br.Transactions[args.Index]
}
case "eth_getTransactionByBlockNumberAndIndex":
args := new(BlockNumIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByNumber(args.BlockNumber)
v := NewBlockRes(block, true)
if v == nil {
*reply = nil
break
}
if args.Index >= int64(len(v.Transactions)) || args.Index < 0 {
// return NewValidationError("Index", "does not exist")
*reply = nil
} else {
*reply = v.Transactions[args.Index]
}
case "eth_getUncleByBlockHashAndIndex":
args := new(HashIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
br := NewBlockRes(api.xeth().EthBlockByHash(args.Hash), false)
if br == nil {
*reply = nil
return nil
}
if args.Index >= int64(len(br.Uncles)) || args.Index < 0 {
// return NewValidationError("Index", "does not exist")
*reply = nil
} else {
*reply = br.Uncles[args.Index]
}
case "eth_getUncleByBlockNumberAndIndex":
args := new(BlockNumIndexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
block := api.xeth().EthBlockByNumber(args.BlockNumber)
v := NewBlockRes(block, true)
if v == nil {
*reply = nil
return nil
}
if args.Index >= int64(len(v.Uncles)) || args.Index < 0 {
// return NewValidationError("Index", "does not exist")
*reply = nil
} else {
*reply = v.Uncles[args.Index]
}
case "eth_getCompilers":
var lang string
if solc, _ := api.xeth().Solc(); solc != nil {
lang = "Solidity"
}
c := []string{lang}
*reply = c
case "eth_compileLLL", "eth_compileSerpent":
return NewNotImplementedError(req.Method)
case "eth_compileSolidity":
solc, _ := api.xeth().Solc()
if solc == nil {
return NewNotAvailableError(req.Method, "solc (solidity compiler) not found")
}
args := new(SourceArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
contracts, err := solc.Compile(args.Source)
if err != nil {
return err
}
*reply = contracts
case "eth_newFilter":
args := new(BlockFilterArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
id := api.xeth().NewLogFilter(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics)
*reply = newHexNum(big.NewInt(int64(id)).Bytes())
case "eth_newBlockFilter":
*reply = newHexNum(api.xeth().NewBlockFilter())
case "eth_newPendingTransactionFilter":
*reply = newHexNum(api.xeth().NewTransactionFilter())
case "eth_uninstallFilter":
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xeth().UninstallFilter(args.Id)
case "eth_getFilterChanges":
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
switch api.xeth().GetFilterType(args.Id) {
case xeth.BlockFilterTy:
*reply = NewHashesRes(api.xeth().BlockFilterChanged(args.Id))
case xeth.TransactionFilterTy:
*reply = NewHashesRes(api.xeth().TransactionFilterChanged(args.Id))
case xeth.LogFilterTy:
*reply = NewLogsRes(api.xeth().LogFilterChanged(args.Id))
default:
*reply = []string{} // reply empty string slice
}
case "eth_getFilterLogs":
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = NewLogsRes(api.xeth().Logs(args.Id))
case "eth_getLogs":
args := new(BlockFilterArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = NewLogsRes(api.xeth().AllLogs(args.Earliest, args.Latest, args.Skip, args.Max, args.Address, args.Topics))
case "eth_getWork":
api.xeth().SetMining(true, 0)
*reply = api.xeth().RemoteMining().GetWork()
case "eth_submitWork":
args := new(SubmitWorkArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xeth().RemoteMining().SubmitWork(args.Nonce, common.HexToHash(args.Digest), common.HexToHash(args.Header))
case "db_putString":
args := new(DbArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
if err := args.requirements(); err != nil {
return err
}
api.xeth().DbPut([]byte(args.Database+args.Key), args.Value)
*reply = true
case "db_getString":
args := new(DbArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
if err := args.requirements(); err != nil {
return err
}
res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
*reply = string(res)
case "db_putHex":
args := new(DbHexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
if err := args.requirements(); err != nil {
return err
}
api.xeth().DbPut([]byte(args.Database+args.Key), args.Value)
*reply = true
case "db_getHex":
args := new(DbHexArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
if err := args.requirements(); err != nil {
return err
}
res, _ := api.xeth().DbGet([]byte(args.Database + args.Key))
*reply = newHexData(res)
case "shh_version":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Retrieves the currently running whisper protocol version
*reply = api.xeth().WhisperVersion()
case "shh_post":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Injects a new message into the whisper network
args := new(WhisperMessageArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
err := api.xeth().Whisper().Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl)
if err != nil {
return err
}
*reply = true
case "shh_newIdentity":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Creates a new whisper identity to use for sending/receiving messages
*reply = api.xeth().Whisper().NewIdentity()
case "shh_hasIdentity":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Checks if an identity if owned or not
args := new(WhisperIdentityArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xeth().Whisper().HasIdentity(args.Identity)
case "shh_newFilter":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Create a new filter to watch and match messages with
args := new(WhisperFilterArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
id := api.xeth().NewWhisperFilter(args.To, args.From, args.Topics)
*reply = newHexNum(big.NewInt(int64(id)).Bytes())
case "shh_uninstallFilter":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Remove an existing filter watching messages
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xeth().UninstallWhisperFilter(args.Id)
case "shh_getFilterChanges":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Retrieve all the new messages arrived since the last request
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xeth().WhisperMessagesChanged(args.Id)
case "shh_getMessages":
// Short circuit if whisper is not running
if api.xeth().Whisper() == nil {
return NewNotAvailableError(req.Method, "whisper offline")
}
// Retrieve all the cached messages matching a specific, existing filter
args := new(FilterIdArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = api.xeth().WhisperMessages(args.Id)
case "eth_hashrate":
*reply = newHexNum(api.xeth().HashRate())
case "ext_disasm":
args := new(SourceArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {
return err
}
*reply = vm.Disasm(common.FromHex(args.Source))
// case "eth_register":
// // Placeholder for actual type
// args := new(HashIndexArgs)
// if err := json.Unmarshal(req.Params, &args); err != nil {
// return err
// }
// *reply = api.xeth().Register(args.Hash)
// case "eth_unregister":
// args := new(HashIndexArgs)
// if err := json.Unmarshal(req.Params, &args); err != nil {
// return err
// }
// *reply = api.xeth().Unregister(args.Hash)
// case "eth_watchTx":
// args := new(HashIndexArgs)
// if err := json.Unmarshal(req.Params, &args); err != nil {
// return err
// }
// *reply = api.xeth().PullWatchTx(args.Hash)
default:
return NewNotImplementedError(req.Method)
}
// glog.V(logger.Detail).Infof("Reply: %v\n", reply)
return nil
}
func (api *EthereumApi) doCall(params json.RawMessage) (string, string, error) {
args := new(CallArgs)
if err := json.Unmarshal(params, &args); err != nil {
return "", "", err
}
var gas string
if args.Gas == nil {
gas = ""
} else {
gas = args.Gas.String()
}
var gasprice string
if args.GasPrice == nil {
gasprice = ""
} else {
gasprice = args.GasPrice.String()
}
return api.xethAtStateNum(args.BlockNumber).Call(args.From, args.To, args.Value.String(), gas, gasprice, args.Data)
}

View File

@ -18,15 +18,13 @@ const (
TxPoolApiName = "txpool"
PersonalApiName = "personal"
Web3ApiName = "web3"
JsonRpcVersion = "2.0"
)
var (
DefaultHttpRpcApis = strings.Join([]string{
DbApiName, EthApiName, NetApiName, Web3ApiName,
}, ",")
// List with all API's which are offered over the IPC interface by default
DefaultIpcApis = strings.Join([]string{
// All API's
AllApis = strings.Join([]string{
AdminApiName, DbApiName, EthApiName, DebugApiName, MinerApiName, NetApiName,
ShhApiName, TxPoolApiName, PersonalApiName, Web3ApiName,
}, ",")

57
rpc/api/args.go Normal file
View File

@ -0,0 +1,57 @@
package api
import (
"encoding/json"
"github.com/ethereum/go-ethereum/rpc/shared"
)
type CompileArgs struct {
Source string
}
func (args *CompileArgs) 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)
}
argstr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("arg0", "is not a string")
}
args.Source = argstr
return nil
}
type FilterStringArgs struct {
Word string
}
func (args *FilterStringArgs) 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)
}
var argstr string
argstr, ok := obj[0].(string)
if !ok {
return shared.NewInvalidTypeError("filter", "not a string")
}
switch argstr {
case "latest", "pending":
break
default:
return shared.NewValidationError("Word", "Must be `latest` or `pending`")
}
args.Word = argstr
return nil
}

View File

@ -1,4 +1,4 @@
package rpc
package api
import (
"bytes"
@ -6,6 +6,7 @@ import (
"fmt"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/rpc/shared"
)
func TestBlockheightInvalidString(t *testing.T) {
@ -68,7 +69,7 @@ func ExpectValidationError(err error) string {
switch err.(type) {
case nil:
str = "Expected error but didn't get one"
case *ValidationError:
case *shared.ValidationError:
break
default:
str = fmt.Sprintf("Expected *rpc.ValidationError but got %T with message `%s`", err, err.Error())
@ -81,7 +82,7 @@ func ExpectInvalidTypeError(err error) string {
switch err.(type) {
case nil:
str = "Expected error but didn't get one"
case *InvalidTypeError:
case *shared.InvalidTypeError:
break
default:
str = fmt.Sprintf("Expected *rpc.InvalidTypeError but got %T with message `%s`", err, err.Error())
@ -94,7 +95,7 @@ func ExpectInsufficientParamsError(err error) string {
switch err.(type) {
case nil:
str = "Expected error but didn't get one"
case *InsufficientParamsError:
case *shared.InsufficientParamsError:
break
default:
str = fmt.Sprintf("Expected *rpc.InsufficientParamsError but got %T with message %s", err, err.Error())
@ -107,7 +108,7 @@ func ExpectDecodeParamError(err error) string {
switch err.(type) {
case nil:
str = "Expected error but didn't get one"
case *DecodeParamError:
case *shared.DecodeParamError:
break
default:
str = fmt.Sprintf("Expected *rpc.DecodeParamError but got %T with message `%s`", err, err.Error())

View File

@ -1,205 +0,0 @@
package rpc
import (
"encoding/json"
"strconv"
"testing"
"github.com/ethereum/go-ethereum/common/compiler"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/xeth"
)
func TestWeb3Sha3(t *testing.T) {
jsonstr := `{"jsonrpc":"2.0","method":"web3_sha3","params":["0x68656c6c6f20776f726c64"],"id":64}`
expected := "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"
api := &EthereumApi{}
var req RpcRequest
json.Unmarshal([]byte(jsonstr), &req)
var response interface{}
_ = api.GetRequestReply(&req, &response)
if response.(string) != expected {
t.Errorf("Expected %s got %s", expected, response)
}
}
const solcVersion = "0.9.23"
func TestCompileSolidity(t *testing.T) {
solc, err := compiler.New("")
if solc == nil {
t.Skip("no solc found: skip")
} else if solc.Version() != solcVersion {
t.Skip("WARNING: skipping test because of solc different version (%v, test written for %v, may need to update)", solc.Version(), solcVersion)
}
source := `contract test {\n` +
" /// @notice Will multiply `a` by 7." + `\n` +
` function multiply(uint a) returns(uint d) {\n` +
` return a * 7;\n` +
` }\n` +
`}\n`
jsonstr := `{"jsonrpc":"2.0","method":"eth_compileSolidity","params":["` + source + `"],"id":64}`
expCode := "0x605880600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b603d6004803590602001506047565b8060005260206000f35b60006007820290506053565b91905056"
expAbiDefinition := `[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"type":"function"}]`
expUserDoc := `{"methods":{"multiply(uint256)":{"notice":"Will multiply ` + "`a`" + ` by 7."}}}`
expDeveloperDoc := `{"methods":{}}`
expCompilerVersion := solc.Version()
expLanguage := "Solidity"
expLanguageVersion := "0"
expSource := source
api := NewEthereumApi(xeth.NewTest(&eth.Ethereum{}, nil))
var req RpcRequest
json.Unmarshal([]byte(jsonstr), &req)
var response interface{}
err = api.GetRequestReply(&req, &response)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
respjson, err := json.Marshal(response)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
var contracts = make(map[string]*compiler.Contract)
err = json.Unmarshal(respjson, &contracts)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if len(contracts) != 1 {
t.Errorf("expected one contract, got %v", len(contracts))
}
contract := contracts["test"]
if contract.Code != expCode {
t.Errorf("Expected \n%s got \n%s", expCode, contract.Code)
}
if strconv.Quote(contract.Info.Source) != `"`+expSource+`"` {
t.Errorf("Expected \n'%s' got \n'%s'", expSource, strconv.Quote(contract.Info.Source))
}
if contract.Info.Language != expLanguage {
t.Errorf("Expected %s got %s", expLanguage, contract.Info.Language)
}
if contract.Info.LanguageVersion != expLanguageVersion {
t.Errorf("Expected %s got %s", expLanguageVersion, contract.Info.LanguageVersion)
}
if contract.Info.CompilerVersion != expCompilerVersion {
t.Errorf("Expected %s got %s", expCompilerVersion, contract.Info.CompilerVersion)
}
userdoc, err := json.Marshal(contract.Info.UserDoc)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
devdoc, err := json.Marshal(contract.Info.DeveloperDoc)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
abidef, err := json.Marshal(contract.Info.AbiDefinition)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if string(abidef) != expAbiDefinition {
t.Errorf("Expected \n'%s' got \n'%s'", expAbiDefinition, string(abidef))
}
if string(userdoc) != expUserDoc {
t.Errorf("Expected \n'%s' got \n'%s'", expUserDoc, string(userdoc))
}
if string(devdoc) != expDeveloperDoc {
t.Errorf("Expected %s got %s", expDeveloperDoc, string(devdoc))
}
}
// func TestDbStr(t *testing.T) {
// jsonput := `{"jsonrpc":"2.0","method":"db_putString","params":["testDB","myKey","myString"],"id":64}`
// jsonget := `{"jsonrpc":"2.0","method":"db_getString","params":["testDB","myKey"],"id":64}`
// expected := "myString"
// xeth := &xeth.XEth{}
// api := NewEthereumApi(xeth)
// var response interface{}
// var req RpcRequest
// json.Unmarshal([]byte(jsonput), &req)
// _ = api.GetRequestReply(&req, &response)
// json.Unmarshal([]byte(jsonget), &req)
// _ = api.GetRequestReply(&req, &response)
// if response.(string) != expected {
// t.Errorf("Expected %s got %s", expected, response)
// }
// }
// func TestDbHexStr(t *testing.T) {
// jsonput := `{"jsonrpc":"2.0","method":"db_putHex","params":["testDB","beefKey","0xbeef"],"id":64}`
// jsonget := `{"jsonrpc":"2.0","method":"db_getHex","params":["testDB","beefKey"],"id":64}`
// expected := "0xbeef"
// xeth := &xeth.XEth{}
// api := NewEthereumApi(xeth)
// defer api.db.Close()
// var response interface{}
// var req RpcRequest
// json.Unmarshal([]byte(jsonput), &req)
// _ = api.GetRequestReply(&req, &response)
// json.Unmarshal([]byte(jsonget), &req)
// _ = api.GetRequestReply(&req, &response)
// if response.(string) != expected {
// t.Errorf("Expected %s got %s", expected, response)
// }
// }
// func TestFilterClose(t *testing.T) {
// t.Skip()
// api := &EthereumApi{
// logs: make(map[int]*logFilter),
// messages: make(map[int]*whisperFilter),
// quit: make(chan struct{}),
// }
// filterTickerTime = 1
// api.logs[0] = &logFilter{}
// api.messages[0] = &whisperFilter{}
// var wg sync.WaitGroup
// wg.Add(1)
// go api.start()
// go func() {
// select {
// case <-time.After(500 * time.Millisecond):
// api.stop()
// wg.Done()
// }
// }()
// wg.Wait()
// if len(api.logs) != 0 {
// t.Error("expected logs to be empty")
// }
// if len(api.messages) != 0 {
// t.Error("expected messages to be empty")
// }
// }

File diff suppressed because it is too large Load Diff

View File

@ -9,16 +9,32 @@ import (
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/shared"
"strings"
)
const (
jsonrpcver = "2.0"
maxHttpSizeReqLength = 1024 * 1024 // 1MB
)
var (
// List with all API's which are offered over the in proc interface by default
DefaultInProcApis = api.AllApis
// List with all API's which are offered over the IPC interface by default
DefaultIpcApis = api.AllApis
// List with API's which are offered over thr HTTP/RPC interface by default
DefaultHttpRpcApis = strings.Join([]string{
api.DbApiName, api.EthApiName, api.NetApiName, api.Web3ApiName,
}, ",")
)
type EthereumClient interface {
// Close underlaying connection
Close()
// Send request
Send(interface{}) error
// Receive response
Recv() (interface{}, error)
}

View File

@ -63,3 +63,27 @@ func StopHttp() {
httpListener = nil
}
}
type httpClient struct {
codec codec.ApiCoder
}
// Create a new in process client
func NewHttpClient(cfg HttpConfig, codec codec.Codec) *httpClient {
return &httpClient{
codec: codec.New(nil),
}
}
func (self *httpClient) Close() {
// do nothing
}
func (self *httpClient) Send(req interface{}) error {
return nil
}
func (self *httpClient) Recv() (interface{}, error) {
return nil, nil
}

View File

@ -90,7 +90,7 @@ func newStoppableHandler(h http.Handler, stop chan struct{}) http.Handler {
case <-stop:
w.Header().Set("Content-Type", "application/json")
err := fmt.Errorf("RPC service stopped")
response := shared.NewRpcResponse(-1, jsonrpcver, nil, err)
response := shared.NewRpcResponse(-1, api.JsonRpcVersion, nil, err)
httpSend(w, response)
default:
h.ServeHTTP(w, r)
@ -110,14 +110,14 @@ func httpSend(writer io.Writer, v interface{}) (n int, err error) {
return writer.Write(payload)
}
func gethHttpHandler(codec codec.Codec, api api.EthereumApi) http.Handler {
func gethHttpHandler(codec codec.Codec, a api.EthereumApi) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
// Limit request size to resist DoS
if req.ContentLength > maxHttpSizeReqLength {
err := fmt.Errorf("Request too large")
response := shared.NewRpcErrorResponse(-1, jsonrpcver, -32700, err)
response := shared.NewRpcErrorResponse(-1, api.JsonRpcVersion, -32700, err)
httpSend(w, &response)
return
}
@ -126,7 +126,7 @@ func gethHttpHandler(codec codec.Codec, api api.EthereumApi) http.Handler {
payload, err := ioutil.ReadAll(req.Body)
if err != nil {
err := fmt.Errorf("Could not read request body")
response := shared.NewRpcErrorResponse(-1, jsonrpcver, -32700, err)
response := shared.NewRpcErrorResponse(-1, api.JsonRpcVersion, -32700, err)
httpSend(w, &response)
return
}
@ -134,7 +134,7 @@ func gethHttpHandler(codec codec.Codec, api api.EthereumApi) http.Handler {
c := codec.New(nil)
var rpcReq shared.Request
if err = c.Decode(payload, &rpcReq); err == nil {
reply, err := api.Execute(&rpcReq)
reply, err := a.Execute(&rpcReq)
res := shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
httpSend(w, &res)
return
@ -146,7 +146,7 @@ func gethHttpHandler(codec codec.Codec, api api.EthereumApi) http.Handler {
resCount := 0
for i, rpcReq := range reqBatch {
reply, err := api.Execute(&rpcReq)
reply, err := a.Execute(&rpcReq)
if rpcReq.Id != nil { // this leaves nil entries in the response batch for later removal
resBatch[i] = shared.NewRpcResponse(rpcReq.Id, rpcReq.Jsonrpc, reply, err)
resCount += 1
@ -161,7 +161,7 @@ func gethHttpHandler(codec codec.Codec, api api.EthereumApi) http.Handler {
// invalid request
err = fmt.Errorf("Could not decode request")
res := shared.NewRpcErrorResponse(-1, jsonrpcver, -32600, err)
res := shared.NewRpcErrorResponse(-1, api.JsonRpcVersion, -32600, err)
httpSend(w, res)
})
}

53
rpc/comms/inproc.go Normal file
View File

@ -0,0 +1,53 @@
package comms
import (
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/shared"
"fmt"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/xeth"
"github.com/ethereum/go-ethereum/eth"
)
type InProcClient struct {
api api.EthereumApi
codec codec.Codec
lastId interface{}
lastJsonrpc string
lastErr error
lastRes interface{}
}
// Create a new in process client
func NewInProcClient(codec codec.Codec) *InProcClient {
return &InProcClient{
codec: codec,
}
}
func (self *InProcClient) Close() {
// do nothing
}
// Need to setup api support
func (self *InProcClient) Initialize(xeth *xeth.XEth, eth *eth.Ethereum) {
if apis, err := api.ParseApiString(api.AllApis, self.codec, xeth, eth); err == nil {
self.api = api.Merge(apis...)
}
}
func (self *InProcClient) Send(req interface{}) error {
if r, ok := req.(*shared.Request); ok {
self.lastId = r.Id
self.lastJsonrpc = r.Jsonrpc
self.lastRes, self.lastErr = self.api.Execute(r)
return self.lastErr
}
return fmt.Errorf("Invalid request (%T)", req)
}
func (self *InProcClient) Recv() (interface{}, error) {
return self.lastRes, self.lastErr
//return *shared.NewRpcResponse(self.lastId, self.lastJsonrpc, self.lastRes, self.lastErr), nil
}

View File

@ -10,19 +10,19 @@ type IpcConfig struct {
}
type ipcClient struct {
c codec.ApiCoder
codec codec.ApiCoder
}
func (self *ipcClient) Close() {
self.c.Close()
self.codec.Close()
}
func (self *ipcClient) Send(req interface{}) error {
return self.c.WriteResponse(req)
return self.codec.WriteResponse(req)
}
func (self *ipcClient) Recv() (interface{}, error) {
return self.c.ReadResponse()
return self.codec.ReadResponse()
}
// Create a new IPC client, UNIX domain socket on posix, named pipe on Windows

View File

@ -1,163 +0,0 @@
package rpc
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"strings"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/xeth"
"github.com/rs/cors"
)
var rpclistener *stoppableTCPListener
const (
jsonrpcver = "2.0"
maxSizeReqLength = 1024 * 1024 // 1MB
)
func Start(pipe *xeth.XEth, config RpcConfig) error {
if rpclistener != nil {
if fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort) != rpclistener.Addr().String() {
return fmt.Errorf("RPC service already running on %s ", rpclistener.Addr().String())
}
return nil // RPC service already running on given host/port
}
l, err := newStoppableTCPListener(fmt.Sprintf("%s:%d", config.ListenAddress, config.ListenPort))
if err != nil {
glog.V(logger.Error).Infof("Can't listen on %s:%d: %v", config.ListenAddress, config.ListenPort, err)
return err
}
rpclistener = l
var handler http.Handler
if len(config.CorsDomain) > 0 {
var opts cors.Options
opts.AllowedMethods = []string{"POST"}
opts.AllowedOrigins = strings.Split(config.CorsDomain, " ")
c := cors.New(opts)
handler = newStoppableHandler(c.Handler(JSONRPC(pipe)), l.stop)
} else {
handler = newStoppableHandler(JSONRPC(pipe), l.stop)
}
go http.Serve(l, handler)
return nil
}
func Stop() error {
if rpclistener != nil {
rpclistener.Stop()
rpclistener = nil
}
return nil
}
// JSONRPC returns a handler that implements the Ethereum JSON-RPC API.
func JSONRPC(pipe *xeth.XEth) http.Handler {
api := NewEthereumApi(pipe)
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
// Limit request size to resist DoS
if req.ContentLength > maxSizeReqLength {
jsonerr := &RpcErrorObject{-32700, "Request too large"}
send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
return
}
// Read request body
defer req.Body.Close()
body, err := ioutil.ReadAll(req.Body)
if err != nil {
jsonerr := &RpcErrorObject{-32700, "Could not read request body"}
send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
}
// Try to parse the request as a single
var reqSingle RpcRequest
if err := json.Unmarshal(body, &reqSingle); err == nil {
response := RpcResponse(api, &reqSingle)
if reqSingle.Id != nil {
send(w, &response)
}
return
}
// Try to parse the request to batch
var reqBatch []RpcRequest
if err := json.Unmarshal(body, &reqBatch); err == nil {
// Build response batch
resBatch := make([]*interface{}, len(reqBatch))
resCount := 0
for i, request := range reqBatch {
response := RpcResponse(api, &request)
// this leaves nil entries in the response batch for later removal
if request.Id != nil {
resBatch[i] = response
resCount = resCount + 1
}
}
// make response omitting nil entries
respBatchComp := make([]*interface{}, resCount)
for _, v := range resBatch {
if v != nil {
respBatchComp[len(respBatchComp)-resCount] = v
resCount = resCount - 1
}
}
send(w, respBatchComp)
return
}
// Not a batch or single request, error
jsonerr := &RpcErrorObject{-32600, "Could not decode request"}
send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
})
}
func RpcResponse(api *EthereumApi, request *RpcRequest) *interface{} {
var reply, response interface{}
reserr := api.GetRequestReply(request, &reply)
switch reserr.(type) {
case nil:
response = &RpcSuccessResponse{Jsonrpc: jsonrpcver, Id: request.Id, Result: reply}
case *NotImplementedError, *NotAvailableError:
jsonerr := &RpcErrorObject{-32601, reserr.Error()}
response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
case *DecodeParamError, *InsufficientParamsError, *ValidationError, *InvalidTypeError:
jsonerr := &RpcErrorObject{-32602, reserr.Error()}
response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
default:
jsonerr := &RpcErrorObject{-32603, reserr.Error()}
response = &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: request.Id, Error: jsonerr}
}
glog.V(logger.Detail).Infof("Generated response: %T %s", response, response)
return &response
}
func send(writer io.Writer, v interface{}) (n int, err error) {
var payload []byte
payload, err = json.MarshalIndent(v, "", "\t")
if err != nil {
glog.V(logger.Error).Infoln("Error marshalling JSON", err)
return 0, err
}
glog.V(logger.Detail).Infof("Sending payload: %s", payload)
return writer.Write(payload)
}

View File

@ -1,31 +1,28 @@
package rpc
import (
"encoding/json"
"fmt"
"reflect"
"github.com/ethereum/go-ethereum/jsre"
"github.com/ethereum/go-ethereum/rpc/codec"
"github.com/ethereum/go-ethereum/rpc/api"
"github.com/ethereum/go-ethereum/rpc/comms"
"github.com/ethereum/go-ethereum/rpc/shared"
"github.com/robertkrimen/otto"
"encoding/json"
"fmt"
)
type Jeth struct {
ethApi *EthereumApi
re *jsre.JSRE
ipcpath string
ethApi api.EthereumApi
re *jsre.JSRE
client comms.EthereumClient
}
func NewJeth(ethApi *EthereumApi, re *jsre.JSRE, ipcpath string) *Jeth {
return &Jeth{ethApi, re, ipcpath}
func NewJeth(ethApi api.EthereumApi, re *jsre.JSRE, client comms.EthereumClient) *Jeth {
return &Jeth{ethApi, re, client}
}
func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface{}) (response otto.Value) {
rpcerr := &RpcErrorObject{code, msg}
call.Otto.Set("ret_jsonrpc", jsonrpcver)
rpcerr := &shared.ErrorObject{code, msg}
call.Otto.Set("ret_jsonrpc", api.JsonRpcVersion)
call.Otto.Set("ret_id", id)
call.Otto.Set("ret_error", rpcerr)
response, _ = call.Otto.Run(`
@ -34,6 +31,7 @@ func (self *Jeth) err(call otto.FunctionCall, code int, msg string, id interface
return
}
func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
reqif, err := call.Argument(0).Export()
if err != nil {
@ -41,11 +39,11 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
}
jsonreq, err := json.Marshal(reqif)
var reqs []RpcRequest
var reqs []shared.Request
batch := true
err = json.Unmarshal(jsonreq, &reqs)
if err != nil {
reqs = make([]RpcRequest, 1)
reqs = make([]shared.Request, 1)
err = json.Unmarshal(jsonreq, &reqs[0])
batch = false
}
@ -55,12 +53,18 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
for i, req := range reqs {
var respif interface{}
err = self.ethApi.GetRequestReply(&req, &respif)
err := self.client.Send(&req)//self.ethApi.Execute(&req)
if err != nil {
fmt.Println("Error request:", err)
return self.err(call, -32603, err.Error(), req.Id)
}
respif, err = self.client.Recv()
if err != nil {
fmt.Println("Error response:", err)
return self.err(call, -32603, err.Error(), req.Id)
}
call.Otto.Set("ret_jsonrpc", jsonrpcver)
call.Otto.Set("ret_jsonrpc", api.JsonRpcVersion)
call.Otto.Set("ret_id", req.Id)
res, _ := json.Marshal(respif)
@ -88,6 +92,7 @@ func (self *Jeth) Send(call otto.FunctionCall) (response otto.Value) {
return
}
/*
func (self *Jeth) SendIpc(call otto.FunctionCall) (response otto.Value) {
reqif, err := call.Argument(0).Export()
if err != nil {
@ -102,11 +107,11 @@ func (self *Jeth) SendIpc(call otto.FunctionCall) (response otto.Value) {
defer client.Close()
jsonreq, err := json.Marshal(reqif)
var reqs []RpcRequest
var reqs []shared.Request
batch := true
err = json.Unmarshal(jsonreq, &reqs)
if err != nil {
reqs = make([]RpcRequest, 1)
reqs = make([]shared.Request, 1)
err = json.Unmarshal(jsonreq, &reqs[0])
batch = false
}
@ -169,3 +174,4 @@ func (self *Jeth) SendIpc(call otto.FunctionCall) (response otto.Value) {
return
}
*/

View File

@ -1,316 +0,0 @@
package rpc
import (
"encoding/json"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
)
type BlockRes struct {
fullTx bool
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *hexnum `json:"size"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"`
Uncles []*UncleRes `json:"uncles"`
}
func (b *BlockRes) MarshalJSON() ([]byte, error) {
if b.fullTx {
var ext struct {
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *hexnum `json:"size"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*TransactionRes `json:"transactions"`
Uncles []*hexdata `json:"uncles"`
}
ext.BlockNumber = b.BlockNumber
ext.BlockHash = b.BlockHash
ext.ParentHash = b.ParentHash
ext.Nonce = b.Nonce
ext.Sha3Uncles = b.Sha3Uncles
ext.LogsBloom = b.LogsBloom
ext.TransactionRoot = b.TransactionRoot
ext.StateRoot = b.StateRoot
ext.Miner = b.Miner
ext.Difficulty = b.Difficulty
ext.TotalDifficulty = b.TotalDifficulty
ext.Size = b.Size
ext.ExtraData = b.ExtraData
ext.GasLimit = b.GasLimit
ext.GasUsed = b.GasUsed
ext.UnixTimestamp = b.UnixTimestamp
ext.Transactions = b.Transactions
ext.Uncles = make([]*hexdata, len(b.Uncles))
for i, u := range b.Uncles {
ext.Uncles[i] = u.BlockHash
}
return json.Marshal(ext)
} else {
var ext struct {
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
TotalDifficulty *hexnum `json:"totalDifficulty"`
Size *hexnum `json:"size"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
Transactions []*hexdata `json:"transactions"`
Uncles []*hexdata `json:"uncles"`
}
ext.BlockNumber = b.BlockNumber
ext.BlockHash = b.BlockHash
ext.ParentHash = b.ParentHash
ext.Nonce = b.Nonce
ext.Sha3Uncles = b.Sha3Uncles
ext.LogsBloom = b.LogsBloom
ext.TransactionRoot = b.TransactionRoot
ext.StateRoot = b.StateRoot
ext.Miner = b.Miner
ext.Difficulty = b.Difficulty
ext.TotalDifficulty = b.TotalDifficulty
ext.Size = b.Size
ext.ExtraData = b.ExtraData
ext.GasLimit = b.GasLimit
ext.GasUsed = b.GasUsed
ext.UnixTimestamp = b.UnixTimestamp
ext.Transactions = make([]*hexdata, len(b.Transactions))
for i, tx := range b.Transactions {
ext.Transactions[i] = tx.Hash
}
ext.Uncles = make([]*hexdata, len(b.Uncles))
for i, u := range b.Uncles {
ext.Uncles[i] = u.BlockHash
}
return json.Marshal(ext)
}
}
func NewBlockRes(block *types.Block, fullTx bool) *BlockRes {
if block == nil {
return nil
}
res := new(BlockRes)
res.fullTx = fullTx
res.BlockNumber = newHexNum(block.Number())
res.BlockHash = newHexData(block.Hash())
res.ParentHash = newHexData(block.ParentHash())
res.Nonce = newHexData(block.Nonce())
res.Sha3Uncles = newHexData(block.Header().UncleHash)
res.LogsBloom = newHexData(block.Bloom())
res.TransactionRoot = newHexData(block.Header().TxHash)
res.StateRoot = newHexData(block.Root())
res.Miner = newHexData(block.Header().Coinbase)
res.Difficulty = newHexNum(block.Difficulty())
res.TotalDifficulty = newHexNum(block.Td)
res.Size = newHexNum(block.Size().Int64())
res.ExtraData = newHexData(block.Header().Extra)
res.GasLimit = newHexNum(block.GasLimit())
res.GasUsed = newHexNum(block.GasUsed())
res.UnixTimestamp = newHexNum(block.Time())
res.Transactions = make([]*TransactionRes, len(block.Transactions()))
for i, tx := range block.Transactions() {
res.Transactions[i] = NewTransactionRes(tx)
res.Transactions[i].BlockHash = res.BlockHash
res.Transactions[i].BlockNumber = res.BlockNumber
res.Transactions[i].TxIndex = newHexNum(i)
}
res.Uncles = make([]*UncleRes, len(block.Uncles()))
for i, uncle := range block.Uncles() {
res.Uncles[i] = NewUncleRes(uncle)
}
return res
}
type TransactionRes struct {
Hash *hexdata `json:"hash"`
Nonce *hexnum `json:"nonce"`
BlockHash *hexdata `json:"blockHash"`
BlockNumber *hexnum `json:"blockNumber"`
TxIndex *hexnum `json:"transactionIndex"`
From *hexdata `json:"from"`
To *hexdata `json:"to"`
Value *hexnum `json:"value"`
Gas *hexnum `json:"gas"`
GasPrice *hexnum `json:"gasPrice"`
Input *hexdata `json:"input"`
}
func NewTransactionRes(tx *types.Transaction) *TransactionRes {
if tx == nil {
return nil
}
var v = new(TransactionRes)
v.Hash = newHexData(tx.Hash())
v.Nonce = newHexNum(tx.Nonce())
// v.BlockHash =
// v.BlockNumber =
// v.TxIndex =
from, _ := tx.From()
v.From = newHexData(from)
v.To = newHexData(tx.To())
v.Value = newHexNum(tx.Value())
v.Gas = newHexNum(tx.Gas())
v.GasPrice = newHexNum(tx.GasPrice())
v.Input = newHexData(tx.Data())
return v
}
type UncleRes struct {
BlockNumber *hexnum `json:"number"`
BlockHash *hexdata `json:"hash"`
ParentHash *hexdata `json:"parentHash"`
Nonce *hexdata `json:"nonce"`
Sha3Uncles *hexdata `json:"sha3Uncles"`
ReceiptHash *hexdata `json:"receiptHash"`
LogsBloom *hexdata `json:"logsBloom"`
TransactionRoot *hexdata `json:"transactionsRoot"`
StateRoot *hexdata `json:"stateRoot"`
Miner *hexdata `json:"miner"`
Difficulty *hexnum `json:"difficulty"`
ExtraData *hexdata `json:"extraData"`
GasLimit *hexnum `json:"gasLimit"`
GasUsed *hexnum `json:"gasUsed"`
UnixTimestamp *hexnum `json:"timestamp"`
}
func NewUncleRes(h *types.Header) *UncleRes {
if h == nil {
return nil
}
var v = new(UncleRes)
v.BlockNumber = newHexNum(h.Number)
v.BlockHash = newHexData(h.Hash())
v.ParentHash = newHexData(h.ParentHash)
v.Sha3Uncles = newHexData(h.UncleHash)
v.Nonce = newHexData(h.Nonce[:])
v.LogsBloom = newHexData(h.Bloom)
v.TransactionRoot = newHexData(h.TxHash)
v.StateRoot = newHexData(h.Root)
v.Miner = newHexData(h.Coinbase)
v.Difficulty = newHexNum(h.Difficulty)
v.ExtraData = newHexData(h.Extra)
v.GasLimit = newHexNum(h.GasLimit)
v.GasUsed = newHexNum(h.GasUsed)
v.UnixTimestamp = newHexNum(h.Time)
v.ReceiptHash = newHexData(h.ReceiptHash)
return v
}
// type FilterLogRes struct {
// Hash string `json:"hash"`
// Address string `json:"address"`
// Data string `json:"data"`
// BlockNumber string `json:"blockNumber"`
// TransactionHash string `json:"transactionHash"`
// BlockHash string `json:"blockHash"`
// TransactionIndex string `json:"transactionIndex"`
// LogIndex string `json:"logIndex"`
// }
// type FilterWhisperRes struct {
// Hash string `json:"hash"`
// From string `json:"from"`
// To string `json:"to"`
// Expiry string `json:"expiry"`
// Sent string `json:"sent"`
// Ttl string `json:"ttl"`
// Topics string `json:"topics"`
// Payload string `json:"payload"`
// WorkProved string `json:"workProved"`
// }
type LogRes struct {
Address *hexdata `json:"address"`
Topics []*hexdata `json:"topics"`
Data *hexdata `json:"data"`
BlockNumber *hexnum `json:"blockNumber"`
LogIndex *hexnum `json:"logIndex"`
BlockHash *hexdata `json:"blockHash"`
TransactionHash *hexdata `json:"transactionHash"`
TransactionIndex *hexnum `json:"transactionIndex"`
}
func NewLogRes(log *state.Log) LogRes {
var l LogRes
l.Topics = make([]*hexdata, len(log.Topics))
for j, topic := range log.Topics {
l.Topics[j] = newHexData(topic)
}
l.Address = newHexData(log.Address)
l.Data = newHexData(log.Data)
l.BlockNumber = newHexNum(log.Number)
l.LogIndex = newHexNum(log.Index)
l.TransactionHash = newHexData(log.TxHash)
l.TransactionIndex = newHexNum(log.TxIndex)
l.BlockHash = newHexData(log.BlockHash)
return l
}
func NewLogsRes(logs state.Logs) (ls []LogRes) {
ls = make([]LogRes, len(logs))
for i, log := range logs {
ls[i] = NewLogRes(log)
}
return
}
func NewHashesRes(hs []common.Hash) []string {
hashes := make([]string, len(hs))
for i, hash := range hs {
hashes[i] = hash.Hex()
}
return hashes
}

View File

@ -1,295 +0,0 @@
package rpc
import (
"encoding/json"
"fmt"
"math/big"
"regexp"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
)
const (
reHash = `"0x[0-9a-f]{64}"` // 32 bytes
reHashOpt = `"(0x[0-9a-f]{64})"|null` // 32 bytes or null
reAddress = `"0x[0-9a-f]{40}"` // 20 bytes
reAddressOpt = `"0x[0-9a-f]{40}"|null` // 20 bytes or null
reNum = `"0x([1-9a-f][0-9a-f]{0,15})|0"` // must not have left-padded zeros
reNumNonZero = `"0x([1-9a-f][0-9a-f]{0,15})"` // non-zero required must not have left-padded zeros
reNumOpt = `"0x([1-9a-f][0-9a-f]{0,15})|0"|null` // must not have left-padded zeros or null
reData = `"0x[0-9a-f]*"` // can be "empty"
// reListHash = `[("\w":"0x[0-9a-f]{64}",?)*]`
// reListObj = `[("\w":(".+"|null),?)*]`
)
func TestNewBlockRes(t *testing.T) {
tests := map[string]string{
"number": reNum,
"hash": reHash,
"parentHash": reHash,
"nonce": reData,
"sha3Uncles": reHash,
"logsBloom": reData,
"transactionsRoot": reHash,
"stateRoot": reHash,
"miner": reAddress,
"difficulty": `"0x1"`,
"totalDifficulty": reNum,
"size": reNumNonZero,
"extraData": reData,
"gasLimit": reNum,
// "minGasPrice": "0x",
"gasUsed": reNum,
"timestamp": reNum,
// "transactions": reListHash,
// "uncles": reListHash,
}
block := makeBlock()
v := NewBlockRes(block, false)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j))
}
}
}
func TestNewBlockResTxFull(t *testing.T) {
tests := map[string]string{
"number": reNum,
"hash": reHash,
"parentHash": reHash,
"nonce": reData,
"sha3Uncles": reHash,
"logsBloom": reData,
"transactionsRoot": reHash,
"stateRoot": reHash,
"miner": reAddress,
"difficulty": `"0x1"`,
"totalDifficulty": reNum,
"size": reNumNonZero,
"extraData": reData,
"gasLimit": reNum,
// "minGasPrice": "0x",
"gasUsed": reNum,
"timestamp": reNum,
// "transactions": reListHash,
// "uncles": reListHash,
}
block := makeBlock()
v := NewBlockRes(block, true)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j))
}
}
}
func TestBlockNil(t *testing.T) {
var block *types.Block
block = nil
u := NewBlockRes(block, false)
j, _ := json.Marshal(u)
if string(j) != "null" {
t.Errorf("Expected null but got %v", string(j))
}
}
func TestNewTransactionRes(t *testing.T) {
to := common.HexToAddress("0x02")
amount := big.NewInt(1)
gasAmount := big.NewInt(1)
gasPrice := big.NewInt(1)
data := []byte{1, 2, 3}
tx := types.NewTransactionMessage(to, amount, gasAmount, gasPrice, data)
tests := map[string]string{
"hash": reHash,
"nonce": reNum,
"blockHash": reHashOpt,
"blockNum": reNumOpt,
"transactionIndex": reNumOpt,
"from": reAddress,
"to": reAddressOpt,
"value": reNum,
"gas": reNum,
"gasPrice": reNum,
"input": reData,
}
v := NewTransactionRes(tx)
v.BlockHash = newHexData(common.HexToHash("0x030201"))
v.BlockNumber = newHexNum(5)
v.TxIndex = newHexNum(0)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("`%s` output json does not match format %s. Source %s", k, re, j))
}
}
}
func TestTransactionNil(t *testing.T) {
var tx *types.Transaction
tx = nil
u := NewTransactionRes(tx)
j, _ := json.Marshal(u)
if string(j) != "null" {
t.Errorf("Expected null but got %v", string(j))
}
}
func TestNewUncleRes(t *testing.T) {
header := makeHeader()
u := NewUncleRes(header)
tests := map[string]string{
"number": reNum,
"hash": reHash,
"parentHash": reHash,
"nonce": reData,
"sha3Uncles": reHash,
"receiptHash": reHash,
"transactionsRoot": reHash,
"stateRoot": reHash,
"miner": reAddress,
"difficulty": reNum,
"extraData": reData,
"gasLimit": reNum,
"gasUsed": reNum,
"timestamp": reNum,
}
j, _ := json.Marshal(u)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("`%s` output json does not match format %s. Source %s", k, re, j))
}
}
}
func TestUncleNil(t *testing.T) {
var header *types.Header
header = nil
u := NewUncleRes(header)
j, _ := json.Marshal(u)
if string(j) != "null" {
t.Errorf("Expected null but got %v", string(j))
}
}
func TestNewLogRes(t *testing.T) {
log := makeStateLog(0)
tests := map[string]string{
"address": reAddress,
// "topics": "[.*]"
"data": reData,
"blockNumber": reNum,
// "hash": reHash,
// "logIndex": reNum,
// "blockHash": reHash,
// "transactionHash": reHash,
"transactionIndex": reNum,
}
v := NewLogRes(log)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`{.*"%s":%s.*}`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("`%s` output json does not match format %s. Got %s", k, re, j))
}
}
}
func TestNewLogsRes(t *testing.T) {
logs := make([]*state.Log, 3)
logs[0] = makeStateLog(1)
logs[1] = makeStateLog(2)
logs[2] = makeStateLog(3)
tests := map[string]string{}
v := NewLogsRes(logs)
j, _ := json.Marshal(v)
for k, re := range tests {
match, _ := regexp.MatchString(fmt.Sprintf(`[{.*"%s":%s.*}]`, k, re), string(j))
if !match {
t.Error(fmt.Sprintf("%s output json does not match format %s. Got %s", k, re, j))
}
}
}
func makeStateLog(num int) *state.Log {
address := common.HexToAddress("0x0")
data := []byte{1, 2, 3}
number := uint64(num)
topics := make([]common.Hash, 3)
topics = append(topics, common.HexToHash("0x00"))
topics = append(topics, common.HexToHash("0x10"))
topics = append(topics, common.HexToHash("0x20"))
log := state.NewLog(address, topics, data, number)
return log
}
func makeHeader() *types.Header {
header := &types.Header{
ParentHash: common.StringToHash("0x00"),
UncleHash: common.StringToHash("0x00"),
Coinbase: common.StringToAddress("0x00"),
Root: common.StringToHash("0x00"),
TxHash: common.StringToHash("0x00"),
ReceiptHash: common.StringToHash("0x00"),
// Bloom:
Difficulty: big.NewInt(88888888),
Number: big.NewInt(16),
GasLimit: big.NewInt(70000),
GasUsed: big.NewInt(25000),
Time: 124356789,
Extra: nil,
MixDigest: common.StringToHash("0x00"),
Nonce: [8]byte{0, 1, 2, 3, 4, 5, 6, 7},
}
return header
}
func makeBlock() *types.Block {
parentHash := common.HexToHash("0x01")
coinbase := common.HexToAddress("0x01")
root := common.HexToHash("0x01")
difficulty := common.Big1
nonce := uint64(1)
block := types.NewBlock(parentHash, coinbase, root, difficulty, nonce, nil)
txto := common.HexToAddress("0x02")
txamount := big.NewInt(1)
txgasAmount := big.NewInt(1)
txgasPrice := big.NewInt(1)
txdata := []byte{1, 2, 3}
tx := types.NewTransactionMessage(txto, txamount, txgasAmount, txgasPrice, txdata)
txs := make([]*types.Transaction, 1)
txs[0] = tx
block.SetTransactions(txs)
uncles := make([]*types.Header, 1)
uncles[0] = makeHeader()
block.SetUncles(uncles)
return block
}

View File

@ -1,381 +0,0 @@
/*
This file is part of go-ethereum
go-ethereum is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
go-ethereum is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
package rpc
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"strings"
"errors"
"net"
"net/http"
"time"
"io"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
type hexdata struct {
data []byte
isNil bool
}
func (d *hexdata) String() string {
return "0x" + common.Bytes2Hex(d.data)
}
func (d *hexdata) MarshalJSON() ([]byte, error) {
if d.isNil {
return json.Marshal(nil)
}
return json.Marshal(d.String())
}
func newHexData(input interface{}) *hexdata {
d := new(hexdata)
if input == nil {
d.isNil = true
return d
}
switch input := input.(type) {
case []byte:
d.data = input
case common.Hash:
d.data = input.Bytes()
case *common.Hash:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case common.Address:
d.data = input.Bytes()
case *common.Address:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case types.Bloom:
d.data = input.Bytes()
case *types.Bloom:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case *big.Int:
if input == nil {
d.isNil = true
} else {
d.data = input.Bytes()
}
case int64:
d.data = big.NewInt(input).Bytes()
case uint64:
buff := make([]byte, 8)
binary.BigEndian.PutUint64(buff, input)
d.data = buff
case int:
d.data = big.NewInt(int64(input)).Bytes()
case uint:
d.data = big.NewInt(int64(input)).Bytes()
case int8:
d.data = big.NewInt(int64(input)).Bytes()
case uint8:
d.data = big.NewInt(int64(input)).Bytes()
case int16:
d.data = big.NewInt(int64(input)).Bytes()
case uint16:
buff := make([]byte, 2)
binary.BigEndian.PutUint16(buff, input)
d.data = buff
case int32:
d.data = big.NewInt(int64(input)).Bytes()
case uint32:
buff := make([]byte, 4)
binary.BigEndian.PutUint32(buff, input)
d.data = buff
case string: // hexstring
// aaargh ffs TODO: avoid back-and-forth hex encodings where unneeded
bytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
d.isNil = true
} else {
d.data = bytes
}
default:
d.isNil = true
}
return d
}
type hexnum struct {
data []byte
isNil bool
}
func (d *hexnum) String() string {
// Get hex string from bytes
out := common.Bytes2Hex(d.data)
// Trim leading 0s
out = strings.TrimLeft(out, "0")
// Output "0x0" when value is 0
if len(out) == 0 {
out = "0"
}
return "0x" + out
}
func (d *hexnum) MarshalJSON() ([]byte, error) {
if d.isNil {
return json.Marshal(nil)
}
return json.Marshal(d.String())
}
func newHexNum(input interface{}) *hexnum {
d := new(hexnum)
d.data = newHexData(input).data
return d
}
type RpcConfig struct {
ListenAddress string
ListenPort uint
CorsDomain string
}
type InvalidTypeError struct {
method string
msg string
}
func (e *InvalidTypeError) Error() string {
return fmt.Sprintf("invalid type on field %s: %s", e.method, e.msg)
}
func NewInvalidTypeError(method, msg string) *InvalidTypeError {
return &InvalidTypeError{
method: method,
msg: msg,
}
}
type InsufficientParamsError struct {
have int
want int
}
func (e *InsufficientParamsError) Error() string {
return fmt.Sprintf("insufficient params, want %d have %d", e.want, e.have)
}
func NewInsufficientParamsError(have int, want int) *InsufficientParamsError {
return &InsufficientParamsError{
have: have,
want: want,
}
}
type NotImplementedError struct {
Method string
}
func (e *NotImplementedError) Error() string {
return fmt.Sprintf("%s method not implemented", e.Method)
}
func NewNotImplementedError(method string) *NotImplementedError {
return &NotImplementedError{
Method: method,
}
}
type NotAvailableError struct {
Method string
Reason string
}
func (e *NotAvailableError) Error() string {
return fmt.Sprintf("%s method not available: %s", e.Method, e.Reason)
}
func NewNotAvailableError(method string, reason string) *NotAvailableError {
return &NotAvailableError{
Method: method,
Reason: reason,
}
}
type DecodeParamError struct {
err string
}
func (e *DecodeParamError) Error() string {
return fmt.Sprintf("could not decode, %s", e.err)
}
func NewDecodeParamError(errstr string) error {
return &DecodeParamError{
err: errstr,
}
}
type ValidationError struct {
ParamName string
msg string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s not valid, %s", e.ParamName, e.msg)
}
func NewValidationError(param string, msg string) error {
return &ValidationError{
ParamName: param,
msg: msg,
}
}
type RpcRequest struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Method string `json:"method"`
Params json.RawMessage `json:"params"`
}
type RpcSuccessResponse struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Result interface{} `json:"result"`
}
type RpcErrorResponse struct {
Id interface{} `json:"id"`
Jsonrpc string `json:"jsonrpc"`
Error *RpcErrorObject `json:"error"`
}
type RpcErrorObject struct {
Code int `json:"code"`
Message string `json:"message"`
// Data interface{} `json:"data"`
}
type listenerHasStoppedError struct {
msg string
}
func (self listenerHasStoppedError) Error() string {
return self.msg
}
var listenerStoppedError = listenerHasStoppedError{"Listener stopped"}
// When https://github.com/golang/go/issues/4674 is fixed this could be replaced
type stoppableTCPListener struct {
*net.TCPListener
stop chan struct{} // closed when the listener must stop
}
// Wraps the default handler and checks if the RPC service was stopped. In that case it returns an
// error indicating that the service was stopped. This will only happen for connections which are
// kept open (HTTP keep-alive) when the RPC service was shutdown.
func newStoppableHandler(h http.Handler, stop chan struct{}) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
case <-stop:
w.Header().Set("Content-Type", "application/json")
jsonerr := &RpcErrorObject{-32603, "RPC service stopped"}
send(w, &RpcErrorResponse{Jsonrpc: jsonrpcver, Id: nil, Error: jsonerr})
default:
h.ServeHTTP(w, r)
}
})
}
// Stop the listener and all accepted and still active connections.
func (self *stoppableTCPListener) Stop() {
close(self.stop)
}
func newStoppableTCPListener(addr string) (*stoppableTCPListener, error) {
wl, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
if tcpl, ok := wl.(*net.TCPListener); ok {
stop := make(chan struct{})
l := &stoppableTCPListener{tcpl, stop}
return l, nil
}
return nil, errors.New("Unable to create TCP listener for RPC service")
}
func (self *stoppableTCPListener) Accept() (net.Conn, error) {
for {
self.SetDeadline(time.Now().Add(time.Duration(1 * time.Second)))
c, err := self.TCPListener.AcceptTCP()
select {
case <-self.stop:
if c != nil { // accept timeout
c.Close()
}
self.TCPListener.Close()
return nil, listenerStoppedError
default:
}
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() && netErr.Temporary() {
continue // regular timeout
}
}
return &closableConnection{c, self.stop}, err
}
}
type closableConnection struct {
*net.TCPConn
closed chan struct{}
}
func (self *closableConnection) Read(b []byte) (n int, err error) {
select {
case <-self.closed:
self.TCPConn.Close()
return 0, io.EOF
default:
return self.TCPConn.Read(b)
}
}

View File

@ -1,204 +0,0 @@
package rpc
import (
"bytes"
"encoding/json"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
func TestInvalidTypeError(t *testing.T) {
err := NewInvalidTypeError("testField", "not string")
expected := "invalid type on field testField: not string"
if err.Error() != expected {
t.Error(err.Error())
}
}
func TestInsufficientParamsError(t *testing.T) {
err := NewInsufficientParamsError(0, 1)
expected := "insufficient params, want 1 have 0"
if err.Error() != expected {
t.Error(err.Error())
}
}
func TestNotImplementedError(t *testing.T) {
err := NewNotImplementedError("foo")
expected := "foo method not implemented"
if err.Error() != expected {
t.Error(err.Error())
}
}
func TestDecodeParamError(t *testing.T) {
err := NewDecodeParamError("foo")
expected := "could not decode, foo"
if err.Error() != expected {
t.Error(err.Error())
}
}
func TestValidationError(t *testing.T) {
err := NewValidationError("foo", "should be `bar`")
expected := "foo not valid, should be `bar`"
if err.Error() != expected {
t.Error(err.Error())
}
}
func TestHexdataMarshalNil(t *testing.T) {
hd := newHexData([]byte{})
hd.isNil = true
v, _ := json.Marshal(hd)
if string(v) != "null" {
t.Errorf("Expected null, got %s", v)
}
}
func TestHexnumMarshalNil(t *testing.T) {
hn := newHexNum([]byte{})
hn.isNil = true
v, _ := json.Marshal(hn)
if string(v) != "null" {
t.Errorf("Expected null, got %s", v)
}
}
func TestHexdataNil(t *testing.T) {
v := newHexData(nil)
if v.isNil != true {
t.Errorf("Expected isNil to be true, but is %v", v.isNil)
}
}
func TestHexdataPtrHash(t *testing.T) {
in := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}
v := newHexData(&in)
if bytes.Compare(in.Bytes(), v.data) != 0 {
t.Errorf("Got % x expected % x", in, v.data)
}
}
func TestHexdataPtrHashNil(t *testing.T) {
var in *common.Hash
in = nil
v := newHexData(in)
if !v.isNil {
t.Errorf("Expect isNil to be true, but is %v", v.isNil)
}
}
func TestHexdataPtrAddress(t *testing.T) {
in := common.Address{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
v := newHexData(&in)
if bytes.Compare(in.Bytes(), v.data) != 0 {
t.Errorf("Got % x expected % x", in, v.data)
}
}
func TestHexdataPtrAddressNil(t *testing.T) {
var in *common.Address
in = nil
v := newHexData(in)
if !v.isNil {
t.Errorf("Expect isNil to be true, but is %v", v.isNil)
}
}
func TestHexdataPtrBloom(t *testing.T) {
in := types.Bloom{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
v := newHexData(&in)
if bytes.Compare(in.Bytes(), v.data) != 0 {
t.Errorf("Got % x expected % x", in, v.data)
}
}
func TestHexdataPtrBloomNil(t *testing.T) {
var in *types.Bloom
in = nil
v := newHexData(in)
if !v.isNil {
t.Errorf("Expect isNil to be true, but is %v", v.isNil)
}
}
func TestHexdataBigintNil(t *testing.T) {
var in *big.Int
in = nil
v := newHexData(in)
if !v.isNil {
t.Errorf("Expect isNil to be true, but is %v", v.isNil)
}
}
func TestHexdataUint(t *testing.T) {
var in = uint(16)
var expected = []byte{0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}
func TestHexdataInt8(t *testing.T) {
var in = int8(16)
var expected = []byte{0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}
func TestHexdataUint8(t *testing.T) {
var in = uint8(16)
var expected = []byte{0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}
func TestHexdataInt16(t *testing.T) {
var in = int16(16)
var expected = []byte{0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}
func TestHexdataUint16(t *testing.T) {
var in = uint16(16)
var expected = []byte{0x0, 0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}
func TestHexdataInt32(t *testing.T) {
var in = int32(16)
var expected = []byte{0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}
func TestHexdataUint32(t *testing.T) {
var in = uint32(16)
var expected = []byte{0x0, 0x0, 0x0, 0x10}
v := newHexData(in)
if bytes.Compare(expected, v.data) != 0 {
t.Errorf("Expected % x got % x", expected, v.data)
}
}