From 75510830e1b2169dbefde98486e2cdca2389e178 Mon Sep 17 00:00:00 2001 From: Silas Davis <silas@monax.io> Date: Tue, 9 Jan 2018 15:40:34 +0000 Subject: [PATCH] Client: propagate account types to client, use updated key client, drop ChainId flag in favour of querying node for it, other miscellany in order get client working. Signed-off-by: Silas Davis <silas@monax.io> --- {definitions => client}/client_do.go | 10 +-- client/cmd/burrow-client.go | 11 ++- client/cmd/genesis.go | 3 +- client/cmd/transaction.go | 11 +-- client/methods/call.go | 11 ++- client/methods/helpers.go | 13 +-- client/methods/send.go | 11 ++- client/methods/status.go | 5 +- client/mock/client_mock.go | 69 +++++++-------- client/node_client.go | 99 +++++++++++---------- client/rpc/client.go | 123 ++++++++++++++++----------- client/rpc/client_test.go | 20 ++--- client/rpc/client_util.go | 116 +++++++++++++------------ client/websocket_client.go | 117 ++++++++++++------------- 14 files changed, 305 insertions(+), 314 deletions(-) rename {definitions => client}/client_do.go (93%) diff --git a/definitions/client_do.go b/client/client_do.go similarity index 93% rename from definitions/client_do.go rename to client/client_do.go index fc0f25fa..4816cafd 100644 --- a/definitions/client_do.go +++ b/client/client_do.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package definitions +package client -type ClientDo struct { +type Do struct { // Persistent flags not reflected in the configuration files // only set through command line flags or environment variables Debug bool // BURROW_DEBUG @@ -25,7 +25,6 @@ type ClientDo struct { NodeAddrFlag string PubkeyFlag string AddrFlag string - ChainidFlag string // signFlag bool // TODO: remove; unsafe signing without monax-keys BroadcastFlag bool @@ -46,8 +45,8 @@ type ClientDo struct { HeightFlag string } -func NewClientDo() *ClientDo { - clientDo := new(ClientDo) +func NewClientDo() *Do { + clientDo := new(Do) clientDo.Debug = false clientDo.Verbose = false @@ -55,7 +54,6 @@ func NewClientDo() *ClientDo { clientDo.NodeAddrFlag = "" clientDo.PubkeyFlag = "" clientDo.AddrFlag = "" - clientDo.ChainidFlag = "" // clientDo.signFlag = false clientDo.BroadcastFlag = false diff --git a/client/cmd/burrow-client.go b/client/cmd/burrow-client.go index bb67c6ef..23e10c44 100644 --- a/client/cmd/burrow-client.go +++ b/client/cmd/burrow-client.go @@ -18,14 +18,13 @@ import ( "os" "strconv" - "github.com/spf13/cobra" - - "github.com/hyperledger/burrow/definitions" + "github.com/hyperledger/burrow/client" "github.com/hyperledger/burrow/version" + "github.com/spf13/cobra" ) // Global flags for persistent flags -var clientDo *definitions.ClientDo +var clientDo *client.Do var BurrowClientCmd = &cobra.Command{ Use: "burrow-client", @@ -47,8 +46,8 @@ func Execute() { } func InitBurrowClientInit() { - // initialise an empty ClientDo struct for command execution - clientDo = definitions.NewClientDo() + // initialise an empty Do struct for command execution + clientDo = client.NewClientDo() } func AddGlobalFlags() { diff --git a/client/cmd/genesis.go b/client/cmd/genesis.go index 3eb7f462..cb2d4fb1 100644 --- a/client/cmd/genesis.go +++ b/client/cmd/genesis.go @@ -17,7 +17,6 @@ package commands import ( "fmt" - "github.com/hyperledger/burrow/common/sanity" "github.com/hyperledger/burrow/genesis" "github.com/spf13/cobra" @@ -38,7 +37,7 @@ var GenesisGenCmd = &cobra.Command{ // TODO refactor to not panic genesisFile, err := genesis.GenerateKnown(args[0], AccountsPathFlag, ValidatorsPathFlag) if err != nil { - sanity.PanicSanity(err) + panic(err) } fmt.Println(genesisFile) // may want to save somewhere instead }, diff --git a/client/cmd/transaction.go b/client/cmd/transaction.go index 21b97e65..0bffd938 100644 --- a/client/cmd/transaction.go +++ b/client/cmd/transaction.go @@ -25,7 +25,7 @@ import ( func buildTransactionCommand() *cobra.Command { // Transaction command has subcommands send, name, call, bond, - // unbond, rebond, permissions. Dupeout transaction is not accessible through the command line. + // unbond, rebond, permissions. transactionCmd := &cobra.Command{ Use: "tx", Short: "burrow-client tx formulates and signs a transaction to a chain", @@ -145,7 +145,6 @@ func addTransactionPersistentFlags(transactionCmd *cobra.Command) { transactionCmd.PersistentFlags().StringVarP(&clientDo.NodeAddrFlag, "node-addr", "", defaultNodeRpcAddress(), "set the burrow node rpc server address (default respects $BURROW_CLIENT_NODE_ADDRESS)") transactionCmd.PersistentFlags().StringVarP(&clientDo.PubkeyFlag, "pubkey", "", defaultPublicKey(), "specify the public key to sign with (defaults to $BURROW_CLIENT_PUBLIC_KEY)") transactionCmd.PersistentFlags().StringVarP(&clientDo.AddrFlag, "addr", "", defaultAddress(), "specify the account address (for which the public key can be found at monax-keys) (default respects $BURROW_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 monax-keys daemon") @@ -156,10 +155,6 @@ func addTransactionPersistentFlags(transactionCmd *cobra.Command) { //------------------------------------------------------------------------------ // Defaults -func defaultChainId() string { - return setDefaultString("CHAIN_ID", "") -} - func defaultKeyDaemonAddress() string { return setDefaultString("BURROW_CLIENT_SIGN_ADDRESS", "http://127.0.0.1:4767") } @@ -180,10 +175,6 @@ func defaultAddress() string { // Helper functions func assertParameters(cmd *cobra.Command, args []string) { - if clientDo.ChainidFlag == "" { - util.Fatalf(`Please provide a chain id either through the flag --chain-id or environment variable $CHAIN_ID.`) - } - if !strings.HasPrefix(clientDo.NodeAddrFlag, "tcp://") && !strings.HasPrefix(clientDo.NodeAddrFlag, "unix://") { // TODO: [ben] go-rpc will deprecate reformatting; also it is bad practice to auto-correct for this; diff --git a/client/methods/call.go b/client/methods/call.go index 9df3a51a..84eed390 100644 --- a/client/methods/call.go +++ b/client/methods/call.go @@ -19,16 +19,15 @@ import ( "github.com/hyperledger/burrow/client" "github.com/hyperledger/burrow/client/rpc" - "github.com/hyperledger/burrow/definitions" "github.com/hyperledger/burrow/keys" ) -func Call(do *definitions.ClientDo) error { +func Call(do *client.Do) error { // construct two clients to call out to keys server and // blockchain node. logger, err := loggerFromClientDo(do, "Call") if err != nil { - return fmt.Errorf("Could not generate logging config from ClientDo: %s", err) + return fmt.Errorf("Could not generate logging config from Do: %s", err) } burrowKeyClient := keys.NewBurrowKeyClient(do.SignAddrFlag, logger) burrowNodeClient := client.NewBurrowNodeClient(do.NodeAddrFlag, logger) @@ -39,10 +38,14 @@ func Call(do *definitions.ClientDo) error { if err != nil { return fmt.Errorf("Failed on forming Call Transaction: %s", err) } + _, chainID, _, err := burrowNodeClient.ChainId() + if err != nil { + return err + } // TODO: [ben] we carry over the sign bool, but always set it to true, // as we move away from and deprecate the api that allows sending unsigned // transactions and relying on (our) receiving node to sign it. - txResult, err := rpc.SignAndBroadcast(do.ChainidFlag, burrowNodeClient, burrowKeyClient, + txResult, err := rpc.SignAndBroadcast(chainID, burrowNodeClient, burrowKeyClient, callTransaction, true, do.BroadcastFlag, do.WaitFlag) if err != nil { diff --git a/client/methods/helpers.go b/client/methods/helpers.go index 2e8bc6fc..6cdb8b3a 100644 --- a/client/methods/helpers.go +++ b/client/methods/helpers.go @@ -15,10 +15,10 @@ package methods import ( + "github.com/hyperledger/burrow/client" "github.com/hyperledger/burrow/client/rpc" - "github.com/hyperledger/burrow/core" - "github.com/hyperledger/burrow/definitions" "github.com/hyperledger/burrow/logging" + "github.com/hyperledger/burrow/logging/config" "github.com/hyperledger/burrow/logging/lifecycle" logging_types "github.com/hyperledger/burrow/logging/types" ) @@ -45,17 +45,12 @@ func unpackSignAndBroadcast(result *rpc.TxResult, logger logging_types.InfoTrace logging.InfoMsg(logger, "SignAndBroadcast result") } -func loggerFromClientDo(do *definitions.ClientDo, scope string) (logging_types.InfoTraceLogger, error) { - lc, err := core.LoadLoggingConfigFromClientDo(do) - if err != nil { - return nil, err - } - logger, err := lifecycle.NewLoggerFromLoggingConfig(lc) +func loggerFromClientDo(do *client.Do, scope string) (logging_types.InfoTraceLogger, error) { + logger, err := lifecycle.NewLoggerFromLoggingConfig(config.DefaultClientLoggingConfig()) if err != nil { return nil, err } logger = logging.WithScope(logger, scope) lifecycle.CaptureStdlibLogOutput(logger) - lifecycle.CaptureTendermintLog15Output(logger) return logger, nil } diff --git a/client/methods/send.go b/client/methods/send.go index 9437a9df..9527bc75 100644 --- a/client/methods/send.go +++ b/client/methods/send.go @@ -19,16 +19,15 @@ import ( "github.com/hyperledger/burrow/client" "github.com/hyperledger/burrow/client/rpc" - "github.com/hyperledger/burrow/definitions" "github.com/hyperledger/burrow/keys" ) -func Send(do *definitions.ClientDo) error { +func Send(do *client.Do) error { // construct two clients to call out to keys server and // blockchain node. logger, err := loggerFromClientDo(do, "Send") if err != nil { - return fmt.Errorf("Could not generate logging config from ClientDo: %s", err) + return fmt.Errorf("Could not generate logging config from Do: %s", err) } burrowKeyClient := keys.NewBurrowKeyClient(do.SignAddrFlag, logger) burrowNodeClient := client.NewBurrowNodeClient(do.NodeAddrFlag, logger) @@ -38,10 +37,14 @@ func Send(do *definitions.ClientDo) error { if err != nil { fmt.Errorf("Failed on forming Send Transaction: %s", err) } + _, chainID, _, err := burrowNodeClient.ChainId() + if err != nil { + return err + } // TODO: [ben] we carry over the sign bool, but always set it to true, // as we move away from and deprecate the api that allows sending unsigned // transactions and relying on (our) receiving node to sign it. - txResult, err := rpc.SignAndBroadcast(do.ChainidFlag, burrowNodeClient, burrowKeyClient, + txResult, err := rpc.SignAndBroadcast(chainID, burrowNodeClient, burrowKeyClient, sendTransaction, true, do.BroadcastFlag, do.WaitFlag) if err != nil { return fmt.Errorf("Failed on signing (and broadcasting) transaction: %s", err) diff --git a/client/methods/status.go b/client/methods/status.go index d14c3290..14a8be60 100644 --- a/client/methods/status.go +++ b/client/methods/status.go @@ -18,13 +18,12 @@ import ( "fmt" "github.com/hyperledger/burrow/client" - "github.com/hyperledger/burrow/definitions" ) -func Status(do *definitions.ClientDo) error { +func Status(do *client.Do) error { logger, err := loggerFromClientDo(do, "Status") if err != nil { - return fmt.Errorf("Could not generate logging config from ClientDo: %s", err) + return fmt.Errorf("Could not generate logging config from Do: %s", err) } burrowNodeClient := client.NewBurrowNodeClient(do.NodeAddrFlag, logger) genesisHash, validatorPublicKey, latestBlockHash, latestBlockHeight, latestBlockTime, err := burrowNodeClient.Status() diff --git a/client/mock/client_mock.go b/client/mock/client_mock.go index c6a0d12b..1289774c 100644 --- a/client/mock/client_mock.go +++ b/client/mock/client_mock.go @@ -15,26 +15,24 @@ package mock import ( - "github.com/tendermint/go-crypto" - - acc "github.com/hyperledger/burrow/account" + acm "github.com/hyperledger/burrow/account" . "github.com/hyperledger/burrow/client" - consensus_types "github.com/hyperledger/burrow/consensus/types" - core_types "github.com/hyperledger/burrow/core/types" "github.com/hyperledger/burrow/logging/loggers" logging_types "github.com/hyperledger/burrow/logging/types" + "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/txs" + "github.com/tendermint/go-crypto" ) var _ NodeClient = (*MockNodeClient)(nil) type MockNodeClient struct { - accounts map[string]*acc.Account + accounts map[string]*acm.ConcreteAccount } func NewMockNodeClient() *MockNodeClient { return &MockNodeClient{ - accounts: make(map[string]*acc.Account), + accounts: make(map[string]*acm.ConcreteAccount), } } @@ -42,8 +40,7 @@ func (mock *MockNodeClient) Broadcast(transaction txs.Tx) (*txs.Receipt, error) // make zero transaction receipt txReceipt := &txs.Receipt{ TxHash: make([]byte, 20), - CreatesContract: 0, - ContractAddr: make([]byte, 20), + CreatesContract: false, } return txReceipt, nil } @@ -52,68 +49,60 @@ func (mock *MockNodeClient) DeriveWebsocketClient() (nodeWsClient NodeWebsocketC return nil, nil } -func (mock *MockNodeClient) GetAccount(address []byte) (*acc.Account, error) { +func (mock *MockNodeClient) GetAccount(address acm.Address) (acm.Account, error) { // make zero account - var zero [32]byte - copyAddressBytes := make([]byte, len(address)) - copy(copyAddressBytes, address) - account := &acc.Account{ - Address: copyAddressBytes, - PubKey: crypto.PubKey(crypto.PubKeyEd25519(zero)), - Sequence: 0, - Balance: 0, + return acm.ConcreteAccount{ + Address: address, + PublicKey: acm.PublicKeyFromPubKey(crypto.PubKeyEd25519{}.Wrap()), Code: make([]byte, 0), StorageRoot: make([]byte, 0), - } - return account, nil + }.Account(), nil } -func (mock *MockNodeClient) MockAddAccount(account *acc.Account) { +func (mock *MockNodeClient) MockAddAccount(account *acm.ConcreteAccount) { addressString := string(account.Address[:]) mock.accounts[addressString] = account.Copy() } -func (mock *MockNodeClient) Status() (ChainId []byte, - ValidatorPublicKey []byte, LatestBlockHash []byte, - BlockHeight int, LatestBlockTime int64, err error) { - // make zero account - var zero [32]byte - ed25519 := crypto.PubKeyEd25519(zero) - pub := crypto.PubKey(ed25519) - +func (mock *MockNodeClient) Status() (ChainId []byte, ValidatorPublicKey []byte, LatestBlockHash []byte, + BlockHeight uint64, LatestBlockTime int64, err error) { // fill return values ChainId = make([]byte, 64) LatestBlockHash = make([]byte, 64) - ValidatorPublicKey = pub.Bytes() + ValidatorPublicKey = crypto.PubKeyEd25519{}.Wrap().Bytes() BlockHeight = 0 LatestBlockTime = 0 return } // QueryContract executes the contract code at address with the given data -func (mock *MockNodeClient) QueryContract(callerAddress, calleeAddress, data []byte) (ret []byte, gasUsed int64, err error) { +func (mock *MockNodeClient) QueryContract(callerAddress, calleeAddress acm.Address, + data []byte) (ret []byte, gasUsed uint64, err error) { + // return zero ret = make([]byte, 0) - return ret, 0, nil + return } // QueryContractCode executes the contract code at address with the given data but with provided code -func (mock *MockNodeClient) QueryContractCode(address, code, data []byte) (ret []byte, gasUsed int64, err error) { +func (mock *MockNodeClient) QueryContractCode(address acm.Address, code, + data []byte) (ret []byte, gasUsed uint64, err error) { // return zero ret = make([]byte, 0) - return ret, 0, nil + return } -func (mock *MockNodeClient) DumpStorage(address []byte) (storage *core_types.Storage, err error) { - return nil, nil +func (mock *MockNodeClient) DumpStorage(address acm.Address) (storage *rpc.ResultDumpStorage, err error) { + return } -func (mock *MockNodeClient) GetName(name string) (owner []byte, data string, expirationBlock int, err error) { - return nil, "", 0, nil +func (mock *MockNodeClient) GetName(name string) (owner acm.Address, data string, expirationBlock uint64, err error) { + return } -func (mock *MockNodeClient) ListValidators() (blockHeight int, bondedValidators, unbondingValidators []consensus_types.Validator, err error) { - return 0, nil, nil, nil +func (mock *MockNodeClient) ListValidators() (blockHeight uint64, bondedValidators, + unbondingValidators []acm.Validator, err error) { + return } func (mock *MockNodeClient) Logger() logging_types.InfoTraceLogger { diff --git a/client/node_client.go b/client/node_client.go index a7d49a14..145adc5f 100644 --- a/client/node_client.go +++ b/client/node_client.go @@ -16,19 +16,14 @@ package client import ( "fmt" - // "strings" - "github.com/tendermint/go-rpc/client" - - acc "github.com/hyperledger/burrow/account" - consensus_types "github.com/hyperledger/burrow/consensus/types" - core_types "github.com/hyperledger/burrow/core/types" + acm "github.com/hyperledger/burrow/account" "github.com/hyperledger/burrow/logging" logging_types "github.com/hyperledger/burrow/logging/types" - tendermint_client "github.com/hyperledger/burrow/rpc/tendermint/client" - tendermint_types "github.com/hyperledger/burrow/rpc/tendermint/core/types" + "github.com/hyperledger/burrow/rpc" + tendermint_client "github.com/hyperledger/burrow/rpc/tm/client" "github.com/hyperledger/burrow/txs" - tmLog15 "github.com/tendermint/log15" + "github.com/tendermint/tendermint/rpc/lib/client" ) type NodeClient interface { @@ -36,14 +31,14 @@ type NodeClient interface { DeriveWebsocketClient() (nodeWsClient NodeWebsocketClient, err error) Status() (ChainId []byte, ValidatorPublicKey []byte, LatestBlockHash []byte, - LatestBlockHeight int, LatestBlockTime int64, err error) - GetAccount(address []byte) (*acc.Account, error) - QueryContract(callerAddress, calleeAddress, data []byte) (ret []byte, gasUsed int64, err error) - QueryContractCode(address, code, data []byte) (ret []byte, gasUsed int64, err error) + LatestBlockHeight uint64, LatestBlockTime int64, err error) + GetAccount(address acm.Address) (acm.Account, error) + QueryContract(callerAddress, calleeAddress acm.Address, data []byte) (ret []byte, gasUsed uint64, err error) + QueryContractCode(address acm.Address, code, data []byte) (ret []byte, gasUsed uint64, err error) - DumpStorage(address []byte) (storage *core_types.Storage, err error) - GetName(name string) (owner []byte, data string, expirationBlock int, err error) - ListValidators() (blockHeight int, bondedValidators, unbondingValidators []consensus_types.Validator, err error) + DumpStorage(address acm.Address) (storage *rpc.ResultDumpStorage, err error) + GetName(name string) (owner acm.Address, data string, expirationBlock uint64, err error) + ListValidators() (blockHeight uint64, bondedValidators, unbondingValidators []acm.Validator, err error) // Logging context for this NodeClient Logger() logging_types.InfoTraceLogger @@ -53,7 +48,7 @@ type NodeWebsocketClient interface { Subscribe(eventId string) error Unsubscribe(eventId string) error - WaitForConfirmation(tx txs.Tx, chainId string, inputAddr []byte) (chan Confirmation, error) + WaitForConfirmation(tx txs.Tx, chainId string, inputAddr acm.Address) (chan Confirmation, error) Close() } @@ -76,13 +71,6 @@ func NewBurrowNodeClient(rpcString string, logger logging_types.InfoTraceLogger) } } -// Note [Ben]: This is a hack to silence Tendermint logger from tendermint/go-rpc -// it needs to be initialised before go-rpc, hence it's placement here. -func init() { - h := tmLog15.LvlFilterHandler(tmLog15.LvlWarn, tmLog15.StdoutHandler) - tmLog15.Root().SetHandler(h) -} - //------------------------------------------------------------------------------------ // broadcast to blockchain node @@ -92,7 +80,7 @@ func (burrowNodeClient *burrowNodeClient) Broadcast(tx txs.Tx) (*txs.Receipt, er if err != nil { return nil, err } - return &receipt, nil + return receipt, nil } func (burrowNodeClient *burrowNodeClient) DeriveWebsocketClient() (nodeWsClient NodeWebsocketClient, err error) { @@ -133,13 +121,15 @@ func (burrowNodeClient *burrowNodeClient) DeriveWebsocketClient() (nodeWsClient // Status returns the ChainId (GenesisHash), validator's PublicKey, latest block hash // the block height and the latest block time. -func (burrowNodeClient *burrowNodeClient) Status() (GenesisHash []byte, ValidatorPublicKey []byte, LatestBlockHash []byte, LatestBlockHeight int, LatestBlockTime int64, err error) { +func (burrowNodeClient *burrowNodeClient) Status() (GenesisHash []byte, ValidatorPublicKey []byte, + LatestBlockHash []byte, LatestBlockHeight uint64, LatestBlockTime int64, err error) { + client := rpcclient.NewJSONRPCClient(burrowNodeClient.broadcastRPC) res, err := tendermint_client.Status(client) if err != nil { err = fmt.Errorf("Error connecting to node (%s) to get status: %s", burrowNodeClient.broadcastRPC, err.Error()) - return nil, nil, nil, int(0), int64(0), err + return } // unwrap return results @@ -169,19 +159,23 @@ func (burrowNodeClient *burrowNodeClient) ChainId() (ChainName, ChainId string, // QueryContract executes the contract code at address with the given data // NOTE: there is no check on the caller; -func (burrowNodeClient *burrowNodeClient) QueryContract(callerAddress, calleeAddress, data []byte) (ret []byte, gasUsed int64, err error) { +func (burrowNodeClient *burrowNodeClient) QueryContract(callerAddress, calleeAddress acm.Address, + data []byte) (ret []byte, gasUsed uint64, err error) { + client := rpcclient.NewJSONRPCClient(burrowNodeClient.broadcastRPC) callResult, err := tendermint_client.Call(client, callerAddress, calleeAddress, data) if err != nil { err = fmt.Errorf("Error (%v) connnecting to node (%s) to query contract at (%X) with data (%X)", err.Error(), burrowNodeClient.broadcastRPC, calleeAddress, data) - return nil, int64(0), err + return } return callResult.Return, callResult.GasUsed, nil } // QueryContractCode executes the contract code at address with the given data but with provided code -func (burrowNodeClient *burrowNodeClient) QueryContractCode(address, code, data []byte) (ret []byte, gasUsed int64, err error) { +func (burrowNodeClient *burrowNodeClient) QueryContractCode(address acm.Address, code, + data []byte) (ret []byte, gasUsed uint64, err error) { + client := rpcclient.NewJSONRPCClient(burrowNodeClient.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. @@ -189,13 +183,13 @@ func (burrowNodeClient *burrowNodeClient) QueryContractCode(address, code, data if err != nil { err = fmt.Errorf("Error connnecting to node (%s) to query contract code at (%X) with data (%X) and code (%X)", burrowNodeClient.broadcastRPC, address, data, code, err.Error()) - return nil, int64(0), err + return nil, uint64(0), err } return callResult.Return, callResult.GasUsed, nil } // GetAccount returns a copy of the account -func (burrowNodeClient *burrowNodeClient) GetAccount(address []byte) (*acc.Account, error) { +func (burrowNodeClient *burrowNodeClient) GetAccount(address acm.Address) (acm.Account, error) { client := rpcclient.NewJSONRPCClient(burrowNodeClient.broadcastRPC) account, err := tendermint_client.GetAccount(client, address) if err != nil { @@ -208,35 +202,32 @@ func (burrowNodeClient *burrowNodeClient) GetAccount(address []byte) (*acc.Accou return nil, err } - return account.Copy(), nil + return account, nil } -// DumpStorage returns the full storage for an account. -func (burrowNodeClient *burrowNodeClient) DumpStorage(address []byte) (storage *core_types.Storage, err error) { +// DumpStorage returns the full storage for an acm. +func (burrowNodeClient *burrowNodeClient) DumpStorage(address acm.Address) (*rpc.ResultDumpStorage, error) { client := rpcclient.NewJSONRPCClient(burrowNodeClient.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", + return nil, fmt.Errorf("error connecting to node (%s) to get storage for account (%X): %s", burrowNodeClient.broadcastRPC, address, err.Error()) - return nil, err } - // UnwrapResultDumpStorage is an inefficient full deep copy, - // to transform the type to /core/types.Storage - // TODO: removing go-wire and go-rpc allows us to collapse these types - storage = tendermint_types.UnwrapResultDumpStorage(resultStorage) - return + return resultStorage, nil } //-------------------------------------------------------------------------------------------- // Name registry -func (burrowNodeClient *burrowNodeClient) GetName(name string) (owner []byte, data string, expirationBlock int, err error) { +func (burrowNodeClient *burrowNodeClient) GetName(name string) (owner acm.Address, data string, + expirationBlock uint64, err error) { + client := rpcclient.NewJSONRPCClient(burrowNodeClient.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)", burrowNodeClient.broadcastRPC, name) - return nil, "", 0, err + return acm.ZeroAddress, "", 0, err } // unwrap return results owner = entryResult.Owner @@ -247,19 +238,25 @@ func (burrowNodeClient *burrowNodeClient) GetName(name string) (owner []byte, da //-------------------------------------------------------------------------------------------- -func (burrowNodeClient *burrowNodeClient) ListValidators() (blockHeight int, - bondedValidators []consensus_types.Validator, unbondingValidators []consensus_types.Validator, err error) { +func (burrowNodeClient *burrowNodeClient) ListValidators() (blockHeight uint64, + bondedValidators, unbondingValidators []acm.Validator, err error) { + client := rpcclient.NewJSONRPCClient(burrowNodeClient.broadcastRPC) validatorsResult, err := tendermint_client.ListValidators(client) if err != nil { - err = fmt.Errorf("Error connecting to node (%s) to get validators", - burrowNodeClient.broadcastRPC) - return 0, nil, nil, err + err = fmt.Errorf("Error connecting to node (%s) to get validators", burrowNodeClient.broadcastRPC) + return } // unwrap return results blockHeight = validatorsResult.BlockHeight - bondedValidators = validatorsResult.BondedValidators - unbondingValidators = validatorsResult.UnbondingValidators + bondedValidators = make([]acm.Validator, len(validatorsResult.BondedValidators)) + for i, cv := range validatorsResult.BondedValidators { + bondedValidators[i] = cv.Validator() + } + unbondingValidators = make([]acm.Validator, len(validatorsResult.UnbondingValidators)) + for i, cv := range validatorsResult.UnbondingValidators { + unbondingValidators[i] = cv.Validator() + } return } diff --git a/client/rpc/client.go b/client/rpc/client.go index d6d7b14e..a874a2ee 100644 --- a/client/rpc/client.go +++ b/client/rpc/client.go @@ -19,8 +19,9 @@ import ( "fmt" "strconv" - ptypes "github.com/hyperledger/burrow/permission/types" + ptypes "github.com/hyperledger/burrow/permission" + acm "github.com/hyperledger/burrow/account" "github.com/hyperledger/burrow/client" "github.com/hyperledger/burrow/keys" "github.com/hyperledger/burrow/txs" @@ -40,14 +41,14 @@ func Send(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, addr, return nil, fmt.Errorf("destination address must be given with --to flag") } - toAddrBytes, err := hex.DecodeString(toAddr) + toAddress, err := addressFromHexString(toAddr) if err != nil { - return nil, fmt.Errorf("toAddr is bad hex: %v", err) + return nil, err } tx := txs.NewSendTx() - tx.AddInputWithNonce(pub, amt, int(nonce)) - tx.AddOutput(toAddrBytes, amt) + tx.AddInputWithNonce(pub, amt, nonce) + tx.AddOutput(toAddress, amt) return tx, nil } @@ -58,17 +59,22 @@ func Call(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, addr, return nil, err } - toAddrBytes, err := hex.DecodeString(toAddr) - if err != nil { - return nil, fmt.Errorf("toAddr is bad hex: %v", err) + var toAddress *acm.Address + + if toAddr != "" { + address, err := addressFromHexString(toAddr) + if err != nil { + return nil, fmt.Errorf("toAddr is bad hex: %v", err) + } + toAddress = &address } - fee, err := strconv.ParseInt(feeS, 10, 64) + fee, err := strconv.ParseUint(feeS, 10, 64) if err != nil { return nil, fmt.Errorf("fee is misformatted: %v", err) } - gas, err := strconv.ParseInt(gasS, 10, 64) + gas, err := strconv.ParseUint(gasS, 10, 64) if err != nil { return nil, fmt.Errorf("gas is misformatted: %v", err) } @@ -78,7 +84,7 @@ func Call(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, addr, return nil, fmt.Errorf("data is bad hex: %v", err) } - tx := txs.NewCallTxWithNonce(pub, toAddrBytes, dataBytes, amt, gas, fee, int(nonce)) + tx := txs.NewCallTxWithNonce(pub, toAddress, dataBytes, amt, gas, fee, nonce) return tx, nil } @@ -88,12 +94,12 @@ func Name(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, addr, return nil, err } - fee, err := strconv.ParseInt(feeS, 10, 64) + fee, err := strconv.ParseUint(feeS, 10, 64) if err != nil { return nil, fmt.Errorf("fee is misformatted: %v", err) } - tx := txs.NewNameTxWithNonce(pub, name, data, amt, fee, int(nonce)) + tx := txs.NewNameTxWithNonce(pub, name, data, amt, fee, nonce) return tx, nil } @@ -102,7 +108,7 @@ func Permissions(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, if err != nil { return nil, err } - var args ptypes.PermArgs + var args *ptypes.PermArgs switch permFunc { case "setBase": addr, pF, err := decodeAddressPermFlag(argsS[0], argsS[1]) @@ -120,13 +126,13 @@ func Permissions(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, } else { return nil, fmt.Errorf("Unknown value %s", argsS[2]) } - args = &ptypes.SetBaseArgs{addr, pF, value} + args = ptypes.SetBaseArgs(addr, pF, value) case "unsetBase": addr, pF, err := decodeAddressPermFlag(argsS[0], argsS[1]) if err != nil { return nil, err } - args = &ptypes.UnsetBaseArgs{addr, pF} + args = ptypes.UnsetBaseArgs(addr, pF) case "setGlobal": pF, err := ptypes.PermStringToFlag(argsS[0]) if err != nil { @@ -140,24 +146,24 @@ func Permissions(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, } else { return nil, fmt.Errorf("Unknown value %s", argsS[1]) } - args = &ptypes.SetGlobalArgs{pF, value} + args = ptypes.SetGlobalArgs(pF, value) case "addRole": - addr, err := hex.DecodeString(argsS[0]) + address, err := addressFromHexString(argsS[0]) if err != nil { return nil, err } - args = &ptypes.AddRoleArgs{addr, argsS[1]} + args = ptypes.AddRoleArgs(address, argsS[1]) case "removeRole": - addr, err := hex.DecodeString(argsS[0]) + address, err := addressFromHexString(argsS[0]) if err != nil { return nil, err } - args = &ptypes.RmRoleArgs{addr, argsS[1]} + args = ptypes.RemoveRoleArgs(address, argsS[1]) default: - return nil, fmt.Errorf("Invalid permission function for use in PermissionsTx: %s", permFunc) + return nil, fmt.Errorf("invalid permission function for use in PermissionsTx: %s", permFunc) } // args := snativeArgs( - tx := txs.NewPermissionsTxWithNonce(pub, args, int(nonce)) + tx := txs.NewPermissionsTxWithNonce(pub, args, nonce) return tx, nil } @@ -167,7 +173,7 @@ func Bond(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, unbond // if err != nil { // return nil, err // } - // var pubKey crypto.PubKeyEd25519 + // var pubKey acm.PublicKeyEd25519 // var unbondAddrBytes []byte // if unbondAddr == "" { @@ -241,7 +247,7 @@ type TxResult struct { Hash []byte // all txs get a hash // only CallTx - Address []byte // only for new contracts + Address *acm.Address // only for new contracts Return []byte Exception string @@ -252,7 +258,8 @@ type TxResult struct { // Preserve func SignAndBroadcast(chainID string, nodeClient client.NodeClient, keyClient keys.KeyClient, tx txs.Tx, sign, broadcast, wait bool) (txResult *TxResult, err error) { - var inputAddr []byte + + var inputAddr acm.Address if sign { inputAddr, tx, err = signTx(keyClient, chainID, tx) if err != nil { @@ -271,31 +278,34 @@ func SignAndBroadcast(chainID string, nodeClient client.NodeClient, keyClient ke confirmationChannel, err = wsClient.WaitForConfirmation(tx, chainID, inputAddr) if err != nil { return nil, err - } else { - defer func() { - if err != nil { - // if broadcast threw an error, just return - return - } - confirmation := <-confirmationChannel - if confirmation.Error != nil { - err = fmt.Errorf("Encountered error waiting for event: %s", confirmation.Error) - return - } - if confirmation.Exception != nil { - err = fmt.Errorf("Encountered Exception from chain: %s", confirmation.Exception) - return - } - txResult.BlockHash = confirmation.BlockHash - txResult.Exception = "" - eventDataTx, ok := confirmation.Event.(*txs.EventDataTx) - if !ok { - err = fmt.Errorf("Received wrong event type.") - return - } - txResult.Return = eventDataTx.Return - }() } + defer func() { + if err != nil { + // if broadcast threw an error, just return + return + } + if txResult == nil { + err = fmt.Errorf("txResult unexpectedly not initialised in SignAndBroadcast") + return + } + confirmation := <-confirmationChannel + if confirmation.Error != nil { + err = fmt.Errorf("encountered error waiting for event: %s", confirmation.Error) + return + } + if confirmation.Exception != nil { + err = fmt.Errorf("encountered Exception from chain: %s", confirmation.Exception) + return + } + txResult.BlockHash = confirmation.BlockHash + txResult.Exception = "" + eventDataTx := confirmation.EventDataTx + if eventDataTx == nil { + err = fmt.Errorf("EventDataTx was nil") + return + } + txResult.Return = eventDataTx.Return + }() } var receipt *txs.Receipt @@ -310,10 +320,19 @@ func SignAndBroadcast(chainID string, nodeClient client.NodeClient, keyClient ke // reasonable to get this returned from the chain directly. Alternatively, // the benefit is that the we don't need to trust the chain node if tx_, ok := tx.(*txs.CallTx); ok { - if len(tx_.Address) == 0 { - txResult.Address = txs.NewContractAddress(tx_.Input.Address, tx_.Input.Sequence) + if tx_.Address == nil { + address := acm.NewContractAddress(tx_.Input.Address, tx_.Input.Sequence) + txResult.Address = &address } } } return } + +func addressFromHexString(addrString string) (acm.Address, error) { + addrBytes, err := hex.DecodeString(addrString) + if err != nil { + return acm.Address{}, err + } + return acm.AddressFromBytes(addrBytes) +} diff --git a/client/rpc/client_test.go b/client/rpc/client_test.go index 603fe793..c731e491 100644 --- a/client/rpc/client_test.go +++ b/client/rpc/client_test.go @@ -22,6 +22,7 @@ import ( mockclient "github.com/hyperledger/burrow/client/mock" mockkeys "github.com/hyperledger/burrow/keys/mock" + "github.com/stretchr/testify/require" ) func Test(t *testing.T) { @@ -40,7 +41,7 @@ func testSend(t *testing.T, nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { // generate an ED25519 key and ripemd160 address - addressString := fmt.Sprintf("%X", keyClient.NewKey()) + addressString := keyClient.NewKey().String() // Public key can be queried from mockKeyClient.PublicKey(address) // but here we let the transaction factory retrieve the public key // which will then also overwrite the address we provide the function. @@ -48,7 +49,7 @@ func testSend(t *testing.T, // to address in generated transation. publicKeyString := "" // generate an additional address to send amount to - toAddressString := fmt.Sprintf("%X", keyClient.NewKey()) + toAddressString := keyClient.NewKey().String() // set an amount to transfer amountString := "1000" // unset nonce so that we retrieve nonce from account @@ -56,10 +57,7 @@ func testSend(t *testing.T, _, err := Send(nodeClient, keyClient, publicKeyString, addressString, toAddressString, amountString, nonceString) - if err != nil { - t.Logf("Error in SendTx: %s", err) - t.Fail() - } + require.NoError(t, err, "Error in Send") // assert.NotEqual(t, txSend) // TODO: test content of Transaction } @@ -68,7 +66,7 @@ func testCall(t *testing.T, nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { // generate an ED25519 key and ripemd160 address - addressString := fmt.Sprintf("%X", keyClient.NewKey()) + addressString := keyClient.NewKey().String() // Public key can be queried from mockKeyClient.PublicKey(address) // but here we let the transaction factory retrieve the public key // which will then also overwrite the address we provide the function. @@ -76,7 +74,7 @@ func testCall(t *testing.T, // to address in generated transation. publicKeyString := "" // generate an additional address to send amount to - toAddressString := fmt.Sprintf("%X", keyClient.NewKey()) + toAddressString := keyClient.NewKey().String() // set an amount to transfer amountString := "1000" // unset nonce so that we retrieve nonce from account @@ -101,7 +99,7 @@ func testName(t *testing.T, nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { // generate an ED25519 key and ripemd160 address - addressString := fmt.Sprintf("%X", keyClient.NewKey()) + addressString := keyClient.NewKey().String() // Public key can be queried from mockKeyClient.PublicKey(address) // but here we let the transaction factory retrieve the public key // which will then also overwrite the address we provide the function. @@ -132,7 +130,7 @@ func testPermissions(t *testing.T, nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { // generate an ED25519 key and ripemd160 address - addressString := fmt.Sprintf("%X", keyClient.NewKey()) + addressString := keyClient.NewKey().String() // Public key can be queried from mockKeyClient.PublicKey(address) // but here we let the transaction factory retrieve the public key // which will then also overwrite the address we provide the function. @@ -140,7 +138,7 @@ func testPermissions(t *testing.T, // to address in generated transation. publicKeyString := "" // generate an additional address to set permissions for - permAddressString := fmt.Sprintf("%X", keyClient.NewKey()) + permAddressString := keyClient.NewKey().String() // unset nonce so that we retrieve nonce from account nonceString := "" diff --git a/client/rpc/client_util.go b/client/rpc/client_util.go index 6711c1ad..02e6ae05 100644 --- a/client/rpc/client_util.go +++ b/client/rpc/client_util.go @@ -19,14 +19,14 @@ import ( "fmt" "strconv" - "github.com/tendermint/go-crypto" - - acc "github.com/hyperledger/burrow/account" + acm "github.com/hyperledger/burrow/account" "github.com/hyperledger/burrow/client" "github.com/hyperledger/burrow/keys" "github.com/hyperledger/burrow/logging" + "github.com/hyperledger/burrow/permission" ptypes "github.com/hyperledger/burrow/permission/types" "github.com/hyperledger/burrow/txs" + "github.com/tendermint/go-crypto" ) //------------------------------------------------------------------------------------ @@ -34,65 +34,71 @@ import ( // 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(keyClient keys.KeyClient, chainID string, tx_ txs.Tx) ([]byte, txs.Tx, error) { - signBytesString := fmt.Sprintf("%X", acc.SignBytes(chainID, tx_)) - var inputAddr []byte - var sigED crypto.SignatureEd25519 +func signTx(keyClient keys.KeyClient, chainID string, tx_ txs.Tx) (acm.Address, txs.Tx, error) { + signBytes := acm.SignBytes(chainID, tx_) + var err error switch tx := tx_.(type) { case *txs.SendTx: - inputAddr = tx.Inputs[0].Address - defer func(s *crypto.SignatureEd25519) { tx.Inputs[0].Signature = *s }(&sigED) + signAddress := tx.Inputs[0].Address + tx.Inputs[0].Signature, err = keyClient.Sign(signAddress, signBytes) + return signAddress, tx, err + case *txs.NameTx: - inputAddr = tx.Input.Address - defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + signAddress := tx.Input.Address + tx.Input.Signature, err = keyClient.Sign(signAddress, signBytes) + return signAddress, tx, err + case *txs.CallTx: - inputAddr = tx.Input.Address - defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + signAddress := tx.Input.Address + tx.Input.Signature, err = keyClient.Sign(signAddress, signBytes) + return signAddress, tx, err + case *txs.PermissionsTx: - inputAddr = tx.Input.Address - defer func(s *crypto.SignatureEd25519) { tx.Input.Signature = *s }(&sigED) + signAddress := tx.Input.Address + tx.Input.Signature, err = keyClient.Sign(signAddress, signBytes) + return signAddress, tx, err + case *txs.BondTx: - inputAddr = tx.Inputs[0].Address - defer func(s *crypto.SignatureEd25519) { - tx.Signature = *s - tx.Inputs[0].Signature = *s - }(&sigED) + signAddress := tx.Inputs[0].Address + tx.Signature, err = keyClient.Sign(signAddress, signBytes) + tx.Inputs[0].Signature = tx.Signature + return signAddress, tx, err + case *txs.UnbondTx: - inputAddr = tx.Address - defer func(s *crypto.SignatureEd25519) { tx.Signature = *s }(&sigED) + signAddress := tx.Address + tx.Signature, err = keyClient.Sign(signAddress, signBytes) + return signAddress, tx, err + case *txs.RebondTx: - inputAddr = tx.Address - defer func(s *crypto.SignatureEd25519) { tx.Signature = *s }(&sigED) - } - sig, err := keyClient.Sign(signBytesString, inputAddr) - if err != nil { - return nil, nil, err + signAddress := tx.Address + tx.Signature, err = keyClient.Sign(signAddress, signBytes) + return signAddress, tx, err + + default: + return acm.ZeroAddress, nil, fmt.Errorf("unknown transaction type for signTx: %#v", tx_) } - // TODO: [ben] temporarily address the type conflict here, to be cleaned up - // with full type restructuring - var sig64 [64]byte - copy(sig64[:], sig) - sigED = crypto.SignatureEd25519(sig64) - return inputAddr, tx_, nil } -func decodeAddressPermFlag(addrS, permFlagS string) (addr []byte, pFlag ptypes.PermFlag, err error) { - if addr, err = hex.DecodeString(addrS); err != nil { +func decodeAddressPermFlag(addrS, permFlagS string) (addr acm.Address, pFlag ptypes.PermFlag, err error) { + var addrBytes []byte + if addrBytes, err = hex.DecodeString(addrS); err != nil { + copy(addr[:], addrBytes) return } - if pFlag, err = ptypes.PermStringToFlag(permFlagS); err != nil { + if pFlag, err = permission.PermStringToFlag(permFlagS); err != nil { return } return } -func checkCommon(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, addr, amtS, nonceS string) (pub crypto.PubKey, amt int64, nonce int64, err error) { +func checkCommon(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, addr, amtS, + nonceS string) (pub acm.PublicKey, amt uint64, nonce uint64, 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 @@ -103,11 +109,16 @@ func checkCommon(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, "address", addr, ) } + var pubKeyBytes []byte pubKeyBytes, err = hex.DecodeString(pubkey) if err != nil { err = fmt.Errorf("pubkey is bad hex: %v", err) return } + + pubKeyEd25519 := crypto.PubKeyEd25519{} + copy(pubKeyEd25519[:], pubKeyBytes) + pub = acm.PublicKeyFromPubKey(pubKeyEd25519.Wrap()) } else { // grab the pubkey from monax-keys addressBytes, err2 := hex.DecodeString(addr) @@ -115,45 +126,42 @@ func checkCommon(nodeClient client.NodeClient, keyClient keys.KeyClient, pubkey, err = fmt.Errorf("Bad hex string for address (%s): %v", addr, err) return } - pubKeyBytes, err2 = keyClient.PublicKey(addressBytes) + address, err2 := acm.AddressFromBytes(addressBytes) + if err2 != nil { + err = fmt.Errorf("Could not convert bytes (%X) to address: %v", addressBytes, err2) + } + pub, err2 = keyClient.PublicKey(address) if err2 != nil { err = fmt.Errorf("Failed to fetch pubkey for address (%s): %v", addr, err2) return } } - if len(pubKeyBytes) == 0 { - err = fmt.Errorf("Error resolving public key") - return - } + var address acm.Address + address = pub.Address() - amt, err = strconv.ParseInt(amtS, 10, 64) + amt, err = strconv.ParseUint(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 nodeClient == nil { err = fmt.Errorf("input must specify a nonce with the --nonce flag or use --node-addr (or BURROW_CLIENT_NODE_ADDR) to fetch the nonce from a node") return } // fetch nonce from node - account, err2 := nodeClient.GetAccount(addrBytes) + account, err2 := nodeClient.GetAccount(address) if err2 != nil { return pub, amt, nonce, err2 } - nonce = int64(account.Sequence) + 1 + nonce = account.Sequence() + 1 logging.TraceMsg(nodeClient.Logger(), "Fetch nonce from node", "nonce", nonce, - "account address", addrBytes, + "account address", address, ) } else { - nonce, err = strconv.ParseInt(nonceS, 10, 64) + nonce, err = strconv.ParseUint(nonceS, 10, 64) if err != nil { err = fmt.Errorf("nonce is misformatted: %v", err) return diff --git a/client/websocket_client.go b/client/websocket_client.go index 428f78fd..6f943ae9 100644 --- a/client/websocket_client.go +++ b/client/websocket_client.go @@ -19,14 +19,17 @@ import ( "fmt" "time" - logging_types "github.com/hyperledger/burrow/logging/types" - "github.com/tendermint/go-rpc/client" - "github.com/tendermint/go-wire" + "encoding/json" + "github.com/hyperledger/burrow/account" + exe_events "github.com/hyperledger/burrow/execution/events" "github.com/hyperledger/burrow/logging" - tendermint_client "github.com/hyperledger/burrow/rpc/tendermint/client" - ctypes "github.com/hyperledger/burrow/rpc/tendermint/core/types" + logging_types "github.com/hyperledger/burrow/logging/types" + "github.com/hyperledger/burrow/rpc" + tendermint_client "github.com/hyperledger/burrow/rpc/tm/client" "github.com/hyperledger/burrow/txs" + "github.com/tendermint/tendermint/rpc/lib/client" + tm_types "github.com/tendermint/tendermint/types" ) const ( @@ -34,10 +37,10 @@ const ( ) type Confirmation struct { - BlockHash []byte - Event txs.EventData - Exception error - Error error + BlockHash []byte + EventDataTx *exe_events.EventDataTx + Exception error + Error error } // NOTE [ben] Compiler check to ensure burrowNodeClient successfully implements @@ -65,37 +68,40 @@ func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) Unsubscribe(subscrip // Returns a channel that will receive a confirmation with a result or the exception that // has been confirmed; or an error is returned and the confirmation channel is nil. -func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) WaitForConfirmation(tx txs.Tx, chainId string, inputAddr []byte) (chan Confirmation, error) { - // check no errors are reported on the websocket - if err := burrowNodeWebsocketClient.assertNoErrors(); err != nil { - return nil, err - } +func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) WaitForConfirmation(tx txs.Tx, chainId string, + inputAddr account.Address) (chan Confirmation, error) { // Setup the confirmation channel to be returned confirmationChannel := make(chan Confirmation, 1) var latestBlockHash []byte - eid := txs.EventStringAccInput(inputAddr) + eid := exe_events.EventStringAccInput(inputAddr) if err := burrowNodeWebsocketClient.Subscribe(eid); err != nil { return nil, fmt.Errorf("Error subscribing to AccInput event (%s): %v", eid, err) } - if err := burrowNodeWebsocketClient.Subscribe(txs.EventStringNewBlock()); err != nil { + if err := burrowNodeWebsocketClient.Subscribe(tm_types.EventStringNewBlock()); err != nil { return nil, fmt.Errorf("Error subscribing to NewBlock event: %v", err) } // Read the incoming events go func() { var err error for { - resultBytes := <-burrowNodeWebsocketClient.tendermintWebsocket.ResultsCh - result := new(ctypes.BurrowResult) - if wire.ReadJSONPtr(result, resultBytes, &err); err != nil { + response := <-burrowNodeWebsocketClient.tendermintWebsocket.ResponsesCh + if response.Error != nil { + logging.InfoMsg(burrowNodeWebsocketClient.logger, + "Error received on websocket channel", "error", err) + continue + } + result := new(rpc.Result) + + if json.Unmarshal(*response.Result, result); err != nil { // keep calm and carry on - logging.InfoMsg(burrowNodeWebsocketClient.logger, "Failed to unmarshal json bytes for websocket event", - "error", err) + logging.InfoMsg(burrowNodeWebsocketClient.logger, + "Failed to unmarshal json bytes for websocket event", "error", err) continue } - subscription, ok := (*result).(*ctypes.ResultSubscribe) + subscription, ok := result.Unwrap().(*rpc.ResultSubscribe) if ok { // Received confirmation of subscription to event streams // TODO: collect subscription IDs, push into channel and on completion @@ -106,16 +112,16 @@ func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) WaitForConfirmation( continue } - event, ok := (*result).(*ctypes.ResultEvent) + resultEvent, ok := result.Unwrap().(*rpc.ResultEvent) if !ok { // keep calm and carry on logging.InfoMsg(burrowNodeWebsocketClient.logger, "Failed to cast to ResultEvent for websocket event", - "event", event.Event) + "event", resultEvent.Event) continue } - blockData, ok := event.Data.(txs.EventDataNewBlock) - if ok { + blockData := resultEvent.EventDataNewBlock() + if blockData != nil { latestBlockHash = blockData.Block.Hash() logging.TraceMsg(burrowNodeWebsocketClient.logger, "Registered new block", "block", blockData.Block, @@ -136,47 +142,47 @@ func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) WaitForConfirmation( // continue // } - if event.Event != eid { + if resultEvent.Event != eid { logging.InfoMsg(burrowNodeWebsocketClient.logger, "Received unsolicited event", - "event_received", event.Event, + "event_received", resultEvent.Event, "event_expected", eid) continue } - data, ok := event.Data.(txs.EventDataTx) - if !ok { + eventDataTx := resultEvent.EventDataTx() + if eventDataTx == nil { // We are on the lookout for EventDataTx confirmationChannel <- Confirmation{ - BlockHash: latestBlockHash, - Event: nil, - Exception: fmt.Errorf("response error: expected result.Data to be *types.EventDataTx"), - Error: nil, + BlockHash: latestBlockHash, + EventDataTx: nil, + Exception: fmt.Errorf("response error: expected result.Data to be *types.EventDataTx"), + Error: nil, } return } - if !bytes.Equal(txs.TxHash(chainId, data.Tx), txs.TxHash(chainId, tx)) { + if !bytes.Equal(txs.TxHash(chainId, eventDataTx.Tx), txs.TxHash(chainId, tx)) { logging.TraceMsg(burrowNodeWebsocketClient.logger, "Received different event", // TODO: consider re-implementing TxID again, or other more clear debug - "received transaction event", txs.TxHash(chainId, data.Tx)) + "received transaction event", txs.TxHash(chainId, eventDataTx.Tx)) continue } - if data.Exception != "" { + if eventDataTx.Exception != "" { confirmationChannel <- Confirmation{ - BlockHash: latestBlockHash, - Event: &data, - Exception: fmt.Errorf("Transaction confirmed with exception: %v", data.Exception), - Error: nil, + BlockHash: latestBlockHash, + EventDataTx: eventDataTx, + Exception: fmt.Errorf("Transaction confirmed with exception: %v", eventDataTx.Exception), + Error: nil, } return } // success, return the full event and blockhash and exit go-routine confirmationChannel <- Confirmation{ - BlockHash: latestBlockHash, - Event: &data, - Exception: nil, - Error: nil, + BlockHash: latestBlockHash, + EventDataTx: eventDataTx, + Exception: nil, + Error: nil, } return } @@ -190,10 +196,10 @@ func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) WaitForConfirmation( go func() { <-timeout confirmationChannel <- Confirmation{ - BlockHash: nil, - Event: nil, - Exception: nil, - Error: fmt.Errorf("timed out waiting for event"), + BlockHash: nil, + EventDataTx: nil, + Exception: nil, + Error: fmt.Errorf("timed out waiting for event"), } }() return confirmationChannel, nil @@ -204,16 +210,3 @@ func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) Close() { burrowNodeWebsocketClient.tendermintWebsocket.Stop() } } - -func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) assertNoErrors() error { - if burrowNodeWebsocketClient.tendermintWebsocket != nil { - select { - case err := <-burrowNodeWebsocketClient.tendermintWebsocket.ErrorsCh: - return err - default: - return nil - } - } else { - return fmt.Errorf("burrow-client has no websocket initialised.") - } -} -- GitLab