From cc18136af85a1d72281ccc0f68dcfe69e1cd386a Mon Sep 17 00:00:00 2001 From: Jae Kwon Date: Tue, 7 Apr 2015 11:44:25 -0700 Subject: [PATCH] RPC refactor to separate core from core_client and the rest of RPC. Other random changes. --- .gitignore | 1 + Makefile | 6 +- cmd/gen_account.go | 20 - cmd/gen_tx.go | 115 --- cmd/gen_validator.go | 24 - cmd/main.go | 46 -- cmd/probe_upnp.go | 24 - daemon/log.go | 7 - {cmd => node}/log.go | 4 +- daemon/daemon.go => node/node.go | 7 +- process/process.go | 61 ++ rpc/core/accounts.go | 27 +- rpc/core/blocks.go | 9 +- rpc/core/mempool.go | 11 +- rpc/core/net.go | 9 +- rpc/core/routes.go | 25 + rpc/core/txs.go | 9 +- rpc/core/{ => types}/responses.go | 8 +- rpc/core/validators.go | 5 +- rpc/{ => core_client}/client.go | 10 +- rpc/core_client/client_methods.go | 769 ++++++++++++++++++ .../client_methods.go.bak} | 0 rpc/handlers.go | 107 +-- rpc/http_server.go | 25 +- rpc/test/http_rpc_test.go | 20 +- rpc/test/json_rpc_test.go | 26 +- rpc/test/test.go | 54 +- 27 files changed, 1015 insertions(+), 414 deletions(-) delete mode 100644 cmd/gen_account.go delete mode 100644 cmd/gen_tx.go delete mode 100644 cmd/gen_validator.go delete mode 100644 cmd/main.go delete mode 100644 cmd/probe_upnp.go delete mode 100644 daemon/log.go rename {cmd => node}/log.go (51%) rename daemon/daemon.go => node/node.go (97%) create mode 100644 process/process.go create mode 100644 rpc/core/routes.go rename rpc/core/{ => types}/responses.go (92%) rename rpc/{ => core_client}/client.go (93%) create mode 100644 rpc/core_client/client_methods.go rename rpc/{client_methods.go => core_client/client_methods.go.bak} (100%) diff --git a/.gitignore b/.gitignore index eba2cac3f..92dc5b771 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ *.swo .bak tendermint +debora .DS_Store rpc/test/.tendermint diff --git a/Makefile b/Makefile index 7531cbe04..e125146c2 100644 --- a/Makefile +++ b/Makefile @@ -3,10 +3,12 @@ all: build build: get_deps - go build -o tendermint github.com/tendermint/tendermint/cmd + go build -o tendermint github.com/tendermint/tendermint/cmd/tendermint + go build -o debora github.com/tendermint/tendermint/cmd/debora build_race: get_deps - go build -race -o tendermint github.com/tendermint/tendermint/cmd + go build -race -o tendermint github.com/tendermint/tendermint/cmd/tendermint + go build -race -o debora github.com/tendermint/tendermint/cmd/debora test: build go test github.com/tendermint/tendermint/... diff --git a/cmd/gen_account.go b/cmd/gen_account.go deleted file mode 100644 index aea29cf9d..000000000 --- a/cmd/gen_account.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/tendermint/tendermint/account" - "github.com/tendermint/tendermint/binary" -) - -func gen_account() { - privAccount := account.GenPrivAccount() - privAccountJSONBytes := binary.JSONBytes(privAccount) - fmt.Printf(`Generated a new account! - -%v - -`, - string(privAccountJSONBytes), - ) -} diff --git a/cmd/gen_tx.go b/cmd/gen_tx.go deleted file mode 100644 index 687339bed..000000000 --- a/cmd/gen_tx.go +++ /dev/null @@ -1,115 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "encoding/hex" - "fmt" - "os" - "strconv" - - "github.com/tendermint/tendermint/account" - "github.com/tendermint/tendermint/binary" - . "github.com/tendermint/tendermint/common" - dbm "github.com/tendermint/tendermint/db" - sm "github.com/tendermint/tendermint/state" - "github.com/tendermint/tendermint/types" -) - -func getString(prompt string) string { - reader := bufio.NewReader(os.Stdin) - fmt.Print(prompt) - input, _ := reader.ReadString('\n') - return input[:len(input)-1] -} - -func getByteSliceFromHex(prompt string) []byte { - input := getString(prompt) - bytes, err := hex.DecodeString(input) - if err != nil { - Exit(Fmt("Not in hex format: %v\nError: %v\n", input, err)) - } - return bytes -} - -func getUint64(prompt string) uint64 { - input := getString(prompt) - i, err := strconv.Atoi(input) - if err != nil { - Exit(Fmt("Not a valid uint64 amount: %v\nError: %v\n", input, err)) - } - return uint64(i) -} - -func gen_tx() { - - // Get State, which may be nil. - stateDB := dbm.GetDB("state") - state := sm.LoadState(stateDB) - - // Get source pubkey - srcPubKeyBytes := getByteSliceFromHex("Enter source pubkey: ") - r, n, err := bytes.NewReader(srcPubKeyBytes), new(int64), new(error) - srcPubKey := binary.ReadBinary(struct{ account.PubKey }{}, r, n, err).(struct{ account.PubKey }).PubKey - if *err != nil { - Exit(Fmt("Invalid PubKey. Error: %v", err)) - } - - // Get the state of the account. - var srcAccount *account.Account - var srcAccountAddress = srcPubKey.Address() - var srcAccountBalanceStr = "unknown" - var srcAccountSequenceStr = "unknown" - srcAddress := srcPubKey.Address() - if state != nil { - srcAccount = state.GetAccount(srcAddress) - srcAccountBalanceStr = Fmt("%v", srcAccount.Balance) - srcAccountSequenceStr = Fmt("%v", srcAccount.Sequence+1) - } - - // Get the amount to send from src account - srcSendAmount := getUint64(Fmt("Enter amount to send from %X (total: %v): ", srcAccountAddress, srcAccountBalanceStr)) - - // Get the next sequence of src account - srcSendSequence := uint(getUint64(Fmt("Enter next sequence for %X (guess: %v): ", srcAccountAddress, srcAccountSequenceStr))) - - // Get dest address - dstAddress := getByteSliceFromHex("Enter destination address: ") - - // Get the amount to send to dst account - dstSendAmount := getUint64(Fmt("Enter amount to send to %X: ", dstAddress)) - - // Construct SendTx - tx := &types.SendTx{ - Inputs: []*types.TxInput{ - &types.TxInput{ - Address: srcAddress, - Amount: srcSendAmount, - Sequence: srcSendSequence, - Signature: account.SignatureEd25519{}, - PubKey: srcPubKey, - }, - }, - Outputs: []*types.TxOutput{ - &types.TxOutput{ - Address: dstAddress, - Amount: dstSendAmount, - }, - }, - } - - // Show the intermediate form. - fmt.Printf("Generated tx: %X\n", binary.BinaryBytes(tx)) - - // Get source privkey (for signing) - srcPrivKeyBytes := getByteSliceFromHex("Enter source privkey (for signing): ") - r, n, err = bytes.NewReader(srcPrivKeyBytes), new(int64), new(error) - srcPrivKey := binary.ReadBinary(struct{ account.PrivKey }{}, r, n, err).(struct{ account.PrivKey }).PrivKey - if *err != nil { - Exit(Fmt("Invalid PrivKey. Error: %v", err)) - } - - // Sign - tx.Inputs[0].Signature = srcPrivKey.Sign(account.SignBytes(tx)) - fmt.Printf("Signed tx: %X\n", binary.BinaryBytes(tx)) -} diff --git a/cmd/gen_validator.go b/cmd/gen_validator.go deleted file mode 100644 index 1d3af701e..000000000 --- a/cmd/gen_validator.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/tendermint/tendermint/binary" - "github.com/tendermint/tendermint/config" - sm "github.com/tendermint/tendermint/state" -) - -func gen_validator() { - - privValidator := sm.GenPrivValidator() - privValidatorJSONBytes := binary.JSONBytes(privValidator) - fmt.Printf(`Generated a new validator! -Paste the following JSON into your %v file - -%v - -`, - config.App().GetString("PrivValidatorFile"), - string(privValidatorJSONBytes), - ) -} diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index e6b42ddf1..000000000 --- a/cmd/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/daemon" - "github.com/tendermint/tendermint/logger" -) - -func main() { - - args := os.Args[1:] - if len(args) == 0 { - fmt.Println(`Tendermint - -Commands: - daemon Run the tendermint node daemon - gen_account Generate new account keypair - gen_validator Generate new validator keypair - gen_tx Generate new transaction - probe_upnp Test UPnP functionality -`) - return - } - - switch args[0] { - case "daemon": - config.ParseFlags(args[1:]) - logger.Reset() - daemon.Daemon() - case "gen_account": - gen_account() - case "gen_validator": - gen_validator() - case "gen_tx": - config.ParseFlags(args[1:]) - logger.Reset() - gen_tx() - case "probe_upnp": - probe_upnp() - default: - fmt.Printf("Unknown command %v\n", args[0]) - } -} diff --git a/cmd/probe_upnp.go b/cmd/probe_upnp.go deleted file mode 100644 index 927e25484..000000000 --- a/cmd/probe_upnp.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - - "github.com/tendermint/tendermint/p2p/upnp" -) - -func probe_upnp() { - - capabilities, err := upnp.Probe() - if err != nil { - fmt.Println("Probe failed: %v", err) - } else { - fmt.Println("Probe success!") - jsonBytes, err := json.Marshal(capabilities) - if err != nil { - panic(err) - } - fmt.Println(string(jsonBytes)) - } - -} diff --git a/daemon/log.go b/daemon/log.go deleted file mode 100644 index b325cd802..000000000 --- a/daemon/log.go +++ /dev/null @@ -1,7 +0,0 @@ -package daemon - -import ( - "github.com/tendermint/tendermint/logger" -) - -var log = logger.New("module", "daemon") diff --git a/cmd/log.go b/node/log.go similarity index 51% rename from cmd/log.go rename to node/log.go index c04723782..65e5e78fe 100644 --- a/cmd/log.go +++ b/node/log.go @@ -1,7 +1,7 @@ -package main +package node import ( "github.com/tendermint/tendermint/logger" ) -var log = logger.New("module", "main") +var log = logger.New("module", "node") diff --git a/daemon/daemon.go b/node/node.go similarity index 97% rename from daemon/daemon.go rename to node/node.go index 419c3786f..f97842a4b 100644 --- a/daemon/daemon.go +++ b/node/node.go @@ -1,4 +1,4 @@ -package daemon +package node import ( "os" @@ -130,7 +130,8 @@ func (n *Node) StartRPC() { core.SetConsensusState(n.consensusState) core.SetMempoolReactor(n.mempoolReactor) core.SetSwitch(n.sw) - rpc.StartHTTPServer() + + rpc.StartHTTPServer(config.App().GetString("RPC.HTTP.ListenAddr"), core.Routes) } func (n *Node) Switch() *p2p.Switch { @@ -147,7 +148,7 @@ func (n *Node) MempoolReactor() *mempl.MempoolReactor { //------------------------------------------------------------------------------ -func Daemon() { +func RunNode() { // Create & start node n := NewNode() l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false) diff --git a/process/process.go b/process/process.go new file mode 100644 index 000000000..99dc64407 --- /dev/null +++ b/process/process.go @@ -0,0 +1,61 @@ +package process + +import ( + "fmt" + "io" + "os" + "os/exec" + "time" +) + +func makeFile(prefix string) *os.File { + now := time.Now() + filename := fmt.Sprintf("%v_%v.out", prefix, now.Format("2006_01_02_15_04_05_MST")) + f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + panic(err) + } + return f +} + +type Process struct { + Cmd *exec.Cmd + Output *os.File +} + +const ( + ProcessModeStd = iota + ProcessModeDaemon +) + +func CreateProcess(mode int, name string, args ...string) *Process { + out := makeFile(name) + cmd := exec.Command(name, args...) + switch mode { + case ProcessModeStd: + cmd.Stdout = io.MultiWriter(os.Stdout, out) + cmd.Stderr = io.MultiWriter(os.Stderr, out) + cmd.Stdin = nil + case ProcessModeDaemon: + cmd.Stdout = out + cmd.Stderr = out + cmd.Stdin = nil + } + if err := cmd.Start(); err != nil { + fmt.Printf("Failed to run command. %v\n", err) + return nil + } else { + fmt.Printf("Success!") + } + return &Process{ + Cmd: cmd, + Output: out, + } +} + +func Watch(proc *Process) { + exitErr := proc.Cmd.Wait() + if exitErr != nil { + fmt.Println("%v", exitErr) + } +} diff --git a/rpc/core/accounts.go b/rpc/core/accounts.go index 4234656b5..813bfd438 100644 --- a/rpc/core/accounts.go +++ b/rpc/core/accounts.go @@ -4,18 +4,19 @@ import ( "fmt" "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/common" + ctypes "github.com/tendermint/tendermint/rpc/core/types" ) -func GenPrivAccount() (*ResponseGenPrivAccount, error) { - return &ResponseGenPrivAccount{account.GenPrivAccount()}, nil +func GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error) { + return &ctypes.ResponseGenPrivAccount{account.GenPrivAccount()}, nil } -func GetAccount(address []byte) (*ResponseGetAccount, error) { +func GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) { cache := mempoolReactor.Mempool.GetCache() - return &ResponseGetAccount{cache.GetAccount(address)}, nil + return &ctypes.ResponseGetAccount{cache.GetAccount(address)}, nil } -func GetStorage(address, slot []byte) (*ResponseGetStorage, error) { +func GetStorage(address, slot []byte) (*ctypes.ResponseGetStorage, error) { state := consensusState.GetState() account := state.GetAccount(address) if account == nil { @@ -26,12 +27,12 @@ func GetStorage(address, slot []byte) (*ResponseGetStorage, error) { _, value := storage.Get(RightPadWord256(slot).Bytes()) if value == nil { - return &ResponseGetStorage{slot, nil}, nil + return &ctypes.ResponseGetStorage{slot, nil}, nil } - return &ResponseGetStorage{slot, value.([]byte)}, nil + return &ctypes.ResponseGetStorage{slot, value.([]byte)}, nil } -func ListAccounts() (*ResponseListAccounts, error) { +func ListAccounts() (*ctypes.ResponseListAccounts, error) { var blockHeight uint var accounts []*account.Account state := consensusState.GetState() @@ -40,10 +41,10 @@ func ListAccounts() (*ResponseListAccounts, error) { accounts = append(accounts, value.(*account.Account)) return false }) - return &ResponseListAccounts{blockHeight, accounts}, nil + return &ctypes.ResponseListAccounts{blockHeight, accounts}, nil } -func DumpStorage(addr []byte) (*ResponseDumpStorage, error) { +func DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) { state := consensusState.GetState() account := state.GetAccount(addr) if account == nil { @@ -51,11 +52,11 @@ func DumpStorage(addr []byte) (*ResponseDumpStorage, error) { } storageRoot := account.StorageRoot storage := state.LoadStorage(storageRoot) - storageItems := []StorageItem{} + storageItems := []ctypes.StorageItem{} storage.Iterate(func(key interface{}, value interface{}) bool { - storageItems = append(storageItems, StorageItem{ + storageItems = append(storageItems, ctypes.StorageItem{ key.([]byte), value.([]byte)}) return false }) - return &ResponseDumpStorage{storageRoot, storageItems}, nil + return &ctypes.ResponseDumpStorage{storageRoot, storageItems}, nil } diff --git a/rpc/core/blocks.go b/rpc/core/blocks.go index ee32cd2f4..4479e926c 100644 --- a/rpc/core/blocks.go +++ b/rpc/core/blocks.go @@ -3,12 +3,13 @@ package core import ( "fmt" . "github.com/tendermint/tendermint/common" + ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/types" ) //----------------------------------------------------------------------------- -func BlockchainInfo(minHeight, maxHeight uint) (*ResponseBlockchainInfo, error) { +func BlockchainInfo(minHeight, maxHeight uint) (*ctypes.ResponseBlockchainInfo, error) { if maxHeight == 0 { maxHeight = blockStore.Height() } else { @@ -25,12 +26,12 @@ func BlockchainInfo(minHeight, maxHeight uint) (*ResponseBlockchainInfo, error) blockMetas = append(blockMetas, blockMeta) } - return &ResponseBlockchainInfo{blockStore.Height(), blockMetas}, nil + return &ctypes.ResponseBlockchainInfo{blockStore.Height(), blockMetas}, nil } //----------------------------------------------------------------------------- -func GetBlock(height uint) (*ResponseGetBlock, error) { +func GetBlock(height uint) (*ctypes.ResponseGetBlock, error) { if height == 0 { return nil, fmt.Errorf("height must be greater than 0") } @@ -40,5 +41,5 @@ func GetBlock(height uint) (*ResponseGetBlock, error) { blockMeta := blockStore.LoadBlockMeta(height) block := blockStore.LoadBlock(height) - return &ResponseGetBlock{blockMeta, block}, nil + return &ctypes.ResponseGetBlock{blockMeta, block}, nil } diff --git a/rpc/core/mempool.go b/rpc/core/mempool.go index 62a2c1091..6f071e035 100644 --- a/rpc/core/mempool.go +++ b/rpc/core/mempool.go @@ -3,21 +3,16 @@ package core import ( "fmt" . "github.com/tendermint/tendermint/common" + ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" ) //----------------------------------------------------------------------------- -type Receipt struct { - TxHash []byte - CreatesContract uint8 - ContractAddr []byte -} - // pass pointer? // Note: tx must be signed -func BroadcastTx(tx types.Tx) (*ResponseBroadcastTx, error) { +func BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error) { err := mempoolReactor.BroadcastTx(tx) if err != nil { return nil, fmt.Errorf("Error broadcasting transaction: %v", err) @@ -33,7 +28,7 @@ func BroadcastTx(tx types.Tx) (*ResponseBroadcastTx, error) { contractAddr = state.NewContractAddress(callTx.Input.Address, uint64(callTx.Input.Sequence)) } } - return &ResponseBroadcastTx{Receipt{txHash, createsContract, contractAddr}}, nil + return &ctypes.ResponseBroadcastTx{ctypes.Receipt{txHash, createsContract, contractAddr}}, nil } /* diff --git a/rpc/core/net.go b/rpc/core/net.go index 84ec575a0..64a3c572d 100644 --- a/rpc/core/net.go +++ b/rpc/core/net.go @@ -3,13 +3,14 @@ package core import ( "github.com/tendermint/tendermint/config" dbm "github.com/tendermint/tendermint/db" + ctypes "github.com/tendermint/tendermint/rpc/core/types" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" ) //----------------------------------------------------------------------------- -func Status() (*ResponseStatus, error) { +func Status() (*ctypes.ResponseStatus, error) { db := dbm.NewMemDB() genesisState := sm.MakeGenesisStateFromFile(db, config.App().GetString("GenesisFile")) genesisHash := genesisState.Hash() @@ -25,12 +26,12 @@ func Status() (*ResponseStatus, error) { latestBlockTime = latestBlockMeta.Header.Time.UnixNano() } - return &ResponseStatus{genesisHash, config.App().GetString("Network"), latestBlockHash, latestHeight, latestBlockTime}, nil + return &ctypes.ResponseStatus{genesisHash, config.App().GetString("Network"), latestBlockHash, latestHeight, latestBlockTime}, nil } //----------------------------------------------------------------------------- -func NetInfo() (*ResponseNetInfo, error) { +func NetInfo() (*ctypes.ResponseNetInfo, error) { listening := p2pSwitch.IsListening() network := config.App().GetString("Network") listeners := []string{} @@ -41,7 +42,7 @@ func NetInfo() (*ResponseNetInfo, error) { for _, peer := range p2pSwitch.Peers().List() { peers = append(peers, peer.String()) } - return &ResponseNetInfo{ + return &ctypes.ResponseNetInfo{ Network: network, Listening: listening, Listeners: listeners, diff --git a/rpc/core/routes.go b/rpc/core/routes.go new file mode 100644 index 000000000..b9d7d211d --- /dev/null +++ b/rpc/core/routes.go @@ -0,0 +1,25 @@ +package core + +import ( + "github.com/tendermint/tendermint/rpc" +) + +/* +TODO: support Call && GetStorage. +*/ + +var Routes = map[string]*rpc.RPCFunc{ + "status": rpc.NewRPCFunc(Status, []string{}), + "net_info": rpc.NewRPCFunc(NetInfo, []string{}), + "blockchain": rpc.NewRPCFunc(BlockchainInfo, []string{"min_height", "max_height"}), + "get_block": rpc.NewRPCFunc(GetBlock, []string{"height"}), + "get_account": rpc.NewRPCFunc(GetAccount, []string{"address"}), + "get_storage": rpc.NewRPCFunc(GetStorage, []string{"address", "storage"}), + "call": rpc.NewRPCFunc(Call, []string{"address", "data"}), + "list_validators": rpc.NewRPCFunc(ListValidators, []string{}), + "dump_storage": rpc.NewRPCFunc(DumpStorage, []string{"address"}), + "broadcast_tx": rpc.NewRPCFunc(BroadcastTx, []string{"tx"}), + "list_accounts": rpc.NewRPCFunc(ListAccounts, []string{}), + "unsafe/gen_priv_account": rpc.NewRPCFunc(GenPrivAccount, []string{}), + "unsafe/sign_tx": rpc.NewRPCFunc(SignTx, []string{"tx", "privAccounts"}), +} diff --git a/rpc/core/txs.go b/rpc/core/txs.go index 655c06695..2b4999f94 100644 --- a/rpc/core/txs.go +++ b/rpc/core/txs.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/tendermint/tendermint/account" . "github.com/tendermint/tendermint/common" + ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/vm" @@ -24,7 +25,7 @@ func toVMAccount(acc *account.Account) *vm.Account { // Run a contract's code on an isolated and unpersisted state // Cannot be used to create new contracts -func Call(address, data []byte) (*ResponseCall, error) { +func Call(address, data []byte) (*ctypes.ResponseCall, error) { st := consensusState.GetState() // performs a copy cache := mempoolReactor.Mempool.GetCache() @@ -48,12 +49,12 @@ func Call(address, data []byte) (*ResponseCall, error) { if err != nil { return nil, err } - return &ResponseCall{Return: ret}, nil + return &ctypes.ResponseCall{Return: ret}, nil } //----------------------------------------------------------------------------- -func SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ResponseSignTx, error) { +func SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ctypes.ResponseSignTx, error) { // more checks? for i, privAccount := range privAccounts { @@ -85,5 +86,5 @@ func SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ResponseSignTx, rebondTx := tx.(*types.RebondTx) rebondTx.Signature = privAccounts[0].Sign(rebondTx).(account.SignatureEd25519) } - return &ResponseSignTx{tx}, nil + return &ctypes.ResponseSignTx{tx}, nil } diff --git a/rpc/core/responses.go b/rpc/core/types/responses.go similarity index 92% rename from rpc/core/responses.go rename to rpc/core/types/responses.go index a9f128fb0..50a3ea549 100644 --- a/rpc/core/responses.go +++ b/rpc/core/types/responses.go @@ -1,4 +1,4 @@ -package core +package core_types import ( "github.com/tendermint/tendermint/account" @@ -55,6 +55,12 @@ type ResponseBroadcastTx struct { Receipt Receipt } +type Receipt struct { + TxHash []byte + CreatesContract uint8 + ContractAddr []byte +} + type ResponseStatus struct { GenesisHash []byte Network string diff --git a/rpc/core/validators.go b/rpc/core/validators.go index 5d156156d..fd8f2d736 100644 --- a/rpc/core/validators.go +++ b/rpc/core/validators.go @@ -1,12 +1,13 @@ package core import ( + ctypes "github.com/tendermint/tendermint/rpc/core/types" sm "github.com/tendermint/tendermint/state" ) //----------------------------------------------------------------------------- -func ListValidators() (*ResponseListValidators, error) { +func ListValidators() (*ctypes.ResponseListValidators, error) { var blockHeight uint var bondedValidators []*sm.Validator var unbondingValidators []*sm.Validator @@ -22,5 +23,5 @@ func ListValidators() (*ResponseListValidators, error) { return false }) - return &ResponseListValidators{blockHeight, bondedValidators, unbondingValidators}, nil + return &ctypes.ResponseListValidators{blockHeight, bondedValidators, unbondingValidators}, nil } diff --git a/rpc/client.go b/rpc/core_client/client.go similarity index 93% rename from rpc/client.go rename to rpc/core_client/client.go index 19b32a9b7..b7ec03782 100644 --- a/rpc/client.go +++ b/rpc/core_client/client.go @@ -1,9 +1,10 @@ -package rpc +package core_client import ( "bytes" "fmt" "github.com/tendermint/tendermint/binary" + "github.com/tendermint/tendermint/rpc" "io/ioutil" "net/http" "net/url" @@ -18,7 +19,7 @@ type Response struct { Error string } -//go:generate go-rpc-gen -interface Client -pkg core -type *ClientHTTP,*ClientJSON -exclude pipe.go -out-pkg rpc +//go:generate go-rpc-gen -interface Client -dir ../core -pkg core -type *ClientHTTP,*ClientJSON -exclude pipe.go -out-pkg core_client type ClientJSON struct { addr string @@ -99,7 +100,7 @@ func (c *ClientHTTP) RequestResponse(method string, values url.Values) (*Respons return response, nil } -func (c *ClientJSON) RequestResponse(s RPCRequest) (b []byte, err error) { +func (c *ClientJSON) RequestResponse(s rpc.RPCRequest) (b []byte, err error) { b = binary.JSONBytes(s) buf := bytes.NewBuffer(b) resp, err := http.Post(c.addr, "text/json", buf) @@ -165,6 +166,7 @@ func argsToURLValues(argNames []string, args ...interface{}) (url.Values, error) /*rpc-gen:imports: github.com/tendermint/tendermint/binary +github.com/tendermint/tendermint/rpc net/http io/ioutil fmt @@ -173,7 +175,7 @@ fmt // Template functions to be filled in /*rpc-gen:template:*ClientJSON func (c *ClientJSON) {{name}}({{args.def}}) ({{response}}) { - request := RPCRequest{ + request := rpc.RPCRequest{ JSONRPC: "2.0", Method: {{lowername}}, Params: []interface{}{ {{args.ident}} }, diff --git a/rpc/core_client/client_methods.go b/rpc/core_client/client_methods.go new file mode 100644 index 000000000..921083a10 --- /dev/null +++ b/rpc/core_client/client_methods.go @@ -0,0 +1,769 @@ +package core_client + +import ( + "fmt" + "github.com/tendermint/tendermint/account" + "github.com/tendermint/tendermint/binary" + "github.com/tendermint/tendermint/rpc" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + "github.com/tendermint/tendermint/types" + "io/ioutil" + "net/http" +) + +type Client interface { + BlockchainInfo(minHeight uint) (*ctypes.ResponseBlockchainInfo, error) + BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error) + Call(address []byte) (*ctypes.ResponseCall, error) + DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) + GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error) + GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) + GetBlock(height uint) (*ctypes.ResponseGetBlock, error) + GetStorage(address []byte) (*ctypes.ResponseGetStorage, error) + ListAccounts() (*ctypes.ResponseListAccounts, error) + ListValidators() (*ctypes.ResponseListValidators, error) + NetInfo() (*ctypes.ResponseNetInfo, error) + SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ctypes.ResponseSignTx, error) + Status() (*ctypes.ResponseStatus, error) +} + +func (c *ClientHTTP) BlockchainInfo(minHeight uint) (*ctypes.ResponseBlockchainInfo, error) { + values, err := argsToURLValues([]string{"minHeight"}, minHeight) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"blockchain_info", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseBlockchainInfo `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error) { + values, err := argsToURLValues([]string{"tx"}, tx) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"broadcast_tx", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseBroadcastTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) Call(address []byte) (*ctypes.ResponseCall, error) { + values, err := argsToURLValues([]string{"address"}, address) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"call", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseCall `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) { + values, err := argsToURLValues([]string{"addr"}, addr) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"dump_storage", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseDumpStorage `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error) { + values, err := argsToURLValues(nil, nil) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"gen_priv_account", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGenPrivAccount `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) { + values, err := argsToURLValues([]string{"address"}, address) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"get_account", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGetAccount `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) GetBlock(height uint) (*ctypes.ResponseGetBlock, error) { + values, err := argsToURLValues([]string{"height"}, height) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"get_block", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGetBlock `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) GetStorage(address []byte) (*ctypes.ResponseGetStorage, error) { + values, err := argsToURLValues([]string{"address"}, address) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"get_storage", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGetStorage `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) ListAccounts() (*ctypes.ResponseListAccounts, error) { + values, err := argsToURLValues(nil, nil) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"list_accounts", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseListAccounts `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) ListValidators() (*ctypes.ResponseListValidators, error) { + values, err := argsToURLValues(nil, nil) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"list_validators", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseListValidators `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) NetInfo() (*ctypes.ResponseNetInfo, error) { + values, err := argsToURLValues(nil, nil) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"net_info", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseNetInfo `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ctypes.ResponseSignTx, error) { + values, err := argsToURLValues([]string{"tx", "privAccounts"}, tx, privAccounts) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"sign_tx", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseSignTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientHTTP) Status() (*ctypes.ResponseStatus, error) { + values, err := argsToURLValues(nil, nil) + if err != nil { + return nil, err + } + resp, err := http.PostForm(c.addr+"status", values) + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseStatus `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) BlockchainInfo(minHeight uint) (*ctypes.ResponseBlockchainInfo, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "blockchain_info", + Params: []interface{}{minHeight}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseBlockchainInfo `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) BroadcastTx(tx types.Tx) (*ctypes.ResponseBroadcastTx, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "broadcast_tx", + Params: []interface{}{tx}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseBroadcastTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) Call(address []byte) (*ctypes.ResponseCall, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "call", + Params: []interface{}{address}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseCall `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) DumpStorage(addr []byte) (*ctypes.ResponseDumpStorage, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "dump_storage", + Params: []interface{}{addr}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseDumpStorage `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) GenPrivAccount() (*ctypes.ResponseGenPrivAccount, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "gen_priv_account", + Params: []interface{}{nil}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGenPrivAccount `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) GetAccount(address []byte) (*ctypes.ResponseGetAccount, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "get_account", + Params: []interface{}{address}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGetAccount `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) GetBlock(height uint) (*ctypes.ResponseGetBlock, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "get_block", + Params: []interface{}{height}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGetBlock `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) GetStorage(address []byte) (*ctypes.ResponseGetStorage, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "get_storage", + Params: []interface{}{address}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseGetStorage `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) ListAccounts() (*ctypes.ResponseListAccounts, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "list_accounts", + Params: []interface{}{nil}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseListAccounts `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) ListValidators() (*ctypes.ResponseListValidators, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "list_validators", + Params: []interface{}{nil}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseListValidators `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) NetInfo() (*ctypes.ResponseNetInfo, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "net_info", + Params: []interface{}{nil}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseNetInfo `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ctypes.ResponseSignTx, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "sign_tx", + Params: []interface{}{tx, privAccounts}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseSignTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} + +func (c *ClientJSON) Status() (*ctypes.ResponseStatus, error) { + request := rpc.RPCRequest{ + JSONRPC: "2.0", + Method: "status", + Params: []interface{}{nil}, + Id: 0, + } + body, err := c.RequestResponse(request) + if err != nil { + return nil, err + } + var response struct { + Result *ctypes.ResponseStatus `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` + } + binary.ReadJSON(&response, body, &err) + if err != nil { + return nil, err + } + if response.Error != "" { + return nil, fmt.Errorf(response.Error) + } + return response.Result, nil +} diff --git a/rpc/client_methods.go b/rpc/core_client/client_methods.go.bak similarity index 100% rename from rpc/client_methods.go rename to rpc/core_client/client_methods.go.bak diff --git a/rpc/handlers.go b/rpc/handlers.go index 69ead12c0..a13ab98b8 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -1,59 +1,34 @@ package rpc -/* -TODO: support Call && GetStorage. -*/ - import ( "encoding/json" "fmt" "github.com/tendermint/tendermint/binary" - "github.com/tendermint/tendermint/rpc/core" "io/ioutil" "net/http" "reflect" ) -// cache all type information about each function up front -// (func, responseStruct, argNames) -var funcMap = map[string]*FuncWrapper{ - "status": funcWrap(core.Status, []string{}), - "net_info": funcWrap(core.NetInfo, []string{}), - "blockchain": funcWrap(core.BlockchainInfo, []string{"min_height", "max_height"}), - "get_block": funcWrap(core.GetBlock, []string{"height"}), - "get_account": funcWrap(core.GetAccount, []string{"address"}), - "get_storage": funcWrap(core.GetStorage, []string{"address", "storage"}), - "call": funcWrap(core.Call, []string{"address", "data"}), - "list_validators": funcWrap(core.ListValidators, []string{}), - "dump_storage": funcWrap(core.DumpStorage, []string{"address"}), - "broadcast_tx": funcWrap(core.BroadcastTx, []string{"tx"}), - "list_accounts": funcWrap(core.ListAccounts, []string{}), - "unsafe/gen_priv_account": funcWrap(core.GenPrivAccount, []string{}), - "unsafe/sign_tx": funcWrap(core.SignTx, []string{"tx", "privAccounts"}), -} - -func initHandlers() { +func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) { // HTTP endpoints - for funcName, funcInfo := range funcMap { - http.HandleFunc("/"+funcName, toHTTPHandler(funcInfo)) + for funcName, rpcFunc := range funcMap { + mux.HandleFunc("/"+funcName, makeHTTPHandler(rpcFunc)) } // JSONRPC endpoints - http.HandleFunc("/", JSONRPCHandler) + mux.HandleFunc("/", makeJSONRPCHandler(funcMap)) } -//------------------------------------- - // holds all type information for each function -type FuncWrapper struct { - f reflect.Value // function from "rpc/core" +type RPCFunc struct { + f reflect.Value // underlying rpc function args []reflect.Type // type of each function arg returns []reflect.Type // type of each return arg argNames []string // name of each argument } -func funcWrap(f interface{}, args []string) *FuncWrapper { - return &FuncWrapper{ +func NewRPCFunc(f interface{}, args []string) *RPCFunc { + return &RPCFunc{ f: reflect.ValueOf(f), args: funcArgTypes(f), returns: funcReturnTypes(f), @@ -85,39 +60,41 @@ func funcReturnTypes(f interface{}) []reflect.Type { // rpc.json // jsonrpc calls grab the given method's function info and runs reflect.Call -func JSONRPCHandler(w http.ResponseWriter, r *http.Request) { - b, _ := ioutil.ReadAll(r.Body) - var request RPCRequest - err := json.Unmarshal(b, &request) - if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) - return - } +func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + b, _ := ioutil.ReadAll(r.Body) + var request RPCRequest + err := json.Unmarshal(b, &request) + if err != nil { + WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + return + } - funcInfo := funcMap[request.Method] - if funcInfo == nil { - WriteRPCResponse(w, NewRPCResponse(nil, "RPC method unknown: "+request.Method)) - return - } - args, err := jsonParamsToArgs(funcInfo, request.Params) - if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) - return - } - returns := funcInfo.f.Call(args) - response, err := unreflectResponse(returns) - if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) - return + rpcFunc := funcMap[request.Method] + if rpcFunc == nil { + WriteRPCResponse(w, NewRPCResponse(nil, "RPC method unknown: "+request.Method)) + return + } + args, err := jsonParamsToArgs(rpcFunc, request.Params) + if err != nil { + WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + return + } + returns := rpcFunc.f.Call(args) + response, err := unreflectResponse(returns) + if err != nil { + WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + return + } + WriteRPCResponse(w, NewRPCResponse(response, "")) } - WriteRPCResponse(w, NewRPCResponse(response, "")) } // covert a list of interfaces to properly typed values -func jsonParamsToArgs(funcInfo *FuncWrapper, params []interface{}) ([]reflect.Value, error) { +func jsonParamsToArgs(rpcFunc *RPCFunc, params []interface{}) ([]reflect.Value, error) { values := make([]reflect.Value, len(params)) for i, p := range params { - ty := funcInfo.args[i] + ty := rpcFunc.args[i] v, err := _jsonObjectToArg(ty, p) if err != nil { return nil, err @@ -143,14 +120,14 @@ func _jsonObjectToArg(ty reflect.Type, object interface{}) (reflect.Value, error // rpc.http // convert from a function name to the http handler -func toHTTPHandler(funcInfo *FuncWrapper) func(http.ResponseWriter, *http.Request) { +func makeHTTPHandler(rpcFunc *RPCFunc) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - args, err := httpParamsToArgs(funcInfo, r) + args, err := httpParamsToArgs(rpcFunc, r) if err != nil { WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) return } - returns := funcInfo.f.Call(args) + returns := rpcFunc.f.Call(args) response, err := unreflectResponse(returns) if err != nil { WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) @@ -162,9 +139,9 @@ func toHTTPHandler(funcInfo *FuncWrapper) func(http.ResponseWriter, *http.Reques // Covert an http query to a list of properly typed values. // To be properly decoded the arg must be a concrete type from tendermint (if its an interface). -func httpParamsToArgs(funcInfo *FuncWrapper, r *http.Request) ([]reflect.Value, error) { - argTypes := funcInfo.args - argNames := funcInfo.argNames +func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error) { + argTypes := rpcFunc.args + argNames := rpcFunc.argNames var err error values := make([]reflect.Value, len(argNames)) diff --git a/rpc/http_server.go b/rpc/http_server.go index 47770f3d8..1aa5888a8 100644 --- a/rpc/http_server.go +++ b/rpc/http_server.go @@ -8,18 +8,20 @@ import ( "runtime/debug" "time" - "github.com/tendermint/tendermint/alert" "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/common" - "github.com/tendermint/tendermint/config" ) -func StartHTTPServer() { - initHandlers() - - log.Info(Fmt("Starting RPC HTTP server on %s", config.App().GetString("RPC.HTTP.ListenAddr"))) +func StartHTTPServer(listenAddr string, funcMap map[string]*RPCFunc) { + log.Info(Fmt("Starting RPC HTTP server on %s", listenAddr)) + mux := http.NewServeMux() + RegisterRPCFuncs(mux, funcMap) go func() { - log.Crit("RPC HTTPServer stopped", "result", http.ListenAndServe(config.App().GetString("RPC.HTTP.ListenAddr"), RecoverAndLogHandler(http.DefaultServeMux))) + res := http.ListenAndServe( + listenAddr, + RecoverAndLogHandler(mux), + ) + log.Crit("RPC HTTPServer stopped", "result", res) }() } @@ -97,12 +99,3 @@ func (w *ResponseWriterWrapper) WriteHeader(status int) { w.Status = status w.ResponseWriter.WriteHeader(status) } - -// Stick it as a deferred statement in gouroutines to prevent the program from crashing. -func Recover(daemonName string) { - if e := recover(); e != nil { - stack := string(debug.Stack()) - errorString := fmt.Sprintf("[%s] %s\n%s", daemonName, e, stack) - alert.Alert(errorString) - } -} diff --git a/rpc/test/http_rpc_test.go b/rpc/test/http_rpc_test.go index c49683eb2..3eb057e48 100644 --- a/rpc/test/http_rpc_test.go +++ b/rpc/test/http_rpc_test.go @@ -7,7 +7,7 @@ import ( "github.com/tendermint/tendermint/binary" . "github.com/tendermint/tendermint/common" "github.com/tendermint/tendermint/merkle" - "github.com/tendermint/tendermint/rpc/core" + ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" "io/ioutil" @@ -27,10 +27,10 @@ func TestHTTPStatus(t *testing.T) { t.Fatal(err) } var response struct { - Result core.ResponseStatus `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseStatus `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } binary.ReadJSON(&response, body, &err) if err != nil { @@ -55,10 +55,10 @@ func TestHTTPGenPriv(t *testing.T) { t.Fatal(err) } var response struct { - Result core.ResponseGenPrivAccount `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseGenPrivAccount `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } binary.ReadJSON(&response, body, &err) if err != nil { @@ -130,7 +130,7 @@ func TestHTTPBroadcastTx(t *testing.T) { func TestHTTPGetStorage(t *testing.T) { priv := state.LoadPrivValidator(".tendermint/priv_validator.json") _ = priv - //core.SetPrivValidator(priv) + //ctypes.SetPrivValidator(priv) byteAddr, _ := hex.DecodeString(userAddr) var byteKey [64]byte diff --git a/rpc/test/json_rpc_test.go b/rpc/test/json_rpc_test.go index 8500bc21d..5b8221ade 100644 --- a/rpc/test/json_rpc_test.go +++ b/rpc/test/json_rpc_test.go @@ -9,7 +9,7 @@ import ( . "github.com/tendermint/tendermint/common" "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/rpc" - "github.com/tendermint/tendermint/rpc/core" + ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/types" "io/ioutil" "net/http" @@ -40,10 +40,10 @@ func TestJSONStatus(t *testing.T) { } var response struct { - Result core.ResponseStatus `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseStatus `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } binary.ReadJSON(&response, body, &err) if err != nil { @@ -80,10 +80,10 @@ func TestJSONGenPriv(t *testing.T) { t.Fatal(err) } var response struct { - Result core.ResponseGenPrivAccount `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseGenPrivAccount `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } binary.ReadJSON(&response, body, &err) if err != nil { @@ -143,10 +143,10 @@ func TestJSONBroadcastTx(t *testing.T) { b := w.Bytes() var response struct { - Result core.ResponseBroadcastTx `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseBroadcastTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } requestResponse(t, "broadcast_tx", url.Values{"tx": {string(b)}}, &response) if response.Error != "" { diff --git a/rpc/test/test.go b/rpc/test/test.go index 0b31525da..ab776cf0b 100644 --- a/rpc/test/test.go +++ b/rpc/test/test.go @@ -6,11 +6,11 @@ import ( "github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/config" - "github.com/tendermint/tendermint/daemon" "github.com/tendermint/tendermint/logger" + nm "github.com/tendermint/tendermint/node" "github.com/tendermint/tendermint/p2p" - "github.com/tendermint/tendermint/rpc" - "github.com/tendermint/tendermint/rpc/core" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + cclient "github.com/tendermint/tendermint/rpc/core_client" "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" "io/ioutil" @@ -23,7 +23,7 @@ var ( rpcAddr = "127.0.0.1:8089" requestAddr = "http://" + rpcAddr + "/" - node *daemon.Node + node *nm.Node mempoolCount = 0 @@ -42,7 +42,7 @@ func decodeHex(hexStr string) []byte { func newNode(ready chan struct{}) { // Create & start node - node = daemon.NewNode() + node = nm.NewNode() l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false) node.AddListener(l) node.Start() @@ -85,12 +85,12 @@ func init() { } func getAccount(t *testing.T, typ string, addr []byte) *account.Account { - var client rpc.Client + var client cclient.Client switch typ { case "JSONRPC": - client = rpc.NewClient(requestAddr, "JSONRPC") + client = cclient.NewClient(requestAddr, "JSONRPC") case "HTTP": - client = rpc.NewClient(requestAddr, "HTTP") + client = cclient.NewClient(requestAddr, "HTTP") } ac, err := client.GetAccount(addr) if err != nil { @@ -130,7 +130,7 @@ func getAccount(t *testing.T, typ string, addr []byte) *account.Account { t.Fatal(err) } var response struct { - Result core.ResponseGetAccount `json:"result"` + Result ctypes.ResponseGetAccount `json:"result"` Error string `json:"error"` Id string `json:"id"` JSONRPC string `json:"jsonrpc"` @@ -242,10 +242,10 @@ func signTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byt } var response struct { - Result core.ResponseSignTx `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseSignTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } requestResponse(t, "unsafe/sign_tx", url.Values{"tx": {string(b)}, "privAccounts": {string(w.Bytes())}}, &response) if response.Error != "" { @@ -255,7 +255,7 @@ func signTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byt return result.Tx, privAcc } -func broadcastTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byte, amt, gaslim, fee uint64) (types.Tx, core.Receipt) { +func broadcastTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byte, amt, gaslim, fee uint64) (types.Tx, ctypes.Receipt) { tx, _ := signTx(t, typ, fromAddr, toAddr, data, key, amt, gaslim, fee) n, w := new(int64), new(bytes.Buffer) @@ -267,10 +267,10 @@ func broadcastTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [6 b := w.Bytes() var response struct { - Result core.ResponseBroadcastTx `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseBroadcastTx `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } requestResponse(t, "broadcast_tx", url.Values{"tx": {string(b)}}, &response) if response.Error != "" { @@ -279,13 +279,13 @@ func broadcastTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [6 return tx, response.Result.Receipt } -func dumpStorage(t *testing.T, addr []byte) core.ResponseDumpStorage { +func dumpStorage(t *testing.T, addr []byte) ctypes.ResponseDumpStorage { addrString := "\"" + hex.EncodeToString(addr) + "\"" var response struct { - Result core.ResponseDumpStorage `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseDumpStorage `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } requestResponse(t, "dump_storage", url.Values{"address": {addrString}}, &response) if response.Error != "" { @@ -298,10 +298,10 @@ func getStorage(t *testing.T, addr, slot []byte) []byte { addrString := "\"" + hex.EncodeToString(addr) + "\"" slotString := "\"" + hex.EncodeToString(slot) + "\"" var response struct { - Result core.ResponseGetStorage `json:"result"` - Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` + Result ctypes.ResponseGetStorage `json:"result"` + Error string `json:"error"` + Id string `json:"id"` + JSONRPC string `json:"jsonrpc"` } requestResponse(t, "get_storage", url.Values{"address": {addrString}, "storage": {slotString}}, &response) if response.Error != "" {