Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
763 changes: 583 additions & 180 deletions api/protoblocktx/block_tx.pb.go

Large diffs are not rendered by default.

59 changes: 54 additions & 5 deletions api/protoblocktx/block_tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ option go_package = "github.com/hyperledger/fabric-x-committer/api/protoblocktx"

package protoblocktx;

// Represents a transaction in the blockchain.
message Tx {
repeated TxNamespace namespaces = 1; // Namespaces associated with the transaction.
repeated bytes signatures = 2; // Signature per namespace.
// A list of namespaces that define the transaction's scope.
repeated TxNamespace namespaces = 1;

// A list of endorsements.
// IMPORTANT: This list MUST be the same size as the namespaces list.
// The Endorsement at index i corresponds to the namespace at index i.
repeated Endorsements endorsements = 2;
}

// Represents a namespace within a transaction.
Expand Down Expand Up @@ -44,9 +48,54 @@ message Write {
bytes value = 2; // The value associated with the key being written.
}

// Endorsements holds all the signatures that correspond to a single namespace
// in the transaction's namespaces list.
message Endorsements {
// The list of individual signatures for the corresponding namespace.
repeated EndorsementWithIdentity endorsements_with_identity = 1;
}

// EndorsementWithIdentity bundles a single signature with the identity of its creator.
message EndorsementWithIdentity {
// The actual cryptographic signature bytes.
bytes endorsement = 1;

// The identity of the creator who produced the signature, i.e., the endorsement.
Identity identity = 2;
}

message Identity {
// The identifier of the associated membership service provider
string msp_id = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: Is this field necessary? Can't we infer the MSP from the certificate's issuing CA?


oneof creator {
// The full raw bytes of the creator's certificate (e.g., an X.509 certificate).
bytes certificate= 2;

// An identifier for a certificate that is pre-stored or known by the committer.
string certificate_id = 3;
}
}

// Represents a namespace policy.
message NamespacePolicy {
string scheme = 1; // The scheme for signature verification.
PolicyType type = 1; // The type of policy used.
bytes policy = 2; // The policy rule.
}

enum PolicyType {
// A policy for verifying a single signature that was generated via a Threshold Signature
// Scheme (TSS). In a TSS, a threshold (T) of N parties must cooperate to
// collectively compute and produce the single signature.
THRESHOLD_RULE = 0;

// A policy defined by an explicit rule that evaluates one or more required signatures.
// For example: "OR('Org1MSP.admin', 'Org2MSP.admin')"
SIGNATURE_RULE = 1;
}

message ThresholdRule {
string scheme = 1; // The scheme for signature verification.
bytes public_key = 2; // The public key for signature verification.
}

Expand Down Expand Up @@ -78,7 +127,7 @@ message NamespacePolicies {

message PolicyItem {
string namespace = 1;
bytes policy = 2;
bytes policy = 2; // This holds the complete NamespacePolicy.
uint64 version = 3;
}

Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ go 1.24.3

require (
github.com/cenkalti/backoff/v4 v4.3.0
github.com/cockroachdb/errors v1.11.3
github.com/cockroachdb/errors v1.12.0
github.com/consensys/gnark-crypto v0.14.0
github.com/docker/docker v28.0.0+incompatible
github.com/docker/go-connections v0.5.0
Expand All @@ -20,7 +20,7 @@ require (
github.com/hyperledger/fabric v1.4.0-rc1.0.20240918034325-94590aa4332b
github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3
github.com/hyperledger/fabric-x-common v0.0.0-20250701155113-a1ddf93333d8
github.com/hyperledger/fabric-x-common v0.0.0-20250929135229-402ed28111ec
github.com/jackc/puddle v1.3.0
github.com/mitchellh/mapstructure v1.5.0
github.com/onsi/gomega v1.34.2
Expand Down Expand Up @@ -79,6 +79,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect
github.com/hyperledger-labs/SmartBFT v0.0.0-20240916013553-852e5be5889b // indirect
github.com/hyperledger/aries-bbs-go v0.0.0-20240528084656-761671ea73bc // indirect
github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 // indirect
Expand Down Expand Up @@ -113,6 +114,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,8 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo=
github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
Expand Down Expand Up @@ -921,8 +921,8 @@ github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5 h1:RPW
github.com/hyperledger/fabric-lib-go v1.1.3-0.20240523144151-25edd1eaf5f5/go.mod h1:SHNCq8AB0VpHAmvJEtdbzabv6NNV1F48JdmDihasBjc=
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk=
github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE=
github.com/hyperledger/fabric-x-common v0.0.0-20250701155113-a1ddf93333d8 h1:6cGlSZDuTxCIFOU2JUNDoaFoxZRhchJ3oncTGo9GDOE=
github.com/hyperledger/fabric-x-common v0.0.0-20250701155113-a1ddf93333d8/go.mod h1:xO5q1ytO5d5/DeWkDKMGAgoaWBnhmLIjT/ZS2BZfFVs=
github.com/hyperledger/fabric-x-common v0.0.0-20250929135229-402ed28111ec h1:qN9nTEzDkwHl8ZXba04tKsbT0UbJwH431EO2SrVEq6s=
github.com/hyperledger/fabric-x-common v0.0.0-20250929135229-402ed28111ec/go.mod h1:Jq5eZFxs8ofSglp5YOYKlNfz1NLw9hBVWTz6bk52vc4=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down
4 changes: 2 additions & 2 deletions integration/runner/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,9 @@ func (c *CommitterRuntime) MakeAndSendTransactionsToOrderer(
Namespaces: namespaces,
}
if expectedStatus != nil && expectedStatus[i] == protoblocktx.Status_ABORTED_SIGNATURE_INVALID {
tx.Signatures = make([][]byte, len(namespaces))
tx.Endorsements = make([]*protoblocktx.Endorsements, len(namespaces))
for nsIdx := range namespaces {
tx.Signatures[nsIdx] = []byte("dummy")
tx.Endorsements[nsIdx] = test.CreateEndorsementsForThresholdRule([]byte("dummy"))[0]
}
}
txs[i] = c.TxBuilder.MakeTx(tx)
Expand Down
2 changes: 1 addition & 1 deletion integration/test/config_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestConfigUpdate(t *testing.T) {
ordererEnv.SubmitConfigBlock(t, &workload.ConfigBlock{
ChannelID: c.SystemConfig.Policy.ChannelID,
OrdererEndpoints: endpoints,
MetaNamespaceVerificationKey: metaPolicy.PublicKey,
MetaNamespaceVerificationKey: metaPolicy.Policy,
})
}
submitConfigBlock(ordererEnv.AllRealOrdererEndpoints())
Expand Down
2 changes: 1 addition & 1 deletion loadgen/workload/config_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func CreateConfigBlock(policy *PolicyProfile) (*common.Block, error) {

// CreateDefaultConfigBlock creates a config block with default values.
func CreateDefaultConfigBlock(conf *ConfigBlock) (*common.Block, error) {
configBlock := genesisconfig.Load(genesisconfig.SampleFabricX, configtest.GetDevConfigDir())
configBlock := genesisconfig.Load(genesisconfig.TwoOrgsSampleFabricX, configtest.GetDevConfigDir())
tlsCertPath := filepath.Join(configtest.GetDevConfigDir(), "msp", "tlscacerts", "tlsroot.pem")
for _, consenter := range configBlock.Orderer.ConsenterMapping {
consenter.Identity = tlsCertPath
Expand Down
7 changes: 4 additions & 3 deletions loadgen/workload/conflicts.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"math/rand"

"github.com/hyperledger/fabric-x-committer/api/protoblocktx"
"github.com/hyperledger/fabric-x-committer/utils/test"
)

// Dependency types.
Expand Down Expand Up @@ -61,9 +62,9 @@ func newSignTxModifier(rnd *rand.Rand, profile *Profile) *signTxModifier {
func (g *signTxModifier) Modify(tx *protoblocktx.Tx) {
if g.invalidSignGenerator.Next() {
// Pre-assigning prevents TxBuilder from re-signing the TX.
tx.Signatures = make([][]byte, len(tx.Namespaces))
for i := range tx.Namespaces {
tx.Signatures[i] = g.invalidSignature
tx.Endorsements = make([]*protoblocktx.Endorsements, len(tx.Namespaces))
for i := range len(tx.Namespaces) {
tx.Endorsements[i] = test.CreateEndorsementsForThresholdRule(g.invalidSignature)[0]
}
}
}
Expand Down
15 changes: 10 additions & 5 deletions loadgen/workload/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import (
"os"

"github.com/cockroachdb/errors"
"github.com/hyperledger/fabric-x-common/protoutil"

"github.com/hyperledger/fabric-x-committer/api/protoblocktx"
"github.com/hyperledger/fabric-x-committer/api/types"
"github.com/hyperledger/fabric-x-committer/utils"
"github.com/hyperledger/fabric-x-committer/utils/logging"
"github.com/hyperledger/fabric-x-committer/utils/signature"
"github.com/hyperledger/fabric-x-committer/utils/signature/sigtest"
"github.com/hyperledger/fabric-x-committer/utils/test"
)

var logger = logging.New("load-gen-sign")
Expand Down Expand Up @@ -57,19 +59,19 @@ func NewTxSignerVerifier(policy *PolicyProfile) *TxSignerVerifier {

// Sign signs a TX.
func (e *TxSignerVerifier) Sign(txID string, tx *protoblocktx.Tx) {
tx.Signatures = make([][]byte, len(tx.Namespaces))
tx.Endorsements = make([]*protoblocktx.Endorsements, len(tx.Namespaces))
for nsIndex, ns := range tx.Namespaces {
signer, ok := e.HashSigners[ns.NsId]
if !ok {
continue
}
tx.Signatures[nsIndex] = signer.Sign(txID, tx, nsIndex)
tx.Endorsements[nsIndex] = test.CreateEndorsementsForThresholdRule(signer.Sign(txID, tx, nsIndex))[0]
}
}

// Verify verifies a signature on the transaction.
func (e *TxSignerVerifier) Verify(txID string, tx *protoblocktx.Tx) bool {
if len(tx.Signatures) < len(tx.Namespaces) {
if len(tx.Endorsements) < len(tx.Namespaces) {
return false
}

Expand Down Expand Up @@ -130,8 +132,11 @@ func (e *HashSignerVerifier) Verify(txID string, tx *protoblocktx.Tx, nsIndex in
// GetVerificationPolicy returns the verification policy.
func (e *HashSignerVerifier) GetVerificationPolicy() *protoblocktx.NamespacePolicy {
return &protoblocktx.NamespacePolicy{
Scheme: e.scheme,
PublicKey: e.pubKey,
Type: protoblocktx.PolicyType_THRESHOLD_RULE,
Policy: protoutil.MarshalOrPanic(&protoblocktx.ThresholdRule{
Scheme: e.scheme,
PublicKey: e.pubKey,
}),
}
}

Expand Down
4 changes: 2 additions & 2 deletions loadgen/workload/tx_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@ func (txb *TxBuilder) makeTx(optionalTxID *string, blockTx *protoblocktx.Tx) *pr

// 2. Signs the TX:
switch {
case blockTx.Signatures != nil:
case len(blockTx.Endorsements) > 0:
// If the TX already have a signature, it doesn't re-sign it.
case txb.TxSigner != nil:
// If TxSigner is given, it is used to sign the TX.
txb.TxSigner.Sign(txID, blockTx)
case txb.TxSigner == nil:
// Otherwise, it puts empty signatures for all namespaces to ensure well-formed TX.
blockTx.Signatures = make([][]byte, len(blockTx.Namespaces))
blockTx.Endorsements = make([]*protoblocktx.Endorsements, len(blockTx.Namespaces))
}

// 3. Serializes the envelope's payload.
Expand Down
2 changes: 1 addition & 1 deletion mock/sigverifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (m *SigVerifier) sendResponseBatch(
}
status := protoblocktx.Status_COMMITTED
isConfig := len(req.Tx.Namespaces) == 1 && req.Tx.Namespaces[0].NsId == types.ConfigNamespaceID
if len(req.Tx.Signatures) == 0 && !isConfig {
if len(req.Tx.Endorsements) == 0 && !isConfig {
status = protoblocktx.Status_ABORTED_SIGNATURE_INVALID
}
respBatch.Responses = append(respBatch.Responses, &protosigverifierservice.Response{
Expand Down
Loading
Loading