Skip to content

Commit 1240736

Browse files
committed
[FAB-9724] Validation plugin infrastructure support
This change set adds support to the handlers to load validation plugins. Change-Id: I1cbf29bfe8899a43569a67d830c21d6f3b67d833 Signed-off-by: yacovm <yacovm@il.ibm.com>
1 parent fc733e6 commit 1240736

File tree

3 files changed

+114
-7
lines changed

3 files changed

+114
-7
lines changed

core/handlers/library/registry.go

+47-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/hyperledger/fabric/core/handlers/auth"
1818
"github.com/hyperledger/fabric/core/handlers/decoration"
1919
endorsement2 "github.com/hyperledger/fabric/core/handlers/endorsement/api"
20+
"github.com/hyperledger/fabric/core/handlers/validation/api"
2021
)
2122

2223
var logger = flogging.MustGetLogger("core/handlers")
@@ -40,16 +41,18 @@ const (
4041
// passed to the chaincode
4142
Decoration
4243
Endorsement
44+
Validation
4345

44-
authPluginFactory = "NewFilter"
45-
decoratorPluginFactory = "NewDecorator"
46-
endorsementPluginFactory = "NewPluginFactory"
46+
authPluginFactory = "NewFilter"
47+
decoratorPluginFactory = "NewDecorator"
48+
pluginFactory = "NewPluginFactory"
4749
)
4850

4951
type registry struct {
5052
filters []auth.Filter
5153
decorators []decoration.Decorator
5254
endorsers map[string]endorsement2.PluginFactory
55+
validators map[string]validation.PluginFactory
5356
}
5457

5558
var once sync.Once
@@ -61,6 +64,7 @@ type Config struct {
6164
AuthFilters []*HandlerConfig `mapstructure:"authFilters" yaml:"authFilters"`
6265
Decorators []*HandlerConfig `mapstructure:"decorators" yaml:"decorators"`
6366
Endorsers PluginMapping `mapstructure:"endorsers" yaml:"endorsers"`
67+
Validators PluginMapping `mapstructure:"validators" yaml:"validators"`
6468
}
6569

6670
type PluginMapping map[string]*HandlerConfig
@@ -75,7 +79,10 @@ type HandlerConfig struct {
7579
// of the registry
7680
func InitRegistry(c Config) Registry {
7781
once.Do(func() {
78-
reg = registry{endorsers: make(map[string]endorsement2.PluginFactory)}
82+
reg = registry{
83+
endorsers: make(map[string]endorsement2.PluginFactory),
84+
validators: make(map[string]validation.PluginFactory),
85+
}
7986
reg.loadHandlers(c)
8087
})
8188
return &reg
@@ -93,6 +100,10 @@ func (r *registry) loadHandlers(c Config) {
93100
for chaincodeID, config := range c.Endorsers {
94101
r.evaluateModeAndLoad(config, Endorsement, chaincodeID)
95102
}
103+
104+
for chaincodeID, config := range c.Validators {
105+
r.evaluateModeAndLoad(config, Validation, chaincodeID)
106+
}
96107
}
97108

98109
// evaluateModeAndLoad if a library path is provided, load the shared object
@@ -124,6 +135,11 @@ func (r *registry) loadCompiled(handlerFactory string, handlerType HandlerType,
124135
logger.Panicf("expected 1 argument in extraArgs")
125136
}
126137
r.endorsers[extraArgs[0]] = inst.(endorsement2.PluginFactory)
138+
} else if handlerType == Validation {
139+
if len(extraArgs) != 1 {
140+
logger.Panicf("expected 1 argument in extraArgs")
141+
}
142+
r.validators[extraArgs[0]] = inst.(validation.PluginFactory)
127143
}
128144
}
129145

@@ -143,6 +159,8 @@ func (r *registry) loadPlugin(pluginPath string, handlerType HandlerType, extraA
143159
r.initDecoratorPlugin(p)
144160
} else if handlerType == Endorsement {
145161
r.initEndorsementPlugin(p, extraArgs...)
162+
} else if handlerType == Validation {
163+
r.initValidationPlugin(p, extraArgs...)
146164
}
147165
}
148166

@@ -183,14 +201,14 @@ func (r *registry) initEndorsementPlugin(p *plugin.Plugin, extraArgs ...string)
183201
if len(extraArgs) != 1 {
184202
logger.Panicf("expected 1 argument in extraArgs")
185203
}
186-
factorySymbol, err := p.Lookup(endorsementPluginFactory)
204+
factorySymbol, err := p.Lookup(pluginFactory)
187205
if err != nil {
188-
panicWithLookupError(endorsementPluginFactory, err)
206+
panicWithLookupError(pluginFactory, err)
189207
}
190208

191209
constructor, ok := factorySymbol.(func() endorsement2.PluginFactory)
192210
if !ok {
193-
panicWithDefinitionError(endorsementPluginFactory)
211+
panicWithDefinitionError(pluginFactory)
194212
}
195213
factory := constructor()
196214
if factory == nil {
@@ -199,6 +217,26 @@ func (r *registry) initEndorsementPlugin(p *plugin.Plugin, extraArgs ...string)
199217
r.endorsers[extraArgs[0]] = factory
200218
}
201219

220+
func (r *registry) initValidationPlugin(p *plugin.Plugin, extraArgs ...string) {
221+
if len(extraArgs) != 1 {
222+
logger.Panicf("expected 1 argument in extraArgs")
223+
}
224+
factorySymbol, err := p.Lookup(pluginFactory)
225+
if err != nil {
226+
panicWithLookupError(pluginFactory, err)
227+
}
228+
229+
constructor, ok := factorySymbol.(func() validation.PluginFactory)
230+
if !ok {
231+
panicWithDefinitionError(pluginFactory)
232+
}
233+
factory := constructor()
234+
if factory == nil {
235+
logger.Panicf("factory instance returned nil")
236+
}
237+
r.validators[extraArgs[0]] = factory
238+
}
239+
202240
// panicWithLookupError panics when a handler constructor lookup fails
203241
func panicWithLookupError(factory string, err error) {
204242
logger.Panicf(fmt.Sprintf("Plugin must contain constructor with name %s. Error from lookup: %s",
@@ -221,6 +259,8 @@ func (r *registry) Lookup(handlerType HandlerType) interface{} {
221259
return r.decorators
222260
} else if handlerType == Endorsement {
223261
return r.endorsers
262+
} else if handlerType == Validation {
263+
return r.validators
224264
}
225265

226266
return nil

core/handlers/library/registry_plugin_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/golang/protobuf/proto"
2222
"github.com/hyperledger/fabric/core/handlers/endorsement/api"
23+
"github.com/hyperledger/fabric/core/handlers/validation/api"
2324
"github.com/hyperledger/fabric/protos/peer"
2425
"github.com/stretchr/testify/assert"
2526
)
@@ -28,6 +29,7 @@ const (
2829
authPluginPackage = "github.com/hyperledger/fabric/core/handlers/auth/plugin"
2930
decoratorPluginPackage = "github.com/hyperledger/fabric/core/handlers/decoration/plugin"
3031
endorsementTestPlugin = "github.com/hyperledger/fabric/core/handlers/endorsement/testdata/"
32+
validationTestPlugin = "github.com/hyperledger/fabric/core/handlers/validation/testdata/"
3133
)
3234

3335
func TestLoadAuthPlugin(t *testing.T) {
@@ -99,6 +101,30 @@ func TestEndorsementPlugin(t *testing.T) {
99101
assert.Equal(t, []byte{1, 2, 3}, output)
100102
}
101103

104+
func TestValidationPlugin(t *testing.T) {
105+
testDir, err := ioutil.TempDir("", "")
106+
assert.NoError(t, err, "Could not create temp directory for plugins")
107+
defer os.Remove(testDir)
108+
109+
pluginPath := strings.Join([]string{testDir, "/", "validationplugin.so"}, "")
110+
111+
cmd := exec.Command("go", "build", "-o", pluginPath, "-buildmode=plugin",
112+
validationTestPlugin)
113+
output, err := cmd.CombinedOutput()
114+
assert.NoError(t, err, "Could not build plugin: "+string(output))
115+
116+
testReg := registry{validators: make(map[string]validation.PluginFactory)}
117+
testReg.loadPlugin(pluginPath, Validation, "vscc")
118+
mapping := testReg.Lookup(Validation).(map[string]validation.PluginFactory)
119+
factory := mapping["vscc"]
120+
assert.NotNil(t, factory)
121+
instance := factory.New()
122+
assert.NotNil(t, instance)
123+
assert.NoError(t, instance.Init())
124+
err = instance.Validate(nil, "", 0, 0)
125+
assert.NoError(t, err)
126+
}
127+
102128
func TestLoadPluginInvalidPath(t *testing.T) {
103129
defer func() {
104130
if r := recover(); r == nil {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package main
8+
9+
import (
10+
"github.com/hyperledger/fabric/core/handlers/validation/api"
11+
"github.com/hyperledger/fabric/protos/common"
12+
)
13+
14+
// NoOpValidator is used to test validation plugin infrastructure
15+
type NoOpValidator struct {
16+
}
17+
18+
// Validate valides the transactions with the given data
19+
func (*NoOpValidator) Validate(_ *common.Block, _ string, _ int, _ int, _ ...validation.ContextDatum) error {
20+
return nil
21+
}
22+
23+
// Init initializes the plugin with the given dependencies
24+
func (*NoOpValidator) Init(dependencies ...validation.Dependency) error {
25+
return nil
26+
}
27+
28+
// NoOpValidatorFactory creates new NoOpValidators
29+
type NoOpValidatorFactory struct {
30+
}
31+
32+
// New returns an instance of a NoOpValidator
33+
func (*NoOpValidatorFactory) New() validation.Plugin {
34+
return &NoOpValidator{}
35+
}
36+
37+
// NewPluginFactory is called by the validation plugin framework to obtain an instance
38+
// of the factory
39+
func NewPluginFactory() validation.PluginFactory {
40+
return &NoOpValidatorFactory{}
41+
}

0 commit comments

Comments
 (0)