Skip to content

Commit

Permalink
Merge "[FAB-14298] Enable FabToken with V2_0 capability"
Browse files Browse the repository at this point in the history
  • Loading branch information
sykesm authored and Gerrit Code Review committed Feb 28, 2019
2 parents 92affbd + 4f4b7f9 commit 484ba11
Show file tree
Hide file tree
Showing 12 changed files with 2,533 additions and 54 deletions.
18 changes: 6 additions & 12 deletions common/capabilities/application.go
Expand Up @@ -30,19 +30,16 @@ const (

// ApplicationResourcesTreeExperimental is the capabilties string for private data using the experimental feature of collections/sideDB.
ApplicationResourcesTreeExperimental = "V1_1_RESOURCETREE_EXPERIMENTAL"

ApplicationFabTokenExperimental = "V1_4_FABTOKEN_EXPERIMENTAL"
)

// ApplicationProvider provides capabilities information for application level config.
type ApplicationProvider struct {
*registry
v11 bool
v12 bool
v13 bool
v20 bool
v11PvtDataExperimental bool
v14FabTokenExperimental bool
v11 bool
v12 bool
v13 bool
v20 bool
v11PvtDataExperimental bool
}

// NewApplicationProvider creates a application capabilities provider.
Expand All @@ -54,7 +51,6 @@ func NewApplicationProvider(capabilities map[string]*cb.Capability) *Application
_, ap.v13 = capabilities[ApplicationV1_3]
_, ap.v20 = capabilities[ApplicationV2_0]
_, ap.v11PvtDataExperimental = capabilities[ApplicationPvtDataExperimental]
_, ap.v14FabTokenExperimental = capabilities[ApplicationFabTokenExperimental]
return ap
}

Expand Down Expand Up @@ -134,7 +130,7 @@ func (ap *ApplicationProvider) KeyLevelEndorsement() bool {

// FabToken returns true if support for fabric token functions is enabled.
func (ap *ApplicationProvider) FabToken() bool {
return ap.v14FabTokenExperimental
return ap.v20
}

// HasCapability returns true if the capability is supported by this binary.
Expand All @@ -153,8 +149,6 @@ func (ap *ApplicationProvider) HasCapability(capability string) bool {
return true
case ApplicationResourcesTreeExperimental:
return true
case ApplicationFabTokenExperimental:
return true
default:
return false
}
Expand Down
8 changes: 1 addition & 7 deletions common/capabilities/application_test.go
Expand Up @@ -70,6 +70,7 @@ func TestApplicationV20(t *testing.T) {
assert.True(t, ap.CollectionUpgrade())
assert.True(t, ap.PrivateChannelData())
assert.True(t, ap.LifecycleV20())
assert.True(t, ap.FabToken())
}

func TestApplicationPvtDataExperimental(t *testing.T) {
Expand All @@ -79,13 +80,6 @@ func TestApplicationPvtDataExperimental(t *testing.T) {
assert.True(t, ap.PrivateChannelData())
}

func TestFabTokenExperimental(t *testing.T) {
ap := NewApplicationProvider(map[string]*cb.Capability{
ApplicationFabTokenExperimental: {},
})
assert.True(t, ap.FabToken())
}

func TestHasCapability(t *testing.T) {
ap := NewApplicationProvider(map[string]*cb.Capability{})
assert.True(t, ap.HasCapability(ApplicationV1_1))
Expand Down
6 changes: 5 additions & 1 deletion integration/nwo/configtx_template.go
Expand Up @@ -117,8 +117,12 @@ Profiles:{{ range .Profiles }}
Consortium: {{ .Consortium }}
Application:
Capabilities:
{{- if .AppCapabilities }}{{ range .AppCapabilities }}
{{ . }}: true
{{- end }}
{{- else }}
V1_3: true
CAPABILITY_PLACEHOLDER: false
{{- end }}
Organizations:{{ range .Organizations }}
- *{{ ($w.Organization .).MSPID }}
{{- end}}
Expand Down
9 changes: 5 additions & 4 deletions integration/nwo/network.go
Expand Up @@ -121,10 +121,11 @@ func (p *Peer) Anchor() bool {

// A profile encapsulates basic information for a configtxgen profile.
type Profile struct {
Name string `yaml:"name,omitempty"`
Orderers []string `yaml:"orderers,omitempty"`
Consortium string `yaml:"consortium,omitempty"`
Organizations []string `yaml:"organizations,omitempty"`
Name string `yaml:"name,omitempty"`
Orderers []string `yaml:"orderers,omitempty"`
Consortium string `yaml:"consortium,omitempty"`
Organizations []string `yaml:"organizations,omitempty"`
AppCapabilities []string `yaml:"appcapabilities,omitempty"`
}

// Network holds information about a fabric network.
Expand Down
11 changes: 11 additions & 0 deletions integration/nwo/standard_networks.go
Expand Up @@ -86,6 +86,17 @@ func BasicSolo() *Config {
}
}

// BasicSoloV20 returns a BasicSolo config with V2_0 application capability
func BasicSoloV20() *Config {
basicSolo := BasicSolo()
for _, profile := range basicSolo.Profiles {
if profile.Consortium != "" {
profile.AppCapabilities = []string{"V2_0"}
}
}
return basicSolo
}

func BasicKafka() *Config {
config := BasicSolo()
config.Consensus.Type = "kafka"
Expand Down
32 changes: 3 additions & 29 deletions integration/token/token_test.go
Expand Up @@ -7,7 +7,6 @@ SPDX-License-Identifier: Apache-2.0
package token

import (
"bytes"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -139,13 +138,9 @@ var _ bool = Describe("Token EndToEnd", func() {
Describe("basic solo network for token transaction e2e using Token CLI", func() {
BeforeEach(func() {
var err error
network = nwo.New(nwo.BasicSolo(), testDir, client, 30000, components)
network = nwo.New(nwo.BasicSoloV20(), testDir, client, 30000, components)
network.GenerateConfigTree()

// update configtx with fabtoken capability
err = updateConfigtx(network)
Expect(err).NotTo(HaveOccurred())

network.Bootstrap()

client, err = docker.NewClientFromEnv()
Expand Down Expand Up @@ -229,13 +224,9 @@ var _ bool = Describe("Token EndToEnd", func() {

BeforeEach(func() {
var err error
network = nwo.New(nwo.BasicSolo(), testDir, client, 30000, components)
network = nwo.New(nwo.BasicSoloV20(), testDir, client, 30000, components)
network.GenerateConfigTree()

// update configtx with fabtoken capability
err = updateConfigtx(network)
Expect(err).NotTo(HaveOccurred())

network.Bootstrap()

client, err = docker.NewClientFromEnv()
Expand Down Expand Up @@ -337,13 +328,9 @@ var _ bool = Describe("Token EndToEnd", func() {

BeforeEach(func() {
var err error
network = nwo.New(nwo.BasicSolo(), testDir, client, 30000, components)
network = nwo.New(nwo.BasicSoloV20(), testDir, client, 30000, components)
network.GenerateConfigTree()

// update configtx with fabtoken capability
err = updateConfigtx(network)
Expect(err).NotTo(HaveOccurred())

network.Bootstrap()

client, err = docker.NewClientFromEnv()
Expand Down Expand Up @@ -826,19 +813,6 @@ func getSigningIdentity(mspConfigPath, mspID, mspType string) (tk.SigningIdentit
return signingIdentity, nil
}

// update configtx.yaml with V1_4_FABTOKEN_EXPERIMENTAL: true
func updateConfigtx(network *nwo.Network) error {
filepath := network.ConfigTxConfigPath()
input, err := ioutil.ReadFile(filepath)
if err != nil {
return err
}

// update the CAPABILITY_PLACEHOLDER to enable fabtoken capability
output := bytes.Replace(input, []byte("CAPABILITY_PLACEHOLDER: false"), []byte("V1_4_FABTOKEN_EXPERIMENTAL: true"), -1)
return ioutil.WriteFile(filepath, output, 0644)
}

// LoadLocalMSPAt loads an MSP whose configuration is stored at 'dir', and whose
// id and type are the passed as arguments.
func LoadLocalMSPAt(dir, id, mspType string) (msp.MSP, error) {
Expand Down
8 changes: 7 additions & 1 deletion token/server/capability_checker.go
Expand Up @@ -23,7 +23,13 @@ type TokenCapabilityChecker struct {
}

func (c *TokenCapabilityChecker) FabToken(channelId string) (bool, error) {
ac, ok := c.PeerOps.GetChannelConfig(channelId).ApplicationConfig()
channelConfig := c.PeerOps.GetChannelConfig(channelId)
if channelConfig == nil {
// no channelConfig is found, most likely the channel does not exist
return false, errors.Errorf("no channel config found for channel %s", channelId)
}

ac, ok := channelConfig.ApplicationConfig()
if !ok {
return false, errors.Errorf("no application config found for channel %s", channelId)
}
Expand Down
105 changes: 105 additions & 0 deletions token/server/capability_checker_test.go
@@ -0,0 +1,105 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package server_test

import (
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/token/server"
"github.com/hyperledger/fabric/token/server/mock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

//go:generate counterfeiter -o mock/peer_operations.go -fake-name PeerOperations . peerOperations

//go:generate counterfeiter -o mock/channel_config.go -fake-name ChannelConfig . channelConfig

//go:generate counterfeiter -o mock/application_config.go -fake-name ApplicationConfig . applicationConfig

//go:generate counterfeiter -o mock/application_capabilities.go -fake-name ApplicationCapabilities . applicationCapabilities

type peerOperations interface {
peer.Operations
}

type channelConfig interface {
channelconfig.Resources
}

type applicationConfig interface {
channelconfig.Application
}

type applicationCapabilities interface {
channelconfig.ApplicationCapabilities
}

var _ = Describe("CapabilityChecker", func() {
var (
channelId = "mychannel"

fakeAppCapabilities *mock.ApplicationCapabilities
fakeAppConfig *mock.ApplicationConfig
fakeChannelConfig *mock.ChannelConfig
fakePeerOperations *mock.PeerOperations

capabilityChecker *server.TokenCapabilityChecker
)

BeforeEach(func() {
fakeAppCapabilities = &mock.ApplicationCapabilities{}
fakeAppCapabilities.FabTokenReturns(true)

fakeAppConfig = &mock.ApplicationConfig{}
fakeAppConfig.CapabilitiesReturns(fakeAppCapabilities)

fakeChannelConfig = &mock.ChannelConfig{}
fakeChannelConfig.ApplicationConfigReturns(fakeAppConfig, true)

fakePeerOperations = &mock.PeerOperations{}
fakePeerOperations.GetChannelConfigReturns(fakeChannelConfig)

capabilityChecker = &server.TokenCapabilityChecker{PeerOps: fakePeerOperations}
})

It("returns FabToken true when application capabilities returns true", func() {
fakeAppCapabilities.FabTokenReturns(true)
result, err := capabilityChecker.FabToken(channelId)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(true))
})

It("returns FabToken false when application capabilities returns false", func() {
fakeAppCapabilities.FabTokenReturns(false)
result, err := capabilityChecker.FabToken(channelId)
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(false))
})

Context("when channel config is not found", func() {
BeforeEach(func() {
fakePeerOperations.GetChannelConfigReturns(nil)
})

It("returns the error", func() {
_, err := capabilityChecker.FabToken(channelId)
Expect(err).To(MatchError("no channel config found for channel " + channelId))
})
})

Context("when application config is not found", func() {
BeforeEach(func() {
fakeChannelConfig.ApplicationConfigReturns(nil, false)
})

It("returns the error", func() {
_, err := capabilityChecker.FabToken(channelId)
Expect(err).To(MatchError("no application config found for channel " + channelId))
})
})
})

0 comments on commit 484ba11

Please sign in to comment.