From e2a168ea9a6295d60d5af4cfe0c711fde974afc3 Mon Sep 17 00:00:00 2001 From: Silas Davis <silas@monax.io> Date: Tue, 13 Feb 2018 22:44:38 +0000 Subject: [PATCH] Make keys_client_test a monax-keys binary-based integration test Signed-off-by: Silas Davis <silas@monax.io> --- .circleci/config.yml | 3 +- Makefile | 5 - account/account.go | 17 ++- account/account_test.go | 14 ++- account/crypto.go | 46 +++++--- account/private_account.go | 3 + client/mock/client_mock.go | 7 +- consensus/tendermint/query/node_view.go | 4 +- core/kernel.go | 5 +- execution/execution_test.go | 30 ++++-- execution/state.go | 25 +++-- execution/state_test.go | 9 +- genesis/deterministic_genesis.go | 9 +- keys/integration/key_client_test.go | 134 ++++++++++++++++++++++++ keys/key_client_test.go | 87 --------------- keys/mock/key_client_mock.go | 2 +- rpc/service.go | 6 +- rpc/v0/codec_test.go | 14 ++- 18 files changed, 261 insertions(+), 159 deletions(-) create mode 100644 keys/integration/key_client_test.go delete mode 100644 keys/key_client_test.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 48e2a273..24d6db7a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -38,10 +38,9 @@ jobs: steps: - attach_workspace: at: . - - run: go get -u github.com/monax/keys/cmd/monax-keys - run: sudo apt-get install libgmp3-dev - run: make test_integration - + ensure_vendor: <<: *defaults steps: diff --git a/Makefile b/Makefile index d796092b..00f9c54a 100644 --- a/Makefile +++ b/Makefile @@ -133,13 +133,8 @@ test: check .PHONY: test_integration test_integration: -<<<<<<< Updated upstream -||||||| merged common ancestors @go get -u github.com/monax/keys/cmd/monax-keys @go test ./keys/integration -tags integration -======= - @go test ./keys/integration -tags integration ->>>>>>> Stashed changes @go test ./rpc/tm/integration -tags integration # test burrow with checks for race conditions diff --git a/account/account.go b/account/account.go index 532bc9e3..f17ceeae 100644 --- a/account/account.go +++ b/account/account.go @@ -65,7 +65,7 @@ type Account interface { Permissions() ptypes.AccountPermissions // Obtain a deterministic serialisation of this account // (i.e. update order and Go runtime independent) - Encode() []byte + Encode() ([]byte, error) } type MutableAccount interface { @@ -118,7 +118,7 @@ func NewConcreteAccount(pubKey PublicKey) ConcreteAccount { } func NewConcreteAccountFromSecret(secret string) ConcreteAccount { - return NewConcreteAccount(PublicKeyFromGoCryptoPubKey(PrivateKeyFromSecret(secret).PubKey())) + return NewConcreteAccount(PrivateKeyFromSecret(secret).PublicKey()) } // Return as immutable Account @@ -131,8 +131,15 @@ func (acc ConcreteAccount) MutableAccount() MutableAccount { return concreteAccountWrapper{&acc} } -func (acc *ConcreteAccount) Encode() []byte { - return wire.BinaryBytes(acc) +func (acc *ConcreteAccount) Encode() ([]byte, error) { + buf := new(bytes.Buffer) + var n int + var err error + wire.WriteBinary(acc, buf, &n, &err) + if err != nil { + return nil, err + } + return buf.Bytes(), nil } func (acc *ConcreteAccount) Copy() *ConcreteAccount { @@ -255,7 +262,7 @@ func (caw concreteAccountWrapper) Permissions() ptypes.AccountPermissions { return caw.ConcreteAccount.Permissions } -func (caw concreteAccountWrapper) Encode() []byte { +func (caw concreteAccountWrapper) Encode() ([]byte, error) { return caw.ConcreteAccount.Encode() } diff --git a/account/account_test.go b/account/account_test.go index f8c775cf..800ea4ff 100644 --- a/account/account_test.go +++ b/account/account_test.go @@ -69,7 +69,8 @@ func TestAccountSerialise(t *testing.T) { accStructOut := AccountContainingStruct{} // We must pass in a value type to read from (accStruct), but provide a pointer type to write into (accStructout - wire.ReadBinaryBytes(wire.BinaryBytes(accStruct), &accStructOut) + err := wire.ReadBinaryBytes(wire.BinaryBytes(accStruct), &accStructOut) + require.NoError(t, err) assert.Equal(t, accStruct, accStructOut) } @@ -77,7 +78,8 @@ func TestAccountSerialise(t *testing.T) { func TestDecodeConcrete(t *testing.T) { concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret") acc := concreteAcc.Account() - encodedAcc := acc.Encode() + encodedAcc, err := acc.Encode() + require.NoError(t, err) concreteAccOut, err := DecodeConcrete(encodedAcc) require.NoError(t, err) assert.Equal(t, concreteAcc, *concreteAccOut) @@ -88,12 +90,14 @@ func TestDecodeConcrete(t *testing.T) { func TestDecode(t *testing.T) { concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret") acc := concreteAcc.Account() - accOut, err := Decode(acc.Encode()) - assert.NoError(t, err) + encodedAcc, err := acc.Encode() + require.NoError(t, err) + accOut, err := Decode(encodedAcc) + require.NoError(t, err) assert.Equal(t, concreteAcc, *AsConcreteAccount(accOut)) accOut, err = Decode([]byte("flungepliffery munknut tolopops")) - assert.Error(t, err) + require.Error(t, err) assert.Nil(t, accOut) } diff --git a/account/crypto.go b/account/crypto.go index e04f257f..942901a3 100644 --- a/account/crypto.go +++ b/account/crypto.go @@ -19,13 +19,18 @@ type Signer interface { } // PublicKey - type PublicKey struct { crypto.PubKey `json:"unwrap"` } -func PublicKeyFromGoCryptoPubKey(pubKey crypto.PubKey) PublicKey { - return PublicKey{PubKey: pubKey} +func PublicKeyFromGoCryptoPubKey(pubKey crypto.PubKey) (PublicKey, error) { + _, err := AddressFromBytes(pubKey.Address()) + if err != nil { + return PublicKey{}, fmt.Errorf("could not make valid address from public key %v: %v", pubKey, err) + } + return PublicKey{ + PubKey: pubKey, + }, nil } // Currently this is a stub that reads the raw bytes returned by key_client and returns @@ -39,9 +44,7 @@ func PublicKeyFromBytes(bs []byte) (PublicKey, error) { len(bs), len(pubKeyEd25519)) } copy(pubKeyEd25519[:], bs) - return PublicKey{ - PubKey: pubKeyEd25519.Wrap(), - }, nil + return PublicKeyFromGoCryptoPubKey(pubKeyEd25519.Wrap()) } // Returns a copy of the raw untyped public key bytes @@ -65,6 +68,9 @@ func (pk PublicKey) VerifyBytes(msg []byte, signature Signature) bool { } func (pk PublicKey) Address() Address { + // We check this on initialisation to avoid this panic, but returning an error here is ugly and caching + // the address on PublicKey initialisation breaks go-wire serialisation since with unwrap we can only have one field. + // We can do something better with better serialisation return MustAddressFromBytes(pk.PubKey.Address()) } @@ -90,8 +96,14 @@ type PrivateKey struct { crypto.PrivKey `json:"unwrap"` } -func PrivateKeyFromGoCryptoPrivKey(privKey crypto.PrivKey) PrivateKey { - return PrivateKey{PrivKey: privKey} +func PrivateKeyFromGoCryptoPrivKey(privKey crypto.PrivKey) (PrivateKey, error) { + _, err := PublicKeyFromGoCryptoPubKey(privKey.PubKey()) + if err != nil { + return PrivateKey{}, fmt.Errorf("could not create public key from private key: %v", err) + } + return PrivateKey{ + PrivKey: privKey, + }, nil } func PrivateKeyFromSecret(secret string) PrivateKey { @@ -126,9 +138,7 @@ func Ed25519PrivateKeyFromRawBytes(privKeyBytes []byte) (PrivateKey, error) { return PrivateKey{}, err } copy(privKeyEd25519[:], privKeyBytes) - return PrivateKey{ - PrivKey: privKeyEd25519.Wrap(), - }, nil + return PrivateKeyFromGoCryptoPrivKey(privKeyEd25519.Wrap()) } // Ensures the last 32 bytes of the ed25519 private key is the public key derived from the first 32 private bytes @@ -148,6 +158,16 @@ func EnsureEd25519PrivateKeyCorrect(candidatePrivateKey ed25519.PrivateKey) erro return nil } +func (pk PrivateKey) PublicKey() PublicKey { + publicKey, err := PublicKeyFromGoCryptoPubKey(pk.PrivKey.PubKey()) + if err != nil { + // We check this on initialisation to avoid this panic, but returning an error here is ugly and caching + // the public key on PrivateKey on initialisation breaks go-wire. We can do something better with better serialisation + panic(fmt.Errorf("error making public key from private key: %v", publicKey)) + } + return publicKey +} + // Returns a copy of the raw untyped private key bytes func (pk PrivateKey) RawBytes() []byte { switch privKey := pk.PrivKey.Unwrap().(type) { @@ -164,10 +184,6 @@ func (pk PrivateKey) RawBytes() []byte { } } -func (pk PrivateKey) PublicKey() PublicKey { - return PublicKeyFromGoCryptoPubKey(pk.PubKey()) -} - func (pk PrivateKey) Sign(msg []byte) (Signature, error) { return Signature{Signature: pk.PrivKey.Sign(msg)}, nil } diff --git a/account/private_account.go b/account/private_account.go index d1c46644..59f8245f 100644 --- a/account/private_account.go +++ b/account/private_account.go @@ -55,6 +55,7 @@ func AsConcretePrivateAccount(privateAccount PrivateAccount) *ConcretePrivateAcc PrivateKey: privateAccount.PrivateKey(), } } + func (cpaw concretePrivateAccountWrapper) Address() Address { return cpaw.ConcretePrivateAccount.Address } @@ -67,6 +68,8 @@ func (cpaw concretePrivateAccountWrapper) PrivateKey() PrivateKey { return cpaw.ConcretePrivateAccount.PrivateKey } +// ConcretePrivateAccount + func (pa ConcretePrivateAccount) PrivateAccount() PrivateAccount { return concretePrivateAccountWrapper{ConcretePrivateAccount: &pa} } diff --git a/client/mock/client_mock.go b/client/mock/client_mock.go index 9ae5f192..5e195aef 100644 --- a/client/mock/client_mock.go +++ b/client/mock/client_mock.go @@ -51,12 +51,7 @@ func (mock *MockNodeClient) DeriveWebsocketClient() (nodeWsClient NodeWebsocketC func (mock *MockNodeClient) GetAccount(address acm.Address) (acm.Account, error) { // make zero account - return acm.ConcreteAccount{ - Address: address, - PublicKey: acm.PublicKeyFromGoCryptoPubKey(crypto.PubKeyEd25519{}.Wrap()), - Code: make([]byte, 0), - StorageRoot: make([]byte, 0), - }.Account(), nil + return acm.FromAddressable(acm.GeneratePrivateAccountFromSecret("mock-node-client-account")), nil } func (mock *MockNodeClient) MockAddAccount(account *acm.ConcreteAccount) { diff --git a/consensus/tendermint/query/node_view.go b/consensus/tendermint/query/node_view.go index 7aa45176..b0ecc2bd 100644 --- a/consensus/tendermint/query/node_view.go +++ b/consensus/tendermint/query/node_view.go @@ -15,7 +15,7 @@ import ( // You're like the interface I never had type NodeView interface { // PrivValidator public key - PrivValidatorPublicKey() acm.PublicKey + PrivValidatorPublicKey() (acm.PublicKey, error) // NodeInfo for this node broadcast to other nodes (including ephemeral STS ED25519 public key) NodeInfo() *p2p.NodeInfo // Whether the Tendermint node is listening @@ -46,7 +46,7 @@ func NewNodeView(tmNode *node.Node, txDecoder txs.Decoder) NodeView { } } -func (nv *nodeView) PrivValidatorPublicKey() acm.PublicKey { +func (nv *nodeView) PrivValidatorPublicKey() (acm.PublicKey, error) { return acm.PublicKeyFromGoCryptoPubKey(nv.tmNode.PrivValidator().GetPubKey()) } diff --git a/core/kernel.go b/core/kernel.go index 8f7b04f3..89123de5 100644 --- a/core/kernel.go +++ b/core/kernel.go @@ -64,7 +64,10 @@ func NewKernel(privValidator tm_types.PrivValidator, genesisDoc *genesis.Genesis logger = logging.WithScope(logger, "NewKernel") stateDB := dbm.NewDB("burrow_state", dbm.GoLevelDBBackendStr, tmConf.DBDir()) - state := execution.MakeGenesisState(stateDB, genesisDoc) + state, err := execution.MakeGenesisState(stateDB, genesisDoc) + if err != nil { + return nil, fmt.Errorf("could not make genesis state: %v", err) + } state.Save() blockchain := bcm.NewBlockchain(genesisDoc) diff --git a/execution/execution_test.go b/execution/execution_test.go index 7d1ac046..a6774d05 100644 --- a/execution/execution_test.go +++ b/execution/execution_test.go @@ -35,6 +35,7 @@ import ( "github.com/hyperledger/burrow/permission" ptypes "github.com/hyperledger/burrow/permission/types" "github.com/hyperledger/burrow/txs" + "github.com/stretchr/testify/require" dbm "github.com/tendermint/tmlibs/db" ) @@ -168,7 +169,8 @@ func TestSendFails(t *testing.T) { genDoc.Accounts[1].Permissions.Base.Set(permission.Send, true) genDoc.Accounts[2].Permissions.Base.Set(permission.Call, true) genDoc.Accounts[3].Permissions.Base.Set(permission.CreateContract, true) - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //------------------- @@ -235,7 +237,8 @@ func TestName(t *testing.T) { genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions) genDoc.Accounts[0].Permissions.Base.Set(permission.Send, true) genDoc.Accounts[1].Permissions.Base.Set(permission.Name, true) - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //------------------- @@ -270,7 +273,8 @@ func TestCallFails(t *testing.T) { genDoc.Accounts[1].Permissions.Base.Set(permission.Send, true) genDoc.Accounts[2].Permissions.Base.Set(permission.Call, true) genDoc.Accounts[3].Permissions.Base.Set(permission.CreateContract, true) - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //------------------- @@ -339,7 +343,8 @@ func TestSendPermission(t *testing.T) { stateDB := dbm.NewDB("state", dbBackend, dbDir) genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions) genDoc.Accounts[0].Permissions.Base.Set(permission.Send, true) // give the 0 account permission - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) // A single input, having the permission, should succeed @@ -375,7 +380,8 @@ func TestCallPermission(t *testing.T) { stateDB := dbm.NewDB("state", dbBackend, dbDir) genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions) genDoc.Accounts[0].Permissions.Base.Set(permission.Call, true) // give the 0 account permission - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //------------------------------ @@ -498,7 +504,8 @@ func TestCreatePermission(t *testing.T) { genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions) genDoc.Accounts[0].Permissions.Base.Set(permission.CreateContract, true) // give the 0 account permission genDoc.Accounts[0].Permissions.Base.Set(permission.Call, true) // give the 0 account permission - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //------------------------------ @@ -613,7 +620,7 @@ func TestCreatePermission(t *testing.T) { func TestBondPermission(t *testing.T) { stateDB := dbm.NewDB("state",dbBackend,dbDir) genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) batchCommitter := makeExecutor(st) var bondAcc *acm.Account @@ -740,7 +747,8 @@ func TestCreateAccountPermission(t *testing.T) { genDoc.Accounts[0].Permissions.Base.Set(permission.Send, true) // give the 0 account permission genDoc.Accounts[1].Permissions.Base.Set(permission.Send, true) // give the 0 account permission genDoc.Accounts[0].Permissions.Base.Set(permission.CreateAccount, true) // give the 0 account permission - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //---------------------------------------------------------- @@ -888,7 +896,8 @@ func TestSNativeCALL(t *testing.T) { genDoc.Accounts[3].Permissions.Base.Set(permission.Bond, true) // some arbitrary permission to play with genDoc.Accounts[3].Permissions.AddRole("bumble") genDoc.Accounts[3].Permissions.AddRole("bee") - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //---------------------------------------------------------- @@ -1023,7 +1032,8 @@ func TestSNativeTx(t *testing.T) { genDoc.Accounts[3].Permissions.Base.Set(permission.Bond, true) // some arbitrary permission to play with genDoc.Accounts[3].Permissions.AddRole("bumble") genDoc.Accounts[3].Permissions.AddRole("bee") - st := MakeGenesisState(stateDB, &genDoc) + st, err := MakeGenesisState(stateDB, &genDoc) + require.NoError(t, err) batchCommitter := makeExecutor(st) //---------------------------------------------------------- diff --git a/execution/state.go b/execution/state.go index eb71cf6b..6928480b 100644 --- a/execution/state.go +++ b/execution/state.go @@ -27,7 +27,6 @@ import ( "github.com/hyperledger/burrow/permission" ptypes "github.com/hyperledger/burrow/permission" "github.com/hyperledger/burrow/txs" - "github.com/hyperledger/burrow/util" "github.com/tendermint/go-wire" "github.com/tendermint/merkleeyes/iavl" dbm "github.com/tendermint/tmlibs/db" @@ -67,9 +66,9 @@ var _ acm.StateIterable = &State{} var _ acm.StateWriter = &State{} -func MakeGenesisState(db dbm.DB, genDoc *genesis.GenesisDoc) *State { +func MakeGenesisState(db dbm.DB, genDoc *genesis.GenesisDoc) (*State, error) { if len(genDoc.Validators) == 0 { - util.Fatalf("The genesis file has no validators") + return nil, fmt.Errorf("the genesis file has no validators") } if genDoc.GenesisTime.IsZero() { @@ -90,7 +89,11 @@ func MakeGenesisState(db dbm.DB, genDoc *genesis.GenesisDoc) *State { Balance: genAcc.Amount, Permissions: perm, } - accounts.Set(acc.Address.Bytes(), acc.Encode()) + encodedAcc, err := acc.Encode() + if err != nil { + return nil, err + } + accounts.Set(acc.Address.Bytes(), encodedAcc) } // global permissions are saved as the 0 address @@ -106,7 +109,11 @@ func MakeGenesisState(db dbm.DB, genDoc *genesis.GenesisDoc) *State { Balance: 1337, Permissions: globalPerms, } - accounts.Set(permsAcc.Address.Bytes(), permsAcc.Encode()) + encodedPermsAcc, err := permsAcc.Encode() + if err != nil { + return nil, err + } + accounts.Set(permsAcc.Address.Bytes(), encodedPermsAcc) // Make validatorInfos state tree && validators slice /* @@ -158,7 +165,7 @@ func MakeGenesisState(db dbm.DB, genDoc *genesis.GenesisDoc) *State { accounts: accounts, //validatorInfos: validatorInfos, nameReg: nameReg, - } + }, nil } func LoadState(db dbm.DB) (*State, error) { @@ -248,7 +255,11 @@ func (s *State) GetAccount(address acm.Address) (acm.Account, error) { func (s *State) UpdateAccount(account acm.Account) error { s.Lock() defer s.Unlock() - s.accounts.Set(account.Address().Bytes(), account.Encode()) + encodedAccount, err := account.Encode() + if err != nil { + return err + } + s.accounts.Set(account.Address().Bytes(), encodedAccount) return nil } diff --git a/execution/state_test.go b/execution/state_test.go index 8ffb5ff2..3297a0d9 100644 --- a/execution/state_test.go +++ b/execution/state_test.go @@ -22,6 +22,7 @@ import ( "fmt" "github.com/hyperledger/burrow/execution/evm/sha3" + "github.com/stretchr/testify/require" "time" @@ -71,7 +72,10 @@ func makeGenesisState(numAccounts int, randBalance bool, minBalance uint64, numV minBonded int64) (*State, []acm.PrivateAccount) { testGenesisDoc, privAccounts := deterministicGenesis.GenesisDoc(numAccounts, randBalance, minBalance, numValidators, randBonded, minBonded) - s0 := MakeGenesisState(dbm.NewMemDB(), testGenesisDoc) + s0, err := MakeGenesisState(dbm.NewMemDB(), testGenesisDoc) + if err != nil { + panic(fmt.Errorf("could not make genesis state: %v", err)) + } s0.Save() return s0, privAccounts } @@ -275,7 +279,8 @@ func TestTxSequence(t *testing.T) { } func TestNameTxs(t *testing.T) { - state := MakeGenesisState(dbm.NewMemDB(), testGenesisDoc) + state, err := MakeGenesisState(dbm.NewMemDB(), testGenesisDoc) + require.NoError(t, err) state.Save() txs.MinNameRegistrationPeriod = 5 diff --git a/genesis/deterministic_genesis.go b/genesis/deterministic_genesis.go index 19d94cbf..d511cc20 100644 --- a/genesis/deterministic_genesis.go +++ b/genesis/deterministic_genesis.go @@ -64,15 +64,14 @@ func (dg *deterministicGenesis) GenesisDoc(numAccounts int, randBalance bool, mi } func (dg *deterministicGenesis) Account(randBalance bool, minBalance uint64) (acm.Account, acm.PrivateAccount) { - privKey, err := acm.GeneratePrivateKey(dg.random) + privateKey, err := acm.GeneratePrivateKey(dg.random) if err != nil { panic(fmt.Errorf("could not generate private key deterministically")) } - pubKey := acm.PublicKeyFromGoCryptoPubKey(privKey.PubKey()) privAccount := &acm.ConcretePrivateAccount{ - PublicKey: pubKey, - PrivateKey: privKey, - Address: pubKey.Address(), + PublicKey: privateKey.PublicKey(), + PrivateKey: privateKey, + Address: privateKey.PublicKey().Address(), } perms := permission.DefaultAccountPermissions acc := &acm.ConcreteAccount{ diff --git a/keys/integration/key_client_test.go b/keys/integration/key_client_test.go new file mode 100644 index 00000000..f165074b --- /dev/null +++ b/keys/integration/key_client_test.go @@ -0,0 +1,134 @@ +// +build integration + +// Space above here matters +package integration + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "testing" + "time" + + acm "github.com/hyperledger/burrow/account" + "github.com/hyperledger/burrow/keys" + "github.com/hyperledger/burrow/logging/loggers" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +//var logger, _ = lifecycle.NewStdErrLogger() +var logger = loggers.NewNoopInfoTraceLogger() + +const monaxKeysBin = "monax-keys" +const keysHost = "localhost" +const keysPort = "56667" +const keysTimeoutSeconds = 3 + +var rpcString = fmt.Sprintf("http://%s:%s", keysHost, keysPort) + +func TestMain(m *testing.M) { + fmt.Fprint(os.Stderr, "Running monax-keys using test main\n") + _, err := exec.LookPath(monaxKeysBin) + if err != nil { + fatalf("could not run keys integration tests because could not find keys binary: %v", err) + } + + keysDir, err := ioutil.TempDir("", "key_client_test") + if err != nil { + fatalf("could not create temp dir: %v", err) + } + cmd := exec.Command(monaxKeysBin, "server", "--dir", keysDir, "--port", keysPort) + err = cmd.Start() + if err != nil { + fatalf("could not start command: %v", err) + } + + select { + case <-waitKeysRunning(): + // A plain call to os.Exit will terminate before deferred calls run, so defer that too. + defer os.Exit(m.Run()) + case <-time.After(keysTimeoutSeconds * time.Second): + defer fatalf("timed out waiting for monax-keys to become live") + } + + defer func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Fprintf(os.Stderr, "Error killing monax-keys from test main:%v\n", err) + } + fmt.Fprint(os.Stderr, "Killed monax-keys from test main\n") + }() +} + +func TestMonaxKeyClient_Generate(t *testing.T) { + keyClient := keys.NewKeyClient(rpcString, logger) + addr, err := keyClient.Generate("I'm a lovely hat", keys.KeyTypeEd25519Ripemd160) + assert.NoError(t, err) + assert.NotEqual(t, acm.ZeroAddress, addr) +} + +func TestMonaxKeyClient_PublicKey(t *testing.T) { + keyClient := keys.NewKeyClient(rpcString, logger) + addr, err := keyClient.Generate("I'm a lovely hat", keys.KeyTypeEd25519Ripemd160) + assert.NoError(t, err) + pubKey, err := keyClient.PublicKey(addr) + assert.Equal(t, addr, pubKey.Address()) +} + +func TestMonaxKeyClient_PublicKey_NonExistent(t *testing.T) { + keyClient := keys.NewKeyClient(rpcString, logger) + _, err := keyClient.PublicKey(acm.Address{8, 7, 6, 222}) + assert.Error(t, err) +} + +func TestMonaxKeyClient_Sign(t *testing.T) { + keyClient := keys.NewKeyClient(rpcString, logger) + addr, err := keyClient.Generate("I'm a lovely hat", keys.KeyTypeEd25519Ripemd160) + require.NoError(t, err) + pubKey, err := keyClient.PublicKey(addr) + assert.NoError(t, err) + message := []byte("I'm a hat, a hat, a hat") + signature, err := keyClient.Sign(addr, message) + assert.NoError(t, err) + assert.True(t, pubKey.VerifyBytes(message, signature), "signature should verify message") +} + +func TestMonaxKeyClient_HealthCheck(t *testing.T) { + deadKeyClient := keys.NewKeyClient("http://localhost:99999", logger) + assert.NotNil(t, deadKeyClient.HealthCheck()) + keyClient := keys.NewKeyClient(rpcString, logger) + assert.Nil(t, keyClient.HealthCheck()) +} + +func TestPublicKeyAddressAgreement(t *testing.T) { + keyClient := keys.NewKeyClient(rpcString, logger) + addr, err := keyClient.Generate("I'm a lovely hat", keys.KeyTypeEd25519Ripemd160) + require.NoError(t, err) + pubKey, err := keyClient.PublicKey(addr) + addrOut := pubKey.Address() + require.NoError(t, err) + assert.Equal(t, addr, addrOut) +} + +func fatalf(format string, a ...interface{}) { + fmt.Fprintf(os.Stderr, format, a...) + os.Exit(1) +} + +func waitKeysRunning() chan bool { + ch := make(chan bool) + keyClient := keys.NewKeyClient(rpcString, logger) + go func() { + for { + err := keyClient.HealthCheck() + if err == nil { + ch <- true + return + } + } + + }() + return ch +} diff --git a/keys/key_client_test.go b/keys/key_client_test.go deleted file mode 100644 index b1c68678..00000000 --- a/keys/key_client_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package keys - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - - acm "github.com/hyperledger/burrow/account" - "github.com/hyperledger/burrow/logging/loggers" - "github.com/monax/keys/monax-keys" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -//var logger, _ = lifecycle.NewStdErrLogger() -var logger = loggers.NewNoopInfoTraceLogger() - -const keysHost = "localhost" -const keysPort = "56757" - -var rpcString = fmt.Sprintf("http://%s:%s", keysHost, keysPort) - -func TestMain(m *testing.M) { - var err error - keys.KeysDir, err = ioutil.TempDir("", "key_client_test") - if err != nil { - fatalf("couldn't create temp dir: %v", err) - } - go keys.StartServer(keysHost, keysPort) - os.Exit(m.Run()) -} - -func TestMonaxKeyClient_Generate(t *testing.T) { - keyClient := NewKeyClient(rpcString, logger) - addr, err := keyClient.Generate("I'm a lovely hat", KeyTypeEd25519Ripemd160) - assert.NoError(t, err) - assert.NotEqual(t, acm.ZeroAddress, addr) -} - -func TestMonaxKeyClient_PublicKey(t *testing.T) { - keyClient := NewKeyClient(rpcString, logger) - addr, err := keyClient.Generate("I'm a lovely hat", KeyTypeEd25519Ripemd160) - assert.NoError(t, err) - pubKey, err := keyClient.PublicKey(addr) - assert.Equal(t, addr, pubKey.Address()) -} - -func TestMonaxKeyClient_PublicKey_NonExistent(t *testing.T) { - keyClient := NewKeyClient(rpcString, logger) - _, err := keyClient.PublicKey(acm.Address{8, 7, 6, 222}) - assert.Error(t, err) -} - -func TestMonaxKeyClient_Sign(t *testing.T) { - keyClient := NewKeyClient(rpcString, logger) - addr, err := keyClient.Generate("I'm a lovely hat", KeyTypeEd25519Ripemd160) - require.NoError(t, err) - pubKey, err := keyClient.PublicKey(addr) - assert.NoError(t, err) - message := []byte("I'm a hat, a hat, a hat") - signature, err := keyClient.Sign(addr, message) - assert.NoError(t, err) - assert.True(t, pubKey.VerifyBytes(message, signature), "signature should verify message") -} - -func TestMonaxKeyClient_HealthCheck(t *testing.T) { - deadKeyClient := NewKeyClient("http://localhost:99999", logger) - assert.NotNil(t, deadKeyClient.HealthCheck()) - keyClient := NewKeyClient(rpcString, logger) - assert.Nil(t, keyClient.HealthCheck()) -} - -func TestPublicKeyAddressAgreement(t *testing.T) { - keyClient := NewKeyClient(rpcString, logger) - addr, err := keyClient.Generate("I'm a lovely hat", KeyTypeEd25519Ripemd160) - require.NoError(t, err) - pubKey, err := keyClient.PublicKey(addr) - addrOut := pubKey.Address() - require.NoError(t, err) - assert.Equal(t, addr, addrOut) -} - -func fatalf(format string, a ...interface{}) { - fmt.Fprintf(os.Stderr, format, a...) - os.Exit(1) -} diff --git a/keys/mock/key_client_mock.go b/keys/mock/key_client_mock.go index 53b311ae..2254c110 100644 --- a/keys/mock/key_client_mock.go +++ b/keys/mock/key_client_mock.go @@ -104,7 +104,7 @@ func (mock *MockKeyClient) PublicKey(address acm.Address) (acm.PublicKey, error) } pubKeyEd25519 := crypto.PubKeyEd25519{} copy(pubKeyEd25519[:], key.PublicKey) - return acm.PublicKeyFromGoCryptoPubKey(pubKeyEd25519.Wrap()), nil + return acm.PublicKeyFromGoCryptoPubKey(pubKeyEd25519.Wrap()) } func (mock *MockKeyClient) Generate(keyName string, keyType KeyType) (acm.Address, error) { diff --git a/rpc/service.go b/rpc/service.go index 8ccc0725..bab21407 100644 --- a/rpc/service.go +++ b/rpc/service.go @@ -143,10 +143,14 @@ func (s *service) Status() (*ResultStatus, error) { latestBlockHash = latestBlockMeta.Header.Hash() latestBlockTime = latestBlockMeta.Header.Time.UnixNano() } + publicKey, err := s.nodeView.PrivValidatorPublicKey() + if err != nil { + return nil, err + } return &ResultStatus{ NodeInfo: s.nodeView.NodeInfo(), GenesisHash: s.blockchain.GenesisHash(), - PubKey: s.nodeView.PrivValidatorPublicKey(), + PubKey: publicKey, LatestBlockHash: latestBlockHash, LatestBlockHeight: latestHeight, LatestBlockTime: latestBlockTime, diff --git a/rpc/v0/codec_test.go b/rpc/v0/codec_test.go index e8ebaa7e..5bd6d231 100644 --- a/rpc/v0/codec_test.go +++ b/rpc/v0/codec_test.go @@ -25,17 +25,21 @@ import ( func TestKeysEncoding(t *testing.T) { codec := NewTCodec() privateKey := acm.PrivateKeyFromSecret("foo") - keyPair := struct { + type keyPair struct { PrivateKey acm.PrivateKey PublicKey acm.PublicKey - }{ + } + + kp := keyPair{ PrivateKey: privateKey, PublicKey: privateKey.PublicKey(), } - bs, err := codec.EncodeBytes(keyPair) + bs, err := codec.EncodeBytes(kp) require.NoError(t, err) - assert.Equal(t, `{"PrivateKey":[1,"2C26B46B68FFC68FF99B453C1D30413413422D706483BFA0F98A5E886266E7AE34D26579DBB456693E540672CF922F52DDE0D6532E35BF06BE013A7C532F20E0"],"PublicKey":[1,"34D26579DBB456693E540672CF922F52DDE0D6532E35BF06BE013A7C532F20E0"]}`, - string(bs)) + kpOut := keyPair{} + codec.DecodeBytes(&kpOut, bs) + + assert.Equal(t, kp, kpOut) } -- GitLab