본문 바로가기

Hyperledger Fabric/Document

[HYPERLEDGER FABRIC v1.0]4. 운영가이드

 운영가이드 ( OPERATION GUIDE )

회원 서비스 제공업체 MSP ( Membership Service Providers )

이 문서는 MSP의 설정 및 모범 사례에 대한 세부 정보를 제공합니다.

멤버쉽 서비스 공급자 (MSP)는 멤버십 운영 아키텍처의 추상화를 제공하는 것을 목표로하는 구성 요소입니다.

특히 MSP는 인증서 발급 및 유효성 검사 및 사용자 인증에 대한 모든 암호화 메커니즘 및 프로토콜을 추상화합니다. MSP는 자신의 신원 개념과 해당 신원을 관리 (신원 확인) 및 인증 (서명 생성 및 검증)하는 규칙을 정의 할 수 있습니다.

Hyperledger 패브릭 블록 체인 네트워크는 하나 이상의 MSP에 의해 관리 될 수 있습니다. 이는 멤버쉽 운영의 모듈화와 다른 멤버쉽 표준 및 아키텍처 간의 상호 운용성을 제공합니다.

이 문서의 나머지 부분에서는 Hyperledger Fabric에서 지원하는 MSP 구현의 설정에 대해 자세히 설명하고 그 사용과 관련된 모범 사례에 대해 논의합니다.


MSP 구성 ( MSP Configuration )

MSP의 인스턴스를 설정하려면 피어 및 발주자 서명을 가능하게하기 위해 각 피어 및 발주자에 로컬로 구성을 지정하고 피어, 발주자, 클라이언트 ID 유효성 검사 및 각 서명 확인을 가능하게하는 채널에서 모든 채널 회원에 의해 구성을 지정해야합니다.

우선, 각각의 MSP에 대한 이름이 네트워크에 해당 MSP를 참조하기 위해 지정 될 필요 (예를 들어msp1org2및 org3.divA). 컨소시엄, 조직 또는 조직 부서를 대표하는 MSP의 멤버십 규칙을 채널에서 참조해야하는 이름입니다. 이를 MSP Identifier 또는 MSP ID 라고도합니다 . MSP 식별자는 MSP 인스턴스마다 고유해야 합니다. 예를 들어, 동일한 식별자를 가진 두 개의 MSP 인스턴스가 시스템 채널 생성에서 감지되어야합니다. 주문자 설정은 실패합니다.

MSP의 기본 구현의 경우 ID (인증서) 유효성 검사 및 서명 확인을 허용하도록 매개 변수 집합을 지정해야합니다. 이 매개 변수는 RFC5280 에 의해 추론되며 다음을 포함합니다.

  • 신뢰의 경로를 구성하는 자체 서명(X.509) 인증서 목록
  • 이 공급자가 인증서 유효성 검사를 위해 고려하는 중간 CA를 나타내는 X.509 인증서 목록 이 인증서는 신뢰의 루트에있는 인증서 중 하나만으로 인증 받아야합니다. 중간 CA는 선택적 매개 변수입니다.
  • 이 MSP의 관리자를 나타낼 수있는 신뢰할 수있는 인증서 경로가있는 X.509 인증서 목록입니다. 이 인증서의 소유자는이 MSP 구성 (예 : 루트 CA, 중간 CA)에 대한 변경을 요청할 수있는 권한이 있습니다.
  • 이 MSP의 유효한 구성원이 X.509 인증서에 포함해야하는 조직 단위 목록 이 매개 변수는 선택적인 구성 매개 변수입니다. 예를 들어 여러 조직에서 동일한 트러스트 루트 및 중간 CA를 활용하고 해당 구성원에 대해 OU 필드를 예약한 경우 사용됩니다
  • 나열된(중간 또는 루트) MSP 인증 기관 중 정확히 하나에 각각 해당하는 인증서 해지 목록 (CRL) 목록 이것은 선택적 매개 변수입니다.

이 MSP 인스턴스의 유효한 ID는 다음 조건을 충족해야합니다.

  • X.509 인증서 형태로되어 있으며 루트 인증서 인증서의 루트 중 하나에 대한 검증 가능한 인증서 경로가 있습니다
  • 그들은 어떤 CRL에도 포함되어 있지 않습니다.
  • 또한 X.509 인증서 구조 필드에 MSP 구성의 조직 구성 단위 중 하나 이상 을 나열합니다OU .

현재 MSP 구현에서 ID의 유효성에 대한 자세한 내용은 독자에게 ID 유효성 검사 규칙 <no title>을 참조하십시오 .

검증 관련 매개 변수 외에도 MSP가 서명 또는 인증을 위해 인스턴스화 된 노드를 활성화하려면 다음을 지정해야합니다.

  • 노드에 의한 서명에 사용되는 서명 키.
  • 노드의 X.509 인증서, 즉이 MSP의 확인 매개 변수 아래에 유효한 ID입니다.


어떻게 MSP 인증서와 서명 키를 생성하나요? ( How to generate MSP certificates and their signing keys? )

X.509 인증서를 생성하여 MSP 구성을 제공하려면 응용 프로그램에서 Openssl 을 사용할 수 있습니다 .

또는 cryptogen 도구 를 사용할 수 있습니다.이 도구의 작업 방법은 시작하기에서 설명 합니다.

fabric-ca 관련 인증서 생성을 위해 독자는 fabric-ca 관련 설명서 인 Setup / ca-setup을 참조하십시오 .


피어 및 발주자 측의 MSP 설정 ( MSP setup on the peer & orderer side )

로컬 MSP (피어 또는 발주자 용)를 설정하려면 관리자는 $MY_PATH/mspconfig6 개의 하위 폴더와 파일을 포함 하는 폴더 (예 :)를 만들어야 합니다.

  1. admincerts관리자 인증서에 각각 해당하는 PEM 파일을 포함 하는 폴더
  2. cacerts루트 CA의 인증서에 각각 해당하는 PEM 파일을 포함 하는 폴더
  3. (선택 사항) intermediatecerts중개 CA 인증서에 각각 해당하는 PEM 파일을 포함 하는 폴더
  4. config.yaml고려 대상 OU에 대한 정보를 포함 하는 파일 (선택 사항) . 후자는 yaml 배열 의 항목 쌍으로 정의됩니다 . 여기서는 이 조직 단위의 구성원을 인증하기 위해 고려해야하는 인증 기관 (루트 또는 중간)의 인증서에 대한 상대 경로를 나타냅니다 (예 : ./cacerts/cacert). pem)이며 X.509 인증서 OU 필드 (예 : "COP")에 나타날 것으로 예상되는 실제 문자열을 나타냅니다.<Certificate, OrganizationalUnitIdentifier>OrganizationalUnitIdentifiersCertificateOrganizationalUnitIdentifier
  5. crls고려 대상 CRL을 포함 할 폴더 (선택 사항)
  6. keystore노드의 서명 키가있는 PEM 파일을 포함 하는 폴더
  7. signcerts노드의 X.509 인증서가있는 PEM 파일을 포함 하는 폴더


채널 MSP 설정 ( Channel MSP setup )

시스템의 기원에서 네트워크에 나타나는 모든 MSP의 확인 매개 변수를 지정하고 시스템 채널의 기원 블록에 포함해야합니다. MSP 확인 매개 변수는 MSP 식별자, 트러스트 인증서 루트, 중간 CA 및 관리자 인증서, OU 사양 및 CRL로 구성됩니다. 시스템 생성 블록은 설치 단계에서 주문자에게 제공되며 채널 생성 요청을 인증 할 수 있습니다. 명령자는 동일한 식별자를 가진 두 개의 MSP를 포함하는 경우 시스템 생성 블록을 거부하므로 결과적으로 네트워크의 부트 스트랩이 실패합니다.

응용 프로그램 채널의 경우 채널을 관리하는 MSP의 확인 구성 요소 만 채널의 생성 블록에 있어야합니다. 하나 이상의 피어에게 채널에 참여하도록 지시하기 전에 정확한 MSP 구성 정보가 채널의 구성 블록 (또는 가장 최근 구성 블록)에 포함되도록하는 것이 응용 프로그램의 책임 임을 강조합니다 .

configtxgen 도구를 사용하여 채널을 부트 스트랩 할 때 mspconfig 폴더에 MSP의 확인 매개 변수를 포함하고 configtx.yaml의 관련 섹션에서 해당 경로를 설정하여 채널 MSP를 구성 할 수 있습니다.

해당 MSP의 CA와 관련된 인증서 해지 목록의 알림을 포함하여 채널에서 MSP를 다시 구성 하는 작업은 MSP config_update의 관리자 인증서 중 하나의 소유자가 개체를 만들어서 수행합니다. 그러면 관리자가 관리하는 클라이언트 응용 프로그램은이 MSP가 나타나는 채널에이 업데이트를 알립니다.


모범 사례 ( Best Practices )

이 섹션에서는 일반적으로 충족되는 시나리오에서 MSP 구성에 대한 모범 사례를 자세히 설명합니다.

1) 단체 / 기업과 MSP 간의 매핑 ( Mapping between organizations/corporations and MSPs )

조직과 MSP 간에는 일대일 매핑이 권장됩니다. 다른 매핑 유형의 매핑이 선택되면 다음 사항을 고려해야합니다.

  • 다양한 MSP를 사용하는 한 조직. 이는 관리 독립성을 이유로 또는 개인 정보 보호를 이유로 MSP로 대표되는 다양한 부서를 포함하는 조직의 경우에 해당합니다. 이 경우 피어는 단일 MSP 만 소유 할 수 있으며 다른 조직의 피어가 동일한 조직의 피어로 인식되지 않습니다. 이것의 의미는 동료들이 가십 조직 범위의 데이터를 실제 조직을 구성하는 전체 제공자가 아닌 동일한 하위 단위의 구성원과 공유 할 수 있다는 것입니다.
  • 단일 MSP를 사용하는 여러 조직. 이것은 유사한 회원 구성에 의해 관리되는 조직의 컨소시엄의 경우에 해당합니다. 동일한 실제 조직에 속해 있는지 여부에 관계없이 동일한 MSP에서 신원이있는 동료에게 동료 범위의 메시지를 전파해야한다는 것을 여기에서 알아야합니다. 이것은 MSP 정의 및 / 또는 피어 구성의 세분화 한계입니다. 패브릭의 차후 버전에서는 (i) 네트워크의 모든 회원 관련 정보를 포함하는 ID 채널, (ii) 피어의 관리자가 피어에서 지정하는 피어의 관리자가 구성 할 수있는 "트러스트 영역"의 피어 개념 MSP 구성원이 조직 범위 메시지를 수신하도록 승인 된 것으로 동료에 의해 처리되어야하는 설정 시간.

2) 하나의 조직은 서로 다른 부서 (조직 단위)를 가지고 있으며 , 서로 다른 채널에 대한 액세스 권한을 부여 ( One organization has different divisions (say organizational units), to which it wants to grant access to different channels )

이것을 처리하는 두 가지 방법 :

  • 모든 조직 구성원의 구성원 자격을 수용하도록 하나의 MSP를 정의하십시오 . 해당 MSP의 구성은 루트 CA, 중간 CA 및 관리자 인증서 목록으로 구성됩니다. 회원 ID에는 OU회원이 속한 조직 단위 ( ) 가 포함 됩니다. 정책을 정의하여 특정 구성원을 파악할 OU수 있으며 이러한 정책은 채널의 읽기 / 쓰기 정책 또는 체인 코드의 승인 정책을 구성 할 수 있습니다. 이 접근 방식의 한계는 가십 피어가 로컬 MSP에서 동일한 회원의 회원 자격을 가진 동료를 동일 조직의 구성원으로 간주하여 결과적으로 조직 범위 데이터 (예 : 자신의 상태)를 가십을 수 있다는 것입니다.
  • 하나의 MSP를 정의하여 각 부서를 나타냅니다 . 여기에는 각 부서에 대해 루트 CA, 중간 CA 및 관리 인증서에 대한 인증서 집합이 지정되므로 MSP간에 중복되는 인증서 경로가 없어야합니다. 이는, 예를 들어 세분당 다른 중간 CA가 사용됨을 의미합니다. 여기서 단점은 하나가 아닌 하나 이상의 MSP를 관리하는 것이지만, 이전 방법에서 제기 된 문제를 우회하는 것입니다. 또한 MSP 구성의 OU 확장을 활용하여 각 부서에 대해 하나의 MSP를 정의 할 수 있습니다.

3) 클라이언트를 동일한 조직의 동료와 분리합니다 ( Separating clients from peers of the same organization )

많은 경우에 신원의 "유형"은 신원 자체에서 검색 할 수 있어야합니다 (예 : 고객 또는 전적으로 주문자가되는 노드가 아닌, 동료가 보증을 보증해야하는 경우).

이러한 요구 사항에 대한 지원은 제한적입니다.

이러한 분리를 허용하는 한 가지 방법은 각 노드 유형에 대해 별도의 중간 CA를 작성하는 것입니다. 하나는 클라이언트 용이고 다른 하나는 동료 / 발주자 용입니다. 두 개의 서로 다른 MSP를 구성하십시오. 하나는 클라이언트 용이고 다른 하나는 피어 / 발주자 용입니다. 이 조직이 액세스해야하는 채널은 두 가지 MSP를 모두 포함해야하며, 인증 정책은 동료를 참조하는 MSP만 사용합니다. 결국 궁극적으로 조직이 두 개의 MSP 인스턴스에 매핑되고 피어와 클라이언트가 상호 작용하는 방식에 어떤 영향을 미칩니다.

동일한 조직의 모든 동료가 여전히 하나의 MSP에 속하기 때문에 험담은 크게 영향을받지 않습니다. 피어는 특정 시스템 체인 코드의 실행을 로컬 MSP 기반 정책으로 제한 할 수 있습니다. 예를 들어 피어는 클라이언트인 로컬 MSP의 관리자 (최종 사용자가 요청의 출처에 있어야 함)의 관리자가 요청을 서명 한 경우에만 "joinChannel"요청을 실행합니다. 피어 / 발주자 MSP의 멤버가되는 유일한 클라이언트가 해당 MSP의 관리자가된다는 사실을 받아들이면이 불일치를 해결할 수 있습니다.

이 접근법으로 고려해야 할 또 다른 포인트는 피어가 자신의 로컬 MSP 내의 요청 발신자의 회원 자격을 기반으로 이벤트 등록 요청을 승인한다는 것입니다. 분명히, 요청의 발신자가 클라이언트이기 때문에, 요청 발신자는 항상 요청 된 피어와 다른 MSP에 속할 것이고, 피어는 요청을 거부 할 것입니다.

4) 관리자 및 CA 인증서 (  Admin and CA certificates )

MSP 관리 인증서가 MSP 또는 중간 CA에 대해 고려 된 인증서와 다른 것으로 설정하는 것이 중요합니다 . 이는 회원 구성 요소 관리의 의무를 새 인증서 발급 및 / 또는 기존 인증서 유효성 검사와 구분하는 일반적인 (보안) 방법입니다.root of trust

5) 중간 CA를 블랙리스트에 올린다 ( Blacklisting an intermediate CA )

이전 섹션에서 언급했듯이 MSP의 재구성은 재구성 메커니즘 (로컬 MSP 인스턴스의 수동 재구성 및 config_update채널의 MSP 인스턴스에 대해 올바르게 구성된 메시지를 통해 수행)을 통해 이루어 집니다. 분명히, MSP에서 간주되는 중간 CA가 더 이상 해당 MSP의 신원 확인을 위해 고려되지 않는지 확인하는 두 가지 방법이 있습니다.

  1. 신뢰할 수있는 중간 CA 인증서 목록에 해당 중간 CA의 인증서를 더 이상 포함하지 않도록 MSP를 다시 구성합니다. 로컬로 구성된 MSP의 경우이 CA의 인증서가 intermediatecerts폴더 에서 제거되었음을 의미 합니다.
  2. 언급 된 중간 CA의 인증서를 거부하는 트러스트 루트에서 생성 된 CRL을 포함하도록 MSP를 다시 구성합니다.

현재 MSP 구현에서 우리는 더 간단하고 더 이상 고려되지 않는 중간 CA를 블랙리스트에 올릴 필요가 없으므로 방법 (1) 만 지원합니다.


채널 구성 ( Channel Configuration(configtx))

Hyperledger Fabric 블록 체인 네트워크의 공유 구성은 채널 당 하나의 수집 구성 트랜잭션에 저장됩니다. 각 구성 트랜잭션은 일반적으로 더 짧은 이름 configtx로 참조 됩니다.

채널 구성에는 다음과 같은 중요한 속성이 있습니다.

  1. 버전 관리 : 구성의 모든 요소에는 모든 수정 작업을 수행하는 관련 버전이 있습니다. 또한 커밋 된 모든 구성은 시퀀스 번호를받습니다.
  2. 허가 됨 : 구성의 각 요소에는 해당 요소에 대한 수정이 허용되는지 여부를 결정하는 관련 정책이 있습니다. 이전 configtx 사본이 있고 추가 정보가없는 사용자는이 정책을 기반으로 새 구성의 유효성을 확인할 수 있습니다.
  3. 계층 구조 : 루트 구성 그룹에는 하위 그룹이 포함되며 계층 구조의 각 그룹에는 연관된 값과 정책이 있습니다. 이러한 정책은 계층 구조를 활용하여 하위 수준의 정책에서 한 수준의 정책을 가져올 수 있습니다.

구성 해부 ( Anatomy of a configuration )

구성은 다른 트랜잭션이없는 블록에 HeaderType_CONFIG 유형의 트랜잭션으로 저장됩니다 . 이러한 블록을 '구성 블록' 이라고하며, 그 중 첫 번째 블록을 '제네시스 블록(Genesis Block)' 이라고합니다.

구성을 위한 프로토 구조는 fabric/protos/common/configtx.proto에 저장됩니다. HeaderType_CONFIG형식의 봉투는 Payload, data필드로 ConfigEnvelope 메시지를 인코드합니다. ConfigEnvelope의 프로토 타입은 다음과 같이 정의됩니다.

message ConfigEnvelope {
    Config config = 1;
    Envelope last_update = 2;
}

이 last_update필드는 아래의 구성 업데이트 섹션 에 정의되어 있지만 구성을 확인하지 않고 읽을 필요가있을 때만 필요합니다. 대신 현재 커밋 된 구성이 Config메시지를 config필드에 저장됩니다.

message Config {
    uint64 sequence = 1;
    ConfigGroup channel_group = 2;
}

sequence수는 각 커밋 구성을위한 하나 증가합니다. channel_group필드 구성을 포함하는 루트 그룹입니다. ConfigGroup구조 재귀 정의되며, 값 및 정책을 포함하는 각각의 그룹의 트리를 구축한다. 그것은 다음과 같이 정의됩니다.

message ConfigGroup {
    uint64 version = 1;
    map<string,ConfigGroup> groups = 2;
    map<string,ConfigValue> values = 3;
    map<string,ConfigPolicy> policies = 4;
    string mod_policy = 5;
}

ConfigGroup은 재귀적 구조이기 때문에 계층 구조로되어 있습니다. 다음 예는 golang 표기법을 명확하게 표현한 것입니다.

// Assume the following groups are defined
var root, child1, child2, grandChild1, grandChild2, grandChild3 *ConfigGroup

// Set the following values
root.Groups["child1"] = child1
root.Groups["child2"] = child2
child1.Groups["grandChild1"] = grandChild1
child2.Groups["grandChild2"] = grandChild2
child2.Groups["grandChild3"] = grandChild3

// The resulting config structure of groups looks like:
// root:
//     child1:
//         grandChild1
//     child2:
//         grandChild2
//         grandChild3

각 그룹은 구성 계층에서 수준을 정의하며 각 그룹은 관련된 값 집합 (문자열 키로 인덱싱 됨)과 정책 (문자열 키로 인덱싱 됨)을 갖습니다.

값은 다음과 같이 정의됩니다.

message ConfigValue {
    uint64 version = 1;
    bytes value = 2;
    string mod_policy = 3;
}

정책은 다음과 같이 정의됩니다.

message ConfigPolicy {
    uint64 version = 1;
    Policy policy = 2;
    string mod_policy = 3;
}

값, 정책 및 그룹에는 모두 버전 및 mod_policy가 있습니다. 요소의 버전은 해당 요소가 수정 될 때마다 증가합니다. mod_policy는 요소를 수정하기 위해 필요한 서명을 관리하는 데 사용됩니다. 그룹의 경우 수정은 값, 정책 또는 그룹 맵에 요소를 추가하거나 제거하거나 mod_policy를 변경하는 것입니다. 값 및 정책의 경우 수정은 값 및 정책 필드를 각각 변경합니다 (또는 mod_policy 변경). 각 요소의 mod_policy는 현재 구성 수준의 컨텍스트에서 평가됩니다. Channel.Groups [ "Application"]에 정의 된 다음 예제 mod 정책을 고려하십시오.( 여기서 golang map 레퍼런스 신텍스를 사용합니다. 그러므로, Channel.Groups["Application"].Policies["policy1"]은 베이스 Channel과 그룹의 Application, 그룹의 Policies, 그룹의 policy1정책을 나타냅니다.

  • policy1Channel.Groups["Application"].Policies["policy1"] 에 매핑됩니다.
  • Org1/policy2 는  Channel.Groups["Application"].Groups["Org1"].Policies["policy2"]에 매핑됩니다.
  • /Channel/policy3 는 Channel.Policies["policy3"]에 매핑됩니다. 

mod_policy가 존재하지 않는 정책을 참조하면 해당 항목을 수정할 수 없습니다.

구성 업데이트 ( Configuration Update )

구성 업데이트는 HeaderType_CONFIG_UPDATE 형식의 Payload 메시지로 전송됩니다. 트랜잭션의 Payload data 는 마샬링 된 ConfigUpdateEnvelope입니다. ConfigUpdateEnvelope는 다음과 같이 정의됩니다.

message ConfigUpdateEnvelope {
    bytes config_update = 1;
    repeated ConfigSignature signatures = 2;
}

signatures  필드에는 구성 업데이트를 인증하는 서명 세트가 들어 있습니다. 메시지 정의는 다음과 같습니다.

message ConfigSignature {
    bytes signature_header = 1;
    bytes signature = 2;
}

시그니처가 ConfigUpdateEnvelope 메시지의 signature_header bytes와 config_update bytes의 연결을 넘는 동안 signature_header는 표준 트랜잭션에 대해 정의 된 것과 같습니다.

ConfigUpdateEnvelope config_update 바이트는 다음과 같이 정의 된 마샬링 된 ConfigUpdate 메시지입니다.

message ConfigUpdate {
    string channel_id = 1;
    ConfigGroup read_set = 2;
    ConfigGroup write_set = 3;
}

channel_id는 업데이트가 바인딩 된 채널 ID이며,이 재구성을 지원하는 시그니처의 범위를 지정하는 데 필요합니다.

read_set 은version  필드 만 설정되고 다른 필드는 채워져서는 안되는 것으로 지정된 기존 구성의 하위 집합을 지정합니다. 특정 ConfigValue value 또는 ConfigPolicy policy필드는 read_set에 절대로 설정되어서는 안됩니다.ConfigGroup 은 config 트리의 더 깊은 요소를 참조 할 수 있도록 맵 필드의 하위 집합을 채울 수 있습니다. 예를 들어  Application  그룹을read_set에 포함 시키려면 해당 부모 (Channel  그룹)도 읽기 세트에 포함되어야하지만 Channel 그룹은 Orderer group  키와 같은 모든 키를 채울 필요는 없으며,  values또는 policies keys. 또는 정책 키 중 하나를 선택하십시오.

write_set 은 수정 된 구성을 지정합니다. 구성의 계층 적 특성으로 인해 계층 구조의 깊숙한 요소에 대한 쓰기는 해당 write_set 의 상위 수준 요소를 포함해야합니다. 그러나 동일한 버전의 read_set에도 지정되어있는 write_set 의 요소는 read_set과 마찬가지로 드문 드문하게 지정해야합니다.

예를 들어 다음과 같은 구성이 있습니다.예를 들어, 구성이 주어진 경우 :

Channel: (version 0)
    Orderer (version 0)
    Appplication (version 3)
       Org1 (version 2)

Org1을 수정하는 구성 업데이트를 제출하려면 read_set이 다음과 같습니다.

Channel: (version 0)
    Application: (version 3)

write_set은 다음과 같습니다.

Channel: (version 0)
    Application: (version 3)
        Org1 (version 3)

CONFIG_UPDATE가 수신되면 순서자는 다음을 수행하여 결과 CONFIG를 계산합니다.

  1. channel_id 및 read_set을 확인합니다. read_set의 모든 요소는 주어진 버전에 존재해야합니다.
  2. read_set의 동일한 버전에 나타나지 않는 write_set의 모든 요소를 수집하여 업데이트 세트를 계산합니다.
  3. 업데이트 세트의 각 요소가 요소 업데이트의 버전 번호를 정확히 1만큼 증가시키는 지 확인합니다.
  4. ConfigUpdateEnvelope에 첨부 된 서명 세트가 업데이트 세트의 각 요소에 대한 mod_policy를 충족시키는지 확인합니다.
  5. 업데이트 세트를 현재 구성에 적용하여 새로운 전체 구성 버전을 계산합니다.
  6. 새 구성을 ConfigEnvelope에 기록하고 CONFIG_UPDATElast_update 필드로, 새 구성을 config 필드에 인코딩 한 후 증가 된 sequence값과 함께 기록합니다.
  7. ConfigEnvelopeCONFIG유형의 Envelope에 기록하고 궁극적으로이를이를 새 구성 블록에 유일한 트랜잭션으로 씁니다.

피어 (또는 전달할 다른 Deliver)가 이 구성 블록을 수신하면 last_update 메시지를 현재 구성에 적용하고 발주자 계산 config 필드에 올바른 새로운 구성이 들어 있는지 확인하여 구성이 적절히 검증되었는지 확인해야합니다.

허용되는 구성 그룹 및 값 ( Permitted configuration groups and values )

유효한 구성은 다음 구성의 서브 세트입니다. 여기서 우리는 표기 peer.<MSG> 를 사용하여 value필드가 fabric/protos/peer/configuration.proto에 정의된 이름 <MSG> 의 마샬링 된 프로토 메시지임을 나타내는 ConfigValue를 정의합니다. 공통된 표기법common.<MSG>msp.<MSG>, and orderer.<MSG>는 비슷하지만 각각 fabric/protos/common/configuration.protofabric/protos/msp/mspconfig.proto, 그리고 fabric/protos/orderer/configuration.proto 에서 정의된 메시지와 함께 부합합니다.

키  {{org_name}} 과 {{consortium_name}}은 임의의 이름을 나타내며 다른 이름으로 반복 될 수있는 요소를 나타냅니다.

&ConfigGroup{
    Groups: map<string, *ConfigGroup> {
        "Application":&ConfigGroup{
            Groups:map<String, *ConfigGroup> {
                {{org_name}}:&ConfigGroup{
                    Values:map<string, *ConfigValue>{
                        "MSP":msp.MSPConfig,
                        "AnchorPeers":peer.AnchorPeers,
                    },
                },
            },
        },
        "Orderer":&ConfigGroup{
            Groups:map<String, *ConfigGroup> {
                {{org_name}}:&ConfigGroup{
                    Values:map<string, *ConfigValue>{
                        "MSP":msp.MSPConfig,
                    },
                },
            },

            Values:map<string, *ConfigValue> {
                "ConsensusType":orderer.ConsensusType,
                "BatchSize":orderer.BatchSize,
                "BatchTimeout":orderer.BatchTimeout,
                "KafkaBrokers":orderer.KafkaBrokers,
            },
        },
        "Consortiums":&ConfigGroup{
            Groups:map<String, *ConfigGroup> {
                {{consortium_name}}:&ConfigGroup{
                    Groups:map<string, *ConfigGroup> {
                        {{org_name}}:&ConfigGroup{
                            Values:map<string, *ConfigValue>{
                                "MSP":msp.MSPConfig,
                            },
                        },
                    },
                    Values:map<string, *ConfigValue> {
                        "ChannelCreationPolicy":common.Policy,
                    }
                },
            },
        },
    },

    Values: map<string, *ConfigValue> {
        "HashingAlgorithm":common.HashingAlgorithm,
        "BlockHashingDataStructure":common.BlockDataHashingStructure,
        "Consortium":common.Consortium,
        "OrdererAddresses":common.OrdererAddresses,
    },
}

시스템 채널 구성 순서 지정 ( Orderer system channel configuration )

주문 시스템 채널은 주문 매개 변수와 채널 생성을위한 컨소시엄을 정의해야합니다. 주문 서비스에 정확히 하나의 주문 시스템 채널이 있어야하며, 생성 (또는 더 정확하게 부트 스트랩)되는 첫 번째 채널입니다. 주문 시스템 채널 제네시스 구성 내에서 응용 프로그램 섹션을 정의하지 않는 것이 좋습니다. 그러나 테스트를 위해 수행 할 수 있습니다. 주문 시스템 채널에 대한 읽기 권한을 가진 회원은 모든 채널 생성을 볼 수 있으므로이 채널의 액세스가 제한되어야합니다.

순서 매개 변수는 config의 다음 서브 세트로 정의됩니다.

&ConfigGroup{
    Groups: map<string, *ConfigGroup> {
        "Orderer":&ConfigGroup{
            Groups:map<String, *ConfigGroup> {
                {{org_name}}:&ConfigGroup{
                    Values:map<string, *ConfigValue>{
                        "MSP":msp.MSPConfig,
                    },
                },
            },

            Values:map<string, *ConfigValue> {
                "ConsensusType":orderer.ConsensusType,
                "BatchSize":orderer.BatchSize,
                "BatchTimeout":orderer.BatchTimeout,
                "KafkaBrokers":orderer.KafkaBrokers,
            },
        },
    },

주문에 참여하는 각 조직에는 Orderer 그룹 아래에 그룹 요소가 있습니다. 이 그룹은 해당 조직에 대한 암호화 신원 정보를 포함하는 단일 매개 변수 MSP를 정의합니다. Orderer그룹의 Values에 따라 정렬 노드의 기능이 결정됩니다. 채널별로 존재하므로 orderer.BatchTimeout은 한 채널에서 다른 채널보다 다르게 지정 될 수 있습니다.

시작시, 주문자는 많은 채널에 대한 정보가 들어있는 파일 시스템에 직면하게됩니다. 주문자는 컨소시엄 그룹이 정의 된 채널을 식별하여 시스템 채널을 식별합니다. 컨소시엄 그룹의 구조는 다음과 같습니다.

&ConfigGroup{
    Groups: map<string, *ConfigGroup> {
        "Consortiums":&ConfigGroup{
            Groups:map<String, *ConfigGroup> {
                {{consortium_name}}:&ConfigGroup{
                    Groups:map<string, *ConfigGroup> {
                        {{org_name}}:&ConfigGroup{
                            Values:map<string, *ConfigValue>{
                                "MSP":msp.MSPConfig,
                            },
                        },
                    },
                    Values:map<string, *ConfigValue> {
                        "ChannelCreationPolicy":common.Policy,
                    }
                },
            },
        },
    },
},

각 컨소시엄은 주문 조직의 조직 구성원과 마찬가지로 구성원 집합을 정의합니다. 각 컨소시엄은 ChannelCreationPolicy도 정의합니다. 이 정책은 채널 생성 요청을 승인하는 데 적용됩니다. 일반적으로이 값은 채널 생성의 권한을 부여하기 위해 채널 서명의 새 구성원을 요구하는 ImplicitMetaPolicy로 설정됩니다. 채널 생성에 대한 자세한 내용은이 문서 뒷부분에 나와 있습니다.

응용 프로그램 채널 구성 ( Application channel configuration )

애플리케이션 구성은 애플리케이션 유형 트랜잭션을 위해 설계된 채널을위한 것입니다. 그것은 다음과 같이 정의됩니다.

&ConfigGroup{
    Groups: map<string, *ConfigGroup> {
        "Application":&ConfigGroup{
            Groups:map<String, *ConfigGroup> {
                {{org_name}}:&ConfigGroup{
                    Values:map<string, *ConfigValue>{
                        "MSP":msp.MSPConfig,
                        "AnchorPeers":peer.AnchorPeers,
                    },
                },
            },
        },
    },
}

Orderer 섹션과 마찬가지로 각 조직은 그룹으로 인코딩됩니다. 그러나 MSP ID 정보 만 인코딩하는 대신 각 조직은 AnchorPeers목록을 추가로 인코딩합니다. 이 목록은 다른 조직의 동료가 피어 가십 네트워킹을 위해 서로 연락 할 수있게합니다.

응용 프로그램 채널은 이러한 매개 변수의 결정적 업데이트를 허용하기 위해 순서자 org 및 합의 옵션의 사본을 인코딩하므로 순서 시스템 채널 구성의 동일한 Orderer 섹션이 포함됩니다. 그러나 응용 프로그램 관점에서 이것은 크게 무시될 수 있습니다.

채널 생성 ( Channel creation )

수행자가 존재하지 않는 채널에 대해  CONFIG_UPDATE를 수신하면, 순서자는 이것이 채널 작성 요구 여야한다고 가정하고 다음을 수행합니다.

  1. 발주자는 채널 생성 요청이 수행 될 컨소시엄을 식별합니다. 최상위 그룹의  Consortium 가치를 살펴봄으로써이를 수행합니다.
  2. 발주자는  Application 그룹에 포함 된 조직이 해당 컨소시엄에 포함 된 조직의 하위 집합이며 ApplicationGroup 이  version 1.로 설정되어 있는지 확인합니다.
  3. Orderer는 컨소시엄에 회원이있는 경우 새로운 채널에도 애플리케이션 회원 (생성 컨소시엄 및 멤버가없는 채널은 테스트에만 유용함)을 확인합니다.
  4. 주문자는 주문 시스템 채널에서 Orderer 그룹을 가져 와서 새로 지정된 멤버로 Application 그룹을 만들고 mod_policy를 컨소시엄 구성에 지정된대로 ChannelCreationPolicy로 지정하여 템플릿 구성을 만듭니다. 이 정책은 새로운 구성 컨텍스트에서 평가되므로 모든 구성원을 요구하는 정책에는 컨소시엄의 모든 구성원이 아닌 모든 새 채널 구성원의 서명이 필요합니다.
  5. 그러면 순서자는 CONFIG_UPDATE를이 템플리트 구성에 대한 갱신 사항으로 적용합니다. CONFIG_UPDATE가 응용 프로그램 그룹 (해당 버전은 1)에 수정 사항을 적용하기 때문에 구성 코드는 ChannelCreationPolicy에 대해 이러한 업데이트의 유효성을 검사합니다. 채널 생성시 개별 조직의 앵커 피어 (peer)와 같은 다른 수정 사항이 포함되어있는 경우 요소에 해당하는 mod 정책이 호출됩니다.
  6. 새 채널 구성을 사용하는 새로운 CONFIG 트랜잭션은 주문 시스템 채널에서 주문을 위해 포장되어 전송됩니다. 주문 후 채널이 생성됩니다.


채널 구성 ( Channel Configuration(configtxgen) )

이 문서는 fabric 채널 구성을 조작하기위한 configtxgen 유틸리티의 사용법을 설명합니다.

현재, 이 도구는 주문자를 부트 스트랩하기위한 기원 블록을 생성하는 데 주력하지만, 기존 채널을 다시 구성하는 것뿐만 아니라 새로운 채널 구성을 생성하기 위해 향후 향상 될 예정입니다.

구성 프로파일 ( Configuration Profiles )

configtxgen도구에 제공된 구성 매개 변수는 주로 configtx.yaml 파일에서 제공합니다. 이 파일은 fabric.git 저장소의 fabric/sampleconfig/configtx.yaml에 있습니다.

이 구성 파일은 주로 세 부분으로 나뉩니다.

  1. Profiles 섹션. 기본적으로 이 섹션에는 시나리오 개발 또는 테스트에 사용할 수있는 샘플 구성이 포함되어 있으며 fabric.git 트리에있는 암호화 자료를 참조하십시오. 이 프로파일은 실제 전개 프로파일을 구성하기위한 좋은 시작점이 될 수 있습니다. configtxgen 도구를 사용하면 -profile 플래그를 전달하여 작동중인 프로필을 지정할 수 있습니다. 프로필은 모든 구성을 명시적으로 선언 할 수 있지만 일반적으로 아래 (3)의 기본값에서 구성을 상속받습니다.
  2. Organizations 섹션. 기본적으로이 섹션에는 sampleconfig MSP 정의에 대한 단일 참조가 포함됩니다. 프로덕션 배포의 경우 샘플 조직을 제거해야하며 네트워크 구성원의 MSP 정의를 대신 참조하고 정의해야합니다. Organizations 섹션의 각 요소는  Profiles섹션에서 정의를 참조 할 수 있도록 &orgName과 같은 앵커 레이블로 태그를 지정해야합니다.
  3. 기본 섹션. Orderer 및 Application 구성에 대한 기본 섹션이 있으며 BatchTimeout과 같은 속성을 포함하며 일반적으로 프로파일의 기본 상속 값으로 사용됩니다.

이 구성 파일을 편집하거나 CONFIGTX_ORDERER_ORDERERTYPE=kafka와 같은 환경 변수를 설정하여 개별 등록 정보를 무시할 수 있습니다. Profiles 요소 및 프로필 이름은 지정하지 않아도 됩니다.

주문자를 부트스트랩하기 ( Bootstrapping the orderer )

원하는대로 구성 프로파일을 작성한 후, 간단히 호출하십시오

configtxgen -profile <profile_name>

그러면 현재 디렉토리에 genesis.block파일이 생성됩니다. 선택적으로 -path 매개 변수를 전달하여 다른 파일 이름을 지정하거나 단순히 파일 구문 분석을 테스트하려는 경우 dryRun 매개 변수를 전달하여 파일 쓰기를 건너 뛸 수 있습니다.

그런 다음이 시작 블록을 사용하려면 순서 지정자를 시작하기 전에 ORDERER_GENERAL_GENESISMETHOD=file 및 ORDERER_GENERAL_GENESISFILE=$PWD/genesis.block을 지정하거나이 값을 코드화하도록 orderer.yaml파일을 수정하십시오.

채널 만들기 ( Creating a channel )

이 도구는 또한 실행을 통해 채널 생성 tx를 출력 할 수 있습니다.

configtxgen -profile <profile_name> -channelID <channel_name> -outputCreateChannelTx <tx_filename>

이렇게하면 채널을 만들기 위해 브로드 캐스트로 보내질 수있는 마샬링 된 봉투 메시지가 출력됩니다.

구성 검토 ( Reviewing a configuration )

구성을 만드는 것 외에도 configtxgen 도구는 구성을 검사 할 수도 있습니다.

구성 블록 및 구성 트랜잭션을 모두 검사 할 수 있습니다. inspect 플래그 -inspectBlock  및 -inspectChannelCreateTx를 파일 경로로 사용하여 검사하여 구성의 사람이 읽을 수있는 (JSON) 표현을 출력할 수 있습니다.

아래의 예처럼 검사를 생성과 결합하고자 할 수도 있습니다.

$ build/bin/configtxgen -channelID foo -outputBlock foo.block -inspectBlock foo.block
2017/03/01 21:24:24 Loading configuration
2017/03/01 21:24:24 Checking for configtx.yaml at:
2017/03/01 21:24:24 Checking for configtx.yaml at:
2017/03/01 21:24:24 Checking for configtx.yaml at: /home/yellickj/go/src/github.com/hyperledger/fabric/common/configtx/tool
2017/03/01 21:24:24 map[orderer:map[BatchSize:map[MaxMessageCount:10 AbsoluteMaxBytes:99 MB PreferredMaxBytes:512 KB] Kafka:map[Brokers:[127.0.0.1:9092]] Organizations:<nil> OrdererType:solo Addresses:[127.0.0.1:7050] BatchTimeout:10s] application:map[Organizations:<nil>] profiles:map[SampleInsecureSolo:map[Orderer:map[BatchTimeout:10s BatchSize:map[MaxMessageCount:10 AbsoluteMaxBytes:99 MB PreferredMaxBytes:512 KB] Kafka:map[Brokers:[127.0.0.1:9092]] Organizations:<nil> OrdererType:solo Addresses:[127.0.0.1:7050]] Application:map[Organizations:<nil>]] SampleInsecureKafka:map[Orderer:map[Addresses:[127.0.0.1:7050] BatchTimeout:10s BatchSize:map[AbsoluteMaxBytes:99 MB PreferredMaxBytes:512 KB MaxMessageCount:10] Kafka:map[Brokers:[127.0.0.1:9092]] Organizations:<nil> OrdererType:kafka] Application:map[Organizations:<nil>]] SampleSingleMSPSolo:map[Orderer:map[OrdererType:solo Addresses:[127.0.0.1:7050] BatchTimeout:10s BatchSize:map[MaxMessageCount:10 AbsoluteMaxBytes:99 MB PreferredMaxBytes:512 KB] Kafka:map[Brokers:[127.0.0.1:9092]] Organizations:[map[Name:SampleOrg ID:DEFAULT MSPDir:msp BCCSP:map[Default:SW SW:map[Hash:SHA3 Security:256 FileKeyStore:map[KeyStore:<nil>]]] AnchorPeers:[map[Host:127.0.0.1 Port:7051]]]]] Application:map[Organizations:[map[Name:SampleOrg ID:DEFAULT MSPDir:msp BCCSP:map[Default:SW SW:map[Hash:SHA3 Security:256 FileKeyStore:map[KeyStore:<nil>]]] AnchorPeers:[map[Port:7051 Host:127.0.0.1]]]]]]] organizations:[map[Name:SampleOrg ID:DEFAULT MSPDir:msp BCCSP:map[Default:SW SW:map[Hash:SHA3 Security:256 FileKeyStore:map[KeyStore:<nil>]]] AnchorPeers:[map[Host:127.0.0.1 Port:7051]]]]]
2017/03/01 21:24:24 Generating genesis block
2017/03/01 21:24:24 Writing genesis block
2017/03/01 21:24:24 Inspecting block
2017/03/01 21:24:24 Parsing genesis block
Config for channel: foo
{
    "": {
        "Values": {},
        "Groups": {
            "/Channel": {
                "Values": {
                    "HashingAlgorithm": {
                        "Version": "0",
                        "ModPolicy": "",
                        "Value": {
                            "name": "SHA256"
                        }
                    },
                    "BlockDataHashingStructure": {
                        "Version": "0",
                        "ModPolicy": "",
                        "Value": {
                            "width": 4294967295
                        }
                    },
                    "OrdererAddresses": {
                        "Version": "0",
                        "ModPolicy": "",
                        "Value": {
                            "addresses": [
                                "127.0.0.1:7050"
                            ]
                        }
                    }
                },
                "Groups": {
                    "/Channel/Orderer": {
                        "Values": {
                            "ChainCreationPolicyNames": {
                                "Version": "0",
                                "ModPolicy": "",
                                "Value": {
                                    "names": [
                                        "AcceptAllPolicy"
                                    ]
                                }
                            },
                            "ConsensusType": {
                                "Version": "0",
                                "ModPolicy": "",
                                "Value": {
                                    "type": "solo"
                                }
                            },
                            "BatchSize": {
                                "Version": "0",
                                "ModPolicy": "",
                                "Value": {
                                    "maxMessageCount": 10,
                                    "absoluteMaxBytes": 103809024,
                                    "preferredMaxBytes": 524288
                                }
                            },
                            "BatchTimeout": {
                                "Version": "0",
                                "ModPolicy": "",
                                "Value": {
                                    "timeout": "10s"
                                }
                            },
                            "IngressPolicyNames": {
                                "Version": "0",
                                "ModPolicy": "",
                                "Value": {
                                    "names": [
                                        "AcceptAllPolicy"
                                    ]
                                }
                            },
                            "EgressPolicyNames": {
                                "Version": "0",
                                "ModPolicy": "",
                                "Value": {
                                    "names": [
                                        "AcceptAllPolicy"
                                    ]
                                }
                            }
                        },
                        "Groups": {}
                    },
                    "/Channel/Application": {
                        "Values": {},
                        "Groups": {}
                    }
                }
            }
        }
    }
}


configtxlator를 사용한 재구성 ( Reconfiguring with configtxlator )

개요 ( Overview )

이 configtxlator도구는 SDK와 독립적 인 재구성을 지원하기 위해 만들어졌습니다. 채널 구성은 채널의 구성 블록에 트랜잭션으로 저장되며 bdd 동작 테스트와 같이 직접 조작 할 수 있습니다. 그러나이 글을 쓰는 시점에서 SDK는 기본적으로 구성을 직접 조작 할 수 있도록 지원하지 않으므로 SDK의 configtxlator소비자가 구성 업데이트를 지원하기 위해 상호 작용할 수있는 API를 제공하도록 설계되었습니다.

툴 이름은 configtx 와 translator 의 portmanteau이며 툴은 서로 다른 데이터 표현을 간단하게 변환한다는 것을 알리기 위한 것입니다. 구성을 생성하지 않습니다. 구성을 제출하거나 검색하지 않습니다. 구성 자체는 수정하지 않고 configtx 형식의 서로 다른보기간에 일부 수동 작업을 제공합니다.

  1. SDK가 최신 설정을 가져옵니다.
  2. configtxlator는 사람이 읽을 수있는 버전의 config를 생성합니다.
  3. 사용자 또는 응용 프로그램이 구성을 편집합니다.
  4. configtxlator는 config에 대한 변경 사항의 구성 업데이트 표현을 계산하는 데 사용됩니다.
  5. SDK는 표지판을 제출하고 구성을 제출합니다.

이 configtxlator도구는 구성 요소와 상호 작용하기 위해 진정으로 상태 비 저장 REST API를 제공합니다. 이러한 REST 구성 요소는 기본 구성 형식을 사람이 읽을 수있는 JSON 표현으로 /에서 변환하거나 두 구성 간의 차이를 기반으로 구성 업데이트를 계산하도록 지원합니다.

때문에 configtxlator서비스가 의도적으로 어떤 암호화 소재, 또는 기타 비밀 정보를 포함하지 않는, 어떤 인증 또는 액세스 제어를 포함하지 않는다. 예상되는 일반적인 배포는 샌드 박스가있는 컨테이너로 응용 프로그램과 함께 로컬로 작동하므로 각 응용 프로그램에 대한 전용 configtxlator프로세스가 있습니다.

configtxlator 실행하기 ( Running the configtxlator )

이 configtxlator도구는 다른 Hyperledger 패브릭 플랫폼 별 바이너리와 함께 다운로드 할 수 있습니다. 자세한 내용은 다운로드 플랫폼 관련 바이너리 를 참조하십시오.

이 도구는 다른 포트에서 수신 대기하도록 구성 될 수 있으며 --portand --hostname플래그를 사용하여 호스트 이름을 지정할 수도 있습니다 . 완전한 명령 및 플래그 집합을 탐색하려면 실행하십시오 .configtxlator --help

바이너리는 지정된 포트에서 청취하는 http 서버를 시작하고 요청을 처리 할 준비가되었습니다.

configtxlator서버 를 시작하려면 다음과 같이하십시오.

configtxlator start
2017-06-21 18:16:58.248 HKT [configtxlator] startServer -> INFO 001 Serving HTTP requests on 0.0.0.0:7059

프로토 번역 ( Proto translation )

확장 성 및 특정 필드가 서명되어야하므로 많은 proto 필드가 바이트로 저장됩니다. 이것은 jsonpb 패키지를 사용하여 protobufs의 사람이 읽을 수있는 버전을 만드는 데 효과가없는 JSON 번역의 자연스러운 프로토 타입을 만듭니다. 대신 configtxlator는 REST 구성 요소를 노출하여보다 정교한 변환을 수행합니다.

proto를 사람이 읽을 수있는 JSON으로 변환하려면 나머지 대상http://$SERVER:$PORT/protolator/decode/<message.Name>에 바이너리 proto를 게시하십시오. 여기서 <message.Name>은 정규화 된 호스트입니다 메세지의 proto 명.

예를 들어,  configuration_block.pb로 저장된 구성 블록을 디코딩하려면 다음 명령을 실행하십시오.

curl -X POST --data-binary @configuration_block.pb http://127.0.0.1:7059/protolator/decode/common.Block

사람이 읽을 수있는 JSON 버전의 프로토 메시지를 변환하려면 JSON 버전을 http : // $ SERVER : $ PORT / protolator / encode / <message.Name에 게시하십시오. 여기서 <message.Name>은 다시 완전한 프로토 타입 이름입니다. 메시지의

예를 들어 configuration_block.json으로 저장된 블록을 다시 인코딩하려면 다음 명령을 실행합니다.

curl -X POST --data-binary @configuration_block.json http://127.0.0.1:7059/protolator/encode/common.Block

common.Block,common.Envelopecommon.ConfigEnvelopecommon.ConfigUpdateEnvelope,common.Config, 및 common.ConfigUpdate 를 비롯한 모든 구성 관련 프로토는 이러한 URL의 유효한 대상입니다. 앞으로 endorser 트랜잭션과 같은 다른 proto 디코딩 유형이 추가 될 수 있습니다.

구성 업데이트 계산 ( Config update computation )

두 개의 서로 다른 구성이 주어지면 두 구성간에 전환되는 구성 업데이트를 계산할 수 있습니다. 두 개의common.Config  프로토 인코딩 된 구성을 multipart/formdata로 게시하고 원본을 원래 필드로 업데이트하고 업데이트 된 필드는 http://$SERVER:$PORT/configtxlator/compute/update-from-configs로 업데이트합니다.

예를 들어 원본 구성을  original_config.pb파일로, 업데이트 된 구성을 채널 desiredchannel의  updated_config.pb파일로 지정하면 다음과 같습니다.

curl -X POST -F channel=desiredchannel -F original=@original_config.pb -F updated=@updated_config.pb http://127.0.0.1:7059/configtxlator/compute/update-from-configs

부트 스트랩 예제 ( Bootstraping example )

먼저 configtxlator를 시작하십시오.

$ configtxlator start
2017-05-31 12:57:22.499 EDT [configtxlator] main -> INFO 001 Serving HTTP requests on port: 7059

먼저 주문 시스템 채널에 대한 genesis 블록을 만듭니다.

$ configtxgen -outputBlock genesis_block.pb
2017-05-31 14:15:16.634 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-05-31 14:15:16.646 EDT [common/configtx/tool] doOutputBlock -> INFO 002 Generating genesis block
2017-05-31 14:15:16.646 EDT [common/configtx/tool] doOutputBlock -> INFO 003 Writing genesis block

genesis 블록을 사람이 편집 가능한 형식으로 디코딩 :

curl -X POST --data-binary @genesis_block.pb http://127.0.0.1:7059/protolator/decode/common.Block > genesis_block.json

즐겨 사용하는 JSON 편집기에서 genesis_block.json파일을 편집 하거나 프로그래밍 방식으로 조작하십시오. 여기에서는 JSON CLI  jq도구를 사용합니다. 간단히하기 위해 단일 숫자 필드이기 때문에 채널의 일괄 처리 크기를 편집하고 있습니다. 그러나 여기에서 정책 및 MSP 편집을 포함한 모든 편집 작업을 수행 할 수 있습니다.

먼저 json에서 속성에 대한 경로를 정의하는 문자열을 보관할 환경 변수를 설정해 보겠습니다.

export MAXBATCHSIZEPATH=".data.data[0].payload.data.config.channel_group.groups.Orderer.values.BatchSize.value.max_message_count"

다음으로, 해당 속성의 값을 표시합시다.

jq "$MAXBATCHSIZEPATH" genesis_block.json
10

이제 새 배치 크기를 설정하고 새 값을 표시합니다.

jq “$MAXBATCHSIZEPATH = 20” genesis_block.json >

updated_genesis_block.json jq “$MAXBATCHSIZEPATH”

updated_genesis_block.json 20

이제 genesis 블록을 원시 프로토 폼으로 다시 인코딩하여 부트 스트랩에 사용할 준비가되었습니다.

curl -X POST --data-binary @updated_genesis_block.json http://127.0.0.1:7059/protolator/encode/common.Block > updated_genesis_block.pb

이 updated_genesis_block.pb파일은 이제 주문 시스템 채널을 부트 스트랩하기위한 기원 블록으로 사용될 수 있습니다.

재구성 예제 ( Reconfiguration example )

다른 터미널 창에서 testchainid 주문 시스템 채널을 생성하는 임시 부트 스트 래퍼를 포함하여 기본 옵션을 사용하여 주문자를 시작하십시오 .

ORDERER_GENERAL_LOGLEVEL=debug orderer

채널을 재구성하는 것은 기원 설정을 수정하는 것과 매우 유사한 방법으로 수행 할 수 있습니다. 먼저 config_block proto를 가져옵니다.

$ peer channel fetch config config_block.pb -o 127.0.0.1:7050 -c testchainid
2017-05-31 15:11:37.617 EDT [msp] getMspConfig -> INFO 001 intermediate certs folder not found at [/home/yellickj/go/src/github.com/hyperledger/fabric/sampleconfig/msp/intermediatecerts]. Skipping.: [stat /home/yellickj/go/src/github.com/hyperledger/fabric/sampleconfig/msp/intermediatecerts: no such file or directory]
2017-05-31 15:11:37.617 EDT [msp] getMspConfig -> INFO 002 crls folder not found at [/home/yellickj/go/src/github.com/hyperledger/fabric/sampleconfig/msp/intermediatecerts]. Skipping.: [stat /home/yellickj/go/src/github.com/hyperledger/fabric/sampleconfig/msp/crls: no such file or directory]
Received block:  1
Received block:  1
2017-05-31 15:11:37.635 EDT [main] main -> INFO 003 Exiting.....

다음으로,디코딩 을 위해  configtxlator서비스에 config 블록을 보냅니다.

curl -X POST --data-binary @config_block.pb http://127.0.0.1:7059/protolator/decode/common.Block > config_block.json

블록에서 config 섹션을 추출합니다.

jq .data.data[0].payload.data.config config_block.json > config.json

구성을 편집하여 새  updated_config.json으로 저장하십시오. 여기서는 일괄 처리 크기를 30으로 설정합니다.

jq ".channel_group.groups.Orderer.values.BatchSize.value.max_message_count = 30" config.json  > updated_config.json

원래의 설정과 업데이트 된 설정을 모두 proto로 다시 인코딩하십시오.

curl -X POST --data-binary @config.json http://127.0.0.1:7059/protolator/encode/common.Config > config.pb
curl -X POST --data-binary @updated_config.json http://127.0.0.1:7059/protolator/encode/common.Config > updated_config.pb

이제, 두 설정이 적절하게 인코딩 된 상태에서  서비스로 보내 설정 업데이트를 계산합니다.

curl -X POST -F original=@config.pb -F updated=@updated_config.pb http://127.0.0.1:7059/configtxlator/compute/update-from-configs -F channel=testchainid > config_update.pb

이 시점에서 계산 된 구성 업데이트가 준비되었습니다. 전통적으로 SDK는이 메시지에 서명하고 래핑하는 데 사용됩니다. 그러나 피어 cli만을 사용하기 위해  를이 작업에 사용할 수도 있습니다.

먼저 텍스트로 작업 할 수 있도록 ConfigUpdate를 디코딩합니다.

$ curl -X POST --data-binary @config_update.pb http://127.0.0.1:7059/protolator/decode/common.ConfigUpdate > config_update.json

그런 다음 봉투 메시지로 포장합니다.

echo '{"payload":{"header":{"channel_header":{"channel_id":"testchainid", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' > config_update_as_envelope.json

그런 다음 원래의 완전한 구성 트랜잭션의 프로토 형식으로 다시 변환하십시오.

curl -X POST --data-binary @config_update_as_envelope.json http://127.0.0.1:7059/protolator/encode/common.Envelope > config_update_as_envelope.pb

마지막으로 구성 업데이트 트랜잭션을 주문에 제출하여 구성 업데이트를 수행합니다.

peer channel update -f config_update_as_envelope.pb -c testchainid -o 127.0.0.1:7050

조직 추가 ( Adding an organization )

먼저 configtxlator 시작:

$ configtxlator start
2017-05-31 12:57:22.499 EDT [configtxlator] main -> INFO 001 Serving HTTP requests on port: 7059

SampleDevModeSolo프로파일 옵션을 사용하여 주문자를 시작하십시오.

ORDERER_GENERAL_LOGLEVEL=debug ORDERER_GENERAL_GENESISPROFILE=SampleDevModeSolo orderer

그런 다음 조직을 추가하는 프로세스는 배치 크기 예제와 동일합니다. 그러나 배치 크기를 설정하는 대신 응용 프로그램 수준에서 새 조직을 정의합니다. 조직을 추가하려면 우선 채널을 만들어야하고 멤버십 집합을 수정해야하기 때문에 약간 더 복잡합니다.


승인 정책 ( Endorsement policies )

승인 정책은 거래가 제대로 승인되었는지 여부를 결정하는 방법을 동료에게 지시하는 데 사용됩니다. 피어가 트랜잭션을 수신하면 트랜잭션 유효성 검증 플로우의 일부로 트랜잭션의 체인 코드와 연관된 VSCC (Validation System Chaincode)를 호출하여 트랜잭션의 유효성을 판별합니다. 거래가 많은지지하는 피어로부터 하나 이상의 추천을 포함한다는 것을 상기하십시오. VSCC는 다음과 같은 결정을해야합니다. - 모든 보증 항목이 유효합니다. 즉, 예상 메시지에 대한 유효한 인증서의 유효한 서명입니다. - 적절한 수의 보증이 있습니다. 예상 소스에서 보증을받습니다.

승인 정책은 두 번째 및 세 번째 사항을 지정하는 방법입니다.

추천 정책 설계 ( Endorsement policy design )

승인 정책에는 두 가지 주요 구성 요소가 있습니다. - 주체 - 임계 게이트

principal P 는 서명이 예상되는 엔티티를 식별합니다.

임계 게이트 T는 두 개의 입력, 즉 정수 t (임계 값) 및 n주체 또는 게이트의리스트를 취한다. 이 게이트는 근본적으로 그 n 주체나 게이트에서 t가 만족 될 것을 요구 받는다는 기대를 포착한다.

예를 들면 다음과 같습니다. -T(2, 'A', 'B', 'C') 는 'A', 'B'또는 'C'중 두 명의 주체로부터 서명을 요청합니다. - T(1, 'A', T(2, 'B', 'C')) 는 주된 A로부터 하나의 서명을 요구하거나 B 와 C로부터 각각 하나의 서명을 요구한다.

CLI의 승인 정책 구문 ( Endorsement policy syntax in the CLI )

CLI에서는 간단한 언어를 사용하여 원칙에 대한 부울 표현에 대한 정책을 표현합니다.

주체는 서명자의 신원을 확인하고 서명자가 해당 MSP 내에서 갖는 역할을 확인하는 임무가있는 MSP와 관련하여 설명됩니다. 현재 member와 admin이라는 두 가지 역할이 지원됩니다. 주체는 MSP.ROLE, 로 설명됩니다. 여기서 MSP는 필수 MSP ID이고 ROLE은 두 개의 문자열 member와 admin 중 하나입니다. 유효한 주체의 예로는 'Org0.admin' (Org0  MSP의 관리자) 또는 'Org1.member' (Org1MSP의 모든 구성원)가 있습니다.

언어 구문은 다음과 같습니다.

EXPR(E[, E...])

EXPR은 두 개의 부울 표현식을 나타내는  AND 또는 OR이고 E는 프린시 펄 (위에 설명 을 참고) 또는 EXPR에 대한 다른 중첩 호출입니다.

예를 들면 다음과 같습니다. - AND ( 'Org1.member', 'Org2.member', 'Org3.member')는 세 가지 주체 각각에서 1 개의 서명을 요청합니다. - OR ( 'Org1.member', 'Org2.member') 요청 1 OR ( 'Org1.member', AND ( 'Org2.member', 'Org3.member'))는 Org1 MSP의 멤버로부터 하나의 서명을 요구하거나 또는 Org1 MSP의 멤버로부터 하나의 서명을 요청합니다. Org2 MSP 및 Org3 MSP 구성원의 서명 1 개.

체인 코드에 대한 보증 정책 지정 ( Specifying endorsement policies for a chaincode )

체인 코드 배포자는이 언어를 사용하여 지정된 정책에 대해 체인 코드의 인증을 확인하도록 요청할 수 있습니다. 참고 - 기본 정책에는 DEFAULT MSP 구성원의 서명이 하나 필요합니다. 이 정책은 CLI에서 정책을 지정하지 않은 경우에 사용됩니다.

정책은 배포시 -P 스위치를 사용하여 정책을 지정한 다음 지정할 수 있습니다.

예를 들면,

peer chaincode deploy -C testchainid -n mycc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Args":["init","a","100","b","200"]}' -P "AND('Org1.member', 'Org2.member')"

이 명령은 AND('Org1.member', 'Org2.member')정책으로 체인 testchainid에 체인코드 mycc를 배포합니다.

향후 개선 사항 ( Future enhancements )

이 섹션에서 우리는 승인 정책에 대한 향후 개선 사항을 목록 : -에는 MSP와의 관계에서 사용자를 식별하는 기존의 방법과 함께, 우리는 자신의 인증서에서 예상되는 조직 단위 (OU)의 측면에서 사용자를 식별 할 계획; 이는 주체 정의에서 요청한 것과 일치하는 OU를 가진 유효한 인증서를 표시하는 ID의 서명을 요청하는 정책을 표현할 때 유용합니다. - AND(., .) 구문 대신에 더 직관적 인 구문으로 이동할 계획입니다. AND . - 우리는 일반화된 임계값 게이트를 AND (n-out-of-n gate) 및 OR (1-out-of-n gate)와 함께 언어로 노출할 계획입니다.

오류 처리 ( Error handling )

일반 개요 ( General Overview )

패브릭 오류 처리 프레임 워크는 패브릭 저장소에서 자료공유오류가 아래에 있습니다. Go에서 제공하는 표준 오류 유형 대신 사용할 새로운 유형의 오류 CallStackError를 정의합니다.

CallStackError는 다음으로 구성됩니다.

  • Component code - 오류를 생성하는 코드의 일반 영역 이름입니다. 구성 요소 코드는 세 개의 대문자로 구성되어야합니다. 수와 특수 문자는 허용되지 않습니다. 구성 요소 코드 세트는 common / errors / codes.go에 정의되어 있습니다.
  • Reason code -- 오류가 발생한 이유를 식별하는 데 도움이되는 짧은 코드입니다. 이유 코드는 세 개의 숫자 값으로 구성되어야합니다. 문자와 특수 문자는 사용할 수 없습니다. 일련의 이유 코드는 common / error / codes.go에 정의되어 있습니다.
  • Error code - 콜론으로 구분 된 구성 요소 코드 및 원인 코드입니다 (예 : MSP : 404
  • Error message - 오류를 설명하는 텍스트 이는 fmt.Errorf()과 Errors.New()에 제공된 입력과 동일합니다. 오류가 현재 오류에 랩핑 된 경우 메시지가 추가됩니다.
  • Callstack - 오류가 생성 될 때 호출 스택입니다. 오류가 현재 오류에 랩핑 된 경우 오류 메시지 및 콜 스택이 추가되어 랩핑 된 오류의 컨텍스트를 유지합니다.

CallStackError 인터페이스는 다음과 같은 기능을 제공합니다.

  • Error () - callstack이 추가 된 오류 메시지를 반환합니다.
  • Message () - 오류 메시지를 반환합니다 (콜 스택이 추가되지 않음).
  • GetComponentCode () - 3 문자 구성 요소 코드를 반환합니다.
  • GetReasonCode () - 3 자리 이유 코드를 반환합니다.
  • GetErrorCode () - "component : reason"오류 코드를 반환합니다.
  • GetStack () - 콜 스택 만 반환합니다.
  • WrapError (error) - 제공된 오류를 CallStackError로 랩핑합니다.

사용 지침 ( Usage Instructions )

fmt.Errorf() or Errors.new()에 대한 모든 호출 대신 새로운 오류 처리 프레임 워크를 사용해야합니다. 이 프레임 워크를 사용하면 오류 메시지에 추가 할 호출 스택을 생성하는 옵션과 함께 확인할 오류 코드가 제공됩니다.

프레임 워크를 사용하는 것은 간단하며 코드를 쉽게 조정할 수 있습니다.

먼저 github.com/hyperledger/fabric/common/errors를이 프레임 워크를 사용하는 파일로 가져와야합니다.

core / chaincode / chaincode_support.go에서 다음을 예로 들어 보겠습니다.

err = fmt.Errorf("Error starting container: %s", err)

이 오류의 경우 오류에 대한 생성자를 호출하고 구성 요소 코드, 이유 코드 및 오류 메시지를 전달합니다. 마지막에는 오류 자체를 전달하면서 WrapError () 함수를 호출합니다.

fmt.Errorf("Error starting container: %s", err)

호출하면, 아래와 같이 나옵니다.

errors.ErrorWithCallstack("CHA", "505", "Error starting container").WrapError(err)

아무런 문제없이 그대로 메시지를 남길 수도 있습니다.

errors.ErrorWithCallstack("CHA", "505", "Error starting container: %s", err)

이 방법을 사용하면 이전 오류의 오류 메시지를 새 오류로 형식화 할 수 있지만 포장 된 오류가 CallStackError 인 경우에는 호출 스택을 인쇄 할 수 없습니다.

오류를 래핑하는 동안 오류 이외의 매개 변수에 대한 명령의 서식을 지정하는 시나리오를 강조 표시하는 두 번째 예는 다음과 같습니다.

fmt.Errorf("failed to get deployment payload %s - %s", canName, err)

호출하면, 아래와 같이 나옵니다.

errors.ErrorWithCallstack("CHA", "506", "Failed to get deployment payload %s", canName).WrapError(err)

오류 메시지 표시 ( Displaying error message )

프레임 워크를 사용하여 오류를 만든 후에 오류 메시지를 표시하는 것은 다음과 같이 간단합니다.

logger.Errorf(err)

또는

fmt.Println(err)

또는

fmt.Printf("%s\n", err)

peer / common / common.go의 예 :

errors.ErrorWithCallstack("PER", "404", "Error trying to connect to local peer").WrapError(err)

오류 메시지가 표시됩니다.

PER:404 - Error trying to connect to local peer
Caused by: grpc: timed out when dialing

노트

  • 콜 스택은 간결함을 위해 이 예에서는 표시되지 않았습니다.

Fabric의 오류 처리에 대한 일반 지침 ( General guidelines for error handling in Fabric )

  • 최선을 다하고있는 일이라면 오류를 기록하고 무시해야합니다.
  • 사용자 요청을 처리하는 중이면 오류를 기록하고이를 반환해야합니다.
  • 패브릭의 다른 곳에서 오류가 발생하면 오류를 감싸는 지 여부를 선택할 수 있습니다. 일반적으로 오류를 래핑하지 않고 그대로 반환하는 것이 가장 좋습니다. 그러나 유틸리티 함수가 호출되는 특정 경우에 오류를 새로운 구성 요소 및 이유 코드로 래핑하면 최종 사용자가 호출 스택을 검사하지 않고 오류가 실제로 발생한 위치를 파악하는 데 도움이됩니다.
  • 패닉은 내부 오류 코드를 던지거나 복구 프로세스를 시작하여 같은 계층에서 처리해야하며 다른 패키지로 전파 할 수 없어야합니다.


로깅 제어 ( Logging Control )

개요 ( Overview )

peer 응용 프로그램 및 shim 인터페이스에서 체인 코드 로깅은 github.com/op/go-logging 패키지에서 제공하는 기능을 사용하여 프로그래밍됩니다. 이 패키지는 아래와 같은 사항을 지원합니다.

  • 메시지의 심각도를 기반으로 로깅 제어
  • 메시지를 생성하는 소프트웨어 모듈을 기반으로 한 로깅 제어
  • 메시지의 심각도를 기반으로 한 다양한 프리티-프린트 옵션

모든 로그는 현재 stderr로 보내지고, 프리티-프린트는 현재 수정되었습니다. 그러나 심각도 별 로깅의 전역 및 모듈 수준 제어는 사용자와 개발자 모두에게 제공됩니다. 현재 각 심각도 수준에서 제공되는 정보 유형에 대한 공식화 된 규칙은 없지만 버그 보고서를 제출할 때 개발자는 전체 로그를 DEBUG 수준으로 보고 싶어할 수 있습니다.

프리티 프린트된 로그에서 로깅 수준은 색상과 4 문자 코드로 표시됩니다 (예 : ERROR에 ERRO, DEBU에 DEBUG 등). 로깅 컨텍스트에서 모듈은 임의의 이름 (문자열)입니다. 개발자가 관련 메시지 그룹에 제공합니다. 아래의 예에서, "peer", "rest"및 "main"로깅 모듈은 로그를 생성합니다.

16:47:09.634 [peer] GetLocalAddress -> INFO 033 Auto detected peer address: 9.3.158.178:7051
16:47:09.635 [rest] StartOpenchainRESTServer -> INFO 035 Initializing the REST service...
16:47:09.635 [main] serve -> INFO 036 Starting peer with id=name:"vp1" , network id=dev, address=9.3.158.178:7051, discovery.rootnode=, validator=true

런타임에 임의의 수의 로깅 모듈을 만들 수 있으므로 모듈의 "마스터 목록"이없고 로깅 제어 구조가 로깅 모듈이 실제로 존재하는지 또는 존재하는지 여부를 확인할 수 없습니다. 또한 로깅 모듈 시스템은 계층 구조 또는 와일드 카드를 이해하지 못합니다. 코드에 "foo / bar"와 같은 모듈 이름이 표시 될 수 있지만 로깅 시스템에는 플랫 문자열 만 표시됩니다. "foo / bar"는 어떤 식 으로든 "foo"와 관련되거나 "foo / *"는 foo의 모든 "하위 모듈"을 나타낼 수 있다는 것을 이해하지 못합니다.

피어 ( peer )

피어 명령의 로깅 수준은 --logging-level 플래그를 사용하여 각 호출에 대해 명령 줄에서 제어 할 수 있습니다. 예를 들면,

peer node start --logging-level=debug

각 개별 피어 부속 명령의 기본 로깅 레벨은 core.yaml 파일에서 설정할 수도 있습니다. 예를 들어, 키 logging.node는 노드 서브 컴 맨드의 기본 레벨을 설정합니다. 이 파일의 주석은 환경 변수를 사용하여 다양한 수준에서 로깅 수준을 재정의하는 방법을 설명합니다.

로깅 심각도 수준은 다음에서 선택된 대 / 소문자를 구분하지 않는 문자열을 사용하여 지정됩니다.

CRITICAL | ERROR | WARNING | NOTICE | INFO | DEBUG

피어의 전체 로깅 수준 사양은 다음과 같습니다.

[<module>[,<module>...]=]<level>[:[<module>[,<module>...]=]<level>...]

로깅 수준 자체가 전체 기본값으로 간주됩니다. 그렇지 않으면 모듈의 개별 또는 그룹에 대한 재정의는 다음을 사용하여 지정할 수 있습니다.

<module>[,<module>...]=<level>

통사론. 사양의 예 (--logging-level, 환경 변수 및 core.yaml 설정 모두에 유효) :

info                                       - Set default to INFO
warning:main,db=debug:chaincode=info       - Default WARNING; Override for main,db,chaincode
chaincode=info:main=debug:db=debug:warning - Same as above

Go 체인코드 ( Go chaincodes )

체인 코드 어플리케이션 내에서 로그하는 표준 메커니즘은 피어를 통해 각 체인 코드 인스턴스에 노출 된 로깅 전송과 통합하는 것입니다. chaincode shim 패키지는 체인 코드가 로그를 형식화하고 shim 로그와 일관되게 인터리브되는 로깅 객체를 만들고 관리 할 수있게 해주는 API를 제공합니다.

독자적으로 실행되는 프로그램으로서 사용자가 제공하는 체인 코드는 기술적으로 stdout / stderr에 출력을 생성 할 수도 있습니다. 자연적으로 "devmode"에 유용하지만 일반적으로 프로덕션 네트워크에서는 이러한 채널이 손상되어 악성 코드의 악용을 방지합니다. 그러나 CORE_VM_DOCKER_ATTACHSTDOUT = true 구성 옵션을 통해 피어 (peer)가 관리하는 컨테이너 (예 : "netmode")의 경우에도이 출력을 피어 단위로 활성화 할 수 있습니다.

활성화되면 각 체인 코드는 container-id에 의해 자체 로깅 채널을 받게됩니다. stdout 또는 stderr에 기록 된 출력은 각 행마다 피어의 로그와 통합됩니다. 프로덕션 환경에서이를 활성화하는 것은 권장되지 않습니다.

API

NewLogger(name string) *ChaincodeLogger - 체인 코드에서 사용할 로깅 개체 만들기

(c *ChaincodeLogger) SetLevel(level LoggingLevel) - 로거의 로깅 수준 설정

(c *ChaincodeLogger) IsEnabledFor(level LoggingLevel) bool - 지정된 레벨로 로그가 생성되는 경우는 true를 리턴

LogLevel(levelString string) (LoggingLevel, error) - 문자열을  LoggingLevel 로 변환

LoggingLevel은 열거 형의 멤버입니다.

LogDebug, LogInfo, LogNotice, LogWarning, LogError, LogCritical

대 / 소문자를 구별하지 않는 버전의 문자열을 전달하여 직접 사용할 수 있습니다.

DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL

다양한 심각도 레벨에서의 형식화 된 로깅은 함수에 의해 제공됩니다.

(c *ChaincodeLogger) Debug(args ...interface{})
(c *ChaincodeLogger) Info(args ...interface{})
(c *ChaincodeLogger) Notice(args ...interface{})
(c *ChaincodeLogger) Warning(args ...interface{})
(c *ChaincodeLogger) Error(args ...interface{})
(c *ChaincodeLogger) Critical(args ...interface{})

(c *ChaincodeLogger) Debugf(format string, args ...interface{})
(c *ChaincodeLogger) Infof(format string, args ...interface{})
(c *ChaincodeLogger) Noticef(format string, args ...interface{})
(c *ChaincodeLogger) Warningf(format string, args ...interface{})
(c *ChaincodeLogger) Errorf(format string, args ...interface{})
(c *ChaincodeLogger) Criticalf(format string, args ...interface{})

f 형식의 로깅 API는 로그의 형식을 정확하게 제어합니다. non-f 형식의 API는 현재 인수의 인쇄 표현 사이에 공백을 삽입하고 임의로 사용할 형식을 선택합니다.

현재 구현에서 shim 및 ChaincodeLogger에 의해 생성 된 로그에는 타임 스탬프가 지정되고 로거 이름 및 심각도 수준으로 표시되어 stderr에 기록됩니다. 로깅 레벨 컨트롤은 현재 ChaincodeLogger가 생성 될 때 제공된 이름을 기반으로합니다. 모호함을 피하기 위해 모든 ChaincodeLogger에는 "shim"이외의 고유 한 이름을 지정해야합니다. 로거 이름은 로거에 의해 작성된 모든 로그 메시지에 나타납니다. shim은 "심"으로 기록됩니다.

Go 언어 체인 코드는 SetLoggingLevel API를 통해 체인 코드shim 인터페이스의 로깅 수준을 제어 할 수도 있습니다.

SetLoggingLevel(LoggingLevel level) - 심의 로깅 수준 제어

shim의 기본 로깅 수준은 LogDebug입니다.

다음은 체인 코드가 LogInfo 레벨에서 로깅하는 개인 로깅 오브젝트를 작성하는 방법과 환경 변수를 기반으로 shim이 제공하는 로깅의 양을 제어하는 간단한 예제입니다.

var logger = shim.NewLogger("myChaincode")

func main() {

    logger.SetLevel(shim.LogInfo)

    logLevel, _ := shim.LogLevel(os.Getenv("SHIM_LOGGING_LEVEL"))
    shim.SetLoggingLevel(logLevel)
    ...
}