Skip to content

Commit

Permalink
Add ability to create new Fabric accounts
Browse files Browse the repository at this point in the history
Signed-off-by: Nicko Guyer <nicko.guyer@kaleido.io>
  • Loading branch information
nguyer committed Apr 7, 2022
1 parent ba68bac commit 0bebae8
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 100 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ all: build
build: ## Builds all go code
cd ff && go build -ldflags="-X 'github.com/hyperledger/firefly-cli/cmd.BuildDate=$(DATE)' -X 'github.com/hyperledger/firefly-cli/cmd.BuildCommit=$(GITREF)'"
install: ## Installs the package
cd ff && go install
cd ff && go install -ldflags="-X 'github.com/hyperledger/firefly-cli/cmd.BuildDate=$(DATE)' -X 'github.com/hyperledger/firefly-cli/cmd.BuildCommit=$(GITREF)'"

lint: ${LINT} ## Checks and reports lint errors
GOGC=20 $(LINT) run -v --timeout 5m
Expand Down
22 changes: 17 additions & 5 deletions cmd/accounts_create.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
// Copyright © 2022 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 cmd

import (
Expand All @@ -17,7 +29,7 @@ var accountsCreateCmd = &cobra.Command{
Use: "create <stack_name>",
Short: "Create a new account in the FireFly stack",
Long: `Create a new account in the FireFly stack`,
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
return docker.CheckDockerConfig()
},
Expand All @@ -27,7 +39,7 @@ var accountsCreateCmd = &cobra.Command{
if err := stackManager.LoadStack(stackName, verbose); err != nil {
return err
}
account, err := stackManager.CreateAccount()
account, err := stackManager.CreateAccount(args[1:])
if err != nil {
return err
}
Expand Down
18 changes: 15 additions & 3 deletions cmd/accounts_list.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
// Copyright © 2022 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 cmd

import (
Expand Down
18 changes: 15 additions & 3 deletions cmd/deploy_ethereum.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
// Copyright © 2022 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 cmd

import (
Expand Down
18 changes: 15 additions & 3 deletions cmd/deploy_fabric.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
/*
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
// Copyright © 2022 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// 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 cmd

import (
Expand Down
3 changes: 2 additions & 1 deletion internal/blockchain/blockchain_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ type IBlockchainProvider interface {
Reset() error
GetContracts(filename string, extraArgs []string) ([]string, error)
DeployContract(filename, contractName string, member *types.Member, extraArgs []string) (interface{}, error)
CreateAccount() (interface{}, error)
CreateAccount(args []string) (interface{}, error)
ParseAccount(interface{}) interface{}
}
28 changes: 18 additions & 10 deletions internal/blockchain/ethereum/besu/besu_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ type BesuProvider struct {
func (p *BesuProvider) WriteConfig(options *types.InitOptions) error {
initDir := filepath.Join(constants.StacksDir, p.Stack.Name, "init")
for i, member := range p.Stack.Members {
account := member.Account.(*ethereum.Account)
// Write the private key to disk for each member
if err := p.writeAccountToDisk(p.Stack.InitDir, member.Address, member.PrivateKey); err != nil {
if err := p.writeAccountToDisk(p.Stack.InitDir, account.Address, account.PrivateKey); err != nil {
return err
}

Expand All @@ -56,7 +57,7 @@ func (p *BesuProvider) WriteConfig(options *types.InitOptions) error {
return nil
}

if err := p.writeTomlKeyFile(p.Stack.InitDir, member.Address); err != nil {
if err := p.writeTomlKeyFile(p.Stack.InitDir, account.Address); err != nil {
return err
}

Expand Down Expand Up @@ -111,7 +112,8 @@ func (p *BesuProvider) FirstTimeSetup() error {
// Mount the directory containing all members' private keys and password, and import the accounts using the geth CLI
// Note: This is needed because of licensing issues with the Go Ethereum library that could do this step
for _, member := range p.Stack.Members {
if err := p.importAccountToEthsigner(member.Address); err != nil {
account := member.Account.(*ethereum.Account)
if err := p.importAccountToEthsigner(account.Address); err != nil {
return err
}
}
Expand Down Expand Up @@ -149,7 +151,8 @@ func (p *BesuProvider) DeployFireFlyContract() (*core.BlockchainConfig, error) {
func (p *BesuProvider) GetDockerServiceDefinitions() []*docker.ServiceDefinition {
addresses := ""
for i, member := range p.Stack.Members {
addresses = addresses + member.Address
account := member.Account.(*ethereum.Account)
addresses = addresses + account.Address
if i+1 < len(p.Stack.Members) {
addresses = addresses + ","
}
Expand Down Expand Up @@ -196,9 +199,10 @@ func (p *BesuProvider) GetDockerServiceDefinitions() []*docker.ServiceDefinition
}

func (p *BesuProvider) GetFireflyConfig(stack *types.Stack, m *types.Member) (blockchainConfig *core.BlockchainConfig, orgConfig *core.OrgConfig) {
account := m.Account.(*ethereum.Account)
orgConfig = &core.OrgConfig{
Name: m.OrgName,
Key: m.Address,
Key: account.Address,
}

blockchainConfig = &core.BlockchainConfig{
Expand All @@ -214,10 +218,6 @@ func (p *BesuProvider) GetFireflyConfig(stack *types.Stack, m *types.Member) (bl
return
}

func (p *BesuProvider) getSmartContractAddressPatchJSON(contractAddress string) []byte {
return []byte(fmt.Sprintf(`{"blockchain":{"ethereum":{"ethconnect":{"instance":"%s"}}}}`, contractAddress))
}

func (p *BesuProvider) Reset() error {
return nil
}
Expand Down Expand Up @@ -246,7 +246,7 @@ func (p *BesuProvider) DeployContract(filename, contractName string, member *typ
}, nil
}

func (p *BesuProvider) CreateAccount() (interface{}, error) {
func (p *BesuProvider) CreateAccount(args []string) (interface{}, error) {
address, privateKey := ethereum.GenerateAddressAndPrivateKey()

if err := p.writeAccountToDisk(p.Stack.RuntimeDir, address, privateKey); err != nil {
Expand Down Expand Up @@ -274,3 +274,11 @@ func (p *BesuProvider) getEthconnectURL(member *types.Member) string {
return fmt.Sprintf("http://127.0.0.1:%v", member.ExposedConnectorPort)
}
}

func (p *BesuProvider) ParseAccount(account interface{}) interface{} {
accountMap := account.(map[string]interface{})
return &ethereum.Account{
Address: accountMap["address"].(string),
PrivateKey: accountMap["privateKey"].(string),
}
}
10 changes: 6 additions & 4 deletions internal/blockchain/ethereum/ethconnect/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func deprecatedRegisterContract(ethconnectUrl string, abiId string, contractAddr

func deployContract(member *types.Member, contract *ethereum.CompiledContract, args map[string]string) (string, error) {
ethconnectUrl := fmt.Sprintf("http://127.0.0.1:%v", member.ExposedConnectorPort)

address := member.Account.(*ethereum.Account).Address
hexBytecode, err := hex.DecodeString(strings.TrimPrefix(contract.Bytecode, "0x"))
if err != nil {
return "", err
Expand All @@ -234,7 +234,7 @@ func deployContract(member *types.Member, contract *ethereum.CompiledContract, a
Headers: EthconnectMessageHeaders{
Type: "DeployContract",
},
From: member.Address,
From: address,
ABI: contract.ABI,
Bytecode: base64Bytecode,
}
Expand All @@ -257,10 +257,11 @@ func deployContract(member *types.Member, contract *ethereum.CompiledContract, a
func DeprecatedDeployContract(member *types.Member, contract *ethereum.CompiledContract, name string, args map[string]string) (string, error) {
ethconnectUrl := fmt.Sprintf("http://127.0.0.1:%v", member.ExposedConnectorPort)
abiResponse, err := publishABI(ethconnectUrl, contract)
address := member.Account.(*ethereum.Account).Address
if err != nil {
return "", err
}
deployResponse, err := deprecatedDeployContract(ethconnectUrl, abiResponse.ID, member.Address, args, name)
deployResponse, err := deprecatedDeployContract(ethconnectUrl, abiResponse.ID, address, args, name)
if err != nil {
return "", err
}
Expand All @@ -270,10 +271,11 @@ func DeprecatedDeployContract(member *types.Member, contract *ethereum.CompiledC
func DeprecatedRegisterContract(member *types.Member, contract *ethereum.CompiledContract, contractAddress string, name string, args map[string]string) error {
ethconnectUrl := fmt.Sprintf("http://127.0.0.1:%v", member.ExposedConnectorPort)
abiResponse, err := publishABI(ethconnectUrl, contract)
address := member.Account.(*ethereum.Account).Address
if err != nil {
return err
}
_, err = deprecatedRegisterContract(ethconnectUrl, abiResponse.ID, contractAddress, member.Address, name, args)
_, err = deprecatedRegisterContract(ethconnectUrl, abiResponse.ID, contractAddress, address, name, args)
if err != nil {
return err
}
Expand Down
5 changes: 5 additions & 0 deletions internal/blockchain/ethereum/ethereum.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ import (
"golang.org/x/crypto/sha3"
)

type Account struct {
Address string `json:"address"`
PrivateKey string `json:"privateKey"`
}

func GenerateAddressAndPrivateKey() (address string, privateKey string) {
newPrivateKey, _ := secp256k1.NewPrivateKey(secp256k1.S256())
privateKeyBytes := newPrivateKey.Serialize()
Expand Down
44 changes: 25 additions & 19 deletions internal/blockchain/ethereum/geth/geth_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ type GethProvider struct {
func (p *GethProvider) WriteConfig(options *types.InitOptions) error {
initDir := filepath.Join(constants.StacksDir, p.Stack.Name, "init")
for i, member := range p.Stack.Members {
account := member.Account.(*ethereum.Account)
// Write the private key to disk for each member
// Drop the 0x on the front of the private key here because that's what geth is expecting in the keyfile
if err := p.writeAccountToDisk(p.Stack.InitDir, member.Address, member.PrivateKey); err != nil {
if err := p.writeAccountToDisk(p.Stack.InitDir, account.Address, account.PrivateKey); err != nil {
return err
}

Expand All @@ -60,8 +61,9 @@ func (p *GethProvider) WriteConfig(options *types.InitOptions) error {
// Create genesis.json
addresses := make([]string, len(p.Stack.Members))
for i, member := range p.Stack.Members {
address := member.Account.(*ethereum.Account).Address
// Drop the 0x on the front of the address here because that's what geth is expecting in the genesis.json
addresses[i] = member.Address[2:]
addresses[i] = address[2:]
}
genesis := CreateGenesis(addresses, options.BlockPeriod)
if err := genesis.WriteGenesisJson(filepath.Join(initDir, "blockchain", "genesis.json")); err != nil {
Expand Down Expand Up @@ -95,7 +97,8 @@ func (p *GethProvider) FirstTimeSetup() error {

// Mount the directory containing all members' private keys and password, and import the accounts using the geth CLI
for _, member := range p.Stack.Members {
p.importAccountToGeth(member.Address)
address := member.Account.(*ethereum.Account).Address
p.importAccountToGeth(address)
}

// Copy the genesis block information
Expand All @@ -122,14 +125,8 @@ func (p *GethProvider) PreStart() error {

func (p *GethProvider) PostStart() error {
// Unlock accounts
for _, m := range p.Stack.Members {
p.Log.Info(fmt.Sprintf("unlocking %s", m.Address))
if err := p.unlockAccount(m.Address, "correcthorsebatterystaple"); err != nil {
return err
}
}
for _, account := range p.Stack.State.Accounts {
address := account.(map[string]string)["address"]
address := account.(*ethereum.Account).Address
p.Log.Info(fmt.Sprintf("unlocking account %s", address))
if err := p.unlockAccount(address, "correcthorsebatterystaple"); err != nil {
return err
Expand Down Expand Up @@ -164,13 +161,13 @@ func (p *GethProvider) DeployFireFlyContract() (*core.BlockchainConfig, error) {
}

func (p *GethProvider) GetDockerServiceDefinitions() []*docker.ServiceDefinition {
addresses := ""
for i, member := range p.Stack.Members {
addresses = addresses + member.Address
if i+1 < len(p.Stack.Members) {
addresses = addresses + ","
}
}
// addresses := ""
// for i, member := range p.Stack.Members {
// addresses = addresses + member.Address
// if i+1 < len(p.Stack.Members) {
// addresses = addresses + ","
// }
// }
gethCommand := fmt.Sprintf(`--datadir /data --syncmode 'full' --port 30311 --http --http.addr "0.0.0.0" --http.port 8545 --http.vhosts "*" --http.api 'admin,personal,eth,net,web3,txpool,miner,clique' --networkid 2021 --miner.gasprice 0 --password /data/password --mine --allow-insecure-unlock --nodiscover`)

serviceDefinitions := make([]*docker.ServiceDefinition, 1)
Expand All @@ -191,9 +188,10 @@ func (p *GethProvider) GetDockerServiceDefinitions() []*docker.ServiceDefinition
}

func (p *GethProvider) GetFireflyConfig(stack *types.Stack, m *types.Member) (blockchainConfig *core.BlockchainConfig, orgConfig *core.OrgConfig) {
account := m.Account.(*ethereum.Account)
orgConfig = &core.OrgConfig{
Name: m.OrgName,
Key: m.Address,
Key: account.Address,
}

blockchainConfig = &core.BlockchainConfig{
Expand Down Expand Up @@ -237,7 +235,7 @@ func (p *GethProvider) DeployContract(filename, contractName string, member *typ
}, nil
}

func (p *GethProvider) CreateAccount() (interface{}, error) {
func (p *GethProvider) CreateAccount(args []string) (interface{}, error) {
address, privateKey := ethereum.GenerateAddressAndPrivateKey()

if err := p.writeAccountToDisk(p.Stack.RuntimeDir, address, privateKey); err != nil {
Expand All @@ -263,3 +261,11 @@ func (p *GethProvider) getEthconnectURL(member *types.Member) string {
return fmt.Sprintf("http://127.0.0.1:%v", member.ExposedConnectorPort)
}
}

func (p *GethProvider) ParseAccount(account interface{}) interface{} {
accountMap := account.(map[string]interface{})
return &ethereum.Account{
Address: accountMap["address"].(string),
PrivateKey: accountMap["privateKey"].(string),
}
}

0 comments on commit 0bebae8

Please sign in to comment.