Skip to content

Commit a93135b

Browse files
author
Srinivasan Muralidharan
committed
FAB-1547 initial create/join chain support
https://jira.hyperledger.org/browse/FAB-1547 With this change the fabric has basic support for create / join chain begun with the implementation of CSCC (configuraton system chaincode) in https://jira.hyperledger.org/browse/FAB-1022. Some todos remain for follow up CRs . docker based commands to channel-setup.md . CONFIGURATION_TRANSACTION validation - https://jira.hyperledger.org/browse/FAB-1639 . further MSP integration (still uses default MSP) . absorption of deliver client management into gossip later - https://jira.hyperledger.org/browse/FAB-1580 . adding specific configuration items to channel create - https://jira.hyperledger.org/browse/FAB-1642 Steps to test chain create / join below. All commands assume shell in "fabric/" directory. Vagrant window 1 - start orderer cd orderer ORDERER_GENERAL_LOGLEVEL=debug ./orderer Vagrant window 2 - ask orderer to create a chain cd peer peer channel create -c myc1 #on successful creation, a genesis block myc1.block is saved #in the same directory Vagrant window 3 - start the peer without **TEST_CHAINID** (basically in a "chainless" mode) #to start with a clean env do "rm -rf /var/hyperledger/*" cd peer peer node start --peer-defaultchain=false #in "--peer-defaultchain=false" mode the peer has to join #chains to create leader and do transactions. It does not #have a default chain or ledger (the **TEST_CHAINID** chain) Vagrant window 4 - ask peer to join a chain cd peer peer channel join -b myc1.block At this point we can issue transactions Vagrant window 2 - deploy a chaincode to myc1 cd peer peer chaincode deploy -C myc1 -n mycc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Args":["init","a","100","b","200"]}' #note the use of "-C myc1" #wait for 10 secs or so Vagrant window 2 - query chaincode cd peer peer chaincode query -C myc1 -n mycc -c '{"Args":["query","a"]}' Change-Id: I7d1d04e8a207eb57597a1e6eb8b986e1080e7811 Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent 9e8fb87 commit a93135b

34 files changed

+1026
-158
lines changed

bddtests/chaincode.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/golang/protobuf/proto"
2323
"github.com/hyperledger/fabric/common/util"
24+
"github.com/hyperledger/fabric/protos/common"
2425
pb "github.com/hyperledger/fabric/protos/peer"
2526
putils "github.com/hyperledger/fabric/protos/utils"
2627
)
@@ -52,5 +53,5 @@ func createProposalForChaincode(ccChaincodeDeploymentSpec *pb.ChaincodeDeploymen
5253
uuid := createProposalID()
5354

5455
// make proposal
55-
return putils.CreateChaincodeProposal(uuid, util.GetTestChainID(), lcChaincodeInvocationSpec, creator)
56+
return putils.CreateChaincodeProposal(uuid, common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), lcChaincodeInvocationSpec, creator)
5657
}

common/configtx/test/helper.go

+5
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,8 @@ func init() {
6363
func MakeGenesisBlock(chainID string) (*cb.Block, error) {
6464
return genesisFactory.Block(chainID)
6565
}
66+
67+
// GetOrderererTemplate returns the test orderer template
68+
func GetOrdererTemplate() configtx.Template {
69+
return template
70+
}

core/chaincode/configer.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ func joinChain(blockBytes []byte) ([]byte, error) {
111111
return nil, fmt.Errorf("Failed to get the chain ID from the configuration block, %s", err)
112112
}
113113

114-
// Initialize all system chainodes on this chain
115-
// TODO: Fix this code to initialize instead of deploy chaincodes
116-
DeploySysCCs(chainID)
114+
if err = peer.CreateDeliveryService(chainID); err != nil {
115+
return nil, err
116+
}
117117

118118
return []byte("200"), nil
119119
}

core/chaincode/configer_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func TestConfigerInvokeJoinChainWrongParams(t *testing.T) {
100100
func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
101101
//t.Skip("Test CI build")
102102
viper.Set("peer.fileSystemPath", "/var/hyperledger/test/")
103+
peer.MockInitialize()
103104
ledgermgmt.InitializeTestEnv()
104105
defer ledgermgmt.CleanupTestEnv()
105106
defer os.RemoveAll("/var/hyperledger/test/")

core/chaincode/exectransaction_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func endTxSimulationCIS(chainID string, txid string, txsim ledger.TxSimulator, p
153153
return err
154154
}
155155
// get a proposal - we need it to get a transaction
156-
prop, err := putils.CreateProposalFromCIS(txid, chainID, cis, ss)
156+
prop, err := putils.CreateProposalFromCIS(txid, common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, ss)
157157
if err != nil {
158158
return err
159159
}

core/committer/txvalidator/validator.go

+16-9
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,14 @@ func (v *txValidator) Validate(block *common.Block) {
9090
// NOT check the validity of endorsements, though. That's a
9191
// job for VSCC below
9292
logger.Debug("Validating transaction peer.ValidateTransaction()")
93-
if payload, _, err := peer.ValidateTransaction(env); err != nil {
93+
var payload *common.Payload
94+
var err error
95+
if payload, _, err = peer.ValidateTransaction(env); err != nil {
9496
logger.Errorf("Invalid transaction with index %d, error %s", tIdx, err)
95-
} else {
97+
continue
98+
}
99+
100+
if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
96101
// Check duplicate transactions
97102
txID := payload.Header.ChainHeader.TxID
98103
if _, err := v.ledger.GetTransactionByID(txID); err == nil {
@@ -107,15 +112,17 @@ func (v *txValidator) Validate(block *common.Block) {
107112
logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err)
108113
continue
109114
}
115+
} 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)
117+
}
110118

111-
if _, err := proto.Marshal(env); err != nil {
112-
logger.Warningf("Cannot marshal transaction due to %s", err)
113-
continue
114-
}
115-
// Succeeded to pass down here, transaction is valid,
116-
// just unset the filter bit array flag.
117-
txsfltr.Unset(uint(tIdx))
119+
if _, err := proto.Marshal(env); err != nil {
120+
logger.Warningf("Cannot marshal transaction due to %s", err)
121+
continue
118122
}
123+
// Succeeded to pass down here, transaction is valid,
124+
// just unset the filter bit array flag.
125+
txsfltr.Unset(uint(tIdx))
119126
} else {
120127
logger.Warning("Nil tx from block")
121128
}

core/endorser/endorser_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/hyperledger/fabric/core/peer"
3333
"github.com/hyperledger/fabric/core/peer/msp"
3434
"github.com/hyperledger/fabric/msp"
35+
"github.com/hyperledger/fabric/protos/common"
3536
pb "github.com/hyperledger/fabric/protos/peer"
3637
pbutils "github.com/hyperledger/fabric/protos/utils"
3738
"github.com/spf13/viper"
@@ -109,7 +110,7 @@ func closeListenerAndSleep(l net.Listener) {
109110
//Currently supported only for Invokes (Queries still go through devops client)
110111
func getInvokeProposal(cis *pb.ChaincodeInvocationSpec, chainID string, creator []byte) (*pb.Proposal, error) {
111112
uuid := util.GenerateUUID()
112-
return pbutils.CreateChaincodeProposal(uuid, chainID, cis, creator)
113+
return pbutils.CreateChaincodeProposal(uuid, common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, creator)
113114
}
114115

115116
func getDeployProposal(cds *pb.ChaincodeDeploymentSpec, chainID string, creator []byte) (*pb.Proposal, error) {

core/ledger/kvledger/txmgmt/validator/statebasedval/state_based_validator.go

+67-26
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,53 @@ func NewValidator(db statedb.VersionedDB) *Validator {
3939
return &Validator{db}
4040
}
4141

42+
//validate endorser transaction
43+
func (v *Validator) validateEndorserTX(envBytes []byte, doMVCCValidation bool, updates *statedb.UpdateBatch) (*rwset.TxReadWriteSet, error) {
44+
// extract actions from the envelope message
45+
respPayload, err := putils.GetActionFromEnvelope(envBytes)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
//preparation for extracting RWSet from transaction
51+
txRWSet := &rwset.TxReadWriteSet{}
52+
53+
// Get the Result from the Action
54+
// and then Unmarshal it into a TxReadWriteSet using custom unmarshalling
55+
if err = txRWSet.Unmarshal(respPayload.Results); err != nil {
56+
return nil, err
57+
}
58+
59+
// trace the first 2000 characters of RWSet only, in case it is huge
60+
if logger.IsEnabledFor(logging.DEBUG) {
61+
txRWSetString := txRWSet.String()
62+
if len(txRWSetString) < 2000 {
63+
logger.Debugf("validating txRWSet:[%s]", txRWSetString)
64+
} else {
65+
logger.Debugf("validating txRWSet:[%s...]", txRWSetString[0:2000])
66+
}
67+
}
68+
69+
//mvccvalidation, may invalidate transaction
70+
if doMVCCValidation {
71+
if valid, err := v.validateTx(txRWSet, updates); err != nil {
72+
return nil, err
73+
} else if !valid {
74+
txRWSet = nil
75+
}
76+
}
77+
78+
return txRWSet, err
79+
}
80+
81+
// TODO validate configuration transaction
82+
func (v *Validator) validateConfigTX(env *common.Envelope) (bool, error) {
83+
return true, nil
84+
}
85+
4286
// ValidateAndPrepareBatch implements method in Validator interface
4387
func (v *Validator) ValidateAndPrepareBatch(block *common.Block, doMVCCValidation bool) (*statedb.UpdateBatch, error) {
4488
logger.Debugf("New block arrived for validation:%#v, doMVCCValidation=%t", block, doMVCCValidation)
45-
var valid bool
4689
updates := statedb.NewUpdateBatch()
4790
logger.Debugf("Validating a block with [%d] transactions", len(block.Data.Data))
4891
txsFilter := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
@@ -53,41 +96,39 @@ func (v *Validator) ValidateAndPrepareBatch(block *common.Block, doMVCCValidatio
5396
continue
5497
}
5598

56-
// extract actions from the envelope message
57-
respPayload, err := putils.GetActionFromEnvelope(envBytes)
99+
env, err := putils.GetEnvelopeFromBlock(envBytes)
58100
if err != nil {
59101
return nil, err
60102
}
61103

62-
//preparation for extracting RWSet from transaction
63-
txRWSet := &rwset.TxReadWriteSet{}
64-
65-
// Get the Result from the Action
66-
// and then Unmarshal it into a TxReadWriteSet using custom unmarshalling
67-
if err = txRWSet.Unmarshal(respPayload.Results); err != nil {
104+
payload, err := putils.GetPayload(env)
105+
if err != nil {
68106
return nil, err
69107
}
70108

71-
// trace the first 2000 characters of RWSet only, in case it is huge
72-
if logger.IsEnabledFor(logging.DEBUG) {
73-
txRWSetString := txRWSet.String()
74-
if len(txRWSetString) < 2000 {
75-
logger.Debugf("validating txRWSet:[%s]", txRWSetString)
76-
} else {
77-
logger.Debugf("validating txRWSet:[%s...]", txRWSetString[0:2000])
109+
valid := false
110+
if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
111+
txRWSet, err := v.validateEndorserTX(envBytes, doMVCCValidation, updates)
112+
if err != nil {
113+
return nil, err
78114
}
115+
//txRWSet != nil => t is valid
116+
if txRWSet != nil {
117+
committingTxHeight := version.NewHeight(block.Header.Number, uint64(txIndex+1))
118+
addWriteSetToBatch(txRWSet, committingTxHeight, updates)
119+
valid = true
120+
}
121+
} else if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_CONFIGURATION_TRANSACTION {
122+
valid, err = v.validateConfigTX(env)
123+
if err != nil {
124+
return nil, err
125+
}
126+
} else {
127+
logger.Errorf("Skipping transaction %d that's not an endorsement or configuration %d", txIndex, payload.Header.ChainHeader.Type)
128+
valid = false
79129
}
80130

81-
if !doMVCCValidation {
82-
valid = true
83-
} else if valid, err = v.validateTx(txRWSet, updates); err != nil {
84-
return nil, err
85-
}
86-
87-
if valid {
88-
committingTxHeight := version.NewHeight(block.Header.Number, uint64(txIndex+1))
89-
addWriteSetToBatch(txRWSet, committingTxHeight, updates)
90-
} else {
131+
if !valid {
91132
// Unset bit in byte array corresponded to the invalid transaction
92133
txsFilter.Set(uint(txIndex))
93134
}

core/peer/fullflow_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/hyperledger/fabric/common/util"
2828
"github.com/hyperledger/fabric/core/peer/msp"
2929
"github.com/hyperledger/fabric/msp"
30+
"github.com/hyperledger/fabric/protos/common"
3031
"github.com/hyperledger/fabric/protos/peer"
3132
"github.com/hyperledger/fabric/protos/utils"
3233
)
@@ -39,7 +40,7 @@ func getProposal() (*peer.Proposal, error) {
3940

4041
uuid := util.GenerateUUID()
4142

42-
return utils.CreateProposalFromCIS(uuid, util.GetTestChainID(), cis, signerSerialized)
43+
return utils.CreateProposalFromCIS(uuid, common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized)
4344
}
4445

4546
func TestGoodPath(t *testing.T) {

core/peer/msgvalidation.go

+12
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm
8989

9090
// continue the validation in a way that depends on the type specified in the header
9191
switch common.HeaderType(hdr.ChainHeader.Type) {
92+
case common.HeaderType_CONFIGURATION_TRANSACTION:
93+
//which the types are different the validation is the same
94+
//viz, validate a proposal to a chaincode. If we need other
95+
//special validation for confguration, we would have to implement
96+
//special validation
97+
fallthrough
9298
case common.HeaderType_ENDORSER_TRANSACTION:
9399
// validation of the proposal message knowing it's of type CHAINCODE
94100
chaincodeHdrExt, err := validateChaincodeProposalMessage(prop, hdr)
@@ -98,6 +104,7 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm
98104

99105
return prop, hdr, chaincodeHdrExt, err
100106
default:
107+
//NOTE : we proably need a case
101108
return nil, nil, nil, fmt.Errorf("Unsupported proposal type %d", common.HeaderType(hdr.ChainHeader.Type))
102109
}
103110
}
@@ -315,6 +322,11 @@ func ValidateTransaction(e *common.Envelope) (*common.Payload, []*pb.Transaction
315322

316323
putilsLogger.Infof("Header is %s", payload.Header)
317324

325+
if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_CONFIGURATION_TRANSACTION {
326+
putilsLogger.Warningf("Skipping common.HeaderType_CONFIGURATION_TRANSACTION validation pending JIRA-1639\n")
327+
return payload, nil, nil
328+
}
329+
318330
// validate the header
319331
err = validateCommonHeader(payload.Header)
320332
if err != nil {

core/peer/msp/config.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,16 @@ func LoadFakeSetupWithLocalMspAndTestChainMsp(dir string) error {
4343
}
4444

4545
// GetMSPManagerFromBlock returns a new MSP manager from a ConfigurationEnvelope
46-
func GetMSPManagerFromBlock(b *common.Block) (msp.MSPManager, error) {
46+
// Note that chainID should really be obtained from the block. Passing it for
47+
// two reasons (1) efficiency (2) getting chainID from block using protos/utils
48+
// will cause import cycles
49+
func GetMSPManagerFromBlock(cid string, b *common.Block) (msp.MSPManager, error) {
4750
mgrConfig, err := msputils.GetMSPManagerConfigFromBlock(b)
4851
if err != nil {
4952
return nil, err
5053
}
5154

52-
mgr := msp.NewMSPManager()
55+
mgr := GetManagerForChain(cid)
5356
err = mgr.Setup(mgrConfig)
5457
if err != nil {
5558
return nil, err

core/peer/msp/peermsp_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestGetMSPManagerFromBlock(t *testing.T) {
5353
t.Fatalf("getTestBlockFromMspConfig failed, err %s", err)
5454
}
5555

56-
mgr, err := GetMSPManagerFromBlock(block)
56+
mgr, err := GetMSPManagerFromBlock("testchainid", block)
5757
if err != nil {
5858
t.Fatalf("GetMSPManagerFromBlock failed, err %s", err)
5959
} else if mgr == nil {

core/peer/peer.go

+22-5
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,17 @@ func MockInitialize() {
5959
ledgermgmt.InitializeTestEnv()
6060
chains.list = nil
6161
chains.list = make(map[string]*chain)
62+
deliveryServiceProvider = func(string) error { return nil }
6263
}
6364

65+
var deliveryServiceProvider func(string) error
66+
6467
// Initialize sets up any chains that the peer has from the persistence. This
6568
// function should be called at the start up when the ledger and gossip
6669
// ready
67-
func Initialize() {
68-
//Till JoinChain works, we continue to use default chain
70+
func Initialize(dsProvider func(string) error) {
71+
deliveryServiceProvider = dsProvider
72+
6973
var cb *common.Block
7074
var ledger ledger.ValidatedLedger
7175
ledgermgmt.Initialize()
@@ -76,12 +80,12 @@ func Initialize() {
7680
for _, cid := range ledgerIds {
7781
peerLogger.Infof("Loading chain %s", cid)
7882
if ledger, err = ledgermgmt.OpenLedger(cid); err != nil {
79-
peerLogger.Warning("Failed to load ledger %s", cid)
83+
peerLogger.Warningf("Failed to load ledger %s(%s)", cid, err)
8084
peerLogger.Debug("Error while loading ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err)
8185
continue
8286
}
8387
if cb, err = getCurrConfigBlockFromLedger(ledger); err != nil {
84-
peerLogger.Warning("Failed to find configuration block on ledger %s", cid)
88+
peerLogger.Warningf("Failed to find configuration block on ledger %s(%s)", cid, err)
8589
peerLogger.Debug("Error while looking for config block on ledger %s with message %s. We continue to the next ledger rather than abort.", cid, err)
8690
continue
8791
}
@@ -90,7 +94,20 @@ func Initialize() {
9094
peerLogger.Warning("Failed to load chain %s", cid)
9195
peerLogger.Debug("Error reloading chain %s with message %s. We continue to the next chain rather than abort.", cid, err)
9296
}
97+
98+
// now create the delivery service for this chain
99+
if err = deliveryServiceProvider(cid); err != nil {
100+
peerLogger.Errorf("Error creating delivery service for %s(err - %s)", cid, err)
101+
}
102+
}
103+
}
104+
105+
//CreateDeliveryService creates the delivery service for the chainID
106+
func CreateDeliveryService(chainID string) error {
107+
if deliveryServiceProvider == nil {
108+
return fmt.Errorf("delivery service provider not available")
93109
}
110+
return deliveryServiceProvider(chainID)
94111
}
95112

96113
func getCurrConfigBlockFromLedger(ledger ledger.ValidatedLedger) (*common.Block, error) {
@@ -129,7 +146,7 @@ func getCurrConfigBlockFromLedger(ledger ledger.ValidatedLedger) (*common.Block,
129146
func createChain(cid string, ledger ledger.ValidatedLedger, cb *common.Block) error {
130147
c := committer.NewLedgerCommitter(ledger)
131148

132-
mgr, err := mspmgmt.GetMSPManagerFromBlock(cb)
149+
mgr, err := mspmgmt.GetMSPManagerFromBlock(cid, cb)
133150
if err != nil {
134151
return err
135152
}

core/peer/peer_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333
func TestInitialize(t *testing.T) {
3434
viper.Set("peer.fileSystemPath", "/var/hyperledger/test/")
3535

36-
Initialize()
36+
Initialize(nil)
3737
}
3838

3939
func TestCreateChainFromBlock(t *testing.T) {
@@ -84,7 +84,7 @@ func TestCreateChainFromBlock(t *testing.T) {
8484
}
8585

8686
// Chaos monkey test
87-
Initialize()
87+
Initialize(nil)
8888

8989
SetCurrConfigBlock(block, testChainID)
9090
}

0 commit comments

Comments
 (0)