Commit 7e355697 authored by Gari Singh's avatar Gari Singh Committed by Gerrit Code Review
Browse files

Merge "skeleton Endorser implemention with a CLI driver" into feature/convergence

parents 0df6a8d1 ec50ad17
......@@ -597,9 +597,9 @@ func (chaincodeSupport *ChaincodeSupport) Deploy(context context.Context, t *pb.
chaincodeLogger.Debugf("deploying chaincode %s(networkid:%s,peerid:%s)", chaincode, chaincodeSupport.peerNetworkID, chaincodeSupport.peerID)
//create image and create container
_, err = container.VMCProcess(context, vmtype, cir)
if err != nil {
err = fmt.Errorf("Error starting container: %s", err)
resp, err2 := container.VMCProcess(context, vmtype, cir)
if err2 != nil || (resp != nil && resp.(container.VMCResp).Err != nil) {
err = fmt.Errorf("Error creating image: %s", err2)
}
return cds, err
......
/*
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 chaincode
import (
"golang.org/x/net/context"
"fmt"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/util"
pb "github.com/hyperledger/fabric/protos"
)
//create a Transactions - this has to change to Proposal when we move chaincode to use Proposals
func createTx(typ pb.Transaction_Type, ccname string, args [][]byte) (*pb.Transaction, error) {
var tx *pb.Transaction
var err error
uuid := util.GenerateUUID()
spec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: ccname}, CtorMsg: &pb.ChaincodeInput{Args: args}}}
tx, err = pb.NewChaincodeExecute(spec, uuid, typ)
if nil != err {
return nil, err
}
return tx, nil
}
// ExecuteChaincode executes a given chaincode given chaincode name and arguments
func ExecuteChaincode(typ pb.Transaction_Type, chainname string, ccname string, args [][]byte) ([]byte, error) {
var tx *pb.Transaction
var err error
var b []byte
var lgr *ledger.Ledger
tx, err = createTx(typ, ccname, args)
lgr, err = ledger.GetLedger()
if err != nil {
return nil, fmt.Errorf("Failed to get handle to ledger: %s ", err)
}
//TODO - new ledger access will change this call to take a context
lgr.BeginTxBatch("1")
b, _, err = Execute(context.Background(), GetChain(ChainName(chainname)), tx)
if err != nil {
return nil, fmt.Errorf("Error deploying chaincode: %s", err)
}
//TODO - new ledger access will change this call to take a context
lgr.CommitTxBatch("1", []*pb.Transaction{tx}, nil, nil)
return b, err
}
......@@ -44,7 +44,11 @@ func (testDB *TestDBWrapper) CleanDB(t testing.TB) {
// at the end of the test
testDB.cleanup()
testDB.removeDBPath()
t.Logf("Creating testDB")
//if we are cleanup once in Main, we don't have a t
if t != nil {
t.Logf("Creating testDB")
}
Start()
testDB.performCleanup = true
......
......@@ -122,8 +122,8 @@ func (*Devops) Build(context context.Context, spec *pb.ChaincodeSpec) (*pb.Chain
return chaincodeDeploymentSpec, nil
}
// get chaincode bytes
func (*Devops) getChaincodeBytes(context context.Context, spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) {
// GetChaincodeBytes get chaincode deployment spec given the chaincode spec
func GetChaincodeBytes(context context.Context, spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) {
mode := viper.GetString("chaincode.mode")
var codePackageBytes []byte
if mode != chaincode.DevModeUserRunsChaincode {
......@@ -147,7 +147,7 @@ func (*Devops) getChaincodeBytes(context context.Context, spec *pb.ChaincodeSpec
// Deploy deploys the supplied chaincode image to the validators through a transaction
func (d *Devops) Deploy(ctx context.Context, spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) {
// get the deployment spec
chaincodeDeploymentSpec, err := d.getChaincodeBytes(ctx, spec)
chaincodeDeploymentSpec, err := GetChaincodeBytes(ctx, spec)
if err != nil {
devopsLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v\n\n error: %s", spec, err))
......
/*
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 endorser
import (
"flag"
"fmt"
"strings"
"github.com/op/go-logging"
"github.com/spf13/viper"
)
// Config the config wrapper structure
type Config struct {
}
func init() {
}
// SetupTestLogging setup the logging during test execution
func SetupTestLogging() {
level, err := logging.LogLevel(viper.GetString("logging.peer"))
if err == nil {
// No error, use the setting
logging.SetLevel(level, "main")
logging.SetLevel(level, "server")
logging.SetLevel(level, "peer")
} else {
logging.SetLevel(logging.ERROR, "main")
logging.SetLevel(logging.ERROR, "server")
logging.SetLevel(logging.ERROR, "peer")
}
}
// SetupTestConfig setup the config during test execution
func SetupTestConfig() {
flag.Parse()
// Now set the configuration file
viper.SetEnvPrefix("CORE")
viper.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
viper.SetConfigName("endorser") // name of config file (without extension)
viper.AddConfigPath("./") // path to look for the config file in
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
SetupTestLogging()
// Set the number of maxprocs
viper.GetInt("peer.gomaxprocs")
}
......@@ -21,6 +21,7 @@ import (
"github.com/op/go-logging"
"golang.org/x/net/context"
"github.com/hyperledger/fabric/core/chaincode"
"github.com/hyperledger/fabric/core/peer"
"github.com/hyperledger/fabric/core/util"
pb "github.com/hyperledger/fabric/protos"
......@@ -28,38 +29,127 @@ import (
var devopsLogger = logging.MustGetLogger("devops")
// The Jira issue that documents Endorser flow along with its relationship to
// the lifecycle chaincode - https://jira.hyperledger.org/browse/FAB-181
// Endorser provides the Endorser service ProcessProposal
type Endorser struct {
coord peer.MessageHandlerCoordinator
}
// NewDevopsServer creates and returns a new Devops server instance.
// NewEndorserServer creates and returns a new Endorser server instance.
func NewEndorserServer(coord peer.MessageHandlerCoordinator) pb.EndorserServer {
e := new(Endorser)
e.coord = coord
return e
}
// ProcessProposal process the Proposal
func (e *Endorser) ProcessProposal(ctx context.Context, proposal *pb.Proposal) (*pb.ProposalResponse, error) {
// if err := crypto.RegisterClient(secret.EnrollId, nil, secret.EnrollId, secret.EnrollSecret); nil != err {
// return &pb.Response{Status: pb.Response_FAILURE, Msg: []byte(err.Error())}, nil
// }
//get the ChaincodeInvocationSpec from the proposal
func (*Endorser) getChaincodeInvocationSpec(prop *pb.Proposal) (*pb.ChaincodeInvocationSpec, error) {
cis := &pb.ChaincodeInvocationSpec{}
err := proto.Unmarshal(prop.Payload, cis)
if err != nil {
return nil, err
}
return cis, nil
}
// Create a dummy action
action := &pb.Action{ProposalHash: util.ComputeCryptoHash(proposal.Payload), SimulationResult: []byte("TODO: Simulated Result")}
//TODO - what would Endorser's ACL be ?
func (*Endorser) checkACL(prop *pb.Proposal) error {
return nil
}
actionBytes, err := proto.Marshal(action)
//TODO - check for escc and vscc
func (*Endorser) checkEsccAndVscc(prop *pb.Proposal) error {
return nil
}
//call specified chaincode (system or user)
func (*Endorser) callChaincode(cis *pb.ChaincodeInvocationSpec) ([]byte, error) {
//TODO - get chainname from cis when defined
chainName := string(chaincode.DefaultChain)
b, err := chaincode.ExecuteChaincode(pb.Transaction_CHAINCODE_INVOKE, chainName, cis.ChaincodeSpec.ChaincodeID.Name, cis.ChaincodeSpec.CtorMsg.Args)
return b, err
}
//simulate the proposal by calling the chaincode
func (e *Endorser) simulateProposal(prop *pb.Proposal) ([]byte, []byte, error) {
//we do expect the payload to be a ChaincodeInvocationSpec
//if we are supporting other payloads in future, this be glaringly point
//as something that should change
cis, err := e.getChaincodeInvocationSpec(prop)
if err != nil {
return nil, err
return nil, nil, err
}
//---1. check ACL
if err = e.checkACL(prop); err != nil {
return nil, nil, err
}
//---2. check ESCC and VSCC for the chaincode
if err = e.checkEsccAndVscc(prop); err != nil {
return nil, nil, err
}
sig, err := e.coord.GetSecHelper().Sign(actionBytes)
//---3. execute the proposal
var resp []byte
resp, err = e.callChaincode(cis)
if err != nil {
return nil, err
return nil, nil, err
}
endorsement := &pb.Endorsement{Signature: sig}
//---4. get simulation results
simulationResult := []byte("TODO: sim results")
return resp, simulationResult, nil
}
//endorse the proposal by calling the ESCC
func (e *Endorser) endorseProposal(proposal *pb.Proposal) (*pb.Endorsement, error) {
/************ TODO
//---4. call ESCC
args := util.ToChaincodeArgs("", "serialized_action", "serialized_proposal", "any", "other", "args")
ecccis := &pb.ChaincodeInvocationSpec{ ChaincodeSpec: &pb.ChaincodeSpec{ Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{ Name: "escc" }, CtorMsg: &pb.ChaincodeInput{ Args: args }}}
var sig []byte
sig, err = e.callChaincode(ecccis)
if err != nil {
return err
}
************/
endorsement := &pb.Endorsement{Signature: []byte("TODO Signature")}
return endorsement, nil
}
// ProcessProposal process the Proposal
func (e *Endorser) ProcessProposal(ctx context.Context, prop *pb.Proposal) (*pb.ProposalResponse, error) {
//1 -- simulate
//TODO what do we do with response ? We need it for Invoke responses for sure
//Which field in PayloadResponse will carry return value ?
_, simulationResult, err := e.simulateProposal(prop)
if err != nil {
return &pb.ProposalResponse{Response: &pb.Response2{Status: 500, Message: err.Error()}}, err
}
//2 -- endorse
//TODO what do we do with response ? We need it for Invoke responses for sure
endorsement, err := e.endorseProposal(prop)
if err != nil {
return &pb.ProposalResponse{Response: &pb.Response2{Status: 500, Message: err.Error()}}, err
}
//3 -- respond
// Create action
action := &pb.Action{ProposalHash: util.ComputeCryptoHash(prop.Payload), SimulationResult: simulationResult}
actionBytes, err := proto.Marshal(action)
if err != nil {
return nil, err
}
//TODO when we have additional field in response, use "resp" bytes from the simulation
resp := &pb.Response2{Status: 200, Message: "Proposal accepted"}
return &pb.ProposalResponse{Response: resp, ActionBytes: actionBytes, Endorsement: endorsement}, nil
}
# CA server parameters
#
server:
# current version of the CA
version: "0.1"
# limits the number of operating system threads used by the CA
gomaxprocs: 2
# path to the OBC state directory and CA state subdirectory
# rootpath: "."
# cadir: ".ca"
# port the CA services are listening on
port: ":20051"
# TLS certificate and key file paths
tls:
security:
# Can be 256 or 384
# Must be the same as in core.yaml
level: 256
# Enabling/disabling different logging levels of the CA.
#
logging:
trace: 0
info: 1
warning: 1
error: 1
panic: 1
# Enable attribute encryption in TCerts generated by TCA
tca:
attribute-encryption:
enabled: true
# Default attributes for Attribute Certificate Authority
aca:
attributes:
attribute-entry-0: user1;bank_a;company;ACompany;2015-01-01T00:00:00-03:00;;
attribute-entry-1: user1;bank_a;position;Software Staff;2015-01-01T00:00:00-03:00;2015-07-12T23:59:59-03:00;
attribute-entry-2: user1;bank_a;position;Software Engineer;2015-07-13T00:00:00-03:00;;
attribute-entry-3: user2;bank_a;company;ACompany;2001-02-02T00:00:00-03:00;;
attribute-entry-4: user2;bank_a;position;Project Manager;2001-02-02T00:00:00-03:00;;
address: localhost:20051
server-name: acap
enabled: true
# Default users to be registered with the CA on first launch. The role is a binary OR
# of the different roles a user can have:
#
# - simple client such as a wallet: CLIENT
# - non-validating peer: PEER
# - validating client: VALIDATOR
# - auditing client: AUDITOR
#
eca:
affiliations:
banks_and_institutions:
banks:
- bank_a
- bank_b
- bank_c
institutions:
- institution_a
users:
# <EnrollmentID>: <role (1:client, 2: peer, 4: validator, 8: auditor)> <EnrollmentPWD> <Affiliation> <Affiliation_Role>
lukas: 1 NPKYL39uKbkj institution_a
diego: 1 DRJ23pEQl16a institution_a
jim: 1 6avZQLwcUe9b institution_a
vp: 4 f3489fy98ghf
###############################################################################
#
# CLI section
#
###############################################################################
cli:
# The address that the cli process will use for callbacks from chaincodes
address: 0.0.0.0:7052
###############################################################################
#
# REST section
#
###############################################################################
rest:
# Enable/disable setting for the REST service. It is recommended to disable
# REST service on validators in production deployment and use non-validating
# nodes to host REST service
enabled: true
# The address that the REST service will listen on for incoming requests.
address: 0.0.0.0:7050
###############################################################################
#
# LOGGING section
#
###############################################################################
logging:
# Valid logging levels are case-insensitive strings chosen from
# CRITICAL | ERROR | WARNING | NOTICE | INFO | DEBUG
# Logging 'module' names are also strings, however valid module names are
# defined at runtime and are not checked for validity during option
# processing.
# Default logging levels are specified here for each of the peer
# commands. For commands that have subcommands, the defaults also apply to
# all subcommands of the command. These logging levels can be overridden
# on the command line using the --logging-level command-line option, or by
# setting the CORE_LOGGING_LEVEL environment variable.
# The logging level specification is of the form
# [<module>[,<module>...]=]<level>[:[<module>[,<module>...]=]<level>...]
# A logging level by itself is taken as the overall default. Otherwise,
# overrides for individual or groups of modules can be specified using the
# <module>[,<module>...]=<level> syntax.
# Examples:
# info - Set default to INFO
# warning:main,db=debug:chaincode=info - Override default WARNING in main,db,chaincode
# chaincode=info:main=debug:db=debug:warning - Same as above
peer: debug
crypto: info
status: warning
stop: warning
login: warning
vm: warning
chaincode: warning
###############################################################################
#
# Peer section
#
###############################################################################
peer:
# Peer Version following version semantics as described here http://semver.org/
# The Peer supplies this version in communications with other Peers
version: 0.1.0
# The Peer id is used for identifying this Peer instance.
id: jdoe
# The privateKey to be used by this peer
# privateKey: 794ef087680e2494fa4918fd8fb80fb284b50b57d321a31423fe42b9ccf6216047cea0b66fe8365a8e3f2a8140c6866cc45852e63124668bee1daa9c97da0c2a
# The networkId allows for logical seperation of networks
# networkId: dev
# networkId: test
networkId: dev
Dockerfile: |
from hyperledger/fabric-baseimage:latest
# Copy GOPATH src and install Peer
COPY src $GOPATH/src
RUN mkdir -p /var/hyperledger/db
WORKDIR $GOPATH/src/github.com/hyperledger/fabric/peer/
RUN CGO_CFLAGS=" " CGO_LDFLAGS="-lrocksdb -lstdc++ -lm -lz -lbz2 -lsnappy" go install && cp $GOPATH/src/github.com/hyperledger/fabric/peer/core.yaml $GOPATH/bin
# The Address this Peer will listen on
listenAddress: 0.0.0.0:21212
# The Address this Peer will bind to for providing services
address: 0.0.0.0:21212
# Whether the Peer should programmatically determine the address to bind to.
# This case is useful for docker containers.
addressAutoDetect: false
# Peer port to accept connections on
port: 21212
# Setting for runtime.GOMAXPROCS(n). If n < 1, it does not change the current setting
gomaxprocs: -1
workers: 2
# Sync related configuration
sync:
blocks:
# Channel size for readonly SyncBlocks messages channel for receiving
# blocks from oppositie Peer Endpoints.
# NOTE: currently messages are not stored and forwarded, but rather
# lost if the channel write blocks.
channelSize: 10
state:
snapshot:
# Channel size for readonly syncStateSnapshot messages channel
# for receiving state deltas for snapshot from oppositie Peer Endpoints.
# NOTE: currently messages are not stored and forwarded, but
# rather lost if the channel write blocks.
channelSize: 50
deltas:
# Channel size for readonly syncStateDeltas messages channel for
# receiving state deltas for a syncBlockRange from oppositie
# Peer Endpoints.
# NOTE: currently messages are not stored and forwarded,
# but rather lost if the channel write blocks.
channelSize: 20
# Validator defines whether this peer is a validating peer or not, and if
# it is enabled, what consensus plugin to load
validator:
enabled: true
consensus:
# Consensus plugin to use. The value is the name of the plugin, e.g. pbft, noops ( this value is case-insensitive)
# if the given value is not recognized, we will default to noops
plugin: noops
# total number of consensus messages which will be buffered per connection before delivery is rejected
buffersize: 1000
events:
# The address that the Event service will be enabled on the validator
address: 0.0.0.0:7053
# total number of events that could be buffered without blocking the
# validator sends
buffersize: 100
# milliseconds timeout for producer to send an event.
# if < 0, if buffer full, unblocks immediately and not send
# if 0, if buffer full, will block and guarantee the event will be sent out
# if > 0, if buffer full, blocks till timeout
timeout: 10
# TLS Settings for p2p communications
tls:
enabled: false
cert:
file: testdata/server1.pem
key:
file: testdata/server1.key
# The server name use to verify the hostname returned by TLS handshake
# The key cert was generated using
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout testdata/server1.key -out testdata/server1.pem
serverhostoverride: dummy
# PKI member services properties
pki:
eca:
paddr: localhost:20051
tca:
paddr: localhost:20051
tlsca:
paddr: localhost:20051
tls:
enabled: false
rootcert:
file: tlsca.cert
# The server name use to verify the hostname returned by TLS handshake
serverhostoverride:
# Peer discovery settings. Controls how this peer discovers other peers
discovery:
# The root nodes are used for bootstrapping purposes, and generally
# supplied through ENV variables
rootnode:
# The duration of time between attempts to asks peers for their connected peers
period: 5s
## leaving this in for example of sub map entry
# testNodes:
# - node : 1
# ip : 127.0.0.1
# port : 21212
# - node : 2
# ip : 127.0.0.1
# port : 21212