Skip to content

Commit ae10d2b

Browse files
committed
[FAB-1639] [FAB-1580] Rework validator
This change-set has removed calls to the txvalidator that were issued right after the peer (the leader) receives blocks from the orderers. The validator is now called to validate messages received from the gossip layer. In order to fix an import cycle, we have introduced the ChaincodeProvider interface in core/common/ccprovider/ccprovider.go, an implementation and a factory. This way, code that needs to use functions from the chaincode package without importing it can simply use (and possibly extend) the ChaincodeProvider interface and implementation. Furthermore, this drop has introduced protocol-level message validation for config transactions that was lacking before. Change-Id: I5906a6fe3da8410b05b5079dd7f0b9d28d20bb85 Signed-off-by: Alessandro Sorniotti <[email protected]>
1 parent dca94df commit ae10d2b

File tree

23 files changed

+431
-93
lines changed

23 files changed

+431
-93
lines changed

common/configtx/template.go

+19-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import (
2222
ab "github.com/hyperledger/fabric/protos/orderer"
2323
"github.com/hyperledger/fabric/protos/utils"
2424

25+
"fmt"
26+
2527
"github.com/golang/protobuf/proto"
28+
"github.com/hyperledger/fabric/msp"
2629
)
2730

2831
const (
@@ -150,16 +153,29 @@ func join(sets ...[]*cb.SignedConfigurationItem) []*cb.SignedConfigurationItem {
150153
}
151154

152155
// MakeChainCreationTransaction is a handy utility function for creating new chain transactions using the underlying Template framework
153-
func MakeChainCreationTransaction(creationPolicy string, chainID string, templates ...Template) (*cb.Envelope, error) {
156+
func MakeChainCreationTransaction(creationPolicy string, chainID string, signer msp.SigningIdentity, templates ...Template) (*cb.Envelope, error) {
154157
newChainTemplate := NewChainCreationTemplate(creationPolicy, NewCompositeTemplate(templates...))
155158
signedConfigItems, err := newChainTemplate.Items(chainID)
156159
if err != nil {
157160
return nil, err
158161
}
159162

163+
sSigner, err := signer.Serialize()
164+
if err != nil {
165+
return nil, fmt.Errorf("Serialization of identity failed, err %s", err)
166+
}
167+
160168
payloadChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_TRANSACTION, msgVersion, chainID, epoch)
161-
payloadSignatureHeader := utils.MakeSignatureHeader(nil, utils.CreateNonceOrPanic())
169+
payloadSignatureHeader := utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())
162170
payloadHeader := utils.MakePayloadHeader(payloadChainHeader, payloadSignatureHeader)
163171
payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(utils.MakeConfigurationEnvelope(signedConfigItems...))}
164-
return &cb.Envelope{Payload: utils.MarshalOrPanic(payload), Signature: nil}, nil
172+
paylBytes := utils.MarshalOrPanic(payload)
173+
174+
// sign the payload
175+
sig, err := signer.Sign(paylBytes)
176+
if err != nil {
177+
return nil, err
178+
}
179+
180+
return &cb.Envelope{Payload: paylBytes, Signature: sig}, nil
165181
}

common/configtx/test/helper.go

+5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ import (
2828
"github.com/golang/protobuf/proto"
2929
)
3030

31+
const (
32+
// AcceptAllPolicyKey is the key of the AcceptAllPolicy.
33+
AcceptAllPolicyKey = "AcceptAllPolicy"
34+
)
35+
3136
var template configtx.Template
3237

3338
var genesisFactory genesis.Factory

core/chaincode/ccproviderimpl.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package chaincode
2+
3+
import (
4+
"context"
5+
6+
"github.com/hyperledger/fabric/core/common/ccprovider"
7+
"github.com/hyperledger/fabric/core/ledger"
8+
"github.com/hyperledger/fabric/protos/peer"
9+
)
10+
11+
// ccProviderFactory implements the ccprovider.ChaincodeProviderFactory
12+
// interface and returns instances of ccprovider.ChaincodeProvider
13+
type ccProviderFactory struct {
14+
}
15+
16+
// NewChaincodeProvider returns pointers to ccProviderImpl as an
17+
// implementer of the ccprovider.ChaincodeProvider interface
18+
func (c *ccProviderFactory) NewChaincodeProvider() ccprovider.ChaincodeProvider {
19+
return &ccProviderImpl{}
20+
}
21+
22+
// init is called when this package is loaded. This implementation registers the factory
23+
func init() {
24+
ccprovider.RegisterChaincodeProviderFactory(&ccProviderFactory{})
25+
}
26+
27+
// ccProviderImpl is an implementation of the ccprovider.ChaincodeProvider interface
28+
type ccProviderImpl struct {
29+
txsim ledger.TxSimulator
30+
}
31+
32+
// ccProviderContextImpl contains the state that is passed around to calls to methods of ccProviderImpl
33+
type ccProviderContextImpl struct {
34+
ctx *CCContext
35+
}
36+
37+
// GetContext returns a context for the supplied ledger, with the appropriate tx simulator
38+
func (c *ccProviderImpl) GetContext(ledger ledger.ValidatedLedger) (context.Context, error) {
39+
var err error
40+
// get context for the chaincode execution
41+
c.txsim, err = ledger.NewTxSimulator()
42+
if err != nil {
43+
return nil, err
44+
}
45+
ctxt := context.WithValue(context.Background(), TXSimulatorKey, c.txsim)
46+
return ctxt, nil
47+
}
48+
49+
// GetCCContext returns an interface that encapsulates a
50+
// chaincode context; the interface is required to avoid
51+
// referencing the chaincode package from the interface definition
52+
func (c *ccProviderImpl) GetCCContext(cid, name, version, txid string, syscc bool, prop *peer.Proposal) interface{} {
53+
ctx := NewCCContext(cid, name, version, txid, syscc, prop)
54+
return &ccProviderContextImpl{ctx: ctx}
55+
}
56+
57+
// GetVSCCFromLCCC returns the VSCC listed in LCCC for the supplied chaincode
58+
func (c *ccProviderImpl) GetVSCCFromLCCC(ctxt context.Context, txid string, prop *peer.Proposal, chainID string, chaincodeID string) (string, error) {
59+
data, err := GetChaincodeDataFromLCCC(ctxt, txid, prop, chainID, chaincodeID)
60+
if err != nil {
61+
return "", err
62+
}
63+
64+
vscc := "vscc"
65+
// Check whenever VSCC defined for chaincode data
66+
if data != nil && data.Vscc != "" {
67+
vscc = data.Vscc
68+
}
69+
70+
return vscc, nil
71+
}
72+
73+
// ExecuteChaincode executes the chaincode specified in the context with the specified arguments
74+
func (c *ccProviderImpl) ExecuteChaincode(ctxt context.Context, cccid interface{}, args [][]byte) ([]byte, *peer.ChaincodeEvent, error) {
75+
return ExecuteChaincode(ctxt, cccid.(*ccProviderContextImpl).ctx, args)
76+
}
77+
78+
// ReleaseContext frees up resources held by the context
79+
func (c *ccProviderImpl) ReleaseContext() {
80+
c.txsim.Done()
81+
}

core/committer/committer_impl.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package committer
1818

1919
import (
20+
"github.com/hyperledger/fabric/core/committer/txvalidator"
2021
"github.com/hyperledger/fabric/core/ledger"
2122
"github.com/hyperledger/fabric/protos/common"
2223
pb "github.com/hyperledger/fabric/protos/peer"
@@ -38,16 +39,21 @@ func init() {
3839
// it keeps the reference to the ledger to commit blocks and retreive
3940
// chain information
4041
type LedgerCommitter struct {
41-
ledger ledger.ValidatedLedger
42+
ledger ledger.ValidatedLedger
43+
validator txvalidator.Validator
4244
}
4345

4446
// NewLedgerCommitter is a factory function to create an instance of the committer
45-
func NewLedgerCommitter(ledger ledger.ValidatedLedger) *LedgerCommitter {
46-
return &LedgerCommitter{ledger}
47+
func NewLedgerCommitter(ledger ledger.ValidatedLedger, validator txvalidator.Validator) *LedgerCommitter {
48+
return &LedgerCommitter{ledger: ledger, validator: validator}
4749
}
4850

4951
// CommitBlock commits block to into the ledger
5052
func (lc *LedgerCommitter) CommitBlock(block *common.Block) error {
53+
// Validate and mark invalid transactions
54+
logger.Debug("Validating block")
55+
lc.validator.Validate(block)
56+
5157
if err := lc.ledger.Commit(block); err != nil {
5258
return err
5359
}

core/committer/committer_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/stretchr/testify/assert"
2525

2626
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
27+
"github.com/hyperledger/fabric/core/mocks/validator"
2728
pb "github.com/hyperledger/fabric/protos/peer"
2829
)
2930

@@ -35,7 +36,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
3536
assert.NoError(t, err, "Error while creating ledger: %s", err)
3637
defer ledger.Close()
3738

38-
committer := NewLedgerCommitter(ledger)
39+
committer := NewLedgerCommitter(ledger, &validator.MockValidator{})
3940
height, err := committer.LedgerHeight()
4041
assert.Equal(t, uint64(0), height)
4142
assert.NoError(t, err)

core/committer/txvalidator/txvalidator_test.go

+3-9
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,22 @@ import (
2424
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
2525
"github.com/hyperledger/fabric/core/ledger/testutil"
2626
"github.com/hyperledger/fabric/core/ledger/util"
27+
"github.com/hyperledger/fabric/core/mocks/validator"
2728
"github.com/hyperledger/fabric/protos/common"
2829
pb "github.com/hyperledger/fabric/protos/peer"
2930
"github.com/hyperledger/fabric/protos/utils"
3031
"github.com/spf13/viper"
3132
"github.com/stretchr/testify/assert"
3233
)
3334

34-
type mockVsccValidator struct {
35-
}
36-
37-
func (v *mockVsccValidator) VSCCValidateTx(payload *common.Payload, envBytes []byte) error {
38-
return nil
39-
}
40-
4135
func TestKVLedgerBlockStorage(t *testing.T) {
4236
viper.Set("peer.fileSystemPath", "/tmp/fabric/txvalidatortest")
4337
ledgermgmt.InitializeTestEnv()
4438
defer ledgermgmt.CleanupTestEnv()
4539
ledger, _ := ledgermgmt.CreateLedger("TestLedger")
4640
defer ledger.Close()
4741

48-
validator := &txValidator{ledger, &mockVsccValidator{}}
42+
validator := &txValidator{ledger, &validator.MockVsccValidator{}}
4943

5044
bcInfo, _ := ledger.GetBlockchainInfo()
5145
testutil.AssertEquals(t, bcInfo, &pb.BlockchainInfo{
@@ -76,7 +70,7 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
7670
ledger, _ := ledgermgmt.CreateLedger("TestLedger")
7771
defer ledger.Close()
7872

79-
validator := &txValidator{ledger, &mockVsccValidator{}}
73+
validator := &txValidator{ledger, &validator.MockVsccValidator{}}
8074

8175
// Create simeple endorsement transaction
8276
payload := &common.Payload{

core/committer/txvalidator/validator.go

+33-24
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@ limitations under the License.
1717
package txvalidator
1818

1919
import (
20-
"context"
2120
"fmt"
2221

2322
"github.com/golang/protobuf/proto"
2423
coreUtil "github.com/hyperledger/fabric/common/util"
25-
"github.com/hyperledger/fabric/core/chaincode"
24+
"github.com/hyperledger/fabric/core/common/ccprovider"
25+
"github.com/hyperledger/fabric/core/common/validation"
2626
"github.com/hyperledger/fabric/core/ledger"
2727
ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
28-
"github.com/hyperledger/fabric/core/peer"
2928
"github.com/hyperledger/fabric/protos/common"
3029
"github.com/hyperledger/fabric/protos/utils"
3130
"github.com/op/go-logging"
@@ -48,7 +47,8 @@ type vsccValidator interface {
4847
// vsccValidator implementation which used to call
4948
// vscc chaincode and validate block transactions
5049
type vsccValidatorImpl struct {
51-
ledger ledger.ValidatedLedger
50+
ledger ledger.ValidatedLedger
51+
ccprovider ccprovider.ChaincodeProvider
5252
}
5353

5454
// implementation of Validator interface, keeps
@@ -69,7 +69,12 @@ func init() {
6969
// NewTxValidator creates new transactions validator
7070
func NewTxValidator(ledger ledger.ValidatedLedger) Validator {
7171
// Encapsulates interface implementation
72-
return &txValidator{ledger, &vsccValidatorImpl{ledger}}
72+
return &txValidator{ledger, &vsccValidatorImpl{ledger: ledger, ccprovider: ccprovider.GetChaincodeProvider()}}
73+
}
74+
75+
func (v *txValidator) chainExists(chain string) bool {
76+
// TODO: implement this function!
77+
return true
7378
}
7479

7580
func (v *txValidator) Validate(block *common.Block) {
@@ -92,11 +97,19 @@ func (v *txValidator) Validate(block *common.Block) {
9297
logger.Debug("Validating transaction peer.ValidateTransaction()")
9398
var payload *common.Payload
9499
var err error
95-
if payload, _, err = peer.ValidateTransaction(env); err != nil {
100+
if payload, err = validation.ValidateTransaction(env); err != nil {
96101
logger.Errorf("Invalid transaction with index %d, error %s", tIdx, err)
97102
continue
98103
}
99104

105+
chain := payload.Header.ChainHeader.ChainID
106+
logger.Debug("Transaction is for chain %s", chain)
107+
108+
if !v.chainExists(chain) {
109+
logger.Errorf("Dropping transaction for non-existent chain %s", chain)
110+
continue
111+
}
112+
100113
if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
101114
// Check duplicate transactions
102115
txID := payload.Header.ChainHeader.TxID
@@ -113,7 +126,13 @@ func (v *txValidator) Validate(block *common.Block) {
113126
continue
114127
}
115128
} else if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_CONFIGURATION_TRANSACTION {
116-
logger.Warningf("Validation for common.HeaderType_CONFIGURATION_TRANSACTION %d pending JIRA-1639", tIdx)
129+
// TODO: here we should call CSCC and pass it the config tx
130+
// note that there is quite a bit more validation necessary
131+
// on this tx, namely, validation that each config item has
132+
// signature matching the policy required for the item from
133+
// the existing configuration; this is taken care of nicely
134+
// by configtx.Manager (see fabric/common/configtx).
135+
logger.Debug("config transaction received for chain %s", chain)
117136
}
118137

119138
if _, err := proto.Marshal(env); err != nil {
@@ -157,15 +176,12 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
157176
// args[1] - serialized Envelope
158177
args := [][]byte{[]byte(""), envBytes}
159178

160-
// get context for the chaincode execution
161-
lgr := v.ledger
162-
txsim, err := lgr.NewTxSimulator()
179+
ctxt, err := v.ccprovider.GetContext(v.ledger)
163180
if err != nil {
164-
logger.Errorf("Cannot obtain tx simulator txid=%s, err %s", txid, err)
181+
logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err)
165182
return err
166183
}
167-
defer txsim.Done()
168-
ctxt := context.WithValue(context.Background(), chaincode.TXSimulatorKey, txsim)
184+
defer v.ccprovider.ReleaseContext()
169185

170186
// get header extensions so we have the visibility field
171187
hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header)
@@ -177,31 +193,24 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
177193
// Explanation: we actually deploying chaincode transaction,
178194
// hence no lccc yet to query for the data, therefore currently
179195
// introducing a workaround to skip obtaining LCCC data.
180-
var data *chaincode.ChaincodeData
196+
vscc := "vscc"
181197
if hdrExt.ChaincodeID.Name != "lccc" {
182198
// Extracting vscc from lccc
183-
logger.Info("Extracting chaincode data from LCCC txid = ", txid, "chainID", chainID, "chaincode name", hdrExt.ChaincodeID.Name)
184-
data, err = chaincode.GetChaincodeDataFromLCCC(ctxt, txid, nil, chainID, hdrExt.ChaincodeID.Name)
199+
vscc, err = v.ccprovider.GetVSCCFromLCCC(ctxt, txid, nil, chainID, hdrExt.ChaincodeID.Name)
185200
if err != nil {
186201
logger.Errorf("Unable to get chaincode data from LCCC for txid %s, due to %s", txid, err)
187202
return err
188203
}
189204
}
190205

191-
vscc := "vscc"
192-
// Check whenever VSCC defined for chaincode data
193-
if data != nil && data.Vscc != "" {
194-
vscc = data.Vscc
195-
}
196-
197206
vscctxid := coreUtil.GenerateUUID()
198207
// Get chaincode version
199208
version := coreUtil.GetSysCCVersion()
200-
cccid := chaincode.NewCCContext(chainID, vscc, version, vscctxid, true, nil)
209+
cccid := v.ccprovider.GetCCContext(chainID, vscc, version, vscctxid, true, nil)
201210

202211
// invoke VSCC
203212
logger.Info("Invoking VSCC txid", txid, "chaindID", chainID)
204-
_, _, err = chaincode.ExecuteChaincode(ctxt, cccid, args)
213+
_, _, err = v.ccprovider.ExecuteChaincode(ctxt, cccid, args)
205214
if err != nil {
206215
logger.Errorf("VSCC check failed for transaction txid=%s, error %s", txid, err)
207216
return err

0 commit comments

Comments
 (0)