Skip to content

Commit

Permalink
Merge pull request #137 from kaleido-io/erc20-erc721
Browse files Browse the repository at this point in the history
Support multiple token connectors in a stack, with ERC20/ERC721
  • Loading branch information
dechdev authored Feb 2, 2022
2 parents 952932e + 68f55de commit 03797a8
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 151 deletions.
16 changes: 7 additions & 9 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import (
var initOptions stacks.InitOptions
var databaseSelection string
var blockchainProviderInput string
var tokensProviderSelection string
var tokenProvidersSelection []string
var promptNames bool

var ffNameValidator = regexp.MustCompile(`^[0-9a-zA-Z]([0-9a-zA-Z._-]{0,62}[0-9a-zA-Z])?$`)
Expand All @@ -53,7 +53,7 @@ var initCmd = &cobra.Command{
if err := validateBlockchainProvider(blockchainProviderInput); err != nil {
return err
}
if err := validateTokensProvider(tokensProviderSelection); err != nil {
if err := validateTokensProvider(tokenProvidersSelection); err != nil {
return err
}

Expand Down Expand Up @@ -100,7 +100,7 @@ var initCmd = &cobra.Command{
initOptions.Verbose = verbose
initOptions.BlockchainProvider, _ = stacks.BlockchainProviderFromString(blockchainProviderInput)
initOptions.DatabaseSelection, _ = stacks.DatabaseSelectionFromString(databaseSelection)
initOptions.TokensProvider, _ = stacks.TokensProviderFromString(tokensProviderSelection)
initOptions.TokenProviders, _ = stacks.TokenProvidersFromStrings(tokenProvidersSelection)

if err := stackManager.InitStack(stackName, memberCount, &initOptions); err != nil {
return err
Expand Down Expand Up @@ -161,14 +161,14 @@ func validateBlockchainProvider(input string) error {

// TODO: When we get tokens on Fabric this should change
if blockchainSelection == stacks.HyperledgerFabric {
tokensProviderSelection = "none"
tokenProvidersSelection = []string{}
}

return nil
}

func validateTokensProvider(input string) error {
_, err := stacks.TokensProviderFromString(input)
func validateTokensProvider(input []string) error {
_, err := stacks.TokenProvidersFromStrings(input)
if err != nil {
return err
}
Expand All @@ -180,13 +180,11 @@ func init() {
initCmd.Flags().IntVarP(&initOptions.ServicesBasePort, "services-base-port", "s", 5100, "Mapped port base of services (100 added for each member)")
initCmd.Flags().StringVarP(&databaseSelection, "database", "d", "sqlite3", fmt.Sprintf("Database type to use. Options are: %v", stacks.DBSelectionStrings))
initCmd.Flags().StringVarP(&blockchainProviderInput, "blockchain-provider", "b", "geth", fmt.Sprintf("Blockchain provider to use. Options are: %v", stacks.BlockchainProviderStrings))
initCmd.Flags().StringVarP(&tokensProviderSelection, "tokens-provider", "t", "erc1155", fmt.Sprintf("Tokens provider to use. Options are: %v", stacks.TokensProviderStrings))
initCmd.Flags().StringArrayVarP(&tokenProvidersSelection, "token-providers", "t", []string{"erc1155", "erc20_erc721"}, fmt.Sprintf("Token providers to use. Options are: %v", stacks.ValidTokenProviders))
initCmd.Flags().IntVarP(&initOptions.ExternalProcesses, "external", "e", 0, "Manage a number of FireFly core processes outside of the docker-compose stack - useful for development and debugging")
initCmd.Flags().StringVarP(&initOptions.FireFlyVersion, "release", "r", "latest", "Select the FireFly release version to use")
initCmd.Flags().StringVarP(&initOptions.ManifestPath, "manifest", "m", "", "Path to a manifest.json file containing the versions of each FireFly microservice to use. Overrides the --release flag.")
initCmd.Flags().BoolVar(&promptNames, "prompt-names", false, "Prompt for org and node names instead of using the defaults")
initCmd.Flags().BoolVar(&initOptions.PrometheusEnabled, "prometheus-enabled", false, "Enables Prometheus metrics exposition and aggregation to a shared Prometheus server")
initCmd.Flags().IntVar(&initOptions.PrometheusPort, "prometheus-port", 9090, "Port for the shared Prometheus server")

rootCmd.AddCommand(initCmd)
}
2 changes: 1 addition & 1 deletion internal/core/firefly_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ type FireflyConfig struct {
Database *DatabaseConfig `yaml:"database,omitempty"`
P2PFS *PublicStorageConfig `yaml:"publicstorage,omitempty"`
DataExchange *DataExchangeConfig `yaml:"dataexchange,omitempty"`
Tokens *TokensConfig `yaml:"tokens,omitempty"`
Tokens TokensConfig `yaml:"tokens,omitempty"`
Event *EventConfig `yaml:"event,omitempty"`
}

Expand Down
6 changes: 4 additions & 2 deletions internal/core/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ func TestGetFireFlyManifest(T *testing.T) {
assert.NotNil(T, manifest.Ethconnect)
assert.NotNil(T, manifest.Fabconnect)
assert.NotNil(T, manifest.DataExchange)
assert.NotNil(T, manifest.Tokens)
assert.NotNil(T, manifest.TokensERC1155)
assert.NotNil(T, manifest.TokensERC20ERC721)
}

func TestGetLatestReleaseManifest(T *testing.T) {
Expand All @@ -48,5 +49,6 @@ func TestGetLatestReleaseManifest(T *testing.T) {
assert.NotNil(T, manifest.Ethconnect)
assert.NotNil(T, manifest.Fabconnect)
assert.NotNil(T, manifest.DataExchange)
assert.NotNil(T, manifest.Tokens)
assert.NotNil(T, manifest.TokensERC1155)
assert.NotNil(T, manifest.TokensERC20ERC721)
}
103 changes: 62 additions & 41 deletions internal/stacks/stack_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import (
"github.com/hyperledger/firefly-cli/internal/docker"
"github.com/hyperledger/firefly-cli/internal/tokens"
"github.com/hyperledger/firefly-cli/internal/tokens/erc1155"
"github.com/hyperledger/firefly-cli/internal/tokens/niltokens"
"github.com/hyperledger/firefly-cli/internal/tokens/erc20erc721"
"github.com/hyperledger/firefly-cli/pkg/types"
"golang.org/x/crypto/sha3"

Expand All @@ -54,7 +54,7 @@ type StackManager struct {
Log log.Logger
Stack *types.Stack
blockchainProvider blockchain.IBlockchainProvider
tokensProvider tokens.ITokensProvider
tokenProviders []tokens.ITokensProvider
}

type PullOptions struct {
Expand All @@ -74,7 +74,7 @@ type InitOptions struct {
OrgNames []string
NodeNames []string
BlockchainProvider BlockchainProvider
TokensProvider TokensProvider
TokenProviders types.TokenProviders
FireFlyVersion string
ManifestPath string
PrometheusEnabled bool
Expand Down Expand Up @@ -114,7 +114,7 @@ func (s *StackManager) InitStack(stackName string, memberCount int, options *Ini
ExposedBlockchainPort: options.ServicesBasePort,
Database: options.DatabaseSelection.String(),
BlockchainProvider: options.BlockchainProvider.String(),
TokensProvider: options.TokensProvider.String(),
TokenProviders: options.TokenProviders,
}

if options.PrometheusEnabled {
Expand Down Expand Up @@ -147,15 +147,17 @@ func (s *StackManager) InitStack(stackName string, memberCount int, options *Ini

s.Stack.VersionManifest = manifest
s.blockchainProvider = s.getBlockchainProvider(false)
s.tokensProvider = s.getTokensProvider(false)
s.tokenProviders = s.getITokenProviders(false)

for i := 0; i < memberCount; i++ {
externalProcess := i < options.ExternalProcesses
s.Stack.Members[i] = createMember(fmt.Sprint(i), i, options, externalProcess)
}
compose := docker.CreateDockerCompose(s.Stack)
extraServices := s.blockchainProvider.GetDockerServiceDefinitions()
extraServices = append(extraServices, s.tokensProvider.GetDockerServiceDefinitions()...)
for i, tp := range s.tokenProviders {
extraServices = append(extraServices, tp.GetDockerServiceDefinitions(i)...)
}

for _, serviceDefinition := range extraServices {
// Add each service definition to the docker compose file
Expand Down Expand Up @@ -215,7 +217,7 @@ func (s *StackManager) LoadStack(stackName string, verbose bool) error {
}
s.Stack = stack
s.blockchainProvider = s.getBlockchainProvider(verbose)
s.tokensProvider = s.getTokensProvider(verbose)
s.tokenProviders = s.getITokenProviders(verbose)
}
// For backwards compatability, add a "default" VersionManifest
// in memory for stacks that were created with old CLI versions
Expand All @@ -237,10 +239,14 @@ func (s *StackManager) LoadStack(stackName string, verbose bool) error {
Image: "ghcr.io/hyperledger/firefly-dataexchange-https",
Tag: "latest",
},
Tokens: &types.ManifestEntry{
TokensERC1155: &types.ManifestEntry{
Image: "ghcr.io/hyperledger/firefly-tokens-erc1155",
Tag: "latest",
},
TokensERC20ERC721: &types.ManifestEntry{
Image: "ghcr.io/hyperledger/firefly-tokens-erc20-erc721",
Tag: "latest",
},
}
}
return nil
Expand Down Expand Up @@ -284,7 +290,9 @@ func (s *StackManager) writeConfigs(verbose bool) error {
for _, member := range s.Stack.Members {
config := core.NewFireflyConfig(s.Stack, member)
config.Blockchain, config.Org = s.blockchainProvider.GetFireflyConfig(member)
config.Tokens = s.tokensProvider.GetFireflyConfig(member)
for iTok, tp := range s.tokenProviders {
config.Tokens = append(config.Tokens, tp.GetFireflyConfig(member, iTok))
}
if err := core.WriteFireflyConfig(config, filepath.Join(stackDir, "configs", fmt.Sprintf("firefly_core_%s.yml", member.ID))); err != nil {
return err
}
Expand Down Expand Up @@ -369,14 +377,18 @@ func createMember(id string, index int, options *InitOptions, external bool) *ty
ExposedDataexchangePort: serviceBase + 5,
ExposedIPFSApiPort: serviceBase + 6,
ExposedIPFSGWPort: serviceBase + 7,
ExposedTokensPort: serviceBase + 8,
External: external,
OrgName: options.OrgNames[index],
NodeName: options.NodeNames[index],
}

nextPort := serviceBase + 8
if options.PrometheusEnabled {
member.ExposedFireflyMetricsPort = serviceBase + 9
member.ExposedFireflyMetricsPort = nextPort
nextPort++
}
for range options.TokenProviders {
member.ExposedTokensPorts = append(member.ExposedTokensPorts, nextPort)
nextPort++
}
return member
}
Expand Down Expand Up @@ -449,8 +461,10 @@ func (s *StackManager) PullStack(verbose bool, options *PullOptions) error {
}

// Iterate over all images used by the tokens provider
for _, service := range s.tokensProvider.GetDockerServiceDefinitions() {
images = append(images, service.Service.Image)
for iTok, tp := range s.tokenProviders {
for _, service := range tp.GetDockerServiceDefinitions(iTok) {
images = append(images, service.Service.Image)
}
}

// Use docker to pull every image - retry on failure
Expand All @@ -468,8 +482,10 @@ func (s *StackManager) removeVolumes(verbose bool) {
for _, service := range s.blockchainProvider.GetDockerServiceDefinitions() {
volumes = append(volumes, service.VolumeNames...)
}
for _, service := range s.tokensProvider.GetDockerServiceDefinitions() {
volumes = append(volumes, service.VolumeNames...)
for iTok, tp := range s.tokenProviders {
for _, service := range tp.GetDockerServiceDefinitions(iTok) {
volumes = append(volumes, service.VolumeNames...)
}
}
for volumeName := range docker.CreateDockerCompose(s.Stack).Volumes {
volumes = append(volumes, volumeName)
Expand Down Expand Up @@ -539,7 +555,7 @@ func (s *StackManager) checkPortsAvailable() error {
ports = append(ports, member.ExposedIPFSGWPort)
ports = append(ports, member.ExposedPostgresPort)
ports = append(ports, member.ExposedUIPort)
ports = append(ports, member.ExposedTokensPort)
ports = append(ports, member.ExposedTokensPorts...)
}

if s.Stack.PrometheusEnabled {
Expand Down Expand Up @@ -633,8 +649,10 @@ func (s *StackManager) runFirstTimeSetup(verbose bool, options *StartOptions) er
if err := s.blockchainProvider.DeploySmartContracts(); err != nil {
return err
}
if err := s.tokensProvider.DeploySmartContracts(); err != nil {
return err
for i, tp := range s.tokenProviders {
if err := tp.DeploySmartContracts(i); err != nil {
return err
}
}

if err := s.patchConfigAndRestartFireflyNodes(verbose); err != nil {
Expand All @@ -647,8 +665,10 @@ func (s *StackManager) runFirstTimeSetup(verbose bool, options *StartOptions) er
}

s.Log.Info("initializing token providers")
if err := s.tokensProvider.FirstTimeSetup(); err != nil {
return err
for iTok, tp := range s.tokenProviders {
if err := tp.FirstTimeSetup(iTok); err != nil {
return err
}
}
return nil
}
Expand Down Expand Up @@ -721,12 +741,9 @@ func (s *StackManager) PrintStackInfo(verbose bool) error {

func (s *StackManager) patchConfigAndRestartFireflyNodes(verbose bool) error {
for _, member := range s.Stack.Members {
configPayload := map[string]interface{}{
"preInit": false,
}
s.Log.Info(fmt.Sprintf("applying configuration changes to %s", member.ID))
configRecordUrl := fmt.Sprintf("http://localhost:%d/admin/api/v1/config/records/admin", member.ExposedFireflyAdminPort)
if err := core.RequestWithRetry("PUT", configRecordUrl, configPayload, nil); err != nil && err != io.EOF {
configRecordUrl := fmt.Sprintf("http://localhost:%d/admin/api/v1/config/records/admin.preInit", member.ExposedFireflyAdminPort)
if err := core.RequestWithRetry("PUT", configRecordUrl, "false", nil); err != nil && err != io.EOF {
return err
}
resetUrl := fmt.Sprintf("http://localhost:%d/admin/api/v1/config/reset", member.ExposedFireflyAdminPort)
Expand Down Expand Up @@ -774,21 +791,25 @@ func (s *StackManager) getBlockchainProvider(verbose bool) blockchain.IBlockchai
}
}

func (s *StackManager) getTokensProvider(verbose bool) tokens.ITokensProvider {
switch s.Stack.TokensProvider {
case NilTokens.String():
return &niltokens.NilTokensProvider{
Verbose: verbose,
Log: s.Log,
Stack: s.Stack,
}
case ERC1155.String():
return &erc1155.ERC1155Provider{
Verbose: verbose,
Log: s.Log,
Stack: s.Stack,
func (s *StackManager) getITokenProviders(verbose bool) []tokens.ITokensProvider {
tps := make([]tokens.ITokensProvider, len(s.Stack.TokenProviders))
for i, tp := range s.Stack.TokenProviders {
switch tp {
case ERC1155:
tps[i] = &erc1155.ERC1155Provider{
Verbose: verbose,
Log: s.Log,
Stack: s.Stack,
}
case ERC20_ERC721:
tps[i] = &erc20erc721.ERC20ERC721Provider{
Verbose: verbose,
Log: s.Log,
Stack: s.Stack,
}
default:
return nil
}
default:
return nil
}
return tps
}
37 changes: 22 additions & 15 deletions internal/stacks/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package stacks
import (
"fmt"
"strings"

"github.com/hyperledger/firefly-cli/pkg/types"
)

type DatabaseSelection int
Expand Down Expand Up @@ -67,24 +69,29 @@ func BlockchainProviderFromString(s string) (BlockchainProvider, error) {
return GoEthereum, fmt.Errorf("\"%s\" is not a valid blockchain provider selection. valid options are: %v", s, BlockchainProviderStrings)
}

type TokensProvider int

const (
NilTokens TokensProvider = iota
ERC1155
NilTokens types.TokenProvider = "none"
ERC1155 types.TokenProvider = "erc1155"
ERC20_ERC721 types.TokenProvider = "erc20_erc721"
)

var TokensProviderStrings = []string{"none", "erc1155"}

func (tokensProvider TokensProvider) String() string {
return TokensProviderStrings[tokensProvider]
}

func TokensProviderFromString(s string) (TokensProvider, error) {
for i, tokensProviderSelection := range TokensProviderStrings {
if strings.ToLower(s) == tokensProviderSelection {
return TokensProvider(i), nil
var ValidTokenProviders = []types.TokenProvider{NilTokens, ERC1155, ERC20_ERC721}

func TokenProvidersFromStrings(strTokens []string) (tps types.TokenProviders, err error) {
tps = make([]types.TokenProvider, 0, len(strTokens))
for _, s := range strTokens {
found := false
for _, tokensProviderSelection := range ValidTokenProviders {
if strings.ToLower(s) == string(tokensProviderSelection) {
found = true
if tokensProviderSelection != NilTokens {
tps = append(tps, tokensProviderSelection)
}
}
}
if !found {
return nil, fmt.Errorf("\"%s\" is not a valid tokens provider selection. valid options are: %v", s, ValidTokenProviders)
}
}
return ERC1155, fmt.Errorf("\"%s\" is not a valid tokens provider selection. valid options are: %v", s, TokensProviderStrings)
return tps, nil
}
4 changes: 2 additions & 2 deletions internal/tokens/erc1155/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ import (

const TOKEN_URI_PATTERN = "firefly://token/{id}"

func DeployContracts(s *types.Stack, log log.Logger, verbose bool) error {
func DeployContracts(s *types.Stack, log log.Logger, verbose bool, tokenIndex int) error {
var containerName string
for _, member := range s.Members {
if !member.External {
containerName = fmt.Sprintf("%s_tokens_%s", s.Name, member.ID)
containerName = fmt.Sprintf("%s_tokens_%s_%d", s.Name, member.ID, tokenIndex)
break
}
}
Expand Down
Loading

0 comments on commit 03797a8

Please sign in to comment.