diff --git a/client/client.go b/client/client.go new file mode 100644 index 0000000000000000000000000000000000000000..4f0bbe030329e4d614da9f6df0e70ff2eb77288d --- /dev/null +++ b/client/client.go @@ -0,0 +1,51 @@ +// 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 client + +import ( + "github.com/tendermint/go-rpc/client" + + tendermint_client "github.com/eris-ltd/eris-db/rpc/tendermint/client" + "github.com/eris-ltd/eris-db/txs" +) + +type Client interface{ + Broadcast(transaction txs.Tx) (*txs.Receipt, error) +} + +// NOTE [ben] Compiler check to ensure ErisClient successfully implements +// eris-db/client.Client +var _ Client = (*ErisClient)(nil) + +// Eris-Client is +type ErisClient struct { + broadcastRPC string +} + +//------------------------------------------------------------------------------------ +// broadcast to blockchain node +// NOTE: [ben] Eris Client first continues from tendermint rpc, but will have handshake to negotiate +// protocol version for moving towards rpc/v1 + +func (erisClient *ErisClient) Broadcast(tx txs.Tx) (*txs.Receipt, error) { + client := rpcclient.NewClientURI(erisClient.broadcastRPC) + receipt, err := tendermint_client.BroadcastTx(client, tx) + if err != nil { + return nil, err + } + return &receipt, nil +} \ No newline at end of file diff --git a/client/client_test.go b/client/client_test.go new file mode 100644 index 0000000000000000000000000000000000000000..54f6621a127ba7f51b512c28082759a25d5e28b6 --- /dev/null +++ b/client/client_test.go @@ -0,0 +1,18 @@ +// 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 client + diff --git a/client/cmd/transaction.go b/client/cmd/transaction.go index f6c8e0b1c17b3f10594a3e73c444d36706e05480..02c21edad1df1f3049a1719d583a46a4b8063b39 100644 --- a/client/cmd/transaction.go +++ b/client/cmd/transaction.go @@ -60,7 +60,7 @@ func buildTransactionCommand() { Short: "eris-client tx name --amt <amt> --name <name> --data <data>", Long: "eris-client tx name --amt <amt> --name <name> --data <data>", Run: func(cmd *cobra.Command, args []string) { - // transaction.Name(clientDo) + transaction.Name(clientDo) }, PreRun: assertParameters, } diff --git a/client/core/core.go b/client/core/transaction_factory.go similarity index 87% rename from client/core/core.go rename to client/core/transaction_factory.go index 4aa2ea7f5142c26756cdba5ddd2ce63d737021e2..ace2eebba538be20169a42d55779d79f2c1b40dc 100644 --- a/client/core/core.go +++ b/client/core/transaction_factory.go @@ -114,18 +114,18 @@ func Name(nodeAddr, signAddr, pubkey, addr, amtS, nonceS, feeS, name, data strin return tx, nil } -// type PermFunc struct { -// Name string -// Args string -// } +type PermFunc struct { + Name string + Args string +} -// var PermsFuncs = []PermFunc{ -// {"set_base", "address, permission flag, value"}, -// {"unset_base", "address, permission flag"}, -// {"set_global", "permission flag, value"}, -// {"add_role", "address, role"}, -// {"rm_role", "address, role"}, -// } +var PermsFuncs = []PermFunc{ + {"set_base", "address, permission flag, value"}, + {"unset_base", "address, permission flag"}, + {"set_global", "permission flag, value"}, + {"add_role", "address, role"}, + {"rm_role", "address, role"}, +} // func Permissions(nodeAddr, signAddr, pubkey, addrS, nonceS, permFunc string, argsS []string) (*txs.PermissionsTx, error) { // pub, _, nonce, err := checkCommon(nodeAddr, signAddr, pubkey, addrS, "0", nonceS) @@ -300,35 +300,6 @@ func coreNewAccount(nodeAddr, pubkey, chainID string) (*types.NewAccountTx, erro //------------------------------------------------------------------------------------ // sign and broadcast -func Pub(addr, rpcAddr string) (pubBytes []byte, err error) { - args := map[string]string{ - "addr": addr, - } - pubS, err := RequestResponse(rpcAddr, "pub", args) - if err != nil { - return - } - return hex.DecodeString(pubS) -} - -func Sign(signBytes, signAddr, signRPC string) (sig [64]byte, err error) { - args := map[string]string{ - "msg": signBytes, - "hash": signBytes, // TODO:[ben] backwards compatibility - "addr": signAddr, - } - sigS, err := RequestResponse(signRPC, "sign", args) - if err != nil { - return - } - sigBytes, err := hex.DecodeString(sigS) - if err != nil { - return - } - copy(sig[:], sigBytes) - return -} - func Broadcast(tx txs.Tx, broadcastRPC string) (*txs.Receipt, error) { client := rpcclient.NewClientURI(broadcastRPC) receipt, err := tendermint_client.BroadcastTx(client, tx) @@ -341,64 +312,64 @@ func Broadcast(tx txs.Tx, broadcastRPC string) (*txs.Receipt, error) { //------------------------------------------------------------------------------------ // utils for talking to the key server -type HTTPResponse struct { - Response string - Error string -} +// type HTTPResponse struct { +// Response string +// Error string +// } -func RequestResponse(addr, method string, args map[string]string) (string, error) { - b, err := json.Marshal(args) - if err != nil { - return "", err - } - endpoint := fmt.Sprintf("%s/%s", addr, method) - log.WithFields(log.Fields{ - "key server endpoint": endpoint, - "request body": string(b), - }).Debugf("Sending request body to key server") - req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(b)) - if err != nil { - return "", err - } - req.Header.Add("Content-Type", "application/json") - res, errS, err := requestResponse(req) - if err != nil { - return "", fmt.Errorf("Error calling eris-keys at %s: %s", endpoint, err.Error()) - } - if errS != "" { - return "", fmt.Errorf("Error (string) calling eris-keys at %s: %s", endpoint, errS) - } - log.WithFields(log.Fields{ - "endpoint": endpoint, - "request body": string(b), - "response": res, - }).Debugf("Received response from key server") - return res, nil -} +// func RequestResponse(addr, method string, args map[string]string) (string, error) { +// b, err := json.Marshal(args) +// if err != nil { +// return "", err +// } +// endpoint := fmt.Sprintf("%s/%s", addr, method) +// log.WithFields(log.Fields{ +// "key server endpoint": endpoint, +// "request body": string(b), +// }).Debugf("Sending request body to key server") +// req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(b)) +// if err != nil { +// return "", err +// } +// req.Header.Add("Content-Type", "application/json") +// res, errS, err := requestResponse(req) +// if err != nil { +// return "", fmt.Errorf("Error calling eris-keys at %s: %s", endpoint, err.Error()) +// } +// if errS != "" { +// return "", fmt.Errorf("Error (string) calling eris-keys at %s: %s", endpoint, errS) +// } +// log.WithFields(log.Fields{ +// "endpoint": endpoint, +// "request body": string(b), +// "response": res, +// }).Debugf("Received response from key server") +// return res, nil +// } -func requestResponse(req *http.Request) (string, string, error) { - client := new(http.Client) - resp, err := client.Do(req) - if err != nil { - return "", "", err - } - if resp.StatusCode >= 400 { - return "", "", fmt.Errorf(resp.Status) - } - return unpackResponse(resp) -} +// func requestResponse(req *http.Request) (string, string, error) { +// client := new(http.Client) +// resp, err := client.Do(req) +// if err != nil { +// return "", "", err +// } +// if resp.StatusCode >= 400 { +// return "", "", fmt.Errorf(resp.Status) +// } +// return unpackResponse(resp) +// } -func unpackResponse(resp *http.Response) (string, string, error) { - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "", "", err - } - r := new(HTTPResponse) - if err := json.Unmarshal(b, r); err != nil { - return "", "", err - } - return r.Response, r.Error, nil -} +// func unpackResponse(resp *http.Response) (string, string, error) { +// b, err := ioutil.ReadAll(resp.Body) +// if err != nil { +// return "", "", err +// } +// r := new(HTTPResponse) +// if err := json.Unmarshal(b, r); err != nil { +// return "", "", err +// } +// return r.Response, r.Error, nil +// } //------------------------------------------------------------------------------------ // sign and broadcast convenience diff --git a/client/core/transaction_factory_test.go b/client/core/transaction_factory_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5ff0eb22f1ca048857ad8e865dbca257343c30e6 --- /dev/null +++ b/client/core/transaction_factory_test.go @@ -0,0 +1,67 @@ +// 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 core + +import ( + "testing" + + "github.com/eris-ltd/eris-db/keys" +) + +// Unit tests for client/core an idael showcase for the need to +// modularise and restructure the components of the code. + +func TestCheckCommon(t *testing.T) { + +} + +func TestSendTransaction(t *testing.T) { + +} + + +func TestUtilInputAddress(t *testing.T) { + // test in parallel + t.Run("ExtractInputAddress from transaction", func (t *testing.T) { + t.Run("SendTransaction", ) + // t.Run("NameTransaction", ) + t.Run("CallTransaction", ) + // t.Run("PermissionTransaction", ) + // t.Run("BondTransaction", ) + // t.Run("UnbondTransaction", ) + // t.Run("RebondTransaction", ) + }) +} + +func testUtilInputAddressSendTx(t *testing.T) { + +} + +//--------------------------------------------------------------------- +// Mock client for replacing signing done by eris-keys + +// NOTE [ben] Compiler check to ensure MockKeysClient successfully implements +// eris-db/client.KeyClient +var _ keys.KeyClient = (*MockKeyClient)(nil) + +type MockKeyClient struct{} + +func (mock *MockKeyClient) Sign(signBytes, signAddress []byte) (signature [64]byte, err error) { + return +} + +func (mock *MockKeyClient) PublicKey(address []byte) (publicKey []byte, err error) diff --git a/client/core/transaction_factory_util.go b/client/core/transaction_factory_util.go new file mode 100644 index 0000000000000000000000000000000000000000..6951dcea59c1af98e2548c4ef5bfdce38ab1246b --- /dev/null +++ b/client/core/transaction_factory_util.go @@ -0,0 +1,193 @@ +// 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 core + +import ( + + keys "github.com/eris-ltd/eris-db/keys" + txs "github.com/eris-ltd/eris-db/txs" +) + +//------------------------------------------------------------------------------------ +// sign and broadcast convenience + +// tx has either one input or we default to the first one (ie for send/bond) +// TODO: better support for multisig and bonding +func signTx(signAddr, chainID string, tx_ txs.Tx) ([]byte, txs.Tx, error) { + signBytes := fmt.Sprintf("%X", account.SignBytes(chainID, tx_)) + var inputAddr []byte + var sigED crypto.SignatureEd25519 + switch tx := tx_.(type) { + case *txs.SendTx: + inputAddr = tx.Inputs[0].Address + defer func(s *crypto.SignatureEd25519) { tx.Inputs[0].Signature = *s }(&sigED) + case *txs.NameTx: + inputAddr = tx.Input.Address + defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + case *txs.CallTx: + inputAddr = tx.Input.Address + defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + case *txs.PermissionsTx: + inputAddr = tx.Input.Address + defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + case *txs.BondTx: + inputAddr = tx.Inputs[0].Address + defer func(s *crypto.SignatureEd25519) { + tx.Signature = *s + tx.Inputs[0].Signature = *s + }(&sigED) + case *txs.UnbondTx: + inputAddr = tx.Address + defer func(s *crypto.SignatureEd25519) { tx.Signature = *s }(&sigED) + case *txs.RebondTx: + inputAddr = tx.Address + defer func(s *crypto.SignatureEd25519) { tx.Signature = *s }(&sigED) + } + addrHex := fmt.Sprintf("%X", inputAddr) + sig, err := Sign(signBytes, addrHex, signAddr) + if err != nil { + return nil, nil, err + } + sigED = crypto.SignatureEd25519(sig) + log.WithFields(log.Fields{ + "transaction sign bytes": signBytes, + "account address": addrHex, + "signature": fmt.Sprintf("%X", sig), + }).Debug("Signed transaction") + return inputAddr, tx_, nil +} + +// readInputAddressFromTransaction returns the hexadecimal string form of the +func readInputAddressFromTransaction(tx_ txs.Tx) (addressHex string) { + // signBytes := fmt.Sprintf("%X", account.SignBytes(chainID, tx_)) + var inputAddr []byte + // var sigED crypto.SignatureEd25519 + switch tx := tx_.(type) { + case *txs.SendTx: + inputAddr = tx.Inputs[0].Address + // defer func(s *crypto.SignatureEd25519) { tx.Inputs[0].Signature = *s }(&sigED) + case *txs.NameTx: + inputAddr = tx.Input.Address + // defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + case *txs.CallTx: + inputAddr = tx.Input.Address + // defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + case *txs.PermissionsTx: + inputAddr = tx.Input.Address + // defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + case *txs.BondTx: + inputAddr = tx.Inputs[0].Address + // defer func(s *crypto.SignatureEd25519) { + // tx.Signature = *s + // tx.Inputs[0].Signature = *s + // }(&sigED) + case *txs.UnbondTx: + inputAddr = tx.Address + // defer func(s *crypto.SignatureEd25519) { tx.Signature = *s }(&sigED) + case *txs.RebondTx: + inputAddr = tx.Address + // defer func(s *crypto.SignatureEd25519) { tx.Signature = *s }(&sigED) + } + addressHex := fmt.Sprintf("%X", inputAddr) + // sig, err := Sign(signBytes, addrHex, signAddr) + // if err != nil { + // return nil, nil, err + // } + // sigED = crypto.SignatureEd25519(sig) + return addressHex +} + +func checkCommon(, keyClient keys.KeyClient, pubkey, addr, amtS, nonceS string) (pub crypto.PubKey, amt int64, nonce int64, err error) { + if amtS == "" { + err = fmt.Errorf("input must specify an amount with the --amt flag") + return + } + + var pubKeyBytes []byte + if pubkey == "" && addr == "" { + err = fmt.Errorf("at least one of --pubkey or --addr must be given") + return + } else if pubkey != "" { + if addr != "" { + log.WithFields(log.Fields{ + "public key": pubkey, + "address": addr, + }).Info("you have specified both a pubkey and an address. the pubkey takes precedent") + } + pubKeyBytes, err = hex.DecodeString(pubkey) + if err != nil { + err = fmt.Errorf("pubkey is bad hex: %v", err) + return + } + } else { + // grab the pubkey from eris-keys + pubKeyBytes, err = Pub(addr, signAddr) + if err != nil { + err = fmt.Errorf("failed to fetch pubkey for address (%s): %v", addr, err) + return + } + + } + + if len(pubKeyBytes) == 0 { + err = fmt.Errorf("Error resolving public key") + return + } + + amt, err = strconv.ParseInt(amtS, 10, 64) + if err != nil { + err = fmt.Errorf("amt is misformatted: %v", err) + } + + var pubArray [32]byte + copy(pubArray[:], pubKeyBytes) + pub = crypto.PubKeyEd25519(pubArray) + addrBytes := pub.Address() + + if nonceS == "" { + if nodeAddr == "" { + err = fmt.Errorf("input must specify a nonce with the --nonce flag or use --node-addr (or ERIS_CLIENT_NODE_ADDR) to fetch the nonce from a node") + return + } + + // fetch nonce from node + client := rpcclient.NewClientURI(nodeAddr) + account, err2 := tendermint_client.GetAccount(client, addrBytes) + if err2 != nil { + err = fmt.Errorf("Error connecting to node (%s) to fetch nonce: %s", nodeAddr, err2.Error()) + return + } + if account == nil { + err = fmt.Errorf("unknown account %X", addrBytes) + return + } + nonce = int64(account.Sequence) + 1 + log.WithFields(log.Fields{ + "nonce": nonce, + "node address": nodeAddr, + "account address": fmt.Sprintf("%X", addrBytes), + }).Debug("Fetch nonce from node") + } else { + nonce, err = strconv.ParseInt(nonceS, 10, 64) + if err != nil { + err = fmt.Errorf("nonce is misformatted: %v", err) + return + } + } + + return +} \ No newline at end of file diff --git a/client/transaction/transaction.go b/client/transaction/transaction.go index faef29683f2a89da2375f74568fc58ee7126ad45..83f617614155bea7c6d4f556d0cf8a880600ea69 100644 --- a/client/transaction/transaction.go +++ b/client/transaction/transaction.go @@ -18,13 +18,13 @@ package transaction import ( "fmt" - // "io/ioutil" "os" log "github.com/eris-ltd/eris-logger" "github.com/eris-ltd/eris-db/client/core" "github.com/eris-ltd/eris-db/definitions" + "github.com/eris-ltd/eris-db/keys" ) func Send(do *definitions.ClientDo) { diff --git a/keys/key_client.go b/keys/key_client.go new file mode 100644 index 0000000000000000000000000000000000000000..90452e0a83b57c8f08a73128cd94a7d3a3f13d03 --- /dev/null +++ b/keys/key_client.go @@ -0,0 +1,81 @@ +// 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 keys + +import ( + "encoding/hex" + "fmt" +) + +type KeyClient interface{ + // Sign needs to return the signature bytes for given message to sign + // and the address to sign it with. + Sign(signBytes, signAddress []byte) (signature [64]byte, err error) + // PublicKey needs to return the public key associated with a given address + PublicKey(address []byte) (publicKey []byte, err error) +} + +// NOTE [ben] Compiler check to ensure ErisKeyClient successfully implements +// eris-db/keys.KeyClient +var _ KeyClient = (*ErisKeyClient)(nil) + +struct ErisKeyClient{ + rpcString string +} + +// ErisKeyClient.New returns a new eris-keys client for provided rpc location +// Eris-keys connects over http request-responses +func (erisKeys *ErisKeyClient) New(rpcString string) ErisKeyClient{ + return &ErisKeysServer{ + rpcString: rpcString, + } +} + +// Eris-keys client Sign requests the signature from ErisKeysClient over rpc for the given +// bytes to be signed and the address to sign them with. +func (erisKeys *ErisKeyClient) Sign(signBytes, signAddress []byte) (signature [64]byte, err error) { + args := map[string]string{ + "msg": string(signBytes), + "hash": string(signBytes), // TODO:[ben] backwards compatibility + "addr": string(signAddress), + } + sigS, err := RequestResponse(erisKeys.rpcString, "sign", args) + if err != nil { + return + } + sigBytes, err := hex.DecodeString(sigS) + if err != nil { + return + } + copy(signature[:], sigBytes) + return +} + +// Eris-keys client PublicKey requests the public key associated with an address from +// the eris-keys server. +func (erisKeys *ErisKeyClient) PublicKey(address []byte) (publicKey []byte, err error) { + args := map[string]string{ + "addr": address, + } + pubS, err := RequestResponse(erisKeys.rpcString, "pub", args) + if err != nil { + return + } + // TODO: [ben] assert that received public key results in + // address + return hex.DecodeString(pubS) +} \ No newline at end of file diff --git a/keys/key_client_util.go b/keys/key_client_util.go new file mode 100644 index 0000000000000000000000000000000000000000..d043779f7e72e2d16a2b7bc7b6560ba0a28a2f4d --- /dev/null +++ b/keys/key_client_util.go @@ -0,0 +1,91 @@ +// 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/>. + +// version provides the current Eris-DB version and a VersionIdentifier +// for the modules to identify their version with. + +package keys + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + log "github.com/eris-ltd/eris-logger" +) + +// Eris-Keys server connects over http request-response structures + +type HTTPResponse struct { + Response string + Error string +} + +func RequestResponse(addr, method string, args map[string]string) (string, error) { + b, err := json.Marshal(args) + if err != nil { + return "", err + } + endpoint := fmt.Sprintf("%s/%s", addr, method) + log.WithFields(log.Fields{ + "key server endpoint": endpoint, + "request body": string(b), + }).Debugf("Sending request body to key server") + req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(b)) + if err != nil { + return "", err + } + req.Header.Add("Content-Type", "application/json") + res, errS, err := requestResponse(req) + if err != nil { + return "", fmt.Errorf("Error calling eris-keys at %s: %s", endpoint, err.Error()) + } + if errS != "" { + return "", fmt.Errorf("Error (string) calling eris-keys at %s: %s", endpoint, errS) + } + log.WithFields(log.Fields{ + "endpoint": endpoint, + "request body": string(b), + "response": res, + }).Debugf("Received response from key server") + return res, nil +} + +func requestResponse(req *http.Request) (string, string, error) { + client := new(http.Client) + resp, err := client.Do(req) + if err != nil { + return "", "", err + } + if resp.StatusCode >= 400 { + return "", "", fmt.Errorf(resp.Status) + } + return unpackResponse(resp) +} + +func unpackResponse(resp *http.Response) (string, string, error) { + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", "", err + } + r := new(HTTPResponse) + if err := json.Unmarshal(b, r); err != nil { + return "", "", err + } + return r.Response, r.Error, nil +} \ No newline at end of file