diff --git a/.circleci/config.yml b/.circleci/config.yml index c8d510a94afa0b6656bbcae56c0530a9c2def611..629b0e2473f2c25aa76e6da51de7e67ff17020ba 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,6 +35,10 @@ jobs: steps: - checkout - run: make test_integration_bosmarmot + - store_artifacts: + path: ./.gopath_bos/src/github.com/monax/bosmarmot/monax/tests/burrow.log + - store_artifacts: + path: ./.gopath_bos/src/github.com/monax/bosmarmot/monax/tests/keys.log ensure_vendor: <<: *defaults diff --git a/Gopkg.lock b/Gopkg.lock index 4267290a7b3c05a706ffc813139ff873f0327cde..d7e39752628439460aa8c3a026c00903ffe5de30 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -474,6 +474,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "ecec019d5ac7140b4607333907f5a4b211fb3551f7cfe51b92e6cc8e3c515488" + inputs-digest = "a434dee26127011ec236d80b300051d321f012ce49cd77b1112034c15e54ac3e" solver-name = "gps-cdcl" solver-version = 1 diff --git a/client/rpc/client_test.go b/client/rpc/client_test.go index d64ab91d48e4ba171df51ca78318a22fb14ac07d..3a8ebc42d7d11c1f5627b360097dcdd785499d84 100644 --- a/client/rpc/client_test.go +++ b/client/rpc/client_test.go @@ -28,31 +28,31 @@ import ( ) func TestSend(t *testing.T) { - mockKeyClient := mockkeys.NewMockKeyClient() + mockKeyClient := mockkeys.NewKeyClient() mockNodeClient := mockclient.NewMockNodeClient() testSend(t, mockNodeClient, mockKeyClient) } func TestCall(t *testing.T) { - mockKeyClient := mockkeys.NewMockKeyClient() + mockKeyClient := mockkeys.NewKeyClient() mockNodeClient := mockclient.NewMockNodeClient() testCall(t, mockNodeClient, mockKeyClient) } func TestName(t *testing.T) { - mockKeyClient := mockkeys.NewMockKeyClient() + mockKeyClient := mockkeys.NewKeyClient() mockNodeClient := mockclient.NewMockNodeClient() testName(t, mockNodeClient, mockKeyClient) } func TestPermissions(t *testing.T) { - mockKeyClient := mockkeys.NewMockKeyClient() + mockKeyClient := mockkeys.NewKeyClient() mockNodeClient := mockclient.NewMockNodeClient() testPermissions(t, mockNodeClient, mockKeyClient) } func testSend(t *testing.T, - nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { + nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.KeyClient) { // generate an ED25519 key and ripemd160 address addressString := keyClient.NewKey("").String() @@ -77,7 +77,7 @@ func testSend(t *testing.T, } func testCall(t *testing.T, - nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { + nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.KeyClient) { // generate an ED25519 key and ripemd160 address addressString := keyClient.NewKey("").String() @@ -110,7 +110,7 @@ func testCall(t *testing.T, } func testName(t *testing.T, - nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { + nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.KeyClient) { // generate an ED25519 key and ripemd160 address addressString := keyClient.NewKey("").String() @@ -141,7 +141,7 @@ func testName(t *testing.T, } func testPermissions(t *testing.T, - nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.MockKeyClient) { + nodeClient *mockclient.MockNodeClient, keyClient *mockkeys.KeyClient) { // generate an ED25519 key and ripemd160 address addressString := keyClient.NewKey("").String() diff --git a/cmd/burrow/commands/configure.go b/cmd/burrow/commands/configure.go index de13421a319bce30a6291396e7fe44dfd4971c50..f1af9e0f878b70e6948a33b9a49c629b7aa08859 100644 --- a/cmd/burrow/commands/configure.go +++ b/cmd/burrow/commands/configure.go @@ -8,6 +8,7 @@ import ( "github.com/hyperledger/burrow/config" "github.com/hyperledger/burrow/config/source" + "github.com/hyperledger/burrow/deployment" "github.com/hyperledger/burrow/execution" "github.com/hyperledger/burrow/genesis" "github.com/hyperledger/burrow/genesis/spec" @@ -37,9 +38,9 @@ func Configure(cmd *cli.Cmd) { "File to output containing secret keys as JSON or according to a custom template (see --keys-template). "+ "Note that using this options means the keys will not be generated in the default keys instance") - keysTemplateOpt := cmd.StringOpt("z keys-template", mock.DefaultDumpKeysFormat, + keysTemplateOpt := cmd.StringOpt("z keys-template", deployment.DefaultDumpKeysFormat, fmt.Sprintf("Go text/template template (left delim: %s right delim: %s) to generate secret keys "+ - "file specified with --generate-keys.", mock.LeftTemplateDelim, mock.RightTemplateDelim)) + "file specified with --generate-keys.", deployment.LeftTemplateDelim, deployment.RightTemplateDelim)) separateGenesisDoc := cmd.StringOpt("w separate-genesis-doc", "", "Emit a separate genesis doc as JSON or TOML") @@ -95,13 +96,14 @@ func Configure(cmd *cli.Cmd) { fatalf("Could not read GenesisSpec: %v", err) } if *generateKeysOpt != "" { - keyClient := mock.NewMockKeyClient() + keyClient := mock.NewKeyClient() conf.GenesisDoc, err = genesisSpec.GenesisDoc(keyClient) if err != nil { fatalf("Could not generate GenesisDoc from GenesisSpec using MockKeyClient: %v", err) } - secretKeysString, err := keyClient.DumpKeys(*keysTemplateOpt) + pkg := deployment.Package{Keys: keyClient.Keys()} + secretKeysString, err := pkg.Dump(*keysTemplateOpt) if err != nil { fatalf("Could not dump keys: %v", err) } diff --git a/cmd/burrow/commands/helpers.go b/cmd/burrow/commands/helpers.go index 232c1f2eb33229e03cf56c43972d5f5c86963d91..a36ca827e80083c257a58f569c60f5f126cead58 100644 --- a/cmd/burrow/commands/helpers.go +++ b/cmd/burrow/commands/helpers.go @@ -23,7 +23,7 @@ func burrowConfigProvider(configFile string) source.ConfigProvider { return source.FirstOf( // Will fail if file doesn't exist, but still skipped it configFile == "" source.File(configFile, false), - source.Environment(config.DefaultBurrowConfigJSONEnvironmentVariable), + source.Environment(config.DefaultBurrowConfigEnvironmentVariable), // Try working directory source.File(config.DefaultBurrowConfigTOMLFileName, true), source.Default(config.DefaultBurrowConfig())) diff --git a/cmd/burrow/commands/spec.go b/cmd/burrow/commands/spec.go index 634006311b0a54082ed4266f7edfb2baed406b5d..6a0d3334439947e279f94703d0035c2f79f46023 100644 --- a/cmd/burrow/commands/spec.go +++ b/cmd/burrow/commands/spec.go @@ -17,7 +17,7 @@ func Spec(cmd *cli.Cmd) { "additional GenesisSpec presets specified by other flags will be merged. GenesisSpecs appearing "+ "later take precedent over those appearing early if multiple --base flags are provided") - accountNamePrefixOpt := cmd.StringOpt("name-prefix", "", "Prefix added to the names of accounts in GenesisSpec") + accountNamePrefixOpt := cmd.StringOpt("x name-prefix", "", "Prefix added to the names of accounts in GenesisSpec") fullOpt := cmd.IntOpt("f full-accounts", 0, "Number of preset Full type accounts") validatorOpt := cmd.IntOpt("v validator-accounts", 0, "Number of preset Validator type accounts") rootOpt := cmd.IntOpt("r root-accounts", 0, "Number of preset Root type accounts") @@ -25,8 +25,8 @@ func Spec(cmd *cli.Cmd) { participantsOpt := cmd.IntOpt("p participant-accounts", 0, "Number of preset Participant type accounts") chainNameOpt := cmd.StringOpt("n chain-name", "", "Default chain name") - cmd.Spec = "[--full-accounts] [--validator-accounts] [--root-accounts] [--developer-accounts] " + - "[--participant-accounts] [--chain-name] [--toml] [BASE...]" + cmd.Spec = "[--name-prexix=<prefix for account names>][--full-accounts] [--validator-accounts] [--root-accounts] " + + "[--developer-accounts] [--participant-accounts] [--chain-name] [--toml] [BASE...]" cmd.Action = func() { specs := make([]spec.GenesisSpec, 0, *participantsOpt+*fullOpt) diff --git a/config/config.go b/config/config.go index fa0e3227d7b115e09437301b0e184cfdf9eb9283..3ce6d2f83ce83178970ed7e7bd8d7b3a0b845a11 100644 --- a/config/config.go +++ b/config/config.go @@ -19,7 +19,7 @@ import ( ) const DefaultBurrowConfigTOMLFileName = "burrow.toml" -const DefaultBurrowConfigJSONEnvironmentVariable = "BURROW_CONFIG_JSON" +const DefaultBurrowConfigEnvironmentVariable = "BURROW_CONFIG_JSON" const DefaultGenesisDocJSONFileName = "genesis.json" type BurrowConfig struct { diff --git a/config/source/source.go b/config/source/source.go index 4b35b901fa0ed76a2230854f9cf8b491521d7200..66e55e8f05c76e2b1aa69e44776b2c4e9fc6a1ad 100644 --- a/config/source/source.go +++ b/config/source/source.go @@ -170,12 +170,12 @@ func XDGBaseDir(configFileName string) *configSource { // Source from a single environment variable with config embedded in JSON func Environment(key string) *configSource { - jsonString := os.Getenv(key) + configString := os.Getenv(key) return &configSource{ - skip: jsonString == "", - from: fmt.Sprintf("'%s' environment variable (as JSON)", key), + skip: configString == "", + from: fmt.Sprintf("'%s' environment variable", key), apply: func(baseConfig interface{}) error { - return FromJSONString(jsonString, baseConfig) + return FromString(configString, baseConfig) }, } } diff --git a/core/integration/test_wrapper.go b/core/integration/test_wrapper.go index 7d0940d135236ebb19fe6d723b8b6c21ae3960ff..b97c7986d1463c20657b3116ded733f8eb599651 100644 --- a/core/integration/test_wrapper.go +++ b/core/integration/test_wrapper.go @@ -79,7 +79,7 @@ func TestWrapper(privateAccounts []acm.PrivateAccount, genesisDoc *genesis.Genes validatorAccount := privateAccounts[0] privValidator := validator.NewPrivValidatorMemory(validatorAccount, validatorAccount) - keyClient := mock.NewMockKeyClient(privateAccounts...) + keyClient := mock.NewKeyClient(privateAccounts...) kernel, err := core.NewKernel(context.Background(), keyClient, privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), nil, logger) if err != nil { diff --git a/core/kernel_test.go b/core/kernel_test.go index e1e4d65d17c0416ae3ea0a613e35632c059915e6..5cd06d36e46d9946ea03a9f4a1832263f1ca1d24 100644 --- a/core/kernel_test.go +++ b/core/kernel_test.go @@ -65,7 +65,7 @@ func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *ge tmConf *tm_config.Config, logger *logging.Logger, blockChecker func(block *tm_types.EventDataNewBlock) (cont bool)) error { - kern, err := NewKernel(context.Background(), mock.NewMockKeyClient(), privValidator, genesisDoc, tmConf, + kern, err := NewKernel(context.Background(), mock.NewKeyClient(), privValidator, genesisDoc, tmConf, rpc.DefaultRPCConfig(), nil, logger) if err != nil { return err diff --git a/deployment/config.go b/deployment/config.go new file mode 100644 index 0000000000000000000000000000000000000000..8f1047b638d8465ae527fc887368add3842e61bd --- /dev/null +++ b/deployment/config.go @@ -0,0 +1,87 @@ +package deployment + +import ( + "bytes" + "encoding/base64" + "fmt" + "reflect" + "text/template" + + "github.com/hyperledger/burrow/config" + "github.com/hyperledger/burrow/keys/mock" + "github.com/pkg/errors" + "github.com/tmthrgd/go-hex" +) + +type Package struct { + Keys []*mock.Key + BurrowConfig *config.BurrowConfig +} + +const DefaultDumpKeysFormat = `{ + "Keys": [<< range $index, $key := . >><< if $index>>,<< end >> + { + "Name": "<< $key.Name >>", + "Address": "<< $key.Address >>", + "PublicKey": "<< base64 $key.PublicKey >>", + "PrivateKey": "<< base64 $key.PrivateKey >>" + }<< end >> + ] +}` + +const HelmDumpKeysFormat = `privateKeys:<< range $key := . >> + << $key.Address >>: + name: << $key.Name >> + address: << $key.Address >> + publicKey: << base64 $key.PublicKey >> + privateKey: << base64 $key.PrivateKey >><< end >> + ` + +const KubernetesKeyDumpFormat = `keysFiles:<< range $index, $key := . >> + key-<< printf "%03d" $index >>: << base64 $key.MonaxKeysJSON >><< end >> +keysAddresses:<< range $index, $key := . >> + key-<< printf "%03d" $index >>: << $key.Address >><< end >> +validatorAddresses:<< range $index, $key := . >> + - << $key.Address >><< end >> +` + +const LeftTemplateDelim = "<<" +const RightTemplateDelim = ">>" + +var templateFuncs template.FuncMap = map[string]interface{}{ + "base64": func(rv reflect.Value) string { + return encode(rv, base64.StdEncoding.EncodeToString) + }, + "hex": func(rv reflect.Value) string { + return encode(rv, hex.EncodeUpperToString) + }, +} + +var DefaultDumpKeysTemplate = template.Must(template.New("MockKeyClient_DumpKeys").Funcs(templateFuncs). + Delims(LeftTemplateDelim, RightTemplateDelim). + Parse(DefaultDumpKeysFormat)) + +func (pkg *Package) Dump(templateString string) (string, error) { + tmpl, err := template.New("DumpKeys").Delims(LeftTemplateDelim, RightTemplateDelim).Funcs(templateFuncs). + Parse(templateString) + if err != nil { + return "", errors.Wrap(err, "could not dump keys to template") + } + buf := new(bytes.Buffer) + err = tmpl.Execute(buf, pkg.Keys) + if err != nil { + return "", err + } + return buf.String(), nil +} + +func encode(rv reflect.Value, encoder func([]byte) string) string { + switch rv.Kind() { + case reflect.Slice: + return encoder(rv.Bytes()) + case reflect.String: + return encoder([]byte(rv.String())) + default: + panic(fmt.Errorf("could not convert %#v to bytes to encode", rv)) + } +} diff --git a/keys/mock/key_client_mock_test.go b/deployment/config_test.go similarity index 57% rename from keys/mock/key_client_mock_test.go rename to deployment/config_test.go index 9a5cbef3f520c7c17d16592f51dfb7aae12f7227..3a159238b538bcca6274ed2370e96f0c049229bf 100644 --- a/keys/mock/key_client_mock_test.go +++ b/deployment/config_test.go @@ -1,28 +1,28 @@ -package mock +package deployment import ( - "testing" - "encoding/json" - "fmt" + "testing" "github.com/hyperledger/burrow/keys" + "github.com/hyperledger/burrow/keys/mock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestMockKeyClient_DumpKeys(t *testing.T) { - keyClient := NewMockKeyClient() + keyClient := mock.NewKeyClient() _, err := keyClient.Generate("foo", keys.KeyTypeEd25519Ripemd160) require.NoError(t, err) _, err = keyClient.Generate("foobar", keys.KeyTypeEd25519Ripemd160) require.NoError(t, err) - dump, err := keyClient.DumpKeys(DefaultDumpKeysFormat) + pkg := Package{Keys: keyClient.Keys()} + dump, err := pkg.Dump(DefaultDumpKeysFormat) require.NoError(t, err) // Check JSON equal - var keys struct{ Keys []*MockKey } + var keys struct{ Keys []*mock.Key } err = json.Unmarshal([]byte(dump), &keys) require.NoError(t, err) bs, err := json.MarshalIndent(keys, "", " ") @@ -31,27 +31,25 @@ func TestMockKeyClient_DumpKeys(t *testing.T) { } func TestMockKeyClient_DumpKeysKubernetes(t *testing.T) { - keyClient := NewMockKeyClient() + keyClient := mock.NewKeyClient() _, err := keyClient.Generate("foo", keys.KeyTypeEd25519Ripemd160) require.NoError(t, err) _, err = keyClient.Generate("foobar", keys.KeyTypeEd25519Ripemd160) require.NoError(t, err) - dump, err := keyClient.DumpKeys(KubernetesKeyDumpFormat) + pkg := Package{Keys: keyClient.Keys()} + dump, err := pkg.Dump(KubernetesKeyDumpFormat) require.NoError(t, err) fmt.Println(dump) } -func TestMockKey_MonaxKeyJSON(t *testing.T) { - key, err := newMockKey("monax-key-test") - require.NoError(t, err) - monaxKey := key.MonaxKeyJSON() - t.Logf("key is: %v", monaxKey) - keyJSON := &plainKeyJSON{} - err = json.Unmarshal([]byte(monaxKey), keyJSON) - require.NoError(t, err) - // byte length of UUID string = 16 * 2 + 4 = 36 - assert.Len(t, keyJSON.Id, 36) - assert.Equal(t, key.Address.String(), keyJSON.Address) - assert.Equal(t, key.PrivateKey, keyJSON.PrivateKey) - assert.Equal(t, string(keys.KeyTypeEd25519Ripemd160), keyJSON.Type) +func TestMockKeyClient_DumpKeysHelm(t *testing.T) { + keyClient := mock.NewKeyClient() + _, err := keyClient.Generate("foo", keys.KeyTypeEd25519Ripemd160) + require.NoError(t, err) + _, err = keyClient.Generate("foobar", keys.KeyTypeEd25519Ripemd160) + require.NoError(t, err) + pkg := Package{Keys: keyClient.Keys()} + dump, err := pkg.Dump(HelmDumpKeysFormat) + require.NoError(t, err) + fmt.Println(dump) } diff --git a/genesis/spec/genesis_spec.go b/genesis/spec/genesis_spec.go index 11549a0171f645cf1f2f4a194500170422cdc3c2..343b7eaf6d6072ce8caf1d3a4f892cc0a83b22cb 100644 --- a/genesis/spec/genesis_spec.go +++ b/genesis/spec/genesis_spec.go @@ -138,6 +138,16 @@ func (ta TemplateAccount) RealisePubKeyAndAddress(keyClient keys.KeyClient) (pub return } +func (gs *GenesisSpec) RealiseKeys(keyClient keys.KeyClient) error { + for _, templateAccount := range gs.Accounts { + _, _, err := templateAccount.RealisePubKeyAndAddress(keyClient) + if err != nil { + return err + } + } + return nil +} + // Produce a fully realised GenesisDoc from a template GenesisDoc that may omit values func (gs *GenesisSpec) GenesisDoc(keyClient keys.KeyClient) (*genesis.GenesisDoc, error) { genesisDoc := new(genesis.GenesisDoc) diff --git a/genesis/spec/genesis_spec_test.go b/genesis/spec/genesis_spec_test.go index 774f64c59e6f1aebde13d5b086b79028ae52e9c5..294c4ed315e600d9907ecd7d749c979d9eac1896 100644 --- a/genesis/spec/genesis_spec_test.go +++ b/genesis/spec/genesis_spec_test.go @@ -11,7 +11,7 @@ import ( ) func TestGenesisSpec_GenesisDoc(t *testing.T) { - keyClient := mock.NewMockKeyClient() + keyClient := mock.NewKeyClient() // Try a spec with a single account/validator amtBonded := uint64(100) diff --git a/genesis/spec/presets_test.go b/genesis/spec/presets_test.go index b8a40cd00be4c59e487302f48daf1db3053fc674..8e578640e8790aab8923006e7ec8d864a3cec5b5 100644 --- a/genesis/spec/presets_test.go +++ b/genesis/spec/presets_test.go @@ -10,7 +10,7 @@ import ( ) func TestMergeGenesisSpecAccounts(t *testing.T) { - keyClient := mock.NewMockKeyClient() + keyClient := mock.NewKeyClient() gs := MergeGenesisSpecs(FullAccount("0"), ParticipantAccount("1"), ParticipantAccount("2")) gd, err := gs.GenesisDoc(keyClient) require.NoError(t, err) diff --git a/keys/mock/key.go b/keys/mock/key.go new file mode 100644 index 0000000000000000000000000000000000000000..313a118347e5be1bb6b0f8ddfbc3a45af0964b0b --- /dev/null +++ b/keys/mock/key.go @@ -0,0 +1,98 @@ +package mock + +import ( + "crypto/rand" + "encoding/json" + "fmt" + + acm "github.com/hyperledger/burrow/account" + "github.com/hyperledger/burrow/keys" + "github.com/pkg/errors" + "github.com/tendermint/go-crypto" + "github.com/wayn3h0/go-uuid" + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/ripemd160" +) + +// Mock ed25510 key for mock keys client +// Simple ed25519 key structure for mock purposes with ripemd160 address +type Key struct { + Name string + Address acm.Address + PublicKey []byte + PrivateKey []byte +} + +func newKey(name string) (*Key, error) { + key := &Key{ + Name: name, + PublicKey: make([]byte, ed25519.PublicKeySize), + PrivateKey: make([]byte, ed25519.PrivateKeySize), + } + // this is a mock key, so the entropy of the source is purely + // for testing + publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, err + } + copy(key.PrivateKey[:], privateKey[:]) + copy(key.PublicKey[:], publicKey[:]) + + // prepend 0x01 for ed25519 public key + typedPublicKeyBytes := append([]byte{0x01}, key.PublicKey...) + hasher := ripemd160.New() + hasher.Write(typedPublicKeyBytes) + key.Address, err = acm.AddressFromBytes(hasher.Sum(nil)) + if err != nil { + return nil, err + } + if key.Name == "" { + key.Name = key.Address.String() + } + return key, nil +} + +func mockKeyFromPrivateAccount(privateAccount acm.PrivateAccount) *Key { + _, ok := privateAccount.PrivateKey().Unwrap().(crypto.PrivKeyEd25519) + if !ok { + panic(fmt.Errorf("mock key client only supports ed25519 private keys at present")) + } + key := &Key{ + Name: privateAccount.Address().String(), + Address: privateAccount.Address(), + PublicKey: privateAccount.PublicKey().RawBytes(), + PrivateKey: privateAccount.PrivateKey().RawBytes(), + } + return key +} + +func (key *Key) Sign(message []byte) (acm.Signature, error) { + return acm.SignatureFromBytes(ed25519.Sign(key.PrivateKey, message)) +} + +// TODO: remove after merging keys taken from there to match serialisation +type plainKeyJSON struct { + Id []byte + Type string + Address string + PrivateKey []byte +} + +// Returns JSON string compatible with that stored by monax-keys +func (key *Key) MonaxKeysJSON() string { + id, err := uuid.NewRandom() + if err != nil { + return errors.Wrap(err, "could not create monax key json").Error() + } + jsonKey := plainKeyJSON{ + Id: []byte(id.String()), + Address: key.Address.String(), + Type: string(keys.KeyTypeEd25519Ripemd160), + PrivateKey: key.PrivateKey, + } + bs, err := json.Marshal(jsonKey) + if err != nil { + return errors.Wrap(err, "could not create monax key json").Error() + } + return string(bs) +} diff --git a/keys/mock/key_client.go b/keys/mock/key_client.go new file mode 100644 index 0000000000000000000000000000000000000000..821c0c82499cb970a5f796497879e8281d9c8cc7 --- /dev/null +++ b/keys/mock/key_client.go @@ -0,0 +1,87 @@ +// Copyright 2017 Monax Industries Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mock + +import ( + "fmt" + + acm "github.com/hyperledger/burrow/account" + "github.com/hyperledger/burrow/keys" + "github.com/tendermint/go-crypto" +) + +//--------------------------------------------------------------------- +// Mock client for replacing signing done by monax-keys + +// Implementation assertion +var _ keys.KeyClient = (*KeyClient)(nil) + +type KeyClient struct { + knownKeys map[acm.Address]*Key +} + +func NewKeyClient(privateAccounts ...acm.PrivateAccount) *KeyClient { + client := &KeyClient{ + knownKeys: make(map[acm.Address]*Key), + } + for _, pa := range privateAccounts { + client.knownKeys[pa.Address()] = mockKeyFromPrivateAccount(pa) + } + return client +} + +func (mkc *KeyClient) NewKey(name string) acm.Address { + // Only tests ED25519 curve and ripemd160. + key, err := newKey(name) + if err != nil { + panic(fmt.Sprintf("Mocked key client failed on key generation: %s", err)) + } + mkc.knownKeys[key.Address] = key + return key.Address +} + +func (mkc *KeyClient) Sign(signAddress acm.Address, message []byte) (acm.Signature, error) { + key := mkc.knownKeys[signAddress] + if key == nil { + return acm.Signature{}, fmt.Errorf("unknown address (%s)", signAddress) + } + return key.Sign(message) +} + +func (mkc *KeyClient) PublicKey(address acm.Address) (acm.PublicKey, error) { + key := mkc.knownKeys[address] + if key == nil { + return acm.PublicKey{}, fmt.Errorf("unknown address (%s)", address) + } + pubKeyEd25519 := crypto.PubKeyEd25519{} + copy(pubKeyEd25519[:], key.PublicKey) + return acm.PublicKeyFromGoCryptoPubKey(pubKeyEd25519.Wrap()) +} + +func (mkc *KeyClient) Generate(keyName string, keyType keys.KeyType) (acm.Address, error) { + return mkc.NewKey(keyName), nil +} + +func (mkc *KeyClient) HealthCheck() error { + return nil +} + +func (mkc *KeyClient) Keys() []*Key { + var knownKeys []*Key + for _, key := range mkc.knownKeys { + knownKeys = append(knownKeys, key) + } + return knownKeys +} diff --git a/keys/mock/key_client_mock.go b/keys/mock/key_client_mock.go deleted file mode 100644 index 47bdca9aeb9dba5840d2da98ba6c692db89c9005..0000000000000000000000000000000000000000 --- a/keys/mock/key_client_mock.go +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2017 Monax Industries Limited -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package mock - -import ( - "bytes" - "crypto/rand" - "encoding/base64" - "fmt" - "text/template" - - "encoding/json" - - "reflect" - - acm "github.com/hyperledger/burrow/account" - . "github.com/hyperledger/burrow/keys" - "github.com/pkg/errors" - "github.com/tendermint/ed25519" - "github.com/tendermint/go-crypto" - "github.com/tmthrgd/go-hex" - "github.com/wayn3h0/go-uuid" - "golang.org/x/crypto/ripemd160" -) - -//--------------------------------------------------------------------- -// Mock ed25510 key for mock keys client - -// Simple ed25519 key structure for mock purposes with ripemd160 address -type MockKey struct { - Name string - Address acm.Address - PublicKey []byte - PrivateKey []byte -} - -const DefaultDumpKeysFormat = `{ - "Keys": [<< range $index, $key := . >><< if $index>>,<< end >> - { - "Name": "<< $key.Name >>", - "Address": "<< $key.Address >>", - "PublicKey": "<< base64 $key.PublicKey >>", - "PrivateKey": "<< base64 $key.PrivateKey >>" - }<< end >> - ] -}` - -const KubernetesKeyDumpFormat = `keysFiles:<< range $index, $key := . >> - key-<< printf "%03d" $index >>: << base64 $key.MonaxKeyJSON >><< end >> -keysAddresses:<< range $index, $key := . >> - key-<< printf "%03d" $index >>: << $key.Address >><< end >> -validatorAddresses:<< range $index, $key := . >> - - << $key.Address >><< end >> -` - -const LeftTemplateDelim = "<<" -const RightTemplateDelim = ">>" - -var templateFuncs template.FuncMap = map[string]interface{}{ - "base64": func(rv reflect.Value) string { - return encode(rv, base64.StdEncoding.EncodeToString) - }, - "hex": func(rv reflect.Value) string { - return encode(rv, hex.EncodeUpperToString) - }, -} - -var DefaultDumpKeysTemplate = template.Must(template.New("MockKeyClient_DumpKeys").Funcs(templateFuncs). - Delims(LeftTemplateDelim, RightTemplateDelim). - Parse(DefaultDumpKeysFormat)) - -func newMockKey(name string) (*MockKey, error) { - key := &MockKey{ - Name: name, - PublicKey: make([]byte, ed25519.PublicKeySize), - PrivateKey: make([]byte, ed25519.PrivateKeySize), - } - // this is a mock key, so the entropy of the source is purely - // for testing - publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) - if err != nil { - return nil, err - } - copy(key.PrivateKey[:], privateKey[:]) - copy(key.PublicKey[:], publicKey[:]) - - // prepend 0x01 for ed25519 public key - typedPublicKeyBytes := append([]byte{0x01}, key.PublicKey...) - hasher := ripemd160.New() - hasher.Write(typedPublicKeyBytes) - key.Address, err = acm.AddressFromBytes(hasher.Sum(nil)) - if err != nil { - return nil, err - } - if key.Name == "" { - key.Name = key.Address.String() - } - return key, nil -} - -func mockKeyFromPrivateAccount(privateAccount acm.PrivateAccount) *MockKey { - _, ok := privateAccount.PrivateKey().Unwrap().(crypto.PrivKeyEd25519) - if !ok { - panic(fmt.Errorf("mock key client only supports ed25519 private keys at present")) - } - key := &MockKey{ - Name: privateAccount.Address().String(), - Address: privateAccount.Address(), - PublicKey: privateAccount.PublicKey().RawBytes(), - PrivateKey: privateAccount.PrivateKey().RawBytes(), - } - return key -} - -func (mockKey *MockKey) Sign(message []byte) (acm.Signature, error) { - var privateKey [ed25519.PrivateKeySize]byte - copy(privateKey[:], mockKey.PrivateKey) - return acm.SignatureFromBytes(ed25519.Sign(&privateKey, message)[:]) -} - -// TODO: remove after merging keys taken from there to match serialisation -type plainKeyJSON struct { - Id []byte - Type string - Address string - PrivateKey []byte -} - -// Returns JSON string compatible with that stored by monax-keys -func (mockKey *MockKey) MonaxKeyJSON() string { - id, err := uuid.NewRandom() - if err != nil { - return errors.Wrap(err, "could not create monax key json").Error() - } - jsonKey := plainKeyJSON{ - Id: []byte(id.String()), - Address: mockKey.Address.String(), - Type: string(KeyTypeEd25519Ripemd160), - PrivateKey: mockKey.PrivateKey, - } - bs, err := json.Marshal(jsonKey) - if err != nil { - return errors.Wrap(err, "could not create monax key json").Error() - } - return string(bs) -} - -//--------------------------------------------------------------------- -// Mock client for replacing signing done by monax-keys - -// Implementation assertion -var _ KeyClient = (*MockKeyClient)(nil) - -type MockKeyClient struct { - knownKeys map[acm.Address]*MockKey -} - -func NewMockKeyClient(privateAccounts ...acm.PrivateAccount) *MockKeyClient { - client := &MockKeyClient{ - knownKeys: make(map[acm.Address]*MockKey), - } - for _, pa := range privateAccounts { - client.knownKeys[pa.Address()] = mockKeyFromPrivateAccount(pa) - } - return client -} - -func (mkc *MockKeyClient) NewKey(name string) acm.Address { - // Only tests ED25519 curve and ripemd160. - key, err := newMockKey(name) - if err != nil { - panic(fmt.Sprintf("Mocked key client failed on key generation: %s", err)) - } - mkc.knownKeys[key.Address] = key - return key.Address -} - -func (mkc *MockKeyClient) Sign(signAddress acm.Address, message []byte) (acm.Signature, error) { - key := mkc.knownKeys[signAddress] - if key == nil { - return acm.Signature{}, fmt.Errorf("Unknown address (%s)", signAddress) - } - return key.Sign(message) -} - -func (mkc *MockKeyClient) PublicKey(address acm.Address) (acm.PublicKey, error) { - key := mkc.knownKeys[address] - if key == nil { - return acm.PublicKey{}, fmt.Errorf("Unknown address (%s)", address) - } - pubKeyEd25519 := crypto.PubKeyEd25519{} - copy(pubKeyEd25519[:], key.PublicKey) - return acm.PublicKeyFromGoCryptoPubKey(pubKeyEd25519.Wrap()) -} - -func (mkc *MockKeyClient) Generate(keyName string, keyType KeyType) (acm.Address, error) { - return mkc.NewKey(keyName), nil -} - -func (mkc *MockKeyClient) HealthCheck() error { - return nil -} - -func (mkc *MockKeyClient) DumpKeys(templateString string) (string, error) { - tmpl, err := template.New("DumpKeys").Delims(LeftTemplateDelim, RightTemplateDelim).Funcs(templateFuncs). - Parse(templateString) - if err != nil { - return "", errors.Wrap(err, "could not dump keys to template") - } - buf := new(bytes.Buffer) - keys := make([]*MockKey, 0, len(mkc.knownKeys)) - for _, k := range mkc.knownKeys { - keys = append(keys, k) - } - err = tmpl.Execute(buf, keys) - if err != nil { - return "", err - } - return buf.String(), nil -} - -func encode(rv reflect.Value, encoder func([]byte) string) string { - switch rv.Kind() { - case reflect.Slice: - return encoder(rv.Bytes()) - case reflect.String: - return encoder([]byte(rv.String())) - default: - panic(fmt.Errorf("could not convert %#v to bytes to encode", rv)) - } -} diff --git a/keys/mock/key_client_test.go b/keys/mock/key_client_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7f74a03733c54f751bcecab7fa6abfe691dbeebf --- /dev/null +++ b/keys/mock/key_client_test.go @@ -0,0 +1,26 @@ +package mock + +import ( + "testing" + + "encoding/json" + + "github.com/hyperledger/burrow/keys" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMockKey_MonaxKeyJSON(t *testing.T) { + key, err := newKey("monax-key-test") + require.NoError(t, err) + monaxKey := key.MonaxKeysJSON() + t.Logf("key is: %v", monaxKey) + keyJSON := &plainKeyJSON{} + err = json.Unmarshal([]byte(monaxKey), keyJSON) + require.NoError(t, err) + // byte length of UUID string = 16 * 2 + 4 = 36 + assert.Len(t, keyJSON.Id, 36) + assert.Equal(t, key.Address.String(), keyJSON.Address) + assert.Equal(t, key.PrivateKey, keyJSON.PrivateKey) + assert.Equal(t, string(keys.KeyTypeEd25519Ripemd160), keyJSON.Type) +} diff --git a/rpc/v0/server/config.go b/rpc/v0/server/config.go index f5b8130c0f7ec64517da44fc3e0ef2b3080c76ba..6db3bdbe875221c317c3d8348166ba48b90aa560 100644 --- a/rpc/v0/server/config.go +++ b/rpc/v0/server/config.go @@ -16,7 +16,6 @@ package server type ( ServerConfig struct { - ChainId string Bind Bind `toml:"bind"` TLS TLS `toml:"TLS"` CORS CORS `toml:"CORS"` diff --git a/rpc/v0/server/server.go b/rpc/v0/server/server.go index 5a6240013cdd6baa6402740bf864dedadccf934d..2ee096c5b2aef767c3d121c6a169888c94296a6d 100644 --- a/rpc/v0/server/server.go +++ b/rpc/v0/server/server.go @@ -120,7 +120,6 @@ func (serveProcess *ServeProcess) Start() error { } serveProcess.srv = srv serveProcess.logger.InfoMsg("Server started.", - "chain_id", serveProcess.config.ChainId, "address", serveProcess.config.Bind.Address, "port", serveProcess.config.Bind.Port) for _, c := range serveProcess.startListenChans {