├── .gitignore ├── protos ├── peer │ ├── chaincode_event.proto │ ├── proposal_response.proto │ ├── chaincode.proto │ ├── chaincode_shim.proto │ ├── transaction.proto │ └── proposal.proto ├── ledger │ └── queryresult │ │ └── kv_query_result.proto ├── msp │ ├── identities.proto │ └── msp_principal.proto └── common │ ├── policies.proto │ └── common.proto ├── Cargo.toml └── src └── client.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | _bldtmp 13 | -------------------------------------------------------------------------------- /protos/peer/chaincode_event.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option java_outer_classname = "ChaincodeEventPackage"; 9 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 10 | 11 | package protos; 12 | 13 | //ChaincodeEvent is used for events and registrations that are specific to chaincode 14 | //string type - "chaincode" 15 | message ChaincodeEvent { 16 | string chaincode_id = 1; 17 | string tx_id = 2; 18 | string event_name = 3; 19 | bytes payload = 4; 20 | } 21 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "helloworld-tonic" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | [[bin]] # Bin to run the HelloWorld gRPC server 7 | name = "helloworld-server" 8 | path = "src/server.rs" 9 | 10 | [[bin]] # Bin to run the HelloWorld gRPC client 11 | name = "shim" 12 | path = "src/client.rs" 13 | 14 | [dependencies] 15 | tonic = "0.3" 16 | prost = "0.6" 17 | futures-core = "0.3" 18 | futures-util = "0.3" 19 | tokio = { version = "0.2", features = ["macros", "sync", "stream", "time"] } 20 | 21 | async-stream = "0.2" 22 | serde = { version = "1.0", features = ["derive"] } 23 | serde_json = "1.0" 24 | rand = "0.7" 25 | prost-types = "0.6.1" 26 | 27 | [build-dependencies] 28 | tonic-build = "0.3" -------------------------------------------------------------------------------- /protos/ledger/queryresult/kv_query_result.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | package queryresult; 8 | 9 | option go_package = "github.com/hyperledger/fabric-protos-go/ledger/queryresult"; 10 | option java_package = "org.hyperledger.fabric.protos.ledger.queryresult"; 11 | 12 | import "google/protobuf/timestamp.proto"; 13 | 14 | 15 | // KV -- QueryResult for range/execute query. Holds a key and corresponding value. 16 | message KV { 17 | string namespace = 1; 18 | string key = 2; 19 | bytes value = 3; 20 | } 21 | 22 | // KeyModification -- QueryResult for history query. Holds a transaction ID, value, 23 | // timestamp, and delete marker which resulted from a history query. 24 | message KeyModification { 25 | string tx_id = 1; 26 | bytes value = 2; 27 | google.protobuf.Timestamp timestamp = 3; 28 | bool is_delete = 4; 29 | } 30 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | use protos::chaincode_support_client::ChaincodeSupportClient; 2 | use protos::ChaincodeMessage; 3 | use protos::chaincode_message::*; 4 | 5 | pub mod protos { 6 | tonic::include_proto!("protos"); 7 | } 8 | pub mod common { 9 | tonic::include_proto!("common"); 10 | } 11 | pub mod msp { 12 | tonic::include_proto!("msp"); 13 | } 14 | pub mod queryresult { 15 | tonic::include_proto!("queryresult"); 16 | } 17 | 18 | pub mod api { 19 | tonic::include_proto!("google.protobuf"); 20 | } 21 | 22 | #[tokio::main] 23 | async fn main() -> Result<(), Box> { 24 | let mut client = ChaincodeSupportClient::connect("http://[::1]:7052").await?; 25 | 26 | let outbound = async_stream::stream! { 27 | let request = ChaincodeMessage { 28 | r#type: 1, 29 | chaincode_event: Option::None, 30 | timestamp: Option::None, 31 | txid: "".to_string(), 32 | proposal: Option::None, 33 | payload: "chaincodeId".as_bytes().to_vec(), 34 | channel_id : "chanel".to_string() 35 | }; 36 | 37 | // this is the place to send requests back to the peer 38 | // eg, return values of transaction functions or requests for 39 | // ledger api calls eg putState 40 | println!("{:?}",request); 41 | 42 | yield request; 43 | }; 44 | 45 | let response = client.register(tonic::Request::new(outbound)).await?; 46 | let mut inbound = response.into_inner(); 47 | 48 | while let Some(note) = inbound.message().await? { 49 | // this is from the peer, and will be either a request for a new transaction or it will be 50 | // response to a ledger api eg getState 51 | 52 | // match and route answer here 53 | println!("NOTE = {:?}", note); 54 | } 55 | 56 | Ok(()) 57 | } -------------------------------------------------------------------------------- /protos/msp/identities.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/msp"; 8 | option java_package = "org.hyperledger.fabric.protos.msp"; 9 | 10 | package msp; 11 | 12 | // This struct represents an Identity 13 | // (with its MSP identifier) to be used 14 | // to serialize it and deserialize it 15 | message SerializedIdentity { 16 | // The identifier of the associated membership service provider 17 | string mspid = 1; 18 | 19 | // the Identity, serialized according to the rules of its MPS 20 | bytes id_bytes = 2; 21 | } 22 | 23 | // This struct represents an Idemix Identity 24 | // to be used to serialize it and deserialize it. 25 | // The IdemixMSP will first serialize an idemix identity to bytes using 26 | // this proto, and then uses these bytes as id_bytes in SerializedIdentity 27 | message SerializedIdemixIdentity { 28 | // nym_x is the X-component of the pseudonym elliptic curve point. 29 | // It is a []byte representation of an amcl.BIG 30 | // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. 31 | bytes nym_x = 1; 32 | 33 | // nym_y is the Y-component of the pseudonym elliptic curve point. 34 | // It is a []byte representation of an amcl.BIG 35 | // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. 36 | bytes nym_y = 2; 37 | 38 | // ou contains the organizational unit of the idemix identity 39 | bytes ou = 3; 40 | 41 | // role contains the role of this identity (e.g., ADMIN or MEMBER) 42 | bytes role = 4; 43 | 44 | // proof contains the cryptographic evidence that this identity is valid 45 | bytes proof = 5; 46 | } 47 | -------------------------------------------------------------------------------- /protos/common/policies.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/common"; 8 | option java_package = "org.hyperledger.fabric.protos.common"; 9 | 10 | package common; 11 | 12 | import "msp/msp_principal.proto"; 13 | 14 | // Policy expresses a policy which the orderer can evaluate, because there has been some desire expressed to support 15 | // multiple policy engines, this is typed as a oneof for now 16 | message Policy { 17 | enum PolicyType { 18 | UNKNOWN = 0; // Reserved to check for proper initialization 19 | SIGNATURE = 1; 20 | MSP = 2; 21 | IMPLICIT_META = 3; 22 | } 23 | int32 type = 1; // For outside implementors, consider the first 1000 types reserved, otherwise one of PolicyType 24 | bytes value = 2; 25 | } 26 | 27 | // SignaturePolicyEnvelope wraps a SignaturePolicy and includes a version for future enhancements 28 | message SignaturePolicyEnvelope { 29 | int32 version = 1; 30 | SignaturePolicy rule = 2; 31 | repeated MSPPrincipal identities = 3; 32 | } 33 | 34 | // SignaturePolicy is a recursive message structure which defines a featherweight DSL for describing 35 | // policies which are more complicated than 'exactly this signature'. The NOutOf operator is sufficent 36 | // to express AND as well as OR, as well as of course N out of the following M policies 37 | // SignedBy implies that the signature is from a valid certificate which is signed by the trusted 38 | // authority specified in the bytes. This will be the certificate itself for a self-signed certificate 39 | // and will be the CA for more traditional certificates 40 | message SignaturePolicy { 41 | message NOutOf { 42 | int32 n = 1; 43 | repeated SignaturePolicy rules = 2; 44 | } 45 | oneof Type { 46 | int32 signed_by = 1; 47 | NOutOf n_out_of = 2; 48 | } 49 | } 50 | 51 | // ImplicitMetaPolicy is a policy type which depends on the hierarchical nature of the configuration 52 | // It is implicit because the rule is generate implicitly based on the number of sub policies 53 | // It is meta because it depends only on the result of other policies 54 | // When evaluated, this policy iterates over all immediate child sub-groups, retrieves the policy 55 | // of name sub_policy, evaluates the collection and applies the rule. 56 | // For example, with 4 sub-groups, and a policy name of "foo", ImplicitMetaPolicy retrieves 57 | // each sub-group, retrieves policy "foo" for each subgroup, evaluates it, and, in the case of ANY 58 | // 1 satisfied is sufficient, ALL would require 4 signatures, and MAJORITY would require 3 signatures. 59 | message ImplicitMetaPolicy { 60 | enum Rule { 61 | ANY = 0; // Requires any of the sub-policies be satisfied, if no sub-policies exist, always returns true 62 | ALL = 1; // Requires all of the sub-policies be satisfied 63 | MAJORITY = 2; // Requires a strict majority (greater than half) of the sub-policies be satisfied 64 | } 65 | string sub_policy = 1; 66 | Rule rule = 2; 67 | } 68 | -------------------------------------------------------------------------------- /protos/peer/proposal_response.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 8 | option java_package = "org.hyperledger.fabric.protos.peer"; 9 | option java_outer_classname = "ProposalResponsePackage"; 10 | 11 | package protos; 12 | 13 | import "google/protobuf/timestamp.proto"; 14 | 15 | // A ProposalResponse is returned from an endorser to the proposal submitter. 16 | // The idea is that this message contains the endorser's response to the 17 | // request of a client to perform an action over a chaincode (or more 18 | // generically on the ledger); the response might be success/error (conveyed in 19 | // the Response field) together with a description of the action and a 20 | // signature over it by that endorser. If a sufficient number of distinct 21 | // endorsers agree on the same action and produce signature to that effect, a 22 | // transaction can be generated and sent for ordering. 23 | message ProposalResponse { 24 | // Version indicates message protocol version 25 | int32 version = 1; 26 | 27 | // Timestamp is the time that the message 28 | // was created as defined by the sender 29 | google.protobuf.Timestamp timestamp = 2; 30 | 31 | // A response message indicating whether the 32 | // endorsement of the action was successful 33 | Response response = 4; 34 | 35 | // The payload of response. It is the bytes of ProposalResponsePayload 36 | bytes payload = 5; 37 | 38 | // The endorsement of the proposal, basically 39 | // the endorser's signature over the payload 40 | Endorsement endorsement = 6; 41 | } 42 | 43 | // A response with a representation similar to an HTTP response that can 44 | // be used within another message. 45 | message Response { 46 | // A status code that should follow the HTTP status codes. 47 | int32 status = 1; 48 | 49 | // A message associated with the response code. 50 | string message = 2; 51 | 52 | // A payload that can be used to include metadata with this response. 53 | bytes payload = 3; 54 | } 55 | 56 | // ProposalResponsePayload is the payload of a proposal response. This message 57 | // is the "bridge" between the client's request and the endorser's action in 58 | // response to that request. Concretely, for chaincodes, it contains a hashed 59 | // representation of the proposal (proposalHash) and a representation of the 60 | // chaincode state changes and events inside the extension field. 61 | message ProposalResponsePayload { 62 | // Hash of the proposal that triggered this response. The hash is used to 63 | // link a response with its proposal, both for bookeeping purposes on an 64 | // asynchronous system and for security reasons (accountability, 65 | // non-repudiation). The hash usually covers the entire Proposal message 66 | // (byte-by-byte). 67 | bytes proposal_hash = 1; 68 | 69 | // Extension should be unmarshaled to a type-specific message. The type of 70 | // the extension in any proposal response depends on the type of the proposal 71 | // that the client selected when the proposal was initially sent out. In 72 | // particular, this information is stored in the type field of a Header. For 73 | // chaincode, it's a ChaincodeAction message 74 | bytes extension = 2; 75 | } 76 | 77 | // An endorsement is a signature of an endorser over a proposal response. By 78 | // producing an endorsement message, an endorser implicitly "approves" that 79 | // proposal response and the actions contained therein. When enough 80 | // endorsements have been collected, a transaction can be generated out of a 81 | // set of proposal responses. Note that this message only contains an identity 82 | // and a signature but no signed payload. This is intentional because 83 | // endorsements are supposed to be collected in a transaction, and they are all 84 | // expected to endorse a single proposal response/action (many endorsements 85 | // over a single proposal response) 86 | message Endorsement { 87 | // Identity of the endorser (e.g. its certificate) 88 | bytes endorser = 1; 89 | 90 | // Signature of the payload included in ProposalResponse concatenated with 91 | // the endorser's certificate; ie, sign(ProposalResponse.payload + endorser) 92 | bytes signature = 2; 93 | } 94 | -------------------------------------------------------------------------------- /protos/peer/chaincode.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 9 | 10 | package protos; 11 | 12 | import "common/policies.proto"; 13 | 14 | //ChaincodeID contains the path as specified by the deploy transaction 15 | //that created it as well as the hashCode that is generated by the 16 | //system for the path. From the user level (ie, CLI, REST API and so on) 17 | //deploy transaction is expected to provide the path and other requests 18 | //are expected to provide the hashCode. The other value will be ignored. 19 | //Internally, the structure could contain both values. For instance, the 20 | //hashCode will be set when first generated using the path 21 | message ChaincodeID { 22 | //deploy transaction will use the path 23 | string path = 1; 24 | 25 | //all other requests will use the name (really a hashcode) generated by 26 | //the deploy transaction 27 | string name = 2; 28 | 29 | //user friendly version name for the chaincode 30 | string version = 3; 31 | } 32 | 33 | // Carries the chaincode function and its arguments. 34 | // UnmarshalJSON in transaction.go converts the string-based REST/JSON input to 35 | // the []byte-based current ChaincodeInput structure. 36 | message ChaincodeInput { 37 | repeated bytes args = 1; 38 | map decorations = 2; 39 | 40 | // is_init is used for the application to signal that an invocation is to be routed 41 | // to the legacy 'Init' function for compatibility with chaincodes which handled 42 | // Init in the old way. New applications should manage their initialized state 43 | // themselves. 44 | bool is_init = 3; 45 | } 46 | 47 | // Carries the chaincode specification. This is the actual metadata required for 48 | // defining a chaincode. 49 | message ChaincodeSpec { 50 | 51 | enum Type { 52 | UNDEFINED = 0; 53 | GOLANG = 1; 54 | NODE = 2; 55 | CAR = 3; 56 | JAVA = 4; 57 | } 58 | 59 | Type type = 1; 60 | ChaincodeID chaincode_id = 2; 61 | ChaincodeInput input = 3; 62 | int32 timeout = 4; 63 | } 64 | 65 | // Specify the deployment of a chaincode. 66 | // TODO: Define `codePackage`. 67 | message ChaincodeDeploymentSpec { 68 | // Prevent removed tag re-use 69 | reserved 2, 4; 70 | reserved "effective_date", "exec_env"; 71 | 72 | ChaincodeSpec chaincode_spec = 1; 73 | bytes code_package = 3; 74 | 75 | } 76 | 77 | // Carries the chaincode function and its arguments. 78 | message ChaincodeInvocationSpec { 79 | // Prevent removed tag re-use 80 | reserved 2; 81 | reserved "id_generation_alg"; 82 | 83 | ChaincodeSpec chaincode_spec = 1; 84 | } 85 | 86 | // LifecycleEvent is used as the payload of the chaincode event emitted by LSCC 87 | message LifecycleEvent { 88 | string chaincode_name = 1; 89 | } 90 | 91 | // CDSData is data stored in the LSCC on instantiation of a CC 92 | // for CDSPackage. This needs to be serialized for ChaincodeData 93 | // hence the protobuf format 94 | message CDSData { 95 | bytes hash = 1; // hash of ChaincodeDeploymentSpec.code_package 96 | bytes metadatahash = 2; // hash of ChaincodeID.name + ChaincodeID.version 97 | } 98 | 99 | // ChaincodeData defines the datastructure for chaincodes to be serialized by proto 100 | // Type provides an additional check by directing to use a specific package after instantiation 101 | // Data is Type specific (see CDSPackage and SignedCDSPackage) 102 | message ChaincodeData { 103 | 104 | // Name of the chaincode 105 | string name = 1; 106 | 107 | // Version of the chaincode 108 | string version = 2; 109 | 110 | // Escc for the chaincode instance 111 | string escc = 3; 112 | 113 | // Vscc for the chaincode instance 114 | string vscc = 4; 115 | 116 | // Policy endorsement policy for the chaincode instance 117 | common.SignaturePolicyEnvelope policy = 5; 118 | 119 | // Data data specific to the package 120 | bytes data = 6; 121 | 122 | // Id of the chaincode that's the unique fingerprint for the CC This is not 123 | // currently used anywhere but serves as a good eyecatcher 124 | bytes id = 7; 125 | 126 | // InstantiationPolicy for the chaincode 127 | common.SignaturePolicyEnvelope instantiation_policy = 8; 128 | } 129 | -------------------------------------------------------------------------------- /protos/peer/chaincode_shim.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option java_package = "org.hyperledger.fabric.protos.peer"; 8 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 9 | 10 | package protos; 11 | 12 | import "peer/chaincode_event.proto"; 13 | import "peer/proposal.proto"; 14 | import "google/protobuf/timestamp.proto"; 15 | 16 | message ChaincodeMessage { 17 | enum Type { 18 | UNDEFINED = 0; 19 | REGISTER = 1; 20 | REGISTERED = 2; 21 | INIT = 3; 22 | READY = 4; 23 | TRANSACTION = 5; 24 | COMPLETED = 6; 25 | ERROR = 7; 26 | GET_STATE = 8; 27 | PUT_STATE = 9; 28 | DEL_STATE = 10; 29 | INVOKE_CHAINCODE = 11; 30 | RESPONSE = 13; 31 | GET_STATE_BY_RANGE = 14; 32 | GET_QUERY_RESULT = 15; 33 | QUERY_STATE_NEXT = 16; 34 | QUERY_STATE_CLOSE = 17; 35 | KEEPALIVE = 18; 36 | GET_HISTORY_FOR_KEY = 19; 37 | GET_STATE_METADATA = 20; 38 | PUT_STATE_METADATA = 21; 39 | GET_PRIVATE_DATA_HASH = 22; 40 | } 41 | 42 | Type type = 1; 43 | google.protobuf.Timestamp timestamp = 2; 44 | bytes payload = 3; 45 | string txid = 4; 46 | 47 | SignedProposal proposal = 5; 48 | 49 | //event emitted by chaincode. Used only with Init or Invoke. 50 | // This event is then stored (currently) 51 | //with Block.NonHashData.TransactionResult 52 | ChaincodeEvent chaincode_event = 6; 53 | 54 | //channel id 55 | string channel_id = 7; 56 | } 57 | 58 | // TODO: We need to finalize the design on chaincode container 59 | // compatibility upon upgrade, see FAB-5777. 60 | 61 | // GetState is the payload of a ChaincodeMessage. It contains a key which 62 | // is to be fetched from the ledger. If the collection is specified, the key 63 | // would be fetched from the collection (i.e., private state) 64 | message GetState { 65 | string key = 1; 66 | string collection = 2; 67 | } 68 | 69 | message GetStateMetadata { 70 | string key = 1; 71 | string collection = 2; 72 | } 73 | 74 | // PutState is the payload of a ChaincodeMessage. It contains a key and value 75 | // which needs to be written to the transaction's write set. If the collection is 76 | // specified, the key and value would be written to the transaction's private 77 | // write set. 78 | message PutState { 79 | string key = 1; 80 | bytes value = 2; 81 | string collection = 3; 82 | } 83 | 84 | message PutStateMetadata { 85 | string key = 1; 86 | string collection = 3; 87 | StateMetadata metadata = 4; 88 | } 89 | 90 | // DelState is the payload of a ChaincodeMessage. It contains a key which 91 | // needs to be recorded in the transaction's write set as a delete operation. 92 | // If the collection is specified, the key needs to be recorded in the 93 | // transaction's private write set as a delete operation. 94 | message DelState { 95 | string key = 1; 96 | string collection = 2; 97 | } 98 | 99 | // GetStateByRange is the payload of a ChaincodeMessage. It contains a start key and 100 | // a end key required to execute range query. If the collection is specified, 101 | // the range query needs to be executed on the private data. The metadata hold 102 | // the byte representation of QueryMetadata. 103 | message GetStateByRange { 104 | string startKey = 1; 105 | string endKey = 2; 106 | string collection = 3; 107 | bytes metadata = 4; 108 | } 109 | 110 | // GetQueryResult is the payload of a ChaincodeMessage. It contains a query 111 | // string in the form that is supported by the underlying state database. 112 | // If the collection is specified, the query needs to be executed on the 113 | // private data. The metadata hold the byte representation of QueryMetadata. 114 | message GetQueryResult { 115 | string query = 1; 116 | string collection = 2; 117 | bytes metadata = 3; 118 | } 119 | 120 | // QueryMetadata is the metadata of a GetStateByRange and GetQueryResult. 121 | // It contains a pageSize which denotes the number of records to be fetched 122 | // and a bookmark. 123 | message QueryMetadata { 124 | int32 pageSize = 1; 125 | string bookmark = 2; 126 | } 127 | 128 | // GetHistoryForKey is the payload of a ChaincodeMessage. It contains a key 129 | // for which the historical values need to be retrieved. 130 | message GetHistoryForKey { 131 | string key = 1; 132 | } 133 | 134 | message QueryStateNext { 135 | string id = 1; 136 | } 137 | 138 | message QueryStateClose { 139 | string id = 1; 140 | } 141 | 142 | // QueryResultBytes hold the byte representation of a record returned by the peer. 143 | message QueryResultBytes { 144 | bytes resultBytes = 1; 145 | } 146 | 147 | // QueryResponse is returned by the peer as a result of a GetStateByRange, 148 | // GetQueryResult, and GetHistoryForKey. It holds a bunch of records in 149 | // results field, a flag to denote whether more results need to be fetched from 150 | // the peer in has_more field, transaction id in id field, and a QueryResponseMetadata 151 | // in metadata field. 152 | message QueryResponse { 153 | repeated QueryResultBytes results = 1; 154 | bool has_more = 2; 155 | string id = 3; 156 | bytes metadata = 4; 157 | } 158 | 159 | // QueryResponseMetadata is the metadata of a QueryResponse. It contains a count 160 | // which denotes the number of records fetched from the ledger and a bookmark. 161 | message QueryResponseMetadata { 162 | int32 fetched_records_count = 1; 163 | string bookmark = 2; 164 | } 165 | 166 | message StateMetadata { 167 | string metakey = 1; 168 | bytes value = 2; 169 | } 170 | 171 | message StateMetadataResult { 172 | repeated StateMetadata entries = 1; 173 | } 174 | 175 | // Interface that provides support to chaincode execution. ChaincodeContext 176 | // provides the context necessary for the server to respond appropriately. 177 | service ChaincodeSupport { 178 | rpc Register(stream ChaincodeMessage) returns (stream ChaincodeMessage); 179 | } 180 | 181 | // Chaincode as a server - peer establishes a connection to the chaincode as a client 182 | // Currently only supports a stream connection. 183 | //service Chaincode { 184 | /// rpc Connect(stream ChaincodeMessage) returns (stream ChaincodeMessage); 185 | //} 186 | -------------------------------------------------------------------------------- /protos/msp/msp_principal.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/msp"; 8 | option java_package = "org.hyperledger.fabric.protos.common"; 9 | 10 | package common; 11 | 12 | // msp_principal.proto contains proto messages defining the generalized 13 | // MSP notion of identity called an MSPPrincipal. It is used as part of 14 | // the chain configuration, in particular as the identity parameters to 15 | // the configuration.proto file. This does not represent the MSP 16 | // configuration for a chain, but is understood by MSPs 17 | 18 | // MSPPrincipal aims to represent an MSP-centric set of identities. 19 | // In particular, this structure allows for definition of 20 | // - a group of identities that are member of the same MSP 21 | // - a group of identities that are member of the same organization unit 22 | // in the same MSP 23 | // - a group of identities that are administering a specific MSP 24 | // - a specific identity 25 | // Expressing these groups is done given two fields of the fields below 26 | // - Classification, that defines the type of classification of identities 27 | // in an MSP this principal would be defined on; Classification can take 28 | // three values: 29 | // (i) ByMSPRole: that represents a classification of identities within 30 | // MSP based on one of the two pre-defined MSP rules, "member" and "admin" 31 | // (ii) ByOrganizationUnit: that represents a classification of identities 32 | // within MSP based on the organization unit an identity belongs to 33 | // (iii)ByIdentity that denotes that MSPPrincipal is mapped to a single 34 | // identity/certificate; this would mean that the Principal bytes 35 | // message 36 | message MSPPrincipal { 37 | enum Classification { 38 | ROLE = 0; // Represents the one of the dedicated MSP roles, the 39 | // one of a member of MSP network, and the one of an 40 | // administrator of an MSP network 41 | ORGANIZATION_UNIT = 1; // Denotes a finer grained (affiliation-based) 42 | // groupping of entities, per MSP affiliation 43 | // E.g., this can well be represented by an MSP's 44 | // Organization unit 45 | IDENTITY = 2; // Denotes a principal that consists of a single 46 | // identity 47 | ANONYMITY = 3; // Denotes a principal that can be used to enforce 48 | // an identity to be anonymous or nominal. 49 | COMBINED = 4; // Denotes a combined principal 50 | } 51 | 52 | // Classification describes the way that one should process 53 | // Principal. An Classification value of "ByOrganizationUnit" reflects 54 | // that "Principal" contains the name of an organization this MSP 55 | // handles. A Classification value "ByIdentity" means that 56 | // "Principal" contains a specific identity. Default value 57 | // denotes that Principal contains one of the groups by 58 | // default supported by all MSPs ("admin" or "member"). 59 | Classification principal_classification = 1; 60 | 61 | // Principal completes the policy principal definition. For the default 62 | // principal types, Principal can be either "Admin" or "Member". 63 | // For the ByOrganizationUnit/ByIdentity values of Classification, 64 | // PolicyPrincipal acquires its value from an organization unit or 65 | // identity, respectively. 66 | // For the Combined Classification type, the Principal is a marshalled 67 | // CombinedPrincipal. 68 | bytes principal = 2; 69 | } 70 | 71 | 72 | // OrganizationUnit governs the organization of the Principal 73 | // field of a policy principal when a specific organization unity members 74 | // are to be defined within a policy principal. 75 | message OrganizationUnit { 76 | 77 | // MSPIdentifier represents the identifier of the MSP this organization unit 78 | // refers to 79 | string msp_identifier = 1; 80 | 81 | // OrganizationUnitIdentifier defines the organizational unit under the 82 | // MSP identified with MSPIdentifier 83 | string organizational_unit_identifier = 2; 84 | 85 | // CertifiersIdentifier is the hash of certificates chain of trust 86 | // related to this organizational unit 87 | bytes certifiers_identifier = 3; 88 | } 89 | 90 | // MSPRole governs the organization of the Principal 91 | // field of an MSPPrincipal when it aims to define one of the 92 | // two dedicated roles within an MSP: Admin and Members. 93 | message MSPRole { 94 | // MSPIdentifier represents the identifier of the MSP this principal 95 | // refers to 96 | string msp_identifier = 1; 97 | 98 | enum MSPRoleType { 99 | MEMBER = 0; // Represents an MSP Member 100 | ADMIN = 1; // Represents an MSP Admin 101 | CLIENT = 2; // Represents an MSP Client 102 | PEER = 3; // Represents an MSP Peer 103 | ORDERER = 4; // Represents an MSP Orderer 104 | } 105 | 106 | // MSPRoleType defines which of the available, pre-defined MSP-roles 107 | // an identiy should posess inside the MSP with identifier MSPidentifier 108 | MSPRoleType role = 2; 109 | } 110 | 111 | // MSPIdentityAnonymity can be used to enforce an identity to be anonymous or nominal. 112 | message MSPIdentityAnonymity { 113 | enum MSPIdentityAnonymityType { 114 | NOMINAL = 0; // Represents a nominal MSP Identity 115 | ANONYMOUS = 1; // Represents an anonymous MSP Identity 116 | } 117 | 118 | MSPIdentityAnonymityType anonymity_type = 1; 119 | } 120 | 121 | // CombinedPrincipal governs the organization of the Principal 122 | // field of a policy principal when principal_classification has 123 | // indicated that a combined form of principals is required 124 | message CombinedPrincipal { 125 | // Principals refer to combined principals 126 | repeated MSPPrincipal principals = 1; 127 | } 128 | 129 | // TODO: Bring msp.SerializedIdentity from fabric/msp/identities.proto here. Reason below. 130 | // SerializedIdentity represents an serialized version of an identity; 131 | // this consists of an MSP-identifier this identity would correspond to 132 | // and the bytes of the actual identity. A serialized form of 133 | // SerializedIdentity would govern "Principal" field of a PolicyPrincipal 134 | // of classification "ByIdentity". 135 | -------------------------------------------------------------------------------- /protos/peer/transaction.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 8 | option java_package = "org.hyperledger.fabric.protos.peer"; 9 | option java_outer_classname = "TransactionPackage"; 10 | 11 | package protos; 12 | 13 | import "peer/proposal_response.proto"; 14 | import "common/common.proto"; 15 | 16 | // This message is necessary to facilitate the verification of the signature 17 | // (in the signature field) over the bytes of the transaction (in the 18 | // transactionBytes field). 19 | message SignedTransaction { 20 | // The bytes of the Transaction. NDD 21 | bytes transaction_bytes = 1; 22 | 23 | // Signature of the transactionBytes The public key of the signature is in 24 | // the header field of TransactionAction There might be multiple 25 | // TransactionAction, so multiple headers, but there should be same 26 | // transactor identity (cert) in all headers 27 | bytes signature = 2; 28 | } 29 | 30 | // ProcessedTransaction wraps an Envelope that includes a transaction along with an indication 31 | // of whether the transaction was validated or invalidated by committing peer. 32 | // The use case is that GetTransactionByID API needs to retrieve the transaction Envelope 33 | // from block storage, and return it to a client, and indicate whether the transaction 34 | // was validated or invalidated by committing peer. So that the originally submitted 35 | // transaction Envelope is not modified, the ProcessedTransaction wrapper is returned. 36 | message ProcessedTransaction { 37 | // An Envelope which includes a processed transaction 38 | common.Envelope transactionEnvelope = 1; 39 | 40 | // An indication of whether the transaction was validated or invalidated by committing peer 41 | int32 validationCode = 2; 42 | } 43 | 44 | // The transaction to be sent to the ordering service. A transaction contains 45 | // one or more TransactionAction. Each TransactionAction binds a proposal to 46 | // potentially multiple actions. The transaction is atomic meaning that either 47 | // all actions in the transaction will be committed or none will. Note that 48 | // while a Transaction might include more than one Header, the Header.creator 49 | // field must be the same in each. 50 | // A single client is free to issue a number of independent Proposal, each with 51 | // their header (Header) and request payload (ChaincodeProposalPayload). Each 52 | // proposal is independently endorsed generating an action 53 | // (ProposalResponsePayload) with one signature per Endorser. Any number of 54 | // independent proposals (and their action) might be included in a transaction 55 | // to ensure that they are treated atomically. 56 | message Transaction { 57 | 58 | // The payload is an array of TransactionAction. An array is necessary to 59 | // accommodate multiple actions per transaction 60 | repeated TransactionAction actions = 1; 61 | } 62 | 63 | // TransactionAction binds a proposal to its action. The type field in the 64 | // header dictates the type of action to be applied to the ledger. 65 | message TransactionAction { 66 | 67 | // The header of the proposal action, which is the proposal header 68 | bytes header = 1; 69 | 70 | // The payload of the action as defined by the type in the header For 71 | // chaincode, it's the bytes of ChaincodeActionPayload 72 | bytes payload = 2; 73 | } 74 | 75 | //---------- Chaincode Transaction ------------ 76 | 77 | // ChaincodeActionPayload is the message to be used for the TransactionAction's 78 | // payload when the Header's type is set to CHAINCODE. It carries the 79 | // chaincodeProposalPayload and an endorsed action to apply to the ledger. 80 | message ChaincodeActionPayload { 81 | // This field contains the bytes of the ChaincodeProposalPayload message from 82 | // the original invocation (essentially the arguments) after the application 83 | // of the visibility function. The main visibility modes are "full" (the 84 | // entire ChaincodeProposalPayload message is included here), "hash" (only 85 | // the hash of the ChaincodeProposalPayload message is included) or 86 | // "nothing". This field will be used to check the consistency of 87 | // ProposalResponsePayload.proposalHash. For the CHAINCODE type, 88 | // ProposalResponsePayload.proposalHash is supposed to be H(ProposalHeader || 89 | // f(ChaincodeProposalPayload)) where f is the visibility function. 90 | bytes chaincode_proposal_payload = 1; 91 | 92 | // The list of actions to apply to the ledger 93 | ChaincodeEndorsedAction action = 2; 94 | } 95 | 96 | // ChaincodeEndorsedAction carries information about the endorsement of a 97 | // specific proposal 98 | message ChaincodeEndorsedAction { 99 | // This is the bytes of the ProposalResponsePayload message signed by the 100 | // endorsers. Recall that for the CHAINCODE type, the 101 | // ProposalResponsePayload's extenstion field carries a ChaincodeAction 102 | bytes proposal_response_payload = 1; 103 | 104 | // The endorsement of the proposal, basically the endorser's signature over 105 | // proposalResponsePayload 106 | repeated Endorsement endorsements = 2; 107 | } 108 | 109 | enum TxValidationCode { 110 | VALID = 0; 111 | NIL_ENVELOPE = 1; 112 | BAD_PAYLOAD = 2; 113 | BAD_COMMON_HEADER = 3; 114 | BAD_CREATOR_SIGNATURE = 4; 115 | INVALID_ENDORSER_TRANSACTION = 5; 116 | INVALID_CONFIG_TRANSACTION = 6; 117 | UNSUPPORTED_TX_PAYLOAD = 7; 118 | BAD_PROPOSAL_TXID = 8; 119 | DUPLICATE_TXID = 9; 120 | ENDORSEMENT_POLICY_FAILURE = 10; 121 | MVCC_READ_CONFLICT = 11; 122 | PHANTOM_READ_CONFLICT = 12; 123 | UNKNOWN_TX_TYPE = 13; 124 | TARGET_CHAIN_NOT_FOUND = 14; 125 | MARSHAL_TX_ERROR = 15; 126 | NIL_TXACTION = 16; 127 | EXPIRED_CHAINCODE = 17; 128 | CHAINCODE_VERSION_CONFLICT = 18; 129 | BAD_HEADER_EXTENSION = 19; 130 | BAD_CHANNEL_HEADER = 20; 131 | BAD_RESPONSE_PAYLOAD = 21; 132 | BAD_RWSET = 22; 133 | ILLEGAL_WRITESET = 23; 134 | INVALID_WRITESET = 24; 135 | INVALID_CHAINCODE = 25; 136 | NOT_VALIDATED = 254; 137 | INVALID_OTHER_REASON = 255; 138 | } 139 | 140 | // Reserved entries in the key-level metadata map 141 | enum MetaDataKeys { 142 | VALIDATION_PARAMETER = 0; 143 | VALIDATION_PARAMETER_V2 = 1; 144 | } 145 | -------------------------------------------------------------------------------- /protos/common/common.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/common"; 8 | option java_package = "org.hyperledger.fabric.protos.common"; 9 | 10 | package common; 11 | 12 | import "google/protobuf/timestamp.proto"; 13 | 14 | // These status codes are intended to resemble selected HTTP status codes 15 | enum Status { 16 | UNKNOWN = 0; 17 | SUCCESS = 200; 18 | BAD_REQUEST = 400; 19 | FORBIDDEN = 403; 20 | NOT_FOUND = 404; 21 | REQUEST_ENTITY_TOO_LARGE = 413; 22 | INTERNAL_SERVER_ERROR = 500; 23 | NOT_IMPLEMENTED = 501; 24 | SERVICE_UNAVAILABLE = 503; 25 | } 26 | 27 | enum HeaderType { 28 | reserved 7, 9; 29 | reserved "PEER_RESOURCE_UPDATE", "TOKEN_TRANSACTION"; 30 | 31 | MESSAGE = 0; // Used for messages which are signed but opaque 32 | CONFIG = 1; // Used for messages which express the channel config 33 | CONFIG_UPDATE = 2; // Used for transactions which update the channel config 34 | ENDORSER_TRANSACTION = 3; // Used by the SDK to submit endorser based transactions 35 | ORDERER_TRANSACTION = 4; // Used internally by the orderer for management 36 | DELIVER_SEEK_INFO = 5; // Used as the type for Envelope messages submitted to instruct the Deliver API to seek 37 | CHAINCODE_PACKAGE = 6; // Used for packaging chaincode artifacts for install 38 | PEER_ADMIN_OPERATION = 8; // Used for invoking an administrative operation on a peer 39 | } 40 | 41 | // This enum enlists indexes of the block metadata array 42 | enum BlockMetadataIndex { 43 | SIGNATURES = 0; // Block metadata array position for block signatures 44 | LAST_CONFIG = 1; // Block metadata array position to store last configuration block sequence number 45 | TRANSACTIONS_FILTER = 2; // Block metadata array position to store serialized bit array filter of invalid transactions 46 | ORDERER = 3 [deprecated=true]; /* Block metadata array position to store operational metadata for orderers 47 | e.g. For Kafka, this is where we store the last offset written to the local ledger */ 48 | COMMIT_HASH = 4; /* Block metadata array position to store the hash of TRANSACTIONS_FILTER, State Updates, 49 | and the COMMIT_HASH of the previous block */ 50 | } 51 | 52 | // LastConfig is the encoded value for the Metadata message which is encoded in the LAST_CONFIGURATION block metadata index 53 | message LastConfig { 54 | uint64 index = 1; 55 | } 56 | 57 | // Metadata is a common structure to be used to encode block metadata 58 | message Metadata { 59 | bytes value = 1; 60 | repeated MetadataSignature signatures = 2; 61 | } 62 | 63 | message MetadataSignature { 64 | bytes signature_header = 1; // An encoded SignatureHeader 65 | bytes signature = 2; // The signature over the concatenation of the Metadata value bytes, signatureHeader, and block header 66 | } 67 | 68 | message Header { 69 | bytes channel_header = 1; 70 | bytes signature_header = 2; 71 | } 72 | 73 | // Header is a generic replay prevention and identity message to include in a signed payload 74 | message ChannelHeader { 75 | int32 type = 1; // Header types 0-10000 are reserved and defined by HeaderType 76 | 77 | // Version indicates message protocol version 78 | int32 version = 2; 79 | 80 | // Timestamp is the local time when the message was created 81 | // by the sender 82 | google.protobuf.Timestamp timestamp = 3; 83 | 84 | // Identifier of the channel this message is bound for 85 | string channel_id = 4; 86 | 87 | // An unique identifier that is used end-to-end. 88 | // - set by higher layers such as end user or SDK 89 | // - passed to the endorser (which will check for uniqueness) 90 | // - as the header is passed along unchanged, it will be 91 | // be retrieved by the committer (uniqueness check here as well) 92 | // - to be stored in the ledger 93 | string tx_id = 5; 94 | 95 | // The epoch in which this header was generated, where epoch is defined based on block height 96 | // Epoch in which the response has been generated. This field identifies a 97 | // logical window of time. A proposal response is accepted by a peer only if 98 | // two conditions hold: 99 | // 1. the epoch specified in the message is the current epoch 100 | // 2. this message has been only seen once during this epoch (i.e. it hasn't 101 | // been replayed) 102 | uint64 epoch = 6; 103 | 104 | // Extension that may be attached based on the header type 105 | bytes extension = 7; 106 | 107 | // If mutual TLS is employed, this represents 108 | // the hash of the client's TLS certificate 109 | bytes tls_cert_hash = 8; 110 | } 111 | 112 | message SignatureHeader { 113 | // Creator of the message, a marshaled msp.SerializedIdentity 114 | bytes creator = 1; 115 | 116 | // Arbitrary number that may only be used once. Can be used to detect replay attacks. 117 | bytes nonce = 2; 118 | } 119 | 120 | // Payload is the message contents (and header to allow for signing) 121 | message Payload { 122 | 123 | // Header is included to provide identity and prevent replay 124 | Header header = 1; 125 | 126 | // Data, the encoding of which is defined by the type in the header 127 | bytes data = 2; 128 | } 129 | 130 | // Envelope wraps a Payload with a signature so that the message may be authenticated 131 | message Envelope { 132 | // A marshaled Payload 133 | bytes payload = 1; 134 | 135 | // A signature by the creator specified in the Payload header 136 | bytes signature = 2; 137 | } 138 | 139 | // This is finalized block structure to be shared among the orderer and peer 140 | // Note that the BlockHeader chains to the previous BlockHeader, and the BlockData hash is embedded 141 | // in the BlockHeader. This makes it natural and obvious that the Data is included in the hash, but 142 | // the Metadata is not. 143 | message Block { 144 | BlockHeader header = 1; 145 | BlockData data = 2; 146 | BlockMetadata metadata = 3; 147 | } 148 | 149 | // BlockHeader is the element of the block which forms the block chain 150 | // The block header is hashed using the configured chain hashing algorithm 151 | // over the ASN.1 encoding of the BlockHeader 152 | message BlockHeader { 153 | uint64 number = 1; // The position in the blockchain 154 | bytes previous_hash = 2; // The hash of the previous block header 155 | bytes data_hash = 3; // The hash of the BlockData, by MerkleTree 156 | } 157 | 158 | message BlockData { 159 | repeated bytes data = 1; 160 | } 161 | 162 | message BlockMetadata { 163 | repeated bytes metadata = 1; 164 | } 165 | 166 | // OrdererBlockMetadata defines metadata that is set by the ordering service. 167 | message OrdererBlockMetadata { 168 | LastConfig last_config = 1; 169 | bytes consenter_metadata = 2; 170 | } 171 | -------------------------------------------------------------------------------- /protos/peer/proposal.proto: -------------------------------------------------------------------------------- 1 | // Copyright the Hyperledger Fabric contributors. All rights reserved. 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | syntax = "proto3"; 6 | 7 | option go_package = "github.com/hyperledger/fabric-protos-go/peer"; 8 | option java_package = "org.hyperledger.fabric.protos.peer"; 9 | option java_outer_classname = "ProposalPackage"; 10 | 11 | package protos; 12 | 13 | import "peer/chaincode.proto"; 14 | import "peer/proposal_response.proto"; 15 | 16 | /* 17 | The flow to get a generic transaction approved goes as follows: 18 | 19 | 1. client sends proposal to endorser 20 | ==================================== 21 | 22 | The proposal is basically a request to do something that will result on some 23 | action with impact on the ledger; a proposal contains a header (with some 24 | metadata describing it, such as the type, the identity of the invoker, the 25 | time, the ID of the chain, a cryptographic nonce..) and an opaque payload that 26 | depends on the type specified in the header. A proposal contains the following 27 | messages: 28 | 29 | SignedProposal 30 | |\_ Signature (signature on the Proposal message by the creator specified in the header) 31 | \_ Proposal 32 | |\_ Header (the header for this proposal) 33 | \_ Payload (the payload for this proposal) 34 | 35 | 2. endorser sends proposal response back to client 36 | ================================================== 37 | 38 | The proposal response contains an endorser's response to a client's proposal. A 39 | proposal response contains a success/error code, a response payload and a 40 | signature (also referred to as endorsement) over the response payload. The 41 | response payload contains a hash of the proposal (to securely link this 42 | response to the corresponding proposal) and an opaque extension field that 43 | depends on the type specified in the header of the corresponding proposal. A 44 | proposal response contains the following messages: 45 | 46 | ProposalResponse 47 | |\_ Endorsement (the endorser's signature over the whole response payload) 48 | \_ ProposalResponsePayload (the payload of the proposal response) 49 | 50 | 3. client assembles endorsements into a transaction 51 | =================================================== 52 | 53 | A transaction message assembles one or more proposals and corresponding 54 | responses into a message to be sent to orderers. After ordering, (batches of) 55 | transactions are delivered to committing peers for validation and final 56 | delivery into the ledger. A transaction contains one or more actions. Each of 57 | them contains a header (same as that of the proposal that requested it) and an 58 | opaque payload that depends on the type specified in the header. 59 | 60 | SignedTransaction 61 | |\_ Signature (signature on the Transaction message by the creator specified in the header) 62 | \_ Transaction 63 | \_ TransactionAction (1...n) 64 | |\_ Header (1) (the header of the proposal that requested this action) 65 | \_ Payload (1) (the payload for this action) 66 | */ 67 | 68 | // This structure is necessary to sign the proposal which contains the header 69 | // and the payload. Without this structure, we would have to concatenate the 70 | // header and the payload to verify the signature, which could be expensive 71 | // with large payload 72 | // 73 | // When an endorser receives a SignedProposal message, it should verify the 74 | // signature over the proposal bytes. This verification requires the following 75 | // steps: 76 | // 1. Verification of the validity of the certificate that was used to produce 77 | // the signature. The certificate will be available once proposalBytes has 78 | // been unmarshalled to a Proposal message, and Proposal.header has been 79 | // unmarshalled to a Header message. While this unmarshalling-before-verifying 80 | // might not be ideal, it is unavoidable because i) the signature needs to also 81 | // protect the signing certificate; ii) it is desirable that Header is created 82 | // once by the client and never changed (for the sake of accountability and 83 | // non-repudiation). Note also that it is actually impossible to conclusively 84 | // verify the validity of the certificate included in a Proposal, because the 85 | // proposal needs to first be endorsed and ordered with respect to certificate 86 | // expiration transactions. Still, it is useful to pre-filter expired 87 | // certificates at this stage. 88 | // 2. Verification that the certificate is trusted (signed by a trusted CA) and 89 | // that it is allowed to transact with us (with respect to some ACLs); 90 | // 3. Verification that the signature on proposalBytes is valid; 91 | // 4. Detect replay attacks; 92 | message SignedProposal { 93 | 94 | // The bytes of Proposal 95 | bytes proposal_bytes = 1; 96 | 97 | // Signaure over proposalBytes; this signature is to be verified against 98 | // the creator identity contained in the header of the Proposal message 99 | // marshaled as proposalBytes 100 | bytes signature = 2; 101 | } 102 | 103 | // A Proposal is sent to an endorser for endorsement. The proposal contains: 104 | // 1. A header which should be unmarshaled to a Header message. Note that 105 | // Header is both the header of a Proposal and of a Transaction, in that i) 106 | // both headers should be unmarshaled to this message; and ii) it is used to 107 | // compute cryptographic hashes and signatures. The header has fields common 108 | // to all proposals/transactions. In addition it has a type field for 109 | // additional customization. An example of this is the ChaincodeHeaderExtension 110 | // message used to extend the Header for type CHAINCODE. 111 | // 2. A payload whose type depends on the header's type field. 112 | // 3. An extension whose type depends on the header's type field. 113 | // 114 | // Let us see an example. For type CHAINCODE (see the Header message), 115 | // we have the following: 116 | // 1. The header is a Header message whose extensions field is a 117 | // ChaincodeHeaderExtension message. 118 | // 2. The payload is a ChaincodeProposalPayload message. 119 | // 3. The extension is a ChaincodeAction that might be used to ask the 120 | // endorsers to endorse a specific ChaincodeAction, thus emulating the 121 | // submitting peer model. 122 | message Proposal { 123 | 124 | // The header of the proposal. It is the bytes of the Header 125 | bytes header = 1; 126 | 127 | // The payload of the proposal as defined by the type in the proposal 128 | // header. 129 | bytes payload = 2; 130 | 131 | // Optional extensions to the proposal. Its content depends on the Header's 132 | // type field. For the type CHAINCODE, it might be the bytes of a 133 | // ChaincodeAction message. 134 | bytes extension = 3; 135 | } 136 | 137 | //-------- the Chaincode Proposal ----------- 138 | 139 | /* 140 | The flow to get a CHAINCODE transaction approved goes as follows: 141 | 142 | 1. client sends proposal to endorser 143 | ==================================== 144 | 145 | The proposal is basically a request to do something on a chaincode, that will 146 | result on some action - some change in the state of a chaincode and/or some 147 | data to be committed to the ledger; a proposal in general contains a header 148 | (with some metadata describing it, such as the type, the identity of the 149 | invoker, the time, the ID of the chain, a cryptographic nonce..) and a payload 150 | (the chaincode ID, invocation arguments..). Optionally, it may contain actions 151 | that the endorser may be asked to endorse, to emulate a submitting peer. A 152 | chaincode proposal contains the following messages: 153 | 154 | SignedProposal 155 | |\_ Signature (signature on the Proposal message by the creator specified in the header) 156 | \_ Proposal 157 | |\_ Header (the header for this proposal) 158 | |\_ ChaincodeProposalPayload (the payload for this proposal) 159 | \_ ChaincodeAction (the actions for this proposal - optional for a proposal) 160 | 161 | 2. endorser sends proposal response back to client 162 | ================================================== 163 | 164 | The proposal response contains an endorser's response to a client's proposal. A 165 | proposal response contains a success/error code, a response payload and a 166 | signature (also referred to as endorsement) over the response payload. The 167 | response payload contains a hash of the proposal (to securely link this 168 | response to the corresponding proposal), a description of the action resulting 169 | from the proposal and the endorser's signature over its payload. Formally, a 170 | chaincode proposal response contains the following messages: 171 | 172 | ProposalResponse 173 | |\_ Endorsement (the endorser's signature over the whole response payload) 174 | \_ ProposalResponsePayload 175 | \_ ChaincodeAction (the actions for this proposal) 176 | 177 | 3. client assembles endorsements into a transaction 178 | =================================================== 179 | 180 | A transaction message assembles one or more proposals and corresponding 181 | responses into a message to be sent to orderers. After ordering, (batches of) 182 | transactions are delivered to committing peers for validation and final 183 | delivery into the ledger. A transaction contains one or more actions. Each of 184 | them contains a header (same as that of the proposal that requested it), a 185 | proposal payload (same as that of the proposal that requested it), a 186 | description of the resulting action and signatures from each of the endorsers 187 | that endorsed the action. 188 | 189 | SignedTransaction 190 | |\_ Signature (signature on the Transaction message by the creator specified in the header) 191 | \_ Transaction 192 | \_ TransactionAction (1...n) 193 | |\_ Header (1) (the header of the proposal that requested this action) 194 | \_ ChaincodeActionPayload (1) 195 | |\_ ChaincodeProposalPayload (1) (payload of the proposal that requested this action) 196 | \_ ChaincodeEndorsedAction (1) 197 | |\_ Endorsement (1...n) (endorsers' signatures over the whole response payload) 198 | \_ ProposalResponsePayload 199 | \_ ChaincodeAction (the actions for this proposal) 200 | */ 201 | 202 | // ChaincodeHeaderExtension is the Header's extentions message to be used when 203 | // the Header's type is CHAINCODE. This extensions is used to specify which 204 | // chaincode to invoke and what should appear on the ledger. 205 | message ChaincodeHeaderExtension { 206 | 207 | reserved 1; 208 | reserved "payload_visbility"; 209 | 210 | // The ID of the chaincode to target. 211 | ChaincodeID chaincode_id = 2; 212 | } 213 | 214 | // ChaincodeProposalPayload is the Proposal's payload message to be used when 215 | // the Header's type is CHAINCODE. It contains the arguments for this 216 | // invocation. 217 | message ChaincodeProposalPayload { 218 | 219 | // Input contains the arguments for this invocation. If this invocation 220 | // deploys a new chaincode, ESCC/VSCC are part of this field. 221 | // This is usually a marshaled ChaincodeInvocationSpec 222 | bytes input = 1; 223 | 224 | // TransientMap contains data (e.g. cryptographic material) that might be used 225 | // to implement some form of application-level confidentiality. The contents 226 | // of this field are supposed to always be omitted from the transaction and 227 | // excluded from the ledger. 228 | map TransientMap = 2; 229 | } 230 | 231 | // ChaincodeAction contains the actions the events generated by the execution 232 | // of the chaincode. 233 | message ChaincodeAction { 234 | reserved 5; 235 | reserved "token_operations"; 236 | 237 | // This field contains the read set and the write set produced by the 238 | // chaincode executing this invocation. 239 | bytes results = 1; 240 | 241 | // This field contains the events generated by the chaincode executing this 242 | // invocation. 243 | bytes events = 2; 244 | 245 | // This field contains the result of executing this invocation. 246 | Response response = 3; 247 | 248 | // This field contains the ChaincodeID of executing this invocation. Endorser 249 | // will set it with the ChaincodeID called by endorser while simulating proposal. 250 | // Committer will validate the version matching with latest chaincode version. 251 | // Adding ChaincodeID to keep version opens up the possibility of multiple 252 | // ChaincodeAction per transaction. 253 | ChaincodeID chaincode_id = 4; 254 | } 255 | --------------------------------------------------------------------------------