Skip to content

Commit

Permalink
FAB-514 Default endorser,validator system chaincodes
Browse files Browse the repository at this point in the history
For now, these scc are no-ops, are used to check the interfaces
between endorsers and committers for the end-to-end skeleton.
Over time, we will add signature and actual validation of blocks

Handles JIRA issue https://jira.hyperledger.org/browse/FAB-514

(patch 3 redid goimports for importsysccs)

Change-Id: I7a35ed87f83c82f14b1675b955ed5521e7fbda70
Signed-off-by: tuand27613 <tdang@us.ibm.com>
  • Loading branch information
tuand27613 committed Sep 30, 2016
1 parent 03c4a70 commit 3f2cb2c
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 0 deletions.
67 changes: 67 additions & 0 deletions core/system_chaincode/escc/endorser_onevalidsignature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package escc

import (
"errors"

"github.com/hyperledger/fabric/core/chaincode/shim"
//"github.com/hyperledger/fabric/core/crypto"
)

// EndorserOneValidSignature implements the default endorsement policy, which is to
// sign the proposal hash and the read-write set
type EndorserOneValidSignature struct {
}

// Init is called once when the chaincode started the first time
func (e *EndorserOneValidSignature) Init(stub shim.ChaincodeStubInterface) ([]byte, error) {
// best practice to do nothing (or very little) in Init
return nil, nil
}

// Invoke is called to endorse the specified Proposal
// For now, we sign the input and return the endorsed result. Later we can expand
// the chaincode to provide more sophisticate policy processing such as enabling
// policy specification to be coded as a transaction of the chaincode and Client
// could select which policy to use for endorsement using parameter
// @return signature of Action object or error
// Note that Peer calls this function with 3 arguments, where args[0] is the
// function name and args[1] is the Action object and args[2] is Proposal object
func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error) {
// args[0] - function name (not used now)
// args[1] - serialized Action object
// args[2] - serialized Proposal object (not used)
args := stub.GetArgs()
if len(args) < 3 {
return nil, errors.New("Incorrect number of arguments")
}

if args[1] == nil {
return nil, errors.New("Action object is null")
}

// TODO: since we are just trying to get the end-to-end happy path going, we return a fake signed proposal
// Once the scc interface is updated to have a pointer to the peer SecHelper, we will compute the actual signature
return []byte("true"), nil
//return crypto.sign(args[1])
}

// Query is here to satisfy the Chaincode interface. We don't need it for this system chaincode
func (e *EndorserOneValidSignature) Query(stub shim.ChaincodeStubInterface) ([]byte, error) {
return nil, nil
}
72 changes: 72 additions & 0 deletions core/system_chaincode/escc/endorser_onevalidsignature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package escc

import (
"fmt"
"testing"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos"
)

func TestInit(t *testing.T) {
e := new(EndorserOneValidSignature)
stub := shim.NewMockStub("endorseronevalidsignature", e)

if _, err := stub.MockInit("1", nil); err != nil {
fmt.Println("Init failed", err)
t.FailNow()
}
}

func TestInvoke(t *testing.T) {
e := new(EndorserOneValidSignature)
stub := shim.NewMockStub("endorseronevalidsignature", e)

// Failed path: Not enough parameters
args := [][]byte{[]byte("test")}
if _, err := stub.MockInvoke("1", args); err == nil {
t.Fatalf("escc invoke should have failed with invalid number of args: %v", args)
}

// Failed path: action struct is null
args = [][]byte{[]byte("test"), []byte("action"), []byte("proposal")}
args[1] = nil
if _, err := stub.MockInvoke("1", args); err == nil {
fmt.Println("Invoke", args, "failed", err)
t.Fatalf("escc invoke should have failed with Action object is null. args: %v", args)
}

// Successful path
args = [][]byte{[]byte("dv"), mockAction(), mockProposal()}
if _, err := stub.MockInvoke("1", args); err != nil {
t.Fatalf("escc invoke failed with: %v", err)
}
// TODO: Check sig here when we actually sign
}

func mockAction() []byte {
action := &pb.Action{}
action.ProposalHash = []byte("123")
action.SimulationResult = []byte("read-write set")
payload, _ := proto.Marshal(action)
return payload
}
func mockProposal() []byte {
return []byte("proposal")
}
16 changes: 16 additions & 0 deletions core/system_chaincode/importsysccs.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"github.com/hyperledger/fabric/core/system_chaincode/api"
//import system chain codes here
"github.com/hyperledger/fabric/bddtests/syschaincode/noop"
"github.com/hyperledger/fabric/core/system_chaincode/escc"
"github.com/hyperledger/fabric/core/system_chaincode/lccc"
"github.com/hyperledger/fabric/core/system_chaincode/vscc"
)

//see systemchaincode_test.go for an example using "sample_syscc"
Expand All @@ -38,6 +40,20 @@ var systemChaincodes = []*api.SystemChaincode{
Path: "github.com/hyperledger/fabric/core/system_chaincode/lccc",
InitArgs: [][]byte{[]byte("")},
Chaincode: &lccc.LifeCycleSysCC{},
},
{
Enabled: true,
Name: "escc",
Path: "github.com/hyperledger/fabric/core/system_chaincode/escc",
InitArgs: [][]byte{[]byte("")},
Chaincode: &escc.EndorserOneValidSignature{},
},
{
Enabled: true,
Name: "vscc",
Path: "github.com/hyperledger/fabric/core/system_chaincode/vscc",
InitArgs: [][]byte{[]byte("")},
Chaincode: &vscc.ValidatorOneValidSignature{},
}}

//RegisterSysCCs is the hook for system chaincodes where system chaincodes are registered with the fabric
Expand Down
96 changes: 96 additions & 0 deletions core/system_chaincode/vscc/validator_onevalidsignature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package vscc

import (
"errors"
"fmt"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/chaincode/shim"
//"github.com/hyperledger/fabric/core/crypto"
pb "github.com/hyperledger/fabric/protos"
)

// ValidatorOneValidSignature implements the default transaction validation policy,
// which is to check the correctness of the read-write set and the endorsement
// signatures
type ValidatorOneValidSignature struct {
}

// Init is called once when the chaincode started the first time
func (vscc *ValidatorOneValidSignature) Init(stub shim.ChaincodeStubInterface) ([]byte, error) {
// best practice to do nothing (or very little) in Init
return nil, nil
}

// Invoke is called to validate the specified block of transactions
// This validation system chaincode will check the read-write set validity and at least 1
// correct endorsement. Later we can create more validation system
// chaincodes to provide more sophisticated policy processing such as enabling
// policy specification to be coded as a transaction of the chaincode and the client
// selecting which policy to use for validation using parameter function
// @return serialized Block of valid and invalid transactions indentified
// Note that Peer calls this function with 2 arguments, where args[0] is the
// function name and args[1] is the block
func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error) {
// args[0] - function name (not used now)
// args[1] - serialized Block object, which contains orderred transactions
args := stub.GetArgs()
if len(args) < 2 {
return nil, errors.New("Incorrect number of arguments")
}

if args[1] == nil {
return nil, errors.New("No block to validate")
}

block := &pb.Block2{}
if err := proto.Unmarshal(args[1], block); err != nil {
return nil, fmt.Errorf("Could not unmarshal block: %s", err)
}

// block.messages is an array, so we can deterministically iterate and
// validate each transaction in order
for _, v := range block.Transactions {
tx := &pb.Transaction{}

// Note: for v1, we do not have encrypted blocks

if err := proto.Unmarshal(v, tx); err != nil {
vscc.invalidate(tx)
} else {
vscc.validate(tx)
}
}

// TODO: fill in after we get the end-to-end v1 skeleton working. Mocked returned value for now
return args[1], nil
}

// Query is here to satisfy the Chaincode interface. We don't need it for this system chaincode
func (vscc *ValidatorOneValidSignature) Query(stub shim.ChaincodeStubInterface) ([]byte, error) {
return nil, nil
}

func (vscc *ValidatorOneValidSignature) validate(tx *pb.Transaction) {
// TODO: fill in after we get the end-to-end v1 skeleton working
}

func (vscc *ValidatorOneValidSignature) invalidate(tx *pb.Transaction) {
// TODO: fill in after we get the end-to-end v1 skeleton working
}
62 changes: 62 additions & 0 deletions core/system_chaincode/vscc/validator_onevalidsignature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vscc

import (
"testing"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos"
)

func TestInit(t *testing.T) {
v := new(ValidatorOneValidSignature)
stub := shim.NewMockStub("validatoronevalidsignature", v)

if _, err := stub.MockInit("1", nil); err != nil {
t.Fatalf("vscc init failed with %v", err)
}
}

func TestInvoke(t *testing.T) {
v := new(ValidatorOneValidSignature)
stub := shim.NewMockStub("validatoronevalidsignature", v)

// Failed path: Invalid arguments
args := [][]byte{[]byte("dv")}
if _, err := stub.MockInvoke("1", args); err == nil {
t.Fatalf("vscc invoke should have returned incorrect number of args: %v", args)
}

args = [][]byte{[]byte("dv"), []byte("tx")}
args[1] = nil
if _, err := stub.MockInvoke("1", args); err == nil {
t.Fatalf("vscc invoke should have returned no block to validate. Input args: %v", args)
}

// Successful path
args = [][]byte{[]byte("dv"), mockBlock()}
if _, err := stub.MockInvoke("1", args); err != nil {
t.Fatalf("vscc invoke failed with: %v", err)
}
}

func mockBlock() []byte {
block := &pb.Block2{}
payload, _ := proto.Marshal(block)
return payload
}
2 changes: 2 additions & 0 deletions peer/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ chaincode:
# whitelist, add "myscc: enable" to the list
system:
lccc: enable
escc: enable
vscc: enable
###############################################################################
#
###############################################################################
Expand Down

0 comments on commit 3f2cb2c

Please sign in to comment.