diff --git a/client/client.go b/client/client.go index b5f66c69a3e3928360db09e4a6855f55c7ae9367..16588f53d2b2991025d34cc8ba06e14438aed858 100644 --- a/client/client.go +++ b/client/client.go @@ -80,16 +80,17 @@ func (erisNodeClient *ErisNodeClient) Broadcast(tx txs.Tx) (*txs.Receipt, error) // Status returns the ChainId (GenesisHash), validator's PublicKey, latest block hash // the block height and the latest block time. -func (erisNodeClient *ErisNodeClient) Status() (ChainId []byte, ValidatorPublicKey []byte, LatestBlockHash []byte, LatestBlockHeight int, LatestBlockTime int64, err error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) +func (erisNodeClient *ErisNodeClient) Status() (GenesisHash []byte, ValidatorPublicKey []byte, LatestBlockHash []byte, LatestBlockHeight int, LatestBlockTime int64, err error) { + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) res, err := tendermint_client.Status(client) if err != nil { err = fmt.Errorf("Error connecting to node (%s) to get status: %s", erisNodeClient.broadcastRPC, err.Error()) return nil, nil, nil, int(0), int64(0), err } + // unwrap return results - ChainId = res.GenesisHash + GenesisHash = res.GenesisHash ValidatorPublicKey = res.PubKey.Bytes() LatestBlockHash = res.LatestBlockHash LatestBlockHeight = res.LatestBlockHeight @@ -97,10 +98,26 @@ func (erisNodeClient *ErisNodeClient) Status() (ChainId []byte, ValidatorPublicK return } +func (erisNodeClient *ErisNodeClient) ChainId() (ChainName, ChainId string, GenesisHash []byte, err error) { + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) + chainIdResult, err := tendermint_client.ChainId(client) + if err != nil { + err = fmt.Errorf("Error connecting to node (%s) to get chain id: %s", + erisNodeClient.broadcastRPC, err.Error()) + return "", "", nil, err + } + // unwrap results + ChainName = chainIdResult.ChainName + ChainId = chainIdResult.ChainId + GenesisHash = make([]byte, len(chainIdResult.GenesisHash)) + copy(GenesisHash[:], chainIdResult.GenesisHash) + return +} + // QueryContract executes the contract code at address with the given data // NOTE: there is no check on the caller; func (erisNodeClient *ErisNodeClient) QueryContract(callerAddress, calleeAddress, data []byte) (ret []byte, gasUsed int64, err error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) callResult, err := tendermint_client.Call(client, callerAddress, calleeAddress, data) if err != nil { err = fmt.Errorf("Error connnecting to node (%s) to query contract at (%X) with data (%X)", @@ -112,7 +129,7 @@ func (erisNodeClient *ErisNodeClient) QueryContract(callerAddress, calleeAddress // QueryContractCode executes the contract code at address with the given data but with provided code func (erisNodeClient *ErisNodeClient) QueryContractCode(address, code, data []byte) (ret []byte, gasUsed int64, err error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) // TODO: [ben] Call and CallCode have an inconsistent signature; it makes sense for both to only // have a single address that is the contract to query. callResult, err := tendermint_client.CallCode(client, address, code, data) @@ -126,7 +143,7 @@ func (erisNodeClient *ErisNodeClient) QueryContractCode(address, code, data []by // GetAccount returns a copy of the account func (erisNodeClient *ErisNodeClient) GetAccount(address []byte) (*acc.Account, error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) account, err := tendermint_client.GetAccount(client, address) if err != nil { err = fmt.Errorf("Error connecting to node (%s) to fetch account (%X): %s", @@ -143,7 +160,7 @@ func (erisNodeClient *ErisNodeClient) GetAccount(address []byte) (*acc.Account, // DumpStorage returns the full storage for an account. func (erisNodeClient *ErisNodeClient) DumpStorage(address []byte) (storage *core_types.Storage, err error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) resultStorage, err := tendermint_client.DumpStorage(client, address) if err != nil { err = fmt.Errorf("Error connecting to node (%s) to get storage for account (%X): %s", @@ -161,7 +178,7 @@ func (erisNodeClient *ErisNodeClient) DumpStorage(address []byte) (storage *core // Name registry func (erisNodeClient *ErisNodeClient) GetName(name string) (owner []byte, data string, expirationBlock int, err error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) entryResult, err := tendermint_client.GetName(client, name) if err != nil { err = fmt.Errorf("Error connecting to node (%s) to get name registrar entry for name (%s)", @@ -180,7 +197,7 @@ func (erisNodeClient *ErisNodeClient) GetName(name string) (owner []byte, data s func (erisNodeClient *ErisNodeClient) ListValidators() (blockHeight int, bondedValidators []consensus_types.Validator, unbondingValidators []consensus_types.Validator, err error) { - client := rpcclient.NewClientURI(erisNodeClient.broadcastRPC) + client := rpcclient.NewClientJSONRPC(erisNodeClient.broadcastRPC) validatorsResult, err := tendermint_client.ListValidators(client) if err != nil { err = fmt.Errorf("Error connecting to node (%s) to get validators", diff --git a/client/cmd/eris-client.go b/client/cmd/eris-client.go index 9176ca0a272daf6ec7105eb22cdf2a654b50d69b..48df67ab121460f278cd8c4144f1f7475e03aeb8 100644 --- a/client/cmd/eris-client.go +++ b/client/cmd/eris-client.go @@ -72,6 +72,9 @@ func AddGlobalFlags() { func AddClientCommands() { buildTransactionCommand() ErisClientCmd.AddCommand(TransactionCmd) + + buildStatusCommand() + ErisClientCmd.AddCommand(StatusCmd) } //------------------------------------------------------------------------------ diff --git a/client/cmd/status.go b/client/cmd/status.go new file mode 100644 index 0000000000000000000000000000000000000000..376976300942b6af0d41fead8a5f1eb21ad052d0 --- /dev/null +++ b/client/cmd/status.go @@ -0,0 +1,49 @@ +// Copyright 2015, 2016 Eris Industries (UK) Ltd. +// This file is part of Eris-RT + +// Eris-RT 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. + +// Eris-RT 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 Eris-RT. If not, see <http://www.gnu.org/licenses/>. + +package commands + +import ( + "github.com/spf13/cobra" + + "github.com/eris-ltd/eris-db/client/methods" +) + +var StatusCmd = &cobra.Command{ + Use: "status", + Short: "eris-client status returns the current status from a chain.", + Long: `eris-client status returns the current status from a chain. +`, + Run: func(cmd *cobra.Command, args []string) { + methods.Status(clientDo) + }, +} + +func buildStatusCommand() { + addStatusPersistentFlags() +} + +func addStatusPersistentFlags() { + StatusCmd.PersistentFlags().StringVarP(&clientDo.NodeAddrFlag, "node-addr", "", defaultNodeRpcAddress(), "set the eris-db node rpc server address (default respects $ERIS_CLIENT_NODE_ADDRESS)") + // TransactionCmd.PersistentFlags().StringVarP(&clientDo.PubkeyFlag, "pubkey", "", defaultPublicKey(), "specify the public key to sign with (defaults to $ERIS_CLIENT_PUBLIC_KEY)") + // TransactionCmd.PersistentFlags().StringVarP(&clientDo.AddrFlag, "addr", "", defaultAddress(), "specify the account address (for which the public key can be found at eris-keys) (default respects $ERIS_CLIENT_ADDRESS)") + // TransactionCmd.PersistentFlags().StringVarP(&clientDo.ChainidFlag, "chain-id", "", defaultChainId(), "specify the chainID (default respects $CHAIN_ID)") + // TransactionCmd.PersistentFlags().StringVarP(&clientDo.NonceFlag, "nonce", "", "", "specify the nonce to use for the transaction (should equal the sender account's nonce + 1)") + + // // TransactionCmd.PersistentFlags().BoolVarP(&clientDo.SignFlag, "sign", "s", false, "sign the transaction using the eris-keys daemon") + // TransactionCmd.PersistentFlags().BoolVarP(&clientDo.BroadcastFlag, "broadcast", "b", true, "broadcast the transaction to the blockchain") + // TransactionCmd.PersistentFlags().BoolVarP(&clientDo.WaitFlag, "wait", "w", false, "wait for the transaction to be committed in a block") +} diff --git a/client/core/transaction_factory.go b/client/core/transaction_factory.go index 40a59893b01631e99a15ca818d3ad6c693ec0d3d..e631144c11bc36f70327b86488bd0ce66347564c 100644 --- a/client/core/transaction_factory.go +++ b/client/core/transaction_factory.go @@ -22,11 +22,11 @@ import ( "strconv" // "strings" // "time" + log "github.com/eris-ltd/eris-logger" ptypes "github.com/eris-ltd/eris-db/permission/types" - // log "github.com/eris-ltd/eris-logger" - + "github.com/eris-ltd/eris-db/account" "github.com/eris-ltd/eris-db/client" "github.com/eris-ltd/eris-db/keys" "github.com/eris-ltd/eris-db/txs" @@ -280,6 +280,9 @@ func SignAndBroadcast(chainID string, nodeClient client.NodeClient, keyClient ke if err != nil { return nil, err } + log.WithFields(log.Fields{ + "transaction": string(account.SignBytes(chainID, tx)), + }).Debug("Signed transaction") } if broadcast { diff --git a/client/core/transaction_factory_test.go b/client/core/transaction_factory_test.go index f480fcaf57d68df6f1e99bfcc69977b1f7b7958b..4544655e1d045332e07678a772b09a1c267b155b 100644 --- a/client/core/transaction_factory_test.go +++ b/client/core/transaction_factory_test.go @@ -20,6 +20,8 @@ import ( "fmt" "testing" + // "github.com/stretchr/testify/assert" + mockclient "github.com/eris-ltd/eris-db/client/mock" mockkeys "github.com/eris-ltd/eris-db/keys/mock" ) @@ -60,6 +62,7 @@ func testTransactionFactorySend(t *testing.T, t.Logf("Error in SendTx: %s", err) t.Fail() } + // assert.NotEqual(t, txSend) // TODO: test content of Transaction } diff --git a/client/core/transaction_factory_util.go b/client/core/transaction_factory_util.go index 6178da75f3b1a738117e6a24fbd41e3a8372e35e..8463e8e64cc06cfea5a523214d2f8580ce28c6a7 100644 --- a/client/core/transaction_factory_util.go +++ b/client/core/transaction_factory_util.go @@ -76,11 +76,6 @@ func signTx(keyClient keys.KeyClient, chainID string, tx_ txs.Tx) ([]byte, txs.T var sig64 [64]byte copy(sig64[:], sig) sigED = crypto.SignatureEd25519(sig64) - log.WithFields(log.Fields{ - "transaction sign bytes": fmt.Sprintf("%X", signBytes), - "account address": fmt.Sprintf("%X", inputAddr), - "signature": fmt.Sprintf("%X", sig64), - }).Debug("Signed transaction") return inputAddr, tx_, nil } diff --git a/client/methods/status.go b/client/methods/status.go new file mode 100644 index 0000000000000000000000000000000000000000..2954fd1d283c759e24eabf66ed6499fd74ff397f --- /dev/null +++ b/client/methods/status.go @@ -0,0 +1,53 @@ +// Copyright 2015, 2016 Eris Industries (UK) Ltd. +// This file is part of Eris-RT + +// Eris-RT 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. + +// Eris-RT 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 Eris-RT. If not, see <http://www.gnu.org/licenses/>. + +package methods + +import ( + "fmt" + + log "github.com/eris-ltd/eris-logger" + + "github.com/eris-ltd/eris-db/client" + "github.com/eris-ltd/eris-db/definitions" +) + +func Status(do *definitions.ClientDo) { + erisNodeClient := client.NewErisNodeClient(do.NodeAddrFlag) + genesisHash, validatorPublicKey, latestBlockHash, latestBlockHeight, latestBlockTime, err := erisNodeClient.Status() + if err != nil { + log.Errorf("Error requesting status from chain at (%s): %s", do.NodeAddrFlag, err) + return + } + + chainName, chainId, genesisHashfromChainId, err := erisNodeClient.ChainId() + if err != nil { + log.Errorf("Error requesting chainId from chain at (%s): %s", do.NodeAddrFlag, err) + return + } + + log.WithFields(log.Fields{ + "chain": do.NodeAddrFlag, + "genesisHash": fmt.Sprintf("%X", genesisHash), + "chainName": chainName, + "chainId": chainId, + "genesisHash from chainId":fmt.Sprintf("%X", genesisHashfromChainId), + "validator public key": fmt.Sprintf("%X", validatorPublicKey), + "latest block hash": fmt.Sprintf("%X", latestBlockHash), + "latest block height": latestBlockHeight, + "latest block time": latestBlockTime, + }).Info("status") +} diff --git a/definitions/tendermint_pipe.go b/definitions/tendermint_pipe.go index 37973ce4dcaffc918d477a19d809ae1a7d808175..e933194d7cb28c1f2bbb163f0ef9b0009d4509f6 100644 --- a/definitions/tendermint_pipe.go +++ b/definitions/tendermint_pipe.go @@ -41,6 +41,7 @@ type TendermintPipe interface { Status() (*rpc_tm_types.ResultStatus, error) NetInfo() (*rpc_tm_types.ResultNetInfo, error) Genesis() (*rpc_tm_types.ResultGenesis, error) + ChainId() (*rpc_tm_types.ResultChainId, error) // Accounts GetAccount(address []byte) (*rpc_tm_types.ResultGetAccount, error) diff --git a/keys/key_client_util.go b/keys/key_client_util.go index 7e3dcbba43d67f732d3ff98213075ccf2973534c..e9e5f4783d51ce2df4e590cea008535ed5f1a4d7 100644 --- a/keys/key_client_util.go +++ b/keys/key_client_util.go @@ -45,7 +45,7 @@ func RequestResponse(addr, method string, args map[string]string) (string, error log.WithFields(log.Fields{ "key server endpoint": endpoint, "request body": string(b), - }).Debugf("Sending request body to key server") + }).Debugf("Eris-client: Sending request body to key server") req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(b)) if err != nil { return "", err diff --git a/manager/eris-mint/pipe.go b/manager/eris-mint/pipe.go index 5370e0778d4074043518aa7a818e094594b40d2b..490a613b468b98ab1dd1193addd29328a0f4a04b 100644 --- a/manager/eris-mint/pipe.go +++ b/manager/eris-mint/pipe.go @@ -278,7 +278,7 @@ func (pipe *erisMintPipe) GenesisHash() []byte { func (pipe *erisMintPipe) Status() (*rpc_tm_types.ResultStatus, error) { if pipe.consensusEngine == nil { - return nil, fmt.Errorf("Consensus Engine is not set in pipe.") + return nil, fmt.Errorf("Consensus Engine not initialised in Erismint pipe.") } latestHeight := pipe.blockchain.Height() var ( @@ -300,6 +300,19 @@ func (pipe *erisMintPipe) Status() (*rpc_tm_types.ResultStatus, error) { LatestBlockTime: latestBlockTime}, nil } +func (pipe *erisMintPipe) ChainId() (*rpc_tm_types.ResultChainId, error) { + if pipe.blockchain == nil { + return nil, fmt.Errorf("Blockchain not initialised in Erismint pipe.") + } + chainId := pipe.blockchain.ChainId() + + return &rpc_tm_types.ResultChainId{ + ChainName: chainId, // MARMOT: copy ChainId for ChainName as a placehodlder + ChainId: chainId, + GenesisHash: pipe.GenesisHash(), + }, nil +} + func (pipe *erisMintPipe) NetInfo() (*rpc_tm_types.ResultNetInfo, error) { listening := pipe.consensusEngine.IsListening() listeners := []string{} diff --git a/rpc/tendermint/client/client.go b/rpc/tendermint/client/client.go index 3108c3f0325befcbfc1791e0697a0030940cd5f8..3da5a1286d8c2aeaf31b28b2b97cc29da32d3a8a 100644 --- a/rpc/tendermint/client/client.go +++ b/rpc/tendermint/client/client.go @@ -20,6 +20,15 @@ func Status(client rpcclient.Client) (*rpc_types.ResultStatus, error) { return res.(*rpc_types.ResultStatus), nil } +func ChainId(client rpcclient.Client) (*rpc_types.ResultChainId, error) { + res, err := performCall(client, "chain_id") + if err != nil { + return nil, err + } + return res.(*rpc_types.ResultChainId), nil +} + + func GenPrivAccount(client rpcclient.Client) (*acm.PrivAccount, error) { res, err := performCall(client, "unsafe/gen_priv_account") if err != nil { diff --git a/rpc/tendermint/core/routes.go b/rpc/tendermint/core/routes.go index a9dfa887eecdc7d9d50bf54c1ceefef099500bbb..5439eb35956ee4f96a669284108b9e31f9a9d4f6 100644 --- a/rpc/tendermint/core/routes.go +++ b/rpc/tendermint/core/routes.go @@ -29,6 +29,7 @@ func (tmRoutes *TendermintRoutes) GetRoutes() map[string]*rpc.RPCFunc { "status": rpc.NewRPCFunc(tmRoutes.StatusResult, ""), "net_info": rpc.NewRPCFunc(tmRoutes.NetInfoResult, ""), "genesis": rpc.NewRPCFunc(tmRoutes.GenesisResult, ""), + "chain_id": rpc.NewRPCFunc(tmRoutes.ChainIdResult, ""), "get_account": rpc.NewRPCFunc(tmRoutes.GetAccountResult, "address"), "get_storage": rpc.NewRPCFunc(tmRoutes.GetStorageResult, "address,key"), "call": rpc.NewRPCFunc(tmRoutes.CallResult, "fromAddress,toAddress,data"), @@ -107,6 +108,14 @@ func (tmRoutes *TendermintRoutes) GenesisResult() (ctypes.ErisDBResult, error) { } } +func (tmRoutes *TendermintRoutes) ChainIdResult() (ctypes.ErisDBResult, error) { + if r, err := tmRoutes.tendermintPipe.ChainId(); err != nil { + return nil, err + } else { + return r, nil + } +} + func (tmRoutes *TendermintRoutes) GetAccountResult(address []byte) (ctypes.ErisDBResult, error) { if r, err := tmRoutes.tendermintPipe.GetAccount(address); err != nil { return nil, err diff --git a/rpc/tendermint/core/types/responses.go b/rpc/tendermint/core/types/responses.go index 69a4dd458a0f62c9713e6a9535b5d671d80b2813..c6494d919f3868507d562eeb3c0f0c30aa831f2e 100644 --- a/rpc/tendermint/core/types/responses.go +++ b/rpc/tendermint/core/types/responses.go @@ -60,6 +60,12 @@ type ResultStatus struct { LatestBlockTime int64 `json:"latest_block_time"` // nano } +type ResultChainId struct { + ChainName string `json:"chain_name"` + ChainId string `json:"chain_id"` + GenesisHash []byte `json:"genesis_hash"` +} + type ResultSubscribe struct { Event string `json:"event"` SubscriptionId string `json:"subscription_id"` @@ -158,6 +164,7 @@ const ( ResultTypeSubscribe = byte(0x14) ResultTypeUnsubscribe = byte(0x15) ResultTypePeerConsensusState = byte(0x16) + ResultTypeChainId = byte(0x17) ) type ErisDBResult interface { @@ -188,6 +195,7 @@ func ConcreteTypes() []wire.ConcreteType { {&ResultEvent{}, ResultTypeEvent}, {&ResultSubscribe{}, ResultTypeSubscribe}, {&ResultUnsubscribe{}, ResultTypeUnsubscribe}, + {&ResultChainId{}, ResultTypeChainId}, } }